| 1 | # Tests every pull request into main, so main can always be deployed. The |
| 2 | # "Default branch" ruleset requires this workflow ("CI") to pass before a |
| 3 | # pull request merges; people may still push to main directly, agents |
| 4 | # may not. Deploy (deploy.yml) ships what lands on main. |
| 5 | # |
| 6 | # rust every crate's tests, natively |
| 7 | # typescript type checks and tests of the apps and TS services, the |
| 8 | # deploy and ops scripts, and the deploy manifest |
| 9 | # build the site, sudo and the docs build as they deploy |
| 10 | # |
| 11 | # On a push to main `rust` and `desktop` run, keeping main's caches current: |
| 12 | # a pull request's run restores from main's cache, never from another pull |
| 13 | # request's, so without them each pull request would start from nothing. |
| 14 | # What each cache holds, its key and which job saves it: CONTRIBUTING.md, |
| 15 | # "How g1t's own CI caches". The Caches workflow (caches.yml) keeps the |
| 16 | # ones only releases build. |
| 17 | name: CI |
| 18 | |
| 19 | on: |
| 20 | pull_request: |
| 21 | branches: [main] |
| 22 | push: |
| 23 | branches: [main] |
| 24 | workflow_dispatch: |
| 25 | |
| 26 | # Its token only reads: it checks the code out and nothing more. |
| 27 | permissions: |
| 28 | contents: read |
| 29 | |
| 30 | concurrency: |
| 31 | group: ci-${{ github.ref }} |
| 32 | cancel-in-progress: true |
| 33 | |
| 34 | env: |
| 35 | CARGO_TERM_COLOR: never |
| 36 | WRANGLER_SEND_METRICS: "false" |
| 37 | |
| 38 | jobs: |
| 39 | rust: |
| 40 | name: Rust |
| 41 | runs-on: g1t-4core |
| 42 | timeout-minutes: 45 |
| 43 | env: |
| 44 | # Line tables, not full debug info: a panic still names its file and |
| 45 | # line, and the test build is a fraction of the size to link, keep |
| 46 | # and restore (at full debug info its cache entry reached 1.7 GB of |
| 47 | # the 2 GB an entry may hold). |
| 48 | CARGO_PROFILE_DEV_DEBUG: line-tables-only |
| 49 | steps: |
| 50 | - uses: actions/checkout@v5 |
| 51 | # rust: the toolchain; cargo: Cargo.lock's crates.io and git packages, |
| 52 | # not the workspace's own versions (scripts/deploy/ci-cache.mjs). |
| 53 | - name: Cache keys |
| 54 | id: keys |
| 55 | run: node scripts/deploy/ci-cache.mjs keys |
| 56 | # Every crate the lockfile names, for every target (the fetch below): |
| 57 | # saved by this job alone, and only restored by Deploy and the |
| 58 | # releases, which each download part of it. |
| 59 | - name: Cache crates |
| 60 | uses: actions/cache@v4 |
| 61 | with: |
| 62 | path: | |
| 63 | ~/.cargo/registry/index |
| 64 | ~/.cargo/registry/cache |
| 65 | key: cargo-crates-${{ runner.os }}-${{ steps.keys.outputs.cargo }} |
| 66 | restore-keys: cargo-crates-${{ runner.os }}- |
| 67 | - name: Every crate the lockfile names |
| 68 | run: cargo fetch --locked |
| 69 | # The compiled dependencies and workspace crates. Saved when the |
| 70 | # dependencies or the toolchain change; otherwise the last entry for |
| 71 | # this toolchain is a start, and only this build's files go into the |
| 72 | # new one (the prune step below). |
| 73 | - name: Cache the test build |
| 74 | id: test-build |
| 75 | uses: actions/cache@v4 |
| 76 | with: |
| 77 | path: | |
| 78 | target/debug |
| 79 | !target/debug/incremental |
| 80 | key: cargo-test-${{ runner.os }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.cargo }} |
| 81 | restore-keys: cargo-test-${{ runner.os }}-${{ steps.keys.outputs.rust }}- |
| 82 | # The workspace's library crates that Cargo compiles again come back |
| 83 | # from the repository's Actions cache when their inputs did not change |
| 84 | # (scripts/sccache.sh). Test harnesses and Workers' own crates are |
| 85 | # linked, and still compiled. |
| 86 | - name: sccache |
| 87 | run: bash scripts/sccache.sh install |
| 88 | - name: Tests |
| 89 | run: cargo test --workspace --locked --quiet |
| 90 | # A restored target keeps the old versions of whatever changed beside |
| 91 | # the new ones; only what this build used goes into the new entry. |
| 92 | - name: Only this build's files are saved |
| 93 | if: ${{ steps.test-build.outputs.cache-hit != 'true' }} |
| 94 | run: node scripts/deploy/ci-cache.mjs prune target/debug -- test --workspace --locked --no-run |
| 95 | - name: sccache's hits and misses |
| 96 | if: ${{ always() }} |
| 97 | run: bash scripts/sccache.sh stats |
| 98 | |
| 99 | typescript: |
| 100 | name: TypeScript |
| 101 | if: ${{ github.event_name != 'push' }} |
| 102 | runs-on: ubuntu-latest |
| 103 | timeout-minutes: 30 |
| 104 | steps: |
| 105 | - uses: actions/checkout@v5 |
| 106 | # npm's downloads, kept between runs: an install reads them first |
| 107 | # and asks the registry only for what changed, so a dropped |
| 108 | # connection to it rarely stops the job. |
| 109 | - name: Cache npm's downloads |
| 110 | uses: actions/cache@v4 |
| 111 | with: |
| 112 | path: ~/.npm |
| 113 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 114 | restore-keys: npm-full-${{ runner.os }}- |
| 115 | - name: Install |
| 116 | run: node scripts/deploy/npm-ci.mjs --prefer-offline --no-audit --no-fund |
| 117 | - name: Type checks |
| 118 | run: npm run typecheck |
| 119 | - name: Tests |
| 120 | run: npm test --workspaces --if-present |
| 121 | - name: The deploy tool's tests |
| 122 | run: npm run test:deploy |
| 123 | - name: The conformance report's tests |
| 124 | run: npm run test:conformance |
| 125 | - name: The ops scripts' tests |
| 126 | run: npm run test:ops |
| 127 | - name: The manifest matches every wrangler.jsonc |
| 128 | run: node scripts/deploy.mjs manifest --check |
| 129 | - name: The Claude Code plugin's tests |
| 130 | run: node --test plugins/claude-code/test/hooks.test.mjs |
| 131 | |
| 132 | build: |
| 133 | name: Build |
| 134 | if: ${{ github.event_name != 'push' }} |
| 135 | runs-on: ubuntu-latest |
| 136 | timeout-minutes: 30 |
| 137 | steps: |
| 138 | - uses: actions/checkout@v5 |
| 139 | # npm's downloads, kept between runs: an install reads them first |
| 140 | # and asks the registry only for what changed, so a dropped |
| 141 | # connection to it rarely stops the job. |
| 142 | - name: Cache npm's downloads |
| 143 | uses: actions/cache@v4 |
| 144 | with: |
| 145 | path: ~/.npm |
| 146 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 147 | restore-keys: npm-full-${{ runner.os }}- |
| 148 | - name: Install |
| 149 | run: node scripts/deploy/npm-ci.mjs --prefer-offline --no-audit --no-fund |
| 150 | - name: The site, sudo and the docs |
| 151 | run: node scripts/deploy.mjs build --only web,sudo,docs |
| 152 | |
| 153 | desktop: |
| 154 | name: Desktop app |
| 155 | # The larger machine, as the Rust job: linking Tauri on the small one |
| 156 | # ran out of room and the linker died with a bus error. |
| 157 | runs-on: g1t-4core |
| 158 | timeout-minutes: 30 |
| 159 | steps: |
| 160 | - uses: actions/checkout@v5 |
| 161 | - name: Cache keys |
| 162 | id: keys |
| 163 | run: node scripts/deploy/ci-cache.mjs keys |
| 164 | # apt's lists and downloads (scripts/apt-install.sh): 110 s of every |
| 165 | # run before, mostly fetching 335 MB. Saved here, on main; the desktop |
| 166 | # release's Linux build restores the same entry. |
| 167 | - name: Cache apt's downloads |
| 168 | uses: actions/cache@v4 |
| 169 | with: |
| 170 | path: ~/.cache/apt/tauri |
| 171 | key: apt-tauri-${{ runner.os }}-${{ hashFiles('scripts/apt-install.sh') }} |
| 172 | - name: What Tauri needs on Linux |
| 173 | run: bash scripts/apt-install.sh tauri |
| 174 | - name: Cache the desktop app's build |
| 175 | id: desktop-build |
| 176 | uses: actions/cache@v4 |
| 177 | with: |
| 178 | path: | |
| 179 | ~/.cargo/registry/index |
| 180 | ~/.cargo/registry/cache |
| 181 | apps/desktop/src-tauri/target/debug |
| 182 | !apps/desktop/src-tauri/target/debug/incremental |
| 183 | key: desktop-check-${{ runner.os }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.desktop }} |
| 184 | restore-keys: desktop-check-${{ runner.os }}-${{ steps.keys.outputs.rust }}- |
| 185 | # Outside the workspace on purpose (Cargo.toml says why): checked and |
| 186 | # tested here, built into installers by desktop-release.yml. |
| 187 | - name: Check and test |
| 188 | run: cargo test --locked --manifest-path apps/desktop/src-tauri/Cargo.toml --quiet |
| 189 | - name: Only this build's files are saved |
| 190 | if: ${{ steps.desktop-build.outputs.cache-hit != 'true' }} |
| 191 | run: node scripts/deploy/ci-cache.mjs prune apps/desktop/src-tauri/target/debug -- test --locked --manifest-path apps/desktop/src-tauri/Cargo.toml --no-run |
| 192 | - name: The release scripts' tests |
| 193 | run: node --test scripts/desktop-release.test.mjs scripts/mobile-release.test.mjs scripts/cli-release.test.mjs |