feat: add Deserialize, Display, Hash, From impls for public types #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # nanodock - CI Pipeline | |
| # Enforces code quality on pull requests. All checks must pass before merging. | |
| # | |
| # Gates (ALL must pass): | |
| # 1. cargo fmt --check -> consistent formatting | |
| # 2. cargo clippy (deny) -> zero lint warnings (all+pedantic+nursery) | |
| # 3. cargo test --locked -> all tests pass, Cargo.lock respected | |
| # 4. cargo bench --no-run -> benchmarks compile without errors | |
| # 5. cargo build -> library compiles | |
| # 6. cargo doc -> documentation + doc-comment format valid | |
| # 7. cargo deny check -> no vulnerable/banned dependencies | |
| # | |
| # Linux benchmark execution: | |
| # - gungraun instruction-count regressions vs PR merge-base | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Principle of least privilege - CI only reads source, never pushes. | |
| permissions: | |
| contents: read | |
| # Cancel any in-progress run for the same PR branch to avoid wasted minutes. | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUSTFLAGS: "-D warnings" | |
| jobs: | |
| quality-gate: | |
| name: Quality Gate (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # 1.94.1 | |
| with: | |
| toolchain: stable | |
| components: rustfmt, clippy | |
| - name: Cache Rust dependencies and build artifacts | |
| uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| cache-on-failure: true | |
| # Gate 1: Formatting - rejects inconsistent style | |
| - name: "Gate 1: cargo fmt --check" | |
| run: cargo fmt --all -- --check | |
| # Gate 2: Clippy (all+pedantic+nursery at deny level) - rejects lint violations. | |
| # Lint levels and per-lint overrides are configured in Cargo.toml [lints.clippy]. | |
| - name: "Gate 2: cargo clippy" | |
| run: cargo clippy --locked --all-targets -- -D warnings | |
| # Gate 3: Tests - rejects broken logic; --locked ensures Cargo.lock is honoured | |
| - name: "Gate 3: cargo test" | |
| run: | | |
| cargo test --locked --lib --tests | |
| cargo test --locked --doc | |
| # Gate 4: Benchmarks - rejects benchmarks that do not compile | |
| - name: "Gate 4: cargo bench --no-run" | |
| run: cargo bench --locked --no-run | |
| # Gate 5: Build - rejects code that does not compile | |
| - name: "Gate 5: cargo build" | |
| run: cargo build --locked | |
| # Gate 6: Documentation & doc-comment format - rejects broken links, bare URLs, | |
| # invalid code blocks, and missing crate-level docs. | |
| - name: "Gate 6: cargo doc" | |
| run: cargo doc --locked --no-deps | |
| env: | |
| RUSTDOCFLAGS: >- | |
| -D warnings | |
| -D rustdoc::bare_urls | |
| -D rustdoc::invalid_rust_codeblocks | |
| -D rustdoc::private_intra_doc_links | |
| -D rustdoc::unescaped_backticks | |
| # Linux-only instruction-count benchmarks with gungraun. | |
| # | |
| # Gungraun executes under valgrind, so benchmark execution is unavailable on | |
| # Windows runners. Pull requests compare the PR head against a merge-base | |
| # baseline from `main` and fail on instruction regressions above the chosen | |
| # Ir limit. Pushes to `main` still run the benchmark suite as a smoke check. | |
| benchmark-regression: | |
| name: Benchmark Regression (Linux) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| GUNGRAUN_SEPARATE_TARGETS: "true" | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # 1.94.1 | |
| with: | |
| toolchain: stable | |
| - name: Cache Rust dependencies and build artifacts | |
| uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| cache-on-failure: true | |
| key: bench | |
| - name: Install Valgrind | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y valgrind | |
| - name: Install gungraun-runner | |
| run: | | |
| version=$(cargo metadata --format-version=1 | python -c "import json, sys; data = json.load(sys.stdin); print(next(pkg['version'] for pkg in data['packages'] if pkg['name'] == 'gungraun'))") | |
| cargo install --locked gungraun-runner --version "$version" | |
| - name: Resolve merge-base | |
| id: base | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| base=$(git merge-base HEAD origin/${{ github.base_ref }}) | |
| echo "sha=$base" >> "$GITHUB_OUTPUT" | |
| echo "Merge-base: $base" | |
| - name: Run benchmarks on merge-base (establish baseline) | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| head_sha=$(git rev-parse HEAD) | |
| git checkout --detach ${{ steps.base.outputs.sha }} | |
| cargo bench --locked --bench benchmarks -- \ | |
| --save-baseline main \ | |
| --callgrind-metrics=ir \ | |
| --save-summary=json | |
| git checkout --detach "$head_sha" | |
| - name: Run PR benchmark comparison | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| cargo bench --locked --bench benchmarks -- \ | |
| --baseline main \ | |
| --callgrind-metrics=ir \ | |
| --callgrind-limits='ir=1.0%' \ | |
| --save-summary=json \ | |
| | tee bench_output.txt | |
| - name: Run benchmark smoke check on main pushes | |
| if: github.event_name != 'pull_request' | |
| run: | | |
| cargo bench --locked --bench benchmarks \ | |
| -- \ | |
| --callgrind-metrics=ir \ | |
| --save-summary=json \ | |
| | tee bench_output.txt | |
| - name: Upload benchmark reports | |
| if: always() | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 | |
| with: | |
| name: benchmark-reports-${{ github.sha }} | |
| path: | | |
| bench_output.txt | |
| target/gungraun | |
| retention-days: 7 | |
| if-no-files-found: warn | |
| # Gate 7: Dependency audit - rejects vulnerable/banned/unlicensed dependencies. | |
| # Uses EmbarkStudios/cargo-deny-action (Docker-based, pre-built binary - no | |
| # manual install or caching needed). Advisories are split into a separate | |
| # matrix entry with continue-on-error so a sudden new advisory announcement | |
| # does not block unrelated PRs. | |
| audit: | |
| name: Dependency Audit (${{ matrix.checks }}) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| matrix: | |
| checks: | |
| - advisories | |
| - bans licenses sources | |
| # A new advisory should warn, not block unrelated work. | |
| continue-on-error: ${{ matrix.checks == 'advisories' }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: "Gate 7: cargo deny check ${{ matrix.checks }}" | |
| uses: EmbarkStudios/cargo-deny-action@82eb9f621fbc699dd0918f3ea06864c14cc84246 # v2 | |
| with: | |
| command: check ${{ matrix.checks }} |