Thank you for your interest in contributing to OxiRS! This document provides guidelines and instructions for contributing to the project.
- Code of Conduct
- Getting Started
- Development Workflow
- Coding Standards
- Testing Guidelines
- Documentation
- Pull Request Process
- RFC Process
- Release Process
OxiRS adheres to the Rust Code of Conduct. By participating in this project, you agree to abide by its terms.
- Rust: 1.70+ (MSRV - Minimum Supported Rust Version)
- Development Tools:
cargo-nextestfor testingcargo-clippyfor lintingrustfmtfor code formattingcargo-denyfor dependency checks (optional)
# Clone the repository
git clone https://github.com/cool-japan/oxirs.git
cd oxirs
# Run setup script
./scripts/setup-dev.sh
# Build the project
cargo build --workspace
# Run tests
cargo nextest run --no-fail-fastgit checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-number-description- Follow the coding standards below
- Add tests for new functionality
- Update documentation as needed
- Ensure all tests pass
We use Conventional Commits for commit messages:
feat: add SPARQL 1.2 aggregation support
fix: resolve memory leak in triple store
docs: update README with new examples
test: add integration tests for federation
refactor: simplify query optimizer logic
perf: optimize triple pattern matching
Sign off your commits using the -s flag (DCO 1.1):
git commit -s -m "feat: add new feature"git push origin feature/your-feature-nameThen create a pull request on GitHub.
-
Formatting: Use
rustfmtwith default settingscargo fmt --all
-
Linting: Pass all
clippycheckscargo clippy --workspace --all-targets -- -D warnings
-
Naming Conventions:
- Variables/functions:
snake_case - Types/traits:
PascalCase - Constants:
SCREAMING_SNAKE_CASE - Modules:
snake_case
- Variables/functions:
- File Size: Keep files under 2000 lines. Use SplitRS for refactoring large files
- Module Structure: Follow the existing module hierarchy
- Imports: Group and order imports logically
// Standard library use std::collections::HashMap; // External crates use anyhow::Result; use serde::{Deserialize, Serialize}; // Internal crates use oxirs_core::Triple; // Local modules use crate::error::FusekiError;
OxiRS uses the SciRS2 scientific computing library instead of direct rand or ndarray usage:
// ❌ WRONG
use ndarray::Array2;
use rand::thread_rng;
// ✅ CORRECT
use scirs2_core::ndarray_ext::Array2;
use scirs2_core::random::rng;See CLAUDE.md for full SciRS2 integration guidelines.
- Use
anyhow::Resultfor application code - Use
thiserrorfor library error types - Provide context with
.context()or.with_context() - Document error conditions in function docs
use anyhow::{Context, Result};
fn load_config(path: &Path) -> Result<Config> {
std::fs::read_to_string(path)
.context("Failed to read config file")?
.parse()
.context("Failed to parse config")
}- Aim for 95%+ test coverage
- Write unit tests for all public APIs
- Add integration tests for cross-module functionality
- Include property-based tests using
proptestwhere appropriate
# Run all tests
cargo nextest run --no-fail-fast
# Run tests for a specific crate
cargo nextest run -p oxirs-core
# Run with all features
cargo nextest run --all-features
# Run specific test
cargo nextest run test_name#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_functionality() {
// Arrange
let input = create_test_input();
// Act
let result = function_under_test(input);
// Assert
assert_eq!(result, expected);
}
#[test]
fn test_error_case() {
let result = function_that_should_fail();
assert!(result.is_err());
}
}Add benchmarks for performance-critical code using criterion:
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn benchmark_query(c: &mut Criterion) {
c.bench_function("sparql_select", |b| {
b.iter(|| execute_query(black_box(&query)))
});
}
criterion_group!(benches, benchmark_query);
criterion_main!(benches);- Add doc comments to all public items
- Include examples in doc comments
- Document panics, errors, and safety requirements
/// Executes a SPARQL query against the RDF store.
///
/// # Arguments
///
/// * `query` - The SPARQL query string to execute
/// * `dataset` - The dataset to query against
///
/// # Returns
///
/// Returns the query results or an error if the query is invalid.
///
/// # Examples
///
/// ```
/// use oxirs_core::Store;
///
/// let store = Store::new();
/// let results = store.query("SELECT * WHERE { ?s ?p ?o }")?;
/// # Ok::<(), anyhow::Error>(())
/// ```
///
/// # Errors
///
/// Returns an error if:
/// - The query syntax is invalid
/// - The dataset is not accessible
/// - An I/O error occurs
pub fn execute_query(query: &str, dataset: &Dataset) -> Result<QueryResults> {
// Implementation
}- Update README.md for user-facing changes
- Add entries to CHANGELOG.md following Keep a Changelog
- Create RFCs for major features (see RFC Process below)
- ✅ All tests pass (
cargo nextest run --no-fail-fast) - ✅ Code is formatted (
cargo fmt --all --check) - ✅ No clippy warnings (
cargo clippy --workspace --all-targets -- -D warnings) - ✅ Documentation is updated
- ✅ CHANGELOG.md is updated (if applicable)
Include in your PR description:
- Summary: What does this PR do?
- Motivation: Why is this change needed?
- Testing: How was this tested?
- Breaking Changes: List any breaking changes
- Related Issues: Link to related issues
- At least one maintainer approval required
- All CI checks must pass
- Address review comments promptly
- Keep PRs focused and reasonably sized
- PRs are squash-merged to maintain clean history
- Commit message follows Conventional Commits
- Delete branch after merge
For significant changes, submit an RFC (Request for Comments):
- New major features
- Breaking API changes
- Architectural changes
- New module additions
-
Create a file in
rfcs/directory:rfcs/YYYY-MM-DD-feature-name.md -
RFC Template:
# RFC: Feature Name **Author**: Your Name **Date**: YYYY-MM-DD **Status**: Draft | Under Review | Accepted | Rejected ## Summary One-paragraph explanation of the feature. ## Motivation Why are we doing this? What use cases does it support? ## Design Detailed technical design. ## Alternatives What other designs were considered? ## Unresolved Questions What questions remain?
-
Submit PR with RFC
-
14-day comment window
-
Lazy consensus (accepted unless objections)
-
Implementation follows after acceptance
OxiRS follows Semantic Versioning:
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
Versions are managed at the workspace level in the root Cargo.toml:
[workspace.package]
version = "0.2.3"- Update CHANGELOG.md
- Update version in Cargo.toml
- Run full test suite
- Update documentation
- Create git tag
- Publish to crates.io (maintainers only)
- Create GitHub release
For files exceeding 2000 lines:
splitrs --input src/large_file.rs \
--output src/large_file/ \
--split-impl-blocks \
--max-impl-lines 200# Check for outdated dependencies
cargo outdated
# Security audit
cargo audit
# Generate documentation
cargo doc --workspace --all-features --no-deps --open
# Check code coverage (requires cargo-tarpaulin)
cargo tarpaulin --workspace --all-features
# Profile tests
cargo nextest run --profile ciRecommended extensions for VS Code:
- rust-analyzer
- Even Better TOML
- Error Lens
- GitLens
- Issues: Open an issue on GitHub
- Discussions: Use GitHub Discussions for questions
- Chat: Join our community (link TBD)
By contributing to OxiRS, you agree that your contributions will be licensed under the Apache-2.0 license.
Contributors are recognized in:
- CHANGELOG.md (for significant contributions)
- GitHub contributors page
- Release notes
Thank you for contributing to OxiRS! 🚀