diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aad6539f..3b7c5121 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,34 @@ jobs: - uses: actions/checkout@v4 - run: bash .github/scripts/check-host-boundary.sh + # Docs-only PRs skip the Rust jobs: no markdown or docs/ file is compiled in. + # Workflow-level `paths-ignore` would leave the required checks pending + # forever, and a matrix job skipped by a job-level `if` reports under an + # unexpanded name, so `build` runs and skips its steps instead. + changes: + name: changes + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + code: ${{ steps.diff.outputs.code }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + # A PR checkout is the merge commit, so its first parent is the base. + # `--no-renames` lists both sides of a move, or `src/x.rs` -> `docs/x.md` + # would show only the docs path. + - id: diff + run: | + files=$(git diff --name-only --no-renames HEAD^1 HEAD) + if [ "${{ github.event_name }}" != pull_request ] \ + || grep -qvE '^docs/|\.mdx?$' <<<"$files"; then + echo "code=true" >> "$GITHUB_OUTPUT" + else + echo "code=false" >> "$GITHUB_OUTPUT" + echo "::notice::docs-only change — Rust jobs skipped" + fi + build: name: build & test (${{ matrix.target }}) strategy: @@ -74,13 +102,18 @@ jobs: target: x86_64-pc-windows-msvc - runner: ubuntu-latest target: x86_64-unknown-linux-gnu + needs: changes runs-on: ${{ matrix.runner }} + # Line tables keep file:line in backtraces but shrink the cached target dir. + env: + CARGO_PROFILE_DEV_DEBUG: line-tables-only # Backstop under the per-step timeouts below. Without any timeout at all a # hung test runs to GitHub's six-hour job limit, which is how a 90-second # step turned into a six-hour one three times in a day. timeout-minutes: 60 steps: - name: Checkout tty7 + if: needs.changes.outputs.code == 'true' uses: actions/checkout@v4 # gpui-component is a git dependency (see Cargo.toml), so no sibling @@ -91,7 +124,7 @@ jobs: # build time (build scripts resolve them via pkg-config). Same set the # README documents for building from source on Linux. - name: Install Linux system dependencies - if: runner.os == 'Linux' + if: needs.changes.outputs.code == 'true' && runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y pkg-config cmake clang libxkbcommon-dev \ @@ -101,10 +134,18 @@ jobs: echo "LIBGSSAPI_IMPL=mit" >> "$GITHUB_ENV" - uses: dtolnay/rust-toolchain@stable + if: needs.changes.outputs.code == 'true' with: targets: ${{ matrix.target }} + # Saved only from main (and manual runs): a cache saved on a PR ref is + # readable by that ref alone, while main's is readable by every branch, + # and per-branch saves of ~2 GB per target blow the 10 GB repo quota. - uses: Swatinem/rust-cache@v2 + if: needs.changes.outputs.code == 'true' + with: + save-if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }} + cache-on-failure: true # `--locked` on the build so a Cargo.lock that disagrees with Cargo.toml # fails here instead of being silently rewritten. Without it the drift is @@ -114,6 +155,7 @@ jobs: # build too; only nightly stays unlocked, because it stamps Cargo.toml's # version and relies on cargo refreshing the lock's own root entry. - name: Build + if: needs.changes.outputs.code == 'true' # Cold-cache builds have been observed at ~10 min; warm ones at ~90s. timeout-minutes: 30 run: cargo build --locked --target ${{ matrix.target }} @@ -133,7 +175,7 @@ jobs: # proc-macro artifacts under it are host units, which are built without # the target's rustflags and legitimately import the CRT dynamically. - name: Assert the Windows binaries need no VC++ redistributable - if: runner.os == 'Windows' + if: needs.changes.outputs.code == 'true' && runner.os == 'Windows' shell: pwsh run: | & ./.github/scripts/assert-no-vcruntime.ps1 ` @@ -154,10 +196,12 @@ jobs: # also has to compile the test targets, on every platform. 20 minutes is # pure headroom, so a trip means a hang, not a slow runner. - name: Test + if: needs.changes.outputs.code == 'true' timeout-minutes: 20 run: cargo test --locked --target ${{ matrix.target }} - name: Test desktop updater + if: needs.changes.outputs.code == 'true' timeout-minutes: 10 run: cargo test --locked --features updater --bin tty7-updater --target ${{ matrix.target }} @@ -190,6 +234,8 @@ jobs: # checks, and reshaping that matrix would wedge branch protection on every open # PR. Keep this job non-required until it has a few weeks of green. server-musl: + needs: changes + if: needs.changes.outputs.code == 'true' name: tty7-server musl (${{ matrix.target }}) runs-on: ubuntu-latest timeout-minutes: 45 @@ -237,6 +283,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} + save-if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }} # The crate split lands separately; until `tty7-server` exists as a # workspace member this job has nothing to build. Skip cleanly rather than @@ -282,6 +329,8 @@ jobs: # same job with an upload step. Non-required until it has a few weeks of # green, for the branch-protection reason spelled out above. server-macos: + needs: changes + if: needs.changes.outputs.code == 'true' name: tty7-server macOS (${{ matrix.target }}) runs-on: macos-latest timeout-minutes: 45 @@ -305,6 +354,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} + save-if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch' }} - name: Look for the tty7-server package id: probe