Files
ironclaw/.github/workflows/code_style.yml
firat.sertgoz 5b80cb0880 Enable distributed sccache in key CI workflows (#5599)
* Enable distributed sccache in key CI workflows

* Fix distributed sccache action config writing

* Skip dist sccache for wasmtime crate tests

* Escape distributed sccache config values

* Disable dist sccache for wasm product adapter tests

* Avoid dist sccache for Reborn wasmtime test graphs

* Use OVH Redis as shared sccache backend

* Use cache-only sccache for Reborn CLI smoke

* Warn on sccache dist status probe failure
2026-07-03 18:23:42 +03:00

370 lines
15 KiB
YAML

name: Code Style
on:
pull_request:
merge_group:
branches:
- main
types:
- checks_requested
# Pushes to main refresh the rust-cache entries that PR and merge-group
# jobs restore from. Non-push runs stay restore-only.
push:
branches:
- main
permissions:
contents: read
concurrency:
group: code-style-${{ github.head_ref || github.ref }}
cancel-in-progress: true
env:
# Tests must never touch the real OS keychain (macOS Keychain auth dialog /
# Linux Secret Service). Guarded by src/secrets/keychain.rs::os_keychain_suppressed:
# cfg!(test) covers unit tests; this covers integration/e2e that link the
# non-cfg(test) library.
IRONCLAW_DISABLE_OS_KEYCHAIN: "1"
jobs:
changes:
name: Detect code changes
runs-on: ubuntu-latest
outputs:
has_code: ${{ steps.non_pr.outputs.has_code || steps.diff.outputs.has_code }}
has_boundary_check: ${{ steps.non_pr.outputs.has_boundary_check || steps.diff.outputs.has_boundary_check }}
has_reborn_cli: ${{ steps.non_pr.outputs.has_reborn_cli || steps.diff.outputs.has_reborn_cli }}
steps:
- id: non_pr
if: github.event_name == 'push'
run: |
echo "has_code=true" >> "$GITHUB_OUTPUT"
echo "has_boundary_check=true" >> "$GITHUB_OUTPUT"
echo "has_reborn_cli=true" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
with:
fetch-depth: 0
persist-credentials: false
- id: diff
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
env:
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
HEAD_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
run: |
CHANGED_FILES="$(git diff --name-only "$BASE_SHA"..."$HEAD_SHA")"
if printf '%s\n' "$CHANGED_FILES" | grep -Eq '^(src/|crates/|channels-src/|tools-src/|tests/|migrations/|Cargo\.toml$|Cargo\.lock$|Dockerfile$|build\.rs$|\.gitignore$|scripts/check_no_panics\.py$|scripts/check_gateway_boundaries\.py$|\.github/workflows/code_style\.yml$)'; then
echo "has_code=true" >> "$GITHUB_OUTPUT"
else
echo "has_code=false" >> "$GITHUB_OUTPUT"
echo "No code changes — style checks will be skipped"
fi
if printf '%s\n' "$CHANGED_FILES" | grep -Eq '^(scripts/check_gateway_boundaries\.py$|\.github/workflows/code_style\.yml$)'; then
echo "has_boundary_check=true" >> "$GITHUB_OUTPUT"
else
echo "has_boundary_check=false" >> "$GITHUB_OUTPUT"
fi
if printf '%s\n' "$CHANGED_FILES" | grep -Eq '^(crates/ironclaw_reborn/|crates/ironclaw_reborn_cli/|crates/ironclaw_reborn_config/|crates/ironclaw_architecture/tests/reborn_dependency_boundaries\.rs$|Cargo\.toml$|Cargo\.lock$|\.github/workflows/code_style\.yml$)'; then
echo "has_reborn_cli=true" >> "$GITHUB_OUTPUT"
else
echo "has_reborn_cli=false" >> "$GITHUB_OUTPUT"
fi
clippy-matrix:
name: Configure clippy matrix
needs: changes
if: needs.changes.outputs.has_code == 'true'
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set.outputs.matrix }}
steps:
- id: set
run: |
FULL='[{"name":"all-features","flags":"--all-features"},{"name":"default","flags":""},{"name":"libsql-only","flags":"--no-default-features --features libsql"}]'
SLIM='[{"name":"all-features","flags":"--all-features"}]'
if [ "${{ github.event_name }}" = "pull_request" ] || [ "${{ github.event_name }}" = "merge_group" ]; then
echo "matrix=${SLIM}" >> "$GITHUB_OUTPUT"
else
echo "matrix=${FULL}" >> "$GITHUB_OUTPUT"
fi
format:
name: Formatting
needs: changes
if: needs.changes.outputs.has_code == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
gateway-js-syntax:
name: Gateway JS syntax
needs: changes
if: needs.changes.outputs.has_code == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
node-version: "22"
- name: Check gateway JS syntax
run: |
find crates/ironclaw_gateway/static/js -type f -name '*.js' \
-exec node --check {} +
deny-check:
name: cargo-deny
needs: changes
if: needs.changes.outputs.has_code == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Run cargo deny
uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979 # v2
tracked-ignored-files:
name: Tracked ignored files
needs: changes
if: needs.changes.outputs.has_code == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Reject tracked files that match .gitignore
run: |
tracked_ignored="$(git ls-files -ci --exclude-standard)"
if [ -n "$tracked_ignored" ]; then
echo "Tracked files match .gitignore; remove them from source control or update .gitignore:"
printf '%s\n' "$tracked_ignored"
exit 1
fi
clippy:
name: Clippy (${{ matrix.name }})
needs: [changes, clippy-matrix]
if: needs.changes.outputs.has_code == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.clippy-matrix.outputs.matrix) }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- name: Install Node.js for WebUI bundle builds
if: contains(matrix.flags, '--all-features')
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: crates/ironclaw_webui_v2/frontend/package-lock.json
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: clippy
# Keep saves to protected-branch and merge_group runs so the ~10 GB
# repo cache LRU is seeded by shared states, not arbitrary PR branches.
save-if: ${{ matrix.name == 'all-features' && ((github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'merge_group') }}
- name: Setup OVH sccache
uses: ./.github/actions/setup-sccache-dist
with:
scheduler-url: ${{ vars.SCCACHE_DIST_SCHEDULER_URL }}
auth-token: ${{ secrets.SCCACHE_DIST_AUTH_TOKEN }}
cache-ssh-host: ${{ vars.SCCACHE_CACHE_SSH_HOST }}
cache-ssh-user: ${{ vars.SCCACHE_CACHE_SSH_USER }}
cache-ssh-port: ${{ vars.SCCACHE_CACHE_SSH_PORT }}
cache-ssh-private-key: ${{ secrets.SCCACHE_CACHE_SSH_PRIVATE_KEY }}
cache-ssh-known-hosts: ${{ secrets.SCCACHE_CACHE_SSH_KNOWN_HOSTS }}
redis-password: ${{ secrets.SCCACHE_REDIS_PASSWORD }}
- name: Check lints
run: cargo clippy --all --tests --examples ${{ matrix.flags }} -- -D warnings
clippy-windows:
name: Clippy Windows (${{ matrix.name }})
needs: [changes, clippy-matrix]
if: needs.changes.outputs.has_code == 'true' && github.event_name == 'push'
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.clippy-matrix.outputs.matrix) }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- name: Install Node.js for WebUI bundle builds
if: contains(matrix.flags, '--all-features')
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: crates/ironclaw_webui_v2/frontend/package-lock.json
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
key: windows-${{ matrix.name }}
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
- name: Check lints
run: cargo clippy --all --tests --examples ${{ matrix.flags }} -- -D warnings
reborn-cli-smoke:
name: Reborn CLI smoke tests
needs: changes
if: needs.changes.outputs.has_reborn_cli == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: reborn-cli-smoke
# Keep saves to protected-branch and merge_group runs so the ~10 GB
# repo cache LRU is seeded by shared states, not arbitrary PR branches.
save-if: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'merge_group' }}
- name: Setup OVH sccache
uses: ./.github/actions/setup-sccache-dist
with:
# Keep this Wasmtime-heavy smoke target cache-only. sccache-dist can
# corrupt generated Wasmtime/Wiggle inputs and produce bogus type
# resolution failures.
cache-ssh-host: ${{ vars.SCCACHE_CACHE_SSH_HOST }}
cache-ssh-user: ${{ vars.SCCACHE_CACHE_SSH_USER }}
cache-ssh-port: ${{ vars.SCCACHE_CACHE_SSH_PORT }}
cache-ssh-private-key: ${{ secrets.SCCACHE_CACHE_SSH_PRIVATE_KEY }}
cache-ssh-known-hosts: ${{ secrets.SCCACHE_CACHE_SSH_KNOWN_HOSTS }}
redis-password: ${{ secrets.SCCACHE_REDIS_PASSWORD }}
- name: Test Reborn boot config crate
run: cargo test -p ironclaw_reborn_config
- name: Test Reborn CLI binary crate
run: cargo test -p ironclaw_reborn_cli
- name: Test Reborn libSQL restart integration
run: |
cargo test -p ironclaw_reborn \
--features libsql-restart-tests \
--test loop_driver_host \
turn_runner_worker_completes_after_libsql_turn_and_thread_services_reopen \
-- --nocapture
- name: Test Reborn architecture boundaries
run: cargo test -p ironclaw_architecture reborn
no-panics:
name: No panics in production code
needs: changes
if: needs.changes.outputs.has_code == 'true' && github.event_name != 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Check for .unwrap(), .expect(), assert!() in production code
env:
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
run: python3 scripts/check_no_panics.py --base "$BASE_SHA" --head HEAD
gateway-boundaries:
name: Gateway platform/feature boundaries
needs: changes
if: needs.changes.outputs.has_code == 'true' || needs.changes.outputs.has_boundary_check == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.12"
- name: Check that platform/ has no back-edges into handlers/ or features/
run: python3 scripts/check_gateway_boundaries.py
- name: Self-test the boundary script
run: python3 scripts/check_gateway_boundaries.py test
code-style:
name: Code Style (fmt + clippy)
runs-on: ubuntu-latest
if: always()
needs:
- changes
- clippy-matrix
- format
- gateway-js-syntax
- clippy
- clippy-windows
- deny-check
- tracked-ignored-files
- reborn-cli-smoke
- no-panics
- gateway-boundaries
steps:
- run: |
if [[ "${{ needs.changes.outputs.has_code }}" == "false" ]]; then
echo "No code changes — style checks skipped correctly"
exit 0
fi
for job_result in \
"format=${{ needs.format.result }}" \
"gateway-js-syntax=${{ needs.gateway-js-syntax.result }}" \
"clippy=${{ needs.clippy.result }}" \
"deny-check=${{ needs.deny-check.result }}" \
"tracked-ignored-files=${{ needs.tracked-ignored-files.result }}" \
"gateway-boundaries=${{ needs.gateway-boundaries.result }}"; do
name="${job_result%%=*}"
result="${job_result##*=}"
if [[ "$result" != "success" ]]; then
echo "$name failed: $result"
exit 1
fi
done
for job_result in \
"no-panics=${{ needs.no-panics.result }}" \
"reborn-cli-smoke=${{ needs.reborn-cli-smoke.result }}" \
"clippy-windows=${{ needs.clippy-windows.result }}"; do
name="${job_result%%=*}"
result="${job_result##*=}"
if [[ "$result" != "success" && "$result" != "skipped" ]]; then
echo "$name failed: $result"
exit 1
fi
done