Recover missing asset-only delta identities #997
Workflow file for this run
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
| name: Rust CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| # Cancel an in-flight CI run when a new push lands on the same PR. | |
| # Only the latest commit matters; older runs would just burn minutes. | |
| concurrency: | |
| group: ci-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_STABLE_TOOLCHAIN: "1.94.1" | |
| RUST_NIGHTLY_TOOLCHAIN: "nightly-2026-05-15" | |
| # Treat any compiler warning as an error to keep the codebase warning-free | |
| RUSTFLAGS: "-Dwarnings" | |
| jobs: | |
| # Detects which categories of files changed in the PR. Downstream jobs | |
| # gate on these outputs to skip when irrelevant. Workflow or script | |
| # changes flip every flag on - those touch CI itself, so re-run everything | |
| # to validate the change doesn't break unrelated jobs. | |
| # Pushes to main run all non-PR-only checks. | |
| detect: | |
| name: Detect changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| code: ${{ steps.filter.outputs.code }} | |
| cargo: ${{ steps.filter.outputs.cargo }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - id: filter | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "$EVENT_NAME" != "pull_request" ]]; then | |
| echo "$EVENT_NAME event -> running all non-PR-only jobs" | |
| { | |
| echo "code=true" | |
| echo "cargo=true" | |
| } >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| files=$(git diff --name-only "${BASE_SHA}"...HEAD) | |
| echo "Changed files:" | |
| printf ' %s\n' $files | |
| echo | |
| if printf '%s\n' "$files" | grep -qE '^\.github/(workflows/|scripts/)'; then | |
| echo "Workflow / scripts change detected -> running all jobs" | |
| { | |
| echo "code=true" | |
| echo "cargo=true" | |
| } >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| code=false; cargo=false | |
| if printf '%s\n' "$files" | grep -qE '^(src/|tests/|build\.rs$|Cargo\.toml$|Cargo\.lock$)'; then | |
| code=true | |
| fi | |
| if printf '%s\n' "$files" | grep -qE '^(Cargo\.toml$|Cargo\.lock$|\.cargo/audit\.toml$)'; then | |
| cargo=true | |
| fi | |
| { | |
| echo "code=$code" | |
| echo "cargo=$cargo" | |
| } >> "$GITHUB_OUTPUT" | |
| # Enforces consistent code style across the project | |
| # Fails if any code isn't formatted with rustfmt | |
| fmt: | |
| name: Format | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| components: rustfmt | |
| - run: cargo fmt --all --check | |
| # Fails when a serializer changes in src/ without a corresponding | |
| # round-trip test. Mirrors `just gate`'s check-roundtrip-gate.sh. | |
| roundtrip: | |
| name: Roundtrip gate | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 0 | |
| - run: bash scripts/check-roundtrip-gate.sh | |
| # Catches common mistakes, unidiomatic code, and potential bugs | |
| # Acts as an additional layer of static analysis beyond the compiler | |
| clippy: | |
| name: Clippy | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| components: clippy | |
| - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| # Caches compiled dependencies to speed up subsequent runs | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| - run: cargo clippy --all-targets --all-features | |
| # Keeps the `--no-default-features` build honest so FreeBSD and any other | |
| # platform without a working C++ toolchain for xmp_toolkit (see #256) can | |
| # still build kei. Runs clippy + tests on the narrower surface; tests | |
| # make sure we also catch runtime regressions, not just compile breaks. | |
| test_no_default: | |
| name: Test (no-default-features) | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| components: clippy | |
| - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| - run: cargo clippy --all-targets --no-default-features -- -D warnings | |
| - run: cargo test --no-default-features | |
| # Runs the test suite on all major platforms to catch platform-specific bugs | |
| # fail-fast: false ensures all platforms run even if one fails | |
| test: | |
| name: Test (${{ matrix.os }}) | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| - name: Install system dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| - run: cargo test --all-features | |
| # Ensures documentation builds without warnings | |
| # Important for maintaining quality docs, especially for published crates | |
| docs: | |
| name: Docs | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| env: | |
| RUSTDOCFLAGS: "-Dwarnings" | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| - name: Check live wiki command documentation | |
| run: | | |
| git clone --depth=1 https://github.com/rhoopr/kei.wiki.git /tmp/kei-wiki | |
| cargo build --bin kei | |
| scripts/check-wiki-commands.sh target/debug/kei /tmp/kei-wiki | |
| - run: cargo doc --no-deps --all-features | |
| # Detects dependencies declared in Cargo.toml but not actually used | |
| # Keeps the dependency tree lean and reduces compile times | |
| # Requires nightly because cargo-udeps uses unstable features | |
| unused-deps: | |
| name: Unused Dependencies | |
| needs: detect | |
| if: needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly | |
| with: | |
| toolchain: ${{ env.RUST_NIGHTLY_TOOLCHAIN }} | |
| - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| - uses: taiki-e/install-action@7170fe35ac006b4d8f0bcdfba8168cf5c431a122 # cargo-udeps | |
| - run: cargo +nightly udeps --all-targets | |
| # Verifies Cargo.lock is committed and in sync with Cargo.toml | |
| # Ensures reproducible builds and prevents "works on my machine" issues | |
| lockfile: | |
| name: Lockfile | |
| needs: detect | |
| if: needs.detect.outputs.cargo == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| - run: cargo fetch --locked | |
| # PR head coverage. Runs in parallel with coverage-base. | |
| # Output artifact feeds into the Coverage aggregator job. | |
| coverage-head: | |
| name: Coverage (head) | |
| needs: detect | |
| if: github.event_name == 'pull_request' && needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| components: llvm-tools-preview | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| key: coverage-head | |
| - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| - uses: taiki-e/install-action@9180ba819ebd9a5f78ccc0e64cb6b06f5917fdff # cargo-llvm-cov | |
| - name: Run coverage | |
| run: | | |
| cargo llvm-cov --all-features --no-report | |
| # Human-readable report for the Actions log | |
| cargo llvm-cov report | |
| # Structured data for parsing - cargo-llvm-cov's text format is | |
| # column-position-fragile and the test summary goes to stderr. | |
| cargo llvm-cov report --json --output-path coverage.json | |
| # Per-line hit counts for patch coverage computation. | |
| cargo llvm-cov report --lcov --output-path coverage.lcov | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: coverage-head | |
| path: | | |
| coverage.json | |
| coverage.lcov | |
| retention-days: 1 | |
| # Base-branch coverage for the delta. Runs in parallel with coverage-head | |
| # on a separate runner. continue-on-error so a broken main only suppresses | |
| # the delta - it doesn't block the PR. | |
| coverage-base: | |
| name: Coverage (base) | |
| needs: detect | |
| if: github.event_name == 'pull_request' && needs.detect.outputs.code == 'true' | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }} | |
| components: llvm-tools-preview | |
| - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 | |
| with: | |
| key: coverage-base | |
| - run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev | |
| - uses: taiki-e/install-action@9180ba819ebd9a5f78ccc0e64cb6b06f5917fdff # cargo-llvm-cov | |
| - name: Run coverage | |
| run: | | |
| cargo llvm-cov --all-features --no-report | |
| cargo llvm-cov report --json --output-path base_coverage.json | |
| cargo llvm-cov report --lcov --output-path base_coverage.lcov | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: coverage-base | |
| path: | | |
| base_coverage.json | |
| base_coverage.lcov | |
| retention-days: 1 | |
| # Aggregates head + base, computes patch coverage, and builds the sticky | |
| # comment body. The comment is posted by a separate workflow triggered via | |
| # workflow_run so cross-fork PRs (which run with a read-only GITHUB_TOKEN) | |
| # can still get comments - this job only builds the artifact. | |
| coverage: | |
| name: Coverage | |
| runs-on: ubuntu-latest | |
| needs: [coverage-head, coverage-base] | |
| if: always() && needs.coverage-head.result == 'success' | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| # Need full history for git diff against base in patch_coverage.py. | |
| fetch-depth: 0 | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| name: coverage-head | |
| - name: Download base coverage | |
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| name: coverage-base | |
| continue-on-error: true | |
| - name: Compute patch coverage | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| run: | | |
| args=(--base "$BASE_SHA" --lcov coverage.lcov --workspace .) | |
| if [ -f base_coverage.lcov ]; then | |
| args+=(--base-lcov base_coverage.lcov) | |
| fi | |
| python3 .github/scripts/patch_coverage.py "${args[@]}" > patch_coverage.json | |
| cat patch_coverage.json | |
| - name: Build coverage comment | |
| env: | |
| MARKER: "<!-- coverage-comment -->" | |
| run: | | |
| set -euo pipefail | |
| # Strip absolute workspace prefix from filenames in JSON. | |
| WORKSPACE="$(pwd)/" | |
| # Reusable jq function defining 2-decimal percent formatting. | |
| PCT_DEF='def pct: (. * 100 | round) as $x | "\($x / 100 | floor).\($x % 100 | tostring | if length == 1 then "0\(.)" else . end)";' | |
| # --- Build headline (line coverage % + delta + patch coverage) --- | |
| HEAD_PCT=$(jq -r '.data[0].totals.lines.percent' coverage.json) | |
| HEADLINE="**Line coverage:** $(printf '%.2f' "$HEAD_PCT")%" | |
| if [ -f base_coverage.json ]; then | |
| BASE_PCT=$(jq -r '.data[0].totals.lines.percent' base_coverage.json) | |
| DELTA=$(awk "BEGIN { printf \"%+.2f\", ${HEAD_PCT} - ${BASE_PCT} }") | |
| HEADLINE="${HEADLINE} (${DELTA}% from main)" | |
| fi | |
| PATCH_TOTAL=$(jq -r '.total_eligible' patch_coverage.json) | |
| if [ "$PATCH_TOTAL" -gt 0 ]; then | |
| PATCH_PCT=$(jq -r '.percent' patch_coverage.json) | |
| PATCH_COVERED=$(jq -r '.total_covered' patch_coverage.json) | |
| HEADLINE="${HEADLINE} · **Patch coverage:** $(printf '%.2f' "$PATCH_PCT")% (${PATCH_COVERED} / ${PATCH_TOTAL} changed lines)" | |
| fi | |
| # --- Build the comment --- | |
| { | |
| echo "$MARKER" | |
| echo "## Coverage Report" | |
| echo "" | |
| echo "$HEADLINE" | |
| echo "" | |
| # Per-file patch coverage, if the PR touched any covered .rs lines. | |
| # Patch column = % of changed lines covered. | |
| # File column = whole-file coverage on PR head. | |
| # Δ column = whole-file delta vs base (blank for new files). | |
| if [ "$PATCH_TOTAL" -gt 0 ]; then | |
| echo "| File | Patch | File Coverage | Δ from main |" | |
| echo "|------|-------|---------------|-------------|" | |
| jq -r "${PCT_DEF}"' | |
| # Format a signed delta as +X.YY / -X.YY. | |
| def signed: if . >= 0 then "+\(. | pct)" else "-\(-1 * . | pct)" end; | |
| .files | sort_by(.percent) | .[] | | |
| "| \(.file) | \(.percent | pct)% (\(.covered) / \(.total)) | " + | |
| (if .file_percent_head == null then "—" else "\(.file_percent_head | pct)%" end) + | |
| " | " + | |
| (if .file_delta == null then (if .file_percent_head != null then "new" else "—" end) else "\(.file_delta | signed)%" end) + | |
| " |" | |
| ' patch_coverage.json | |
| echo "" | |
| fi | |
| echo "### Project totals" | |
| echo "" | |
| echo "| Metric | Coverage | Covered / Total |" | |
| echo "|--------|----------|-----------------|" | |
| jq -r "${PCT_DEF}"' | |
| .data[0].totals as $t | | |
| [ | |
| ["Lines", $t.lines], | |
| ["Functions", $t.functions], | |
| ["Regions", $t.regions], | |
| ["Branches", $t.branches] | |
| ] | |
| | map(select(.[1].count > 0)) | |
| | .[] | |
| | "| \(.[0]) | \(.[1].percent | pct)% | \(.[1].covered) / \(.[1].count) |" | |
| ' coverage.json | |
| echo "" | |
| # Lowest-covered files (line coverage ascending), excluding 100%. | |
| LOWEST=$(jq -r --arg ws "$WORKSPACE" "${PCT_DEF}"' | |
| .data[0].files | |
| | map(select(.summary.lines.percent < 100)) | |
| | sort_by(.summary.lines.percent) | |
| | .[:10] | |
| | .[] | |
| | "| \(.filename | sub($ws; "")) | \(.summary.lines.percent | pct)% | \(.summary.lines.covered) / \(.summary.lines.count) |" | |
| ' coverage.json) | |
| if [ -n "$LOWEST" ]; then | |
| N=$(printf '%s\n' "$LOWEST" | wc -l) | |
| echo "<details><summary>${N} lowest-covered files (line coverage, project-wide)</summary>" | |
| echo "" | |
| echo "| File | Lines | Covered / Total |" | |
| echo "|------|-------|-----------------|" | |
| printf '%s\n' "$LOWEST" | |
| echo "" | |
| echo "</details>" | |
| echo "" | |
| fi | |
| # Files at 100% line coverage. | |
| FULL=$(jq -r --arg ws "$WORKSPACE" ' | |
| .data[0].files | |
| | map(select(.summary.lines.percent == 100)) | |
| | sort_by(.filename) | |
| | .[] | |
| | "- \(.filename | sub($ws; ""))" | |
| ' coverage.json) | |
| if [ -n "$FULL" ]; then | |
| N=$(printf '%s\n' "$FULL" | wc -l) | |
| echo "<details><summary>${N} files at 100% line coverage</summary>" | |
| echo "" | |
| printf '%s\n' "$FULL" | |
| echo "" | |
| echo "</details>" | |
| fi | |
| } > comment.md | |
| # Mirror to the Actions step summary so the report is visible in the run UI. | |
| cat comment.md >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload coverage comment | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: coverage-comment | |
| path: comment.md | |
| retention-days: 1 | |
| # PR metadata for the coverage-comment workflow. workflow_run events | |
| # don't carry PR context, and looking it up from the head SHA is | |
| # unreliable for fork PRs, so we pass it via artifact. | |
| - name: Record PR metadata | |
| env: | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| printf '%s\n' "$PR_NUMBER" > pr_number.txt | |
| printf '%s\n' "$PR_HEAD_SHA" > pr_head_sha.txt | |
| - name: Upload PR metadata | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: coverage-comment-meta | |
| path: | | |
| pr_number.txt | |
| pr_head_sha.txt | |
| retention-days: 1 | |
| # Checks dependencies against the RustSec Advisory Database | |
| # Catches known security vulnerabilities in your dependency tree | |
| security: | |
| name: Security Audit | |
| needs: detect | |
| if: needs.detect.outputs.cargo == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: taiki-e/install-action@b7d831ec1a6ef0d81d27cf61932d92140b2271d4 # cargo-audit | |
| # Ignore list + rationale: .cargo/audit.toml. | |
| - run: cargo audit --deny warnings | |
| # Guards the Actions supply-chain hardening rules that keep PRs | |
| # from reintroducing mutable action refs or privileged manual publishes. | |
| workflow-hardening: | |
| name: Workflow hardening | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - run: python3 .github/scripts/check_workflow_hardening.py | |
| - run: | | |
| mkdir -p /tmp/codex/kei/pycache | |
| PYTHONPYCACHEPREFIX=/tmp/codex/kei/pycache python3 -m py_compile .github/scripts/*.py | |
| # Cheap deterministic syntax check for repository helper scripts. Heavier | |
| # shellcheck/shfmt/ruff/actionlint checks are exposed through local | |
| # `just lint-scripts` / `just lint-workflows` recipes and full-test prereq | |
| # reporting, but this job keeps obvious syntax breaks out of protected CI. | |
| script-lint: | |
| name: Script lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Check shell and Python helper syntax | |
| run: | | |
| set -euo pipefail | |
| mapfile -t shell_files < <(find scripts tests/shell docker -maxdepth 3 -type f \( -name '*.sh' -o -name 'entrypoint.sh' -o -name 'check-contracts' \) -print | sort) | |
| mapfile -t python_files < <(find scripts .github/scripts -maxdepth 3 -type f -name '*.py' -print | sort) | |
| bash -n "${shell_files[@]}" | |
| mkdir -p /tmp/codex/kei/pycache | |
| PYTHONPYCACHEPREFIX=/tmp/codex/kei/pycache python3 -m py_compile "${python_files[@]}" | |
| # Catches spelling mistakes in code, comments, and documentation | |
| # Small thing but helps maintain a professional codebase. Always runs | |
| # since typos can land in any kind of file. | |
| typos: | |
| name: Typos | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: crate-ci/typos@5374cbf686e897b15713110e233094e2874de7ef # master | |
| # Single required check that gates merging. Skipped jobs (path-filtered | |
| # out) count as success; only real failures or cancellations block. | |
| # The branch ruleset should require this name and nothing else. | |
| ci: | |
| name: CI | |
| if: always() | |
| needs: | |
| - detect | |
| - fmt | |
| - roundtrip | |
| - clippy | |
| - test_no_default | |
| - test | |
| - docs | |
| - unused-deps | |
| - lockfile | |
| - coverage | |
| - security | |
| - workflow-hardening | |
| - script-lint | |
| - typos | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Verify all required jobs passed or were skipped | |
| env: | |
| NEEDS: ${{ toJSON(needs) }} | |
| run: | | |
| set -euo pipefail | |
| echo "$NEEDS" | jq . | |
| if echo "$NEEDS" | jq -e 'all(.[]; .result == "success" or .result == "skipped")' > /dev/null; then | |
| echo "All required jobs passed or were skipped." | |
| else | |
| echo "One or more required jobs failed or were cancelled." >&2 | |
| exit 1 | |
| fi |