diff --git a/.github/mlc_config.json b/.github/mlc_config.json new file mode 100644 index 0000000..d74c272 --- /dev/null +++ b/.github/mlc_config.json @@ -0,0 +1,23 @@ +{ + "ignorePatterns": [ + { + "pattern": "^http://localhost" + }, + { + "pattern": "^https://localhost" + } + ], + "replacementPatterns": [], + "httpHeaders": [ + { + "urls": ["https://crates.io", "https://docs.rs"], + "headers": { + "User-Agent": "Mozilla/5.0 (compatible; link-checker)" + } + } + ], + "timeout": "10s", + "retryOn429": true, + "retryCount": 3, + "fallbackHttpStatus": [400, 401, 403, 404, 429, 500, 502, 503, 504] +} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cd4878b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,112 @@ +name: CI + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - beta + - nightly + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Check formatting + if: matrix.rust == 'stable' + run: cargo fmt --all -- --check + + - name: Run clippy + if: matrix.rust == 'stable' + run: cargo clippy --all-targets --all-features -- -D warnings + + - name: Build + run: cargo build --verbose --all-features + + - name: Run tests + run: cargo test --verbose --all-features + + - name: Test CLI + run: | + cargo run -- --help + cargo run -- check --help + cargo run -- rules + + coverage: + name: Coverage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: Generate code coverage + run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: lcov.info + fail_ci_if_error: true + + security: + name: Security Audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install cargo-audit + run: cargo install cargo-audit + + - name: Run security audit + run: cargo audit + + minimal-versions: + name: Minimal Versions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@nightly + + - name: Install minimal-versions + run: cargo install cargo-minimal-versions + + - name: Check minimal versions + run: cargo minimal-versions check \ No newline at end of file diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..0b2f7ed --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,95 @@ +name: Documentation + +on: + push: + branches: [ main ] + paths: + - 'src/**' + - 'README.md' + - 'Cargo.toml' + - 'examples/**' + pull_request: + branches: [ main ] + paths: + - 'src/**' + - 'README.md' + - 'Cargo.toml' + - 'examples/**' + +env: + CARGO_TERM_COLOR: always + +jobs: + doc-tests: + name: Documentation Tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Test documentation examples + run: cargo test --doc --all-features + + - name: Build documentation + run: | + cargo doc --all-features --no-deps + # Check that docs build without warnings + cargo doc --all-features --no-deps 2>&1 | tee doc-warnings.txt + if grep -q "warning:" doc-warnings.txt; then + echo "Documentation has warnings!" + cat doc-warnings.txt + exit 1 + fi + + - name: Check README examples + run: | + # Extract and test code examples from README + echo "Checking README examples compile..." + # This is a basic check - in practice you might want more sophisticated validation + + check-links: + name: Check Documentation Links + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Check links in README + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' + use-verbose-mode: 'yes' + config-file: '.github/mlc_config.json' + + validate-metadata: + name: Validate Package Metadata + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Check package metadata + run: | + # Verify all required metadata is present for crates.io + echo "Checking package metadata..." + cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "rust-guardian") | {name, version, description, license, repository, documentation, keywords, categories}' + + # Verify the package can be packaged (list files) + cargo package --list --allow-dirty \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d8d49cc --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,160 @@ +name: Release + +on: + push: + tags: + - 'v*' + +env: + CARGO_TERM_COLOR: always + +jobs: + pre-release-checks: + name: Pre-release Checks + runs-on: ubuntu-latest + outputs: + version: ${{ steps.get_version.outputs.version }} + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Get version from tag + id: get_version + run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Verify version matches Cargo.toml + run: | + CARGO_VERSION=$(grep "^version = " Cargo.toml | sed 's/version = "\(.*\)"/\1/') + if [ "$CARGO_VERSION" != "${{ steps.get_version.outputs.version }}" ]; then + echo "Version mismatch: Cargo.toml has $CARGO_VERSION but tag is ${{ steps.get_version.outputs.version }}" + exit 1 + fi + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Run clippy + run: cargo clippy --all-targets --all-features -- -D warnings + + - name: Build + run: cargo build --verbose --all-features + + - name: Run tests + run: cargo test --verbose --all-features + + - name: Test CLI functionality + run: | + cargo run -- --help + cargo run -- check --help + cargo run -- rules + + publish-crates-io: + name: Publish to crates.io + needs: pre-release-checks + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Publish to crates.io + run: cargo publish --token ${{ secrets.CRATES_TOKEN }} + + create-github-release: + name: Create GitHub Release + needs: [pre-release-checks, publish-crates-io] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Build release binaries + run: | + # Build for different targets + cargo build --release --all-features + + # Create release directory + mkdir -p release-artifacts + + # Copy binary and create archive + cp target/release/rust-guardian release-artifacts/ + tar -czf release-artifacts/rust-guardian-${{ needs.pre-release-checks.outputs.version }}-x86_64-unknown-linux-gnu.tar.gz -C release-artifacts rust-guardian + + # Generate checksums + cd release-artifacts + sha256sum * > checksums.txt + + - name: Generate changelog + id: changelog + run: | + # Try to get changelog from git log since last tag + PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + if [ -n "$PREVIOUS_TAG" ]; then + echo "## Changes since $PREVIOUS_TAG" > CHANGELOG.md + git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..HEAD >> CHANGELOG.md + else + echo "## Release ${{ needs.pre-release-checks.outputs.version }}" > CHANGELOG.md + echo "Initial release of rust-guardian" >> CHANGELOG.md + fi + + # Add installation instructions + echo "" >> CHANGELOG.md + echo "## Installation" >> CHANGELOG.md + echo "" >> CHANGELOG.md + echo "\`\`\`bash" >> CHANGELOG.md + echo "cargo install rust-guardian" >> CHANGELOG.md + echo "\`\`\`" >> CHANGELOG.md + echo "" >> CHANGELOG.md + echo "## Documentation" >> CHANGELOG.md + echo "" >> CHANGELOG.md + echo "- [Crates.io](https://crates.io/crates/rust-guardian)" >> CHANGELOG.md + echo "- [Documentation](https://docs.rs/rust-guardian)" >> CHANGELOG.md + echo "- [Repository](https://github.com/cloudfunnels/rust-guardian)" >> CHANGELOG.md + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ needs.pre-release-checks.outputs.version }} + name: Release v${{ needs.pre-release-checks.outputs.version }} + body_path: CHANGELOG.md + files: | + release-artifacts/*.tar.gz + release-artifacts/checksums.txt + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index f740324..de0fdcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Rust build artifacts -/target/ +/target +Cargo.lock # IDE files .vscode/ @@ -20,9 +21,21 @@ Thumbs.db # Log files *.log +# Environment files +.env +.env.local + +# Coverage reports +tarpaulin-report.html +lcov.info +coverage/ + +# Benchmark results +target/criterion/ + # Temporary files *.tmp *.temp # Guardian specific -guardian-report.* \ No newline at end of file +guardian-report.* diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ed838..57efc92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.1.0] - 2024-08-10 +### Added +- GitHub Actions workflows for CI/CD and automated publishing +- Automated release process with version verification +- Documentation validation workflows +- Security audit integration in CI +- Code coverage reporting +- Release documentation and guidelines + +### Changed +- Improved project structure for crates.io publishing + +## [0.1.0] - TBD ### Added -- Initial release of Rust Guardian +- Initial release of rust-guardian +- Dynamic code quality enforcement for Rust projects +- Pattern-based analysis for placeholder code detection +- CLI tool and library API +- Comprehensive configuration system with YAML support +- Multiple output formats (human, JSON, JUnit, SARIF, GitHub Actions) +- Watch mode for real-time validation +- Parallel processing with intelligent caching +- Architectural boundary enforcement +- Support for custom patterns and rules - Pattern-based code analysis for detecting placeholder code and TODO comments - Support for regex patterns, AST patterns, and semantic patterns - CLI tool with multiple output formats (human, JSON, JUnit, SARIF, GitHub Actions) @@ -31,15 +51,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Comprehensive test coverage - Documentation and examples -### Changed +### Features +- **Pattern Detection**: TODO comments, unimplemented macros, placeholder code +- **Architecture Enforcement**: Module boundary validation, bounded context integrity +- **Performance**: Async API, parallel processing, file caching +- **Integration**: CI/CD support, multiple output formats +- **Flexibility**: Custom .guardianignore files, configurable severity levels +- **CLI Tools**: Check, watch, validate-config, list-rules, explain commands -### Deprecated - -### Removed - -### Fixed - -### Security +### Added [Unreleased]: https://github.com/cloudfunnels/rust-guardian/compare/v0.1.0...HEAD [0.1.0]: https://github.com/cloudfunnels/rust-guardian/releases/tag/v0.1.0 \ No newline at end of file diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..c83cff6 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,164 @@ +# Release Process + +This document describes the automated release process for rust-guardian. + +## Overview + +The project uses GitHub Actions to automate the entire release process, including: +- Pre-release validation (tests, linting, formatting) +- Publishing to crates.io +- Creating GitHub releases with binaries + +## Setup Requirements + +Before releases can be automated, the following secrets must be configured in the GitHub repository: + +### Required Secrets + +1. **CRATES_TOKEN**: A crates.io API token for publishing + - Go to https://crates.io/me + - Generate a new token with `publish-update` scope + - Add it as a repository secret named `CRATES_TOKEN` + +### Automatic Setup + +- **GITHUB_TOKEN**: Automatically provided by GitHub Actions (no setup required) + +## Release Process + +### 1. Prepare for Release + +1. Update the version in `Cargo.toml`: + ```toml + version = "0.2.0" # Update this + ``` + +2. Update the changelog/documentation if needed + +3. Commit and push changes: + ```bash + git add Cargo.toml + git commit -m "Bump version to 0.2.0" + git push origin main + ``` + +### 2. Create Release + +1. Create and push a version tag: + ```bash + git tag v0.2.0 + git push origin v0.2.0 + ``` + +2. The GitHub Actions workflow will automatically: + - Run all tests and quality checks + - Verify the tag version matches `Cargo.toml` + - Build the project with all features + - Publish to crates.io + - Create a GitHub release with: + - Release notes from git commits + - Binary artifacts + - Checksums + +### 3. Post-Release + +After the automated release: + +1. **crates.io**: The crate will be available at https://crates.io/crates/rust-guardian +2. **docs.rs**: Documentation will be automatically built at https://docs.rs/rust-guardian +3. **GitHub**: Release will be available with downloadable binaries + +## Workflow Details + +### CI Workflow (`.github/workflows/ci.yml`) + +Runs on every push and pull request: +- Tests on stable, beta, and nightly Rust +- Code formatting checks (`cargo fmt`) +- Linting (`cargo clippy`) +- Security audit (`cargo audit`) +- Coverage reporting +- CLI functionality tests + +### Release Workflow (`.github/workflows/release.yml`) + +Triggered on version tags (e.g., `v0.2.0`): +- Pre-release validation (same as CI) +- Version verification +- crates.io publishing +- GitHub release creation +- Binary artifact generation + +### Documentation Workflow (`.github/workflows/docs.yml`) + +Runs on documentation changes: +- Documentation tests (`cargo test --doc`) +- Link checking in README +- Package metadata validation + +## Troubleshooting + +### Failed Release + +If a release fails: + +1. Check the GitHub Actions logs for specific errors +2. Common issues: + - Version mismatch between tag and `Cargo.toml` + - Missing or invalid `CRATES_TOKEN` + - Test failures + - Formatting issues + +### Fixing a Failed Release + +1. Fix the underlying issue +2. Delete the failed tag (if needed): + ```bash + git tag -d v0.2.0 + git push origin :refs/tags/v0.2.0 + ``` +3. Create the tag again after fixes + +### Manual Release + +If automation fails and manual release is needed: + +```bash +# Ensure you're on the correct commit +git checkout v0.2.0 + +# Build and test +cargo build --release --all-features +cargo test --all-features + +# Publish to crates.io +cargo publish --token YOUR_CRATES_TOKEN +``` + +## Version Strategy + +This project follows [Semantic Versioning](https://semver.org/): + +- **MAJOR** version: Incompatible API changes +- **MINOR** version: Backward-compatible functionality additions +- **PATCH** version: Backward-compatible bug fixes + +Pre-release versions can use suffixes: +- `1.0.0-alpha.1`: Alpha release +- `1.0.0-beta.1`: Beta release +- `1.0.0-rc.1`: Release candidate + +## Crates.io Configuration + +The crate is configured for optimal crates.io and docs.rs integration: + +```toml +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +``` + +This ensures: +- All features are documented on docs.rs +- Documentation builds with the `docsrs` cfg flag for conditional compilation +- Examples and integration tests are properly documented \ No newline at end of file diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..8c7a8f4 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,109 @@ +# Setup Instructions for Automated Publishing + +This document provides instructions for repository maintainers to complete the setup for automated publishing to crates.io. + +## Required Setup + +### 1. Configure Crates.io API Token + +To enable automated publishing to crates.io, you need to create and configure a crates.io API token: + +#### Steps: + +1. **Get a crates.io account**: + - Sign up or log in at https://crates.io/ + +2. **Generate an API token**: + - Go to https://crates.io/me + - Click on "API Tokens" + - Click "New Token" + - Name: `rust-guardian-ci` (or any descriptive name) + - Scope: Select `publish-update` to allow publishing and updating existing crates + - Click "Create" + - **Important**: Copy the token immediately - you won't be able to see it again + +3. **Add the token to GitHub repository secrets**: + - Go to the GitHub repository: https://github.com/cloudfunnels/rust-guardian + - Navigate to: Settings → Secrets and variables → Actions + - Click "New repository secret" + - Name: `CRATES_TOKEN` + - Value: Paste the token you copied from crates.io + - Click "Add secret" + +### 2. Verify Setup + +Once the token is configured, you can test the automation: + +1. **Test CI workflow**: + ```bash + # Any push to main will trigger CI + git push origin main + ``` + +2. **Test release workflow**: + ```bash + # Update version in Cargo.toml first + git tag v0.1.0 + git push origin v0.1.0 + ``` + +## What Happens After Setup + +### On Every Push/PR: +- ✅ Code formatting checks +- ✅ Linting with clippy +- ✅ Tests on stable, beta, nightly Rust +- ✅ Security audit +- ✅ Documentation validation + +### On Version Tag (e.g., `v0.1.0`): +- ✅ All CI checks +- ✅ Version verification +- ✅ Automatic crates.io publishing +- ✅ GitHub release creation +- ✅ Binary artifact generation + +## Repository URLs After Publishing + +- **Crates.io**: https://crates.io/crates/rust-guardian +- **Documentation**: https://docs.rs/rust-guardian (automatically updated) +- **Repository**: https://github.com/cloudfunnels/rust-guardian + +## Troubleshooting + +### Common Issues: + +1. **"Invalid token" error**: + - Verify the CRATES_TOKEN secret is correctly set + - Ensure the token has `publish-update` scope + +2. **"Version already exists" error**: + - Crates.io doesn't allow republishing the same version + - Increment the version in Cargo.toml and create a new tag + +3. **Test failures**: + - The release will be blocked if any tests fail + - Fix issues and create a new tag + +### Getting Help: + +- Check GitHub Actions logs for detailed error messages +- See `RELEASE.md` for detailed release process documentation +- Create an issue if you encounter problems + +## Security Notes + +- The CRATES_TOKEN should only have `publish-update` scope (not admin access) +- Only repository maintainers should have access to manage secrets +- The token is only used for publishing, not for downloading or other operations +- Consider rotating the token periodically for security + +## Ready to Publish! + +Once the CRATES_TOKEN secret is configured, the repository is ready for automated publishing to crates.io. The first release can be created by: + +1. Ensuring the version in `Cargo.toml` is correct (e.g., `0.1.0`) +2. Creating and pushing a version tag: `git tag v0.1.0 && git push origin v0.1.0` +3. The automation will handle the rest! + +The crate will then be available at https://crates.io/crates/rust-guardian and documentation will be published at https://docs.rs/rust-guardian. \ No newline at end of file