From 226918d9d8e722874200f1e815b1d266dfd4f8dc Mon Sep 17 00:00:00 2001 From: pandaadir05 Date: Fri, 21 Nov 2025 12:58:06 +0200 Subject: [PATCH] Implement comprehensive CI/CD pipeline with best practices Major improvements: - Matrix testing across Linux (stable/beta/nightly), Windows, and macOS - Test with multiple feature combinations (default, yara-scanning, no-default) - Code coverage reporting with codecov integration - Security auditing with cargo-audit and dependency review - Automated release builds for multiple targets - Performance benchmarking with trend tracking - Concurrency control to cancel outdated runs - Rust cache optimization for faster builds - Documentation generation checks - Weekly scheduled runs for proactive monitoring Additional workflows: - Automated dependency updates via Dependabot - Weekly Cargo dependency update PRs - Stale issue and PR management Project templates: - Pull request template with checklist - Bug report issue template - Feature request issue template - Codecov configuration with 70% coverage target --- .github/ISSUE_TEMPLATE/bug_report.md | 44 +++ .github/ISSUE_TEMPLATE/feature_request.md | 36 ++ .github/PULL_REQUEST_TEMPLATE.md | 37 ++ .github/dependabot.yml | 34 ++ .github/workflows/ci.yml | 390 +++++++++++++++------- .github/workflows/dependencies.yml | 36 ++ .github/workflows/stale.yml | 36 ++ codecov.yml | 27 ++ 8 files changed, 525 insertions(+), 115 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/dependencies.yml create mode 100644 .github/workflows/stale.yml create mode 100644 codecov.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..e721922 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,44 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: '[BUG] ' +labels: bug +assignees: '' +--- + +## Bug Description + +A clear and concise description of what the bug is. + +## To Reproduce + +Steps to reproduce the behavior: +1. Run '...' +2. Execute '...' +3. See error + +## Expected Behavior + +A clear and concise description of what you expected to happen. + +## Actual Behavior + +What actually happened. + +## Environment + +- OS: [e.g., Windows 11, Ubuntu 22.04, macOS 14] +- Ghost Version: [e.g., 0.1.0] +- Rust Version: [e.g., 1.75.0] + +## Additional Context + +Add any other context about the problem here, including: +- Log output +- Stack traces +- Configuration files +- Screenshots (if applicable) + +## Possible Solution + +If you have ideas on how to fix the bug, please share them here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..581b643 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,36 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: '[FEATURE] ' +labels: enhancement +assignees: '' +--- + +## Feature Description + +A clear and concise description of what feature you'd like to see. + +## Problem Statement + +Is your feature request related to a problem? Please describe. +Example: I'm always frustrated when [...] + +## Proposed Solution + +A clear and concise description of what you want to happen. + +## Alternatives Considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Use Case + +Describe the use case or scenario where this feature would be useful. + +## Implementation Ideas + +If you have thoughts on how this could be implemented, please share them here. + +## Additional Context + +Add any other context, screenshots, or examples about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ef253d1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,37 @@ +## Description + +Please provide a clear and concise description of what this PR does. + +## Type of Change + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Performance improvement +- [ ] Code refactoring +- [ ] Test improvements + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. + +- [ ] Unit tests +- [ ] Integration tests +- [ ] Manual testing +- [ ] Platform-specific testing (Windows/Linux/macOS) + +## Checklist + +- [ ] My code follows the project's style guidelines +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published + +## Additional Context + +Add any other context about the pull request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..859bba3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 10 + reviewers: + - "pandaadir05" + labels: + - "dependencies" + - "rust" + commit-message: + prefix: "chore" + include: "scope" + groups: + dev-dependencies: + dependency-type: "development" + update-types: + - "minor" + - "patch" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff1ee94..87d5299 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,163 +2,323 @@ name: CI/CD Pipeline on: push: - branches: [ main, develop ] + branches: [main, develop] + tags: + - 'v*' pull_request: - branches: [ main ] + branches: [main, develop] + schedule: + - cron: '0 0 * * 0' env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 + RUSTFLAGS: -D warnings + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - format: - name: Format Check + check: + name: Code Quality Checks runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy - - name: Check formatting - run: cargo fmt --all -- --check + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "check" - clippy: - name: Clippy Lints - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Check formatting + run: cargo fmt --all -- --check - - name: Install YARA - run: sudo apt-get update && sudo apt-get install -y libyara-dev + - name: Run clippy (without YARA) + run: cargo clippy --workspace --all-targets --no-default-features -- -D warnings - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - components: clippy - - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo- - - - name: Run clippy - run: cargo clippy --all-targets -- -A clippy::too_many_arguments -A clippy::type_complexity -A dead_code + - name: Check documentation + run: cargo doc --workspace --no-deps --no-default-features + env: + RUSTDOCFLAGS: -D warnings test-linux: - name: Test on Linux + name: Test - Linux runs-on: ubuntu-latest - needs: [format, clippy] + needs: check + strategy: + matrix: + rust: [stable, beta, nightly] + features: ['', '--features yara-scanning', '--no-default-features'] + continue-on-error: ${{ matrix.rust == 'nightly' }} steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Install YARA - run: sudo apt-get update && sudo apt-get install -y libyara-dev + - name: Install YARA + if: contains(matrix.features, 'yara-scanning') + run: | + sudo apt-get update + sudo apt-get install -y libyara-dev pkg-config - - name: Install Rust - uses: dtolnay/rust-toolchain@stable + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-test- - ${{ runner.os }}-cargo- + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "test-linux-${{ matrix.rust }}-${{ matrix.features }}" - - name: Build - run: cargo build --verbose + - name: Build + run: cargo build --workspace --verbose ${{ matrix.features }} - - name: Run tests - run: cargo test --verbose + - name: Run tests + run: cargo test --workspace --verbose ${{ matrix.features }} + + - name: Run doc tests + run: cargo test --workspace --doc ${{ matrix.features }} test-windows: - name: Test on Windows + name: Test - Windows runs-on: windows-latest - needs: [format, clippy] + needs: check + strategy: + matrix: + rust: [stable] + features: ['', '--no-default-features'] steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~\.cargo\registry - ~\.cargo\git - target - key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-test- - ${{ runner.os }}-cargo- + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "test-windows-${{ matrix.rust }}" - - name: Build - run: cargo build --verbose - continue-on-error: true + - name: Build + run: cargo build --workspace --verbose ${{ matrix.features }} - - name: Run tests - run: cargo test --verbose - continue-on-error: true + - name: Run tests + run: cargo test --workspace --verbose ${{ matrix.features }} test-macos: - name: Test on macOS + name: Test - macOS runs-on: macos-latest - needs: [format, clippy] + needs: check + strategy: + matrix: + rust: [stable] + features: ['', '--no-default-features'] steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-test- - ${{ runner.os }}-cargo- + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "test-macos-${{ matrix.rust }}" - - name: Build - run: cargo build --verbose + - name: Build + run: cargo build --workspace --verbose ${{ matrix.features }} - - name: Run tests - run: cargo test --verbose + - name: Run tests + run: cargo test --workspace --verbose ${{ matrix.features }} - security: + coverage: + name: Code Coverage + runs-on: ubuntu-latest + needs: check + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + + - name: Generate coverage + run: cargo llvm-cov --workspace --no-default-features --lcov --output-path lcov.info + + - name: Upload to codecov.io + uses: codecov/codecov-action@v4 + with: + files: lcov.info + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + + security-audit: name: Security Audit runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Install YARA - run: sudo apt-get update && sudo apt-get install -y libyara-dev + - name: Run cargo-audit + uses: rustsec/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} - - name: Run cargo-deny - uses: EmbarkStudios/cargo-deny-action@v1 - with: - log-level: warn - command: check + dependency-review: + name: Dependency Review + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Dependency Review + uses: actions/dependency-review-action@v4 + + build-release: + name: Build Release - ${{ matrix.target }} + runs-on: ${{ matrix.os }} + needs: [test-linux, test-windows, test-macos] + if: startsWith(github.ref, 'refs/tags/v') + strategy: + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: x86_64-unknown-linux-musl + os: ubuntu-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + - target: x86_64-apple-darwin + os: macos-latest + - target: aarch64-apple-darwin + os: macos-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + shared-key: "release-${{ matrix.target }}" + + - name: Install musl tools + if: matrix.target == 'x86_64-unknown-linux-musl' + run: sudo apt-get install -y musl-tools + + - name: Build release + run: cargo build --release --target ${{ matrix.target }} --no-default-features + + - name: Create archive + shell: bash + run: | + VERSION="${GITHUB_REF#refs/tags/v}" + if [[ "${{ matrix.os }}" == "windows-latest" ]]; then + ARCHIVE="ghost-${VERSION}-${{ matrix.target }}.zip" + 7z a "${ARCHIVE}" ./target/${{ matrix.target }}/release/ghost.exe + else + ARCHIVE="ghost-${VERSION}-${{ matrix.target }}.tar.gz" + tar czf "${ARCHIVE}" -C ./target/${{ matrix.target }}/release ghost + fi + echo "ARCHIVE=${ARCHIVE}" >> $GITHUB_ENV + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ghost-${{ matrix.target }} + path: ${{ env.ARCHIVE }} + + release: + name: Create Release + runs-on: ubuntu-latest + needs: build-release + if: startsWith(github.ref, 'refs/tags/v') + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + draft: false + prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }} + generate_release_notes: true + files: artifacts/**/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + benchmark: + name: Performance Benchmarks + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + + - name: Run benchmarks + run: cargo bench --no-default-features --no-fail-fast + + - name: Store benchmark result + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: 'cargo' + output-file-path: target/criterion/output.json + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true + alert-threshold: '200%' + comment-on-alert: true + fail-on-alert: false + + all-checks-pass: + name: All Checks Pass + runs-on: ubuntu-latest + needs: [check, test-linux, test-windows, test-macos, coverage, security-audit] + if: always() + steps: + - name: Check job results + run: | + if [[ "${{ needs.check.result }}" != "success" ]] || \ + [[ "${{ needs.test-linux.result }}" != "success" ]] || \ + [[ "${{ needs.test-windows.result }}" != "success" ]] || \ + [[ "${{ needs.test-macos.result }}" != "success" ]] || \ + [[ "${{ needs.coverage.result }}" != "success" ]] || \ + [[ "${{ needs.security-audit.result }}" != "success" ]]; then + echo "One or more required checks failed" + exit 1 + fi + echo "All required checks passed" diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml new file mode 100644 index 0000000..afe8e69 --- /dev/null +++ b/.github/workflows/dependencies.yml @@ -0,0 +1,36 @@ +name: Dependency Management + +on: + schedule: + - cron: '0 0 * * 1' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-dependencies: + name: Update Dependencies + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Update dependencies + run: cargo update + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + commit-message: Update Cargo dependencies + title: 'chore: update Cargo dependencies' + body: | + Automated dependency update generated by GitHub Actions. + + Please review the changes and ensure all tests pass before merging. + branch: deps/cargo-update + delete-branch: true diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..0efd1e3 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,36 @@ +name: Issue and PR Cleanup + +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + name: Mark Stale Issues and PRs + runs-on: ubuntu-latest + steps: + - name: Mark stale issues and PRs + uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: | + This issue has been automatically marked as stale because it has not had recent activity. + It will be closed in 7 days if no further activity occurs. + If this is still relevant, please add a comment to keep it open. + stale-pr-message: | + This pull request has been automatically marked as stale because it has not had recent activity. + It will be closed in 7 days if no further activity occurs. + If you're still working on this, please add a comment or update the PR. + close-issue-message: 'This issue was closed because it has been stale for 7 days with no activity.' + close-pr-message: 'This PR was closed because it has been stale for 7 days with no activity.' + days-before-stale: 30 + days-before-close: 7 + stale-issue-label: 'stale' + stale-pr-label: 'stale' + exempt-issue-labels: 'pinned,security,enhancement' + exempt-pr-labels: 'pinned,security' diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..f78d83e --- /dev/null +++ b/codecov.yml @@ -0,0 +1,27 @@ +coverage: + precision: 2 + round: down + range: 70..100 + status: + project: + default: + target: 70% + threshold: 5% + if_ci_failed: error + patch: + default: + target: 80% + threshold: 10% + +comment: + layout: "header, diff, flags, components, files, footer" + behavior: default + require_changes: false + require_base: false + require_head: true + +ignore: + - "tests/**" + - "benches/**" + - "examples/**" + - "**/*_test.rs"