Repository navigation
deploy: repin graft-dev to ba889c2 (WI-2577, D39 attribution) #681
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: ci | |
| # Required checks for the merge queue: fmt, clippy, test. | |
| # They run on pull requests and in the merge queue. There is no push trigger | |
| # for main: the queue has already tested what lands (docs/plan.md, CONTRIBUTING.md). | |
| on: | |
| pull_request: | |
| merge_group: | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUSTFLAGS: -D warnings | |
| jobs: | |
| # The runner-policy gate (vogt's pattern, inline). Every job names a | |
| # self-hosted runner, and no job selects one dynamically. graft is public: | |
| # fork pull requests are held for approval by the repository's fork-PR | |
| # setting, and no workflow here uses pull_request_target or gives a PR job | |
| # a secret. If you fork this repo, point `runs-on:` at a GitHub-hosted | |
| # runner locally; do not commit that change upstream. | |
| runner-policy: | |
| runs-on: [self-hosted] | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: every job names a self-hosted runner | |
| run: | | |
| set -euo pipefail | |
| bad=0 | |
| # Built from parts: the literal two-brace sequence is an Actions | |
| # expression anywhere in a workflow file, even inside `run:`. | |
| # shellcheck disable=SC2016 | |
| expr_open='${'"{" | |
| while IFS=: read -r file number line; do | |
| # The whole runs-on value: key and any trailing comment stripped, | |
| # surrounding whitespace trimmed. | |
| value=${line#*runs-on:} | |
| value=${value%%#*} | |
| value=$(printf '%s' "$value" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//') | |
| case "$value" in | |
| *"$expr_open"*) | |
| echo "::error file=$file,line=$number::dynamic runner selection is not allowed" | |
| bad=1 | |
| continue | |
| ;; | |
| esac | |
| case "$value" in | |
| # Self-hosted lists. The graft-dev runner is self-hosted but | |
| # registered with --no-default-labels, so its only label is | |
| # graft-dev. | |
| "[self-hosted]"|"[self-hosted,"*"]"|"[graft-dev]") ;; | |
| # Operator decision 2026-10-26: release builds in release.yml | |
| # only use these hosted labels, matched exactly. Required PR | |
| # checks in ci.yml stay self-hosted. | |
| ubuntu-24.04|ubuntu-24.04-arm|macos-14|"[ubuntu-24.04]"|"[ubuntu-24.04-arm]"|"[macos-14]") | |
| if [ "$file" != .github/workflows/release.yml ]; then | |
| echo "::error file=$file,line=$number::hosted runners are allowed only in release.yml" | |
| bad=1 | |
| fi | |
| ;; | |
| *) | |
| echo "::error file=$file,line=$number::job does not name an allowed runner" | |
| bad=1 | |
| ;; | |
| esac | |
| done < <(grep -RnE '^[[:space:]]*runs-on:' .github/workflows \ | |
| --include='*.yml' --include='*.yaml') | |
| [ "$bad" -eq 0 ] | |
| # The self-hosted image ships no language runtime: rust-toolchain installs | |
| # rustup and the toolchain on a bare runner. | |
| fmt: | |
| runs-on: [self-hosted] | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Docs-only diffs skip the build but still report the check (WI-2401). | |
| - id: scope | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} | |
| run: .github/scripts/docs-only.sh "$BASE_SHA" | |
| - if: steps.scope.outputs.docs_only == 'true' | |
| run: echo "docs-only change; skipping the Rust build" | |
| - if: steps.scope.outputs.docs_only == 'true' | |
| run: python3 bench/render.py docs/guide/bench.svg | |
| - uses: dtolnay/rust-toolchain@stable | |
| if: steps.scope.outputs.docs_only != 'true' | |
| with: | |
| components: rustfmt | |
| - run: cargo fmt --all -- --check | |
| if: steps.scope.outputs.docs_only != 'true' | |
| clippy: | |
| runs-on: [self-hosted] | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Docs-only diffs skip the build but still report the check (WI-2401). | |
| - id: scope | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} | |
| run: .github/scripts/docs-only.sh "$BASE_SHA" | |
| - if: steps.scope.outputs.docs_only == 'true' | |
| run: echo "docs-only change; skipping the Rust build" | |
| - uses: dtolnay/rust-toolchain@stable | |
| if: steps.scope.outputs.docs_only != 'true' | |
| with: | |
| components: clippy | |
| # Only main writes the cache back; every ref restores what main saved. | |
| - uses: Swatinem/rust-cache@v2 | |
| if: steps.scope.outputs.docs_only != 'true' | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - run: cargo clippy --workspace --all-targets --all-features -- -D warnings | |
| if: steps.scope.outputs.docs_only != 'true' | |
| test: | |
| runs-on: [self-hosted] | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Docs-only diffs skip the build but still report the check (WI-2401). | |
| - id: scope | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} | |
| run: .github/scripts/docs-only.sh "$BASE_SHA" | |
| - if: steps.scope.outputs.docs_only == 'true' | |
| run: echo "docs-only change; skipping the Rust build" | |
| - uses: dtolnay/rust-toolchain@stable | |
| if: steps.scope.outputs.docs_only != 'true' | |
| # Only main writes the cache back; every ref restores what main saved. | |
| - uses: Swatinem/rust-cache@v2 | |
| if: steps.scope.outputs.docs_only != 'true' | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| # Pinned cargo-nextest, run from the job's temp dir. Some self-hosted | |
| # runners carry an older cargo-nextest in $CARGO_HOME/bin, which cargo | |
| # resolves before PATH, so neither install-action nor a PATH prepend | |
| # is enough. | |
| - if: steps.scope.outputs.docs_only != 'true' | |
| run: | | |
| curl -fsSL https://get.nexte.st/0.9.148/linux | tar -xzf - -C "$RUNNER_TEMP" | |
| "$RUNNER_TEMP/cargo-nextest" nextest --version | |
| # Quarantine (WI-2314, docs/known-flakes.md): rustc, cargo or the | |
| # linker is sometimes OOM-killed on a shared runner. Retry once only | |
| # when the log matches .github/scripts/oom-flake-signature.sh; any | |
| # other failure fails at once. Runs on pull_request and merge_group | |
| # alike. Remove with the host fix. | |
| - name: nextest | |
| if: steps.scope.outputs.docs_only != 'true' | |
| shell: bash | |
| run: | | |
| set +e | |
| nextest() { | |
| "$RUNNER_TEMP/cargo-nextest" nextest run --workspace --all-features --no-tests=pass 2>&1 \ | |
| | tee "$RUNNER_TEMP/nextest.log" | |
| return "${PIPESTATUS[0]}" | |
| } | |
| nextest; status=$? | |
| if [ "$status" -ne 0 ] && .github/scripts/oom-flake-signature.sh "$RUNNER_TEMP/nextest.log"; then | |
| echo "::warning::known OOM flake (WI-2314): rustc killed with no diagnostic; retrying once" | |
| nextest; status=$? | |
| fi | |
| exit "$status" | |
| - run: cargo test --workspace --all-features --doc | |
| if: steps.scope.outputs.docs_only != 'true' | |
| # Not a required check (WI-2480). Records restart-to-serving time on the | |
| # merge queue. continue-on-error means a slow host, or a crash in the | |
| # measurement, never fails the workflow. There is no time assert. | |
| restart-timing: | |
| runs-on: [self-hosted] | |
| timeout-minutes: 30 | |
| continue-on-error: true | |
| if: github.event_name == 'merge_group' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - run: | | |
| curl -fsSL https://get.nexte.st/0.9.148/linux | tar -xzf - -C "$RUNNER_TEMP" | |
| - name: measure restart | |
| shell: bash | |
| run: | | |
| "$RUNNER_TEMP/cargo-nextest" nextest run -p graft-server --all-features \ | |
| -E 'test(restart_serves_and_keeps_an_acknowledged_write)' --no-capture | |
| # Not a required check. Runs the README quick starts only in the merge | |
| # queue (WI-2478). A failing step or a missed line-merge fails the job. | |
| docs-smoke: | |
| runs-on: [self-hosted] | |
| timeout-minutes: 30 | |
| continue-on-error: false | |
| if: github.event_name == 'merge_group' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| - name: build graft | |
| run: cargo build -p graft-cli | |
| env: | |
| CARGO_BUILD_JOBS: "4" | |
| - name: README quick starts | |
| run: scripts/docs-smoke.sh | |
| env: | |
| GRAFT_BIN: ${{ github.workspace }}/target/debug/graft |