| 1 | # Keeps, on main, the cache entries that only other workflows' runs would |
| 2 | # otherwise make. A run restores from its own ref, then its pull request's |
| 3 | # base branch, then main (docs.g1t.sh/guides/actions/#the-cache): a release |
| 4 | # tag's run never sees another tag's entries, and before this every release |
| 5 | # built its Rust from the start (desktop: 10 of 14 Linux and 12 of 13 |
| 6 | # Windows builds found nothing). So what a release restores is saved here. |
| 7 | # |
| 8 | # look looks every key up without downloading anything; a |
| 9 | # lookup counts as a use, so a warm entry is never taken |
| 10 | # for an unused one, and an entry past its 28 days is |
| 11 | # simply made again |
| 12 | # npm npm's downloads for the whole lockfile, which every npm |
| 13 | # install in every workflow starts from |
| 14 | # runner the runner release's build, for each target |
| 15 | # desktop-linux the desktop release's Linux build |
| 16 | # desktop-windows its Windows cross build, cargo-xwin, the MSVC CRT and |
| 17 | # apt's downloads for it |
| 18 | # cli the CLI release's build of every platform, in the |
| 19 | # cargo-zigbuild image |
| 20 | # |
| 21 | # A job runs only when its key is missing (a new lockfile, a new toolchain, |
| 22 | # or an expired entry), and builds what the release builds. Nothing waits for |
| 23 | # this workflow, and a failed build only leaves the cache as it was. CI |
| 24 | # keeps the rest of main's caches (ci.yml); CONTRIBUTING.md ("How g1t's own |
| 25 | # CI caches") has the whole scheme, and the paths and keys here must stay |
| 26 | # the same as the steps that restore them (repository_workflows.rs checks). |
| 27 | name: Caches |
| 28 | |
| 29 | on: |
| 30 | push: |
| 31 | branches: [main] |
| 32 | workflow_dispatch: |
| 33 | |
| 34 | permissions: |
| 35 | contents: read |
| 36 | |
| 37 | # A build half done saves nothing, so one is never cut off; the next run |
| 38 | # waits, and finds the key saved. |
| 39 | concurrency: |
| 40 | group: caches-${{ github.ref }} |
| 41 | cancel-in-progress: false |
| 42 | |
| 43 | env: |
| 44 | CARGO_TERM_COLOR: never |
| 45 | |
| 46 | jobs: |
| 47 | look: |
| 48 | name: What is missing |
| 49 | runs-on: ubuntu-latest |
| 50 | timeout-minutes: 10 |
| 51 | outputs: |
| 52 | npm: ${{ steps.npm.outputs.cache-hit != 'true' }} |
| 53 | runner: ${{ steps.missing.outputs.runner }} |
| 54 | desktop-linux: ${{ steps.desktop-linux.outputs.cache-hit != 'true' }} |
| 55 | desktop-windows: ${{ steps.desktop-windows.outputs.cache-hit != 'true' || steps.xwin.outputs.cache-hit != 'true' || steps.apt-windows.outputs.cache-hit != 'true' }} |
| 56 | cli: ${{ steps.cli.outputs.cache-hit != 'true' }} |
| 57 | steps: |
| 58 | - uses: actions/checkout@v5 |
| 59 | - name: Cache keys |
| 60 | id: keys |
| 61 | run: node scripts/deploy/ci-cache.mjs keys |
| 62 | - id: npm |
| 63 | uses: actions/cache/restore@v4 |
| 64 | with: |
| 65 | path: ~/.npm |
| 66 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 67 | lookup-only: true |
| 68 | - id: zig |
| 69 | uses: actions/cache/restore@v4 |
| 70 | with: |
| 71 | path: | |
| 72 | ~/.local/lib/python3*/site-packages/ziglang |
| 73 | ~/.local/bin |
| 74 | ~/.cargo/bin/cargo-zigbuild |
| 75 | key: zig-0.13.0-zigbuild-${{ runner.os }}-1 |
| 76 | lookup-only: true |
| 77 | - id: runner-linux-x64 |
| 78 | uses: actions/cache/restore@v4 |
| 79 | with: |
| 80 | path: | |
| 81 | target |
| 82 | !target/runner-release |
| 83 | !target/**/incremental |
| 84 | key: runner-release-${{ runner.os }}-linux-x64-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.cargo }} |
| 85 | lookup-only: true |
| 86 | - id: runner-linux-arm64 |
| 87 | uses: actions/cache/restore@v4 |
| 88 | with: |
| 89 | path: | |
| 90 | target |
| 91 | !target/runner-release |
| 92 | !target/**/incremental |
| 93 | key: runner-release-${{ runner.os }}-linux-arm64-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.cargo }} |
| 94 | lookup-only: true |
| 95 | - id: runner-windows-x64 |
| 96 | uses: actions/cache/restore@v4 |
| 97 | with: |
| 98 | path: | |
| 99 | target |
| 100 | !target/runner-release |
| 101 | !target/**/incremental |
| 102 | key: runner-release-${{ runner.os }}-windows-x64-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.cargo }} |
| 103 | lookup-only: true |
| 104 | - id: desktop-linux |
| 105 | uses: actions/cache/restore@v4 |
| 106 | with: |
| 107 | path: | |
| 108 | ~/.cargo/registry/index |
| 109 | ~/.cargo/registry/cache |
| 110 | apps/desktop/src-tauri/target/release |
| 111 | !apps/desktop/src-tauri/target/release/bundle |
| 112 | !apps/desktop/src-tauri/target/**/incremental |
| 113 | key: desktop-release-linux-${{ runner.os }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.desktop }} |
| 114 | lookup-only: true |
| 115 | - id: desktop-windows |
| 116 | uses: actions/cache/restore@v4 |
| 117 | with: |
| 118 | path: | |
| 119 | ~/.cargo/registry/index |
| 120 | ~/.cargo/registry/cache |
| 121 | apps/desktop/src-tauri/target/release |
| 122 | apps/desktop/src-tauri/target/x86_64-pc-windows-msvc/release |
| 123 | !apps/desktop/src-tauri/target/**/bundle |
| 124 | !apps/desktop/src-tauri/target/**/incremental |
| 125 | key: desktop-release-windows-${{ runner.os }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.desktop }} |
| 126 | lookup-only: true |
| 127 | - id: xwin |
| 128 | uses: actions/cache/restore@v4 |
| 129 | with: |
| 130 | path: | |
| 131 | ~/.cargo/bin/cargo-xwin |
| 132 | ~/.cache/cargo-xwin |
| 133 | key: xwin-${{ runner.os }}-0.23.1 |
| 134 | lookup-only: true |
| 135 | - id: apt-windows |
| 136 | uses: actions/cache/restore@v4 |
| 137 | with: |
| 138 | path: ~/.cache/apt/tauri-windows |
| 139 | key: apt-tauri-windows-${{ runner.os }}-${{ hashFiles('scripts/apt-install.sh') }} |
| 140 | lookup-only: true |
| 141 | - id: cli |
| 142 | uses: actions/cache/restore@v4 |
| 143 | with: |
| 144 | path: | |
| 145 | target/zig |
| 146 | !target/zig/**/incremental |
| 147 | key: cli-release-${{ runner.os }}-${{ steps.keys.outputs.zigbuild }}-${{ steps.keys.outputs.cargo }} |
| 148 | lookup-only: true |
| 149 | # The runner's targets to build: those whose build is missing, or all |
| 150 | # of them when zig is (each saves it, the first to finish wins). |
| 151 | - name: The runner's targets to build |
| 152 | id: missing |
| 153 | env: |
| 154 | ZIG: ${{ steps.zig.outputs.cache-hit }} |
| 155 | LINUX_X64: ${{ steps.runner-linux-x64.outputs.cache-hit }} |
| 156 | LINUX_ARM64: ${{ steps.runner-linux-arm64.outputs.cache-hit }} |
| 157 | WINDOWS_X64: ${{ steps.runner-windows-x64.outputs.cache-hit }} |
| 158 | # Each with its Rust triple, as scripts/runner-release.mjs names it. |
| 159 | run: | |
| 160 | targets=() |
| 161 | [ "$ZIG" = true ] && [ "$LINUX_X64" = true ] || targets+=('{"target":"linux-x64","triple":"x86_64-unknown-linux-musl"}') |
| 162 | [ "$ZIG" = true ] && [ "$LINUX_ARM64" = true ] || targets+=('{"target":"linux-arm64","triple":"aarch64-unknown-linux-musl"}') |
| 163 | [ "$ZIG" = true ] && [ "$WINDOWS_X64" = true ] || targets+=('{"target":"windows-x64","triple":"x86_64-pc-windows-gnu"}') |
| 164 | list="[$(IFS=,; echo "${targets[*]}")]" |
| 165 | echo "runner=$list" >> "$GITHUB_OUTPUT" |
| 166 | echo "The runner's targets to build: $list" |
| 167 | |
| 168 | # npm's downloads for the whole lockfile, saved once for each lockfile. |
| 169 | # Before, every job saved its own part under one key, and the first to |
| 170 | # finish (Wrangler alone, 73 MB) stood in for the rest: each stage then |
| 171 | # downloaded hundreds of MB through the runner's egress, 50 MB tarballs |
| 172 | # among them. Starts from the last lockfile's, with scripts off. |
| 173 | npm: |
| 174 | name: npm's downloads |
| 175 | needs: look |
| 176 | if: ${{ needs.look.outputs.npm == 'true' }} |
| 177 | runs-on: ubuntu-latest |
| 178 | timeout-minutes: 20 |
| 179 | steps: |
| 180 | - uses: actions/checkout@v5 |
| 181 | - name: Start from the last lockfile's |
| 182 | uses: actions/cache/restore@v4 |
| 183 | with: |
| 184 | path: ~/.npm |
| 185 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 186 | restore-keys: npm-full-${{ runner.os }}- |
| 187 | # A failed download leaves the cache as it was, and the run green. |
| 188 | - name: Download every package |
| 189 | id: download |
| 190 | continue-on-error: true |
| 191 | run: node scripts/deploy/npm-ci.mjs --prefer-offline --ignore-scripts --no-audit --no-fund |
| 192 | - name: Save them |
| 193 | if: ${{ steps.download.outcome == 'success' }} |
| 194 | uses: actions/cache/save@v4 |
| 195 | with: |
| 196 | path: ~/.npm |
| 197 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 198 | |
| 199 | # The steps of runner-release.yml's binaries job that fill its cache. |
| 200 | runner: |
| 201 | name: The runner's build for ${{ matrix.target }} |
| 202 | needs: look |
| 203 | if: ${{ needs.look.outputs.runner != '[]' }} |
| 204 | runs-on: ubuntu-latest |
| 205 | timeout-minutes: 60 |
| 206 | strategy: |
| 207 | fail-fast: false |
| 208 | matrix: |
| 209 | include: ${{ fromJSON(needs.look.outputs.runner) }} |
| 210 | env: |
| 211 | G1T_RUNNER_RELEASE_KEY: ${{ vars.RUNNER_RELEASE_PUBLIC_KEY }} |
| 212 | steps: |
| 213 | - uses: actions/checkout@v5 |
| 214 | - name: Cache zig and cargo-zigbuild |
| 215 | id: zig |
| 216 | uses: actions/cache@v4 |
| 217 | with: |
| 218 | path: | |
| 219 | ~/.local/lib/python3*/site-packages/ziglang |
| 220 | ~/.local/bin |
| 221 | ~/.cargo/bin/cargo-zigbuild |
| 222 | key: zig-0.13.0-zigbuild-${{ runner.os }}-1 |
| 223 | - name: Install zig and cargo-zigbuild |
| 224 | if: steps.zig.outputs.cache-hit != 'true' |
| 225 | run: | |
| 226 | pip install --user --break-system-packages ziglang==0.13.0 |
| 227 | cargo install --locked cargo-zigbuild |
| 228 | - name: zig on the PATH |
| 229 | run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" |
| 230 | - name: Cache keys |
| 231 | id: keys |
| 232 | run: node scripts/deploy/ci-cache.mjs keys |
| 233 | - name: Cache crates |
| 234 | uses: actions/cache/restore@v4 |
| 235 | with: |
| 236 | path: | |
| 237 | ~/.cargo/registry/index |
| 238 | ~/.cargo/registry/cache |
| 239 | key: cargo-crates-${{ runner.os }}-${{ steps.keys.outputs.cargo }} |
| 240 | restore-keys: cargo-crates-${{ runner.os }}- |
| 241 | - name: Cache the runner's build |
| 242 | id: runner-build |
| 243 | uses: actions/cache@v4 |
| 244 | with: |
| 245 | path: | |
| 246 | target |
| 247 | !target/runner-release |
| 248 | !target/**/incremental |
| 249 | key: runner-release-${{ runner.os }}-${{ matrix.target }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.cargo }} |
| 250 | restore-keys: runner-release-${{ runner.os }}-${{ matrix.target }}-${{ steps.keys.outputs.rust }}- |
| 251 | - name: sccache |
| 252 | run: bash scripts/sccache.sh install |
| 253 | - name: Build |
| 254 | run: node scripts/runner-release.mjs build --targets ${{ matrix.target }} |
| 255 | - name: Only this build's files are saved |
| 256 | if: ${{ steps.runner-build.outputs.cache-hit != 'true' }} |
| 257 | run: node scripts/deploy/ci-cache.mjs prune target/release target/${{ matrix.triple }}/release -- zigbuild --release --locked --package g1t-runner --target ${{ matrix.triple }} |
| 258 | - name: sccache's hits and misses |
| 259 | if: ${{ always() }} |
| 260 | run: bash scripts/sccache.sh stats |
| 261 | |
| 262 | # desktop-release.yml's Linux build, without its installers: `tauri |
| 263 | # build --no-bundle` compiles exactly what `tauri build` does, and needs |
| 264 | # no signing key. |
| 265 | desktop-linux: |
| 266 | name: The desktop app's Linux build |
| 267 | needs: look |
| 268 | if: ${{ needs.look.outputs.desktop-linux == 'true' }} |
| 269 | # The larger machine: linking Tauri on the small one dies with a bus error. |
| 270 | runs-on: g1t-4core |
| 271 | timeout-minutes: 60 |
| 272 | steps: |
| 273 | - uses: actions/checkout@v5 |
| 274 | - name: Cache keys |
| 275 | id: keys |
| 276 | run: node scripts/deploy/ci-cache.mjs keys |
| 277 | # Saved by CI's desktop job; only restored here. |
| 278 | - name: Cache apt's downloads |
| 279 | uses: actions/cache/restore@v4 |
| 280 | with: |
| 281 | path: ~/.cache/apt/tauri |
| 282 | key: apt-tauri-${{ runner.os }}-${{ hashFiles('scripts/apt-install.sh') }} |
| 283 | - name: What Tauri needs on Linux |
| 284 | run: bash scripts/apt-install.sh tauri |
| 285 | - name: Cache the release build |
| 286 | uses: actions/cache@v4 |
| 287 | with: |
| 288 | path: | |
| 289 | ~/.cargo/registry/index |
| 290 | ~/.cargo/registry/cache |
| 291 | apps/desktop/src-tauri/target/release |
| 292 | !apps/desktop/src-tauri/target/release/bundle |
| 293 | !apps/desktop/src-tauri/target/**/incremental |
| 294 | key: desktop-release-linux-${{ runner.os }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.desktop }} |
| 295 | restore-keys: desktop-release-linux-${{ runner.os }}-${{ steps.keys.outputs.rust }}- |
| 296 | - name: Cache npm's downloads |
| 297 | uses: actions/cache/restore@v4 |
| 298 | with: |
| 299 | path: ~/.npm |
| 300 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 301 | restore-keys: npm-full-${{ runner.os }}- |
| 302 | - name: Install |
| 303 | run: node scripts/deploy/npm-ci.mjs --prefer-offline --no-audit --no-fund |
| 304 | - name: Build |
| 305 | working-directory: apps/desktop |
| 306 | run: npx tauri build --ci --no-bundle |
| 307 | |
| 308 | # desktop-release.yml's Windows cross build, without its installer. |
| 309 | desktop-windows: |
| 310 | name: The desktop app's Windows build |
| 311 | needs: look |
| 312 | if: ${{ needs.look.outputs.desktop-windows == 'true' && vars.DESKTOP_WINDOWS_FROM_LINUX == 'true' && vars.DESKTOP_WINDOWS_RUNNER != 'true' }} |
| 313 | runs-on: g1t-4core |
| 314 | timeout-minutes: 60 |
| 315 | steps: |
| 316 | - uses: actions/checkout@v5 |
| 317 | - name: Cache keys |
| 318 | id: keys |
| 319 | run: node scripts/deploy/ci-cache.mjs keys |
| 320 | - name: Cache apt's downloads |
| 321 | uses: actions/cache@v4 |
| 322 | with: |
| 323 | path: ~/.cache/apt/tauri-windows |
| 324 | key: apt-tauri-windows-${{ runner.os }}-${{ hashFiles('scripts/apt-install.sh') }} |
| 325 | - name: What the cross build needs |
| 326 | run: bash scripts/desktop-cross-tools.sh |
| 327 | - name: Cache cargo-xwin and the MSVC CRT |
| 328 | id: xwin |
| 329 | uses: actions/cache@v4 |
| 330 | with: |
| 331 | path: | |
| 332 | ~/.cargo/bin/cargo-xwin |
| 333 | ~/.cache/cargo-xwin |
| 334 | key: xwin-${{ runner.os }}-0.23.1 |
| 335 | - name: cargo-xwin |
| 336 | if: ${{ steps.xwin.outputs.cache-hit != 'true' }} |
| 337 | run: cargo install --locked cargo-xwin@0.23.1 |
| 338 | - name: Cache the release build |
| 339 | uses: actions/cache@v4 |
| 340 | with: |
| 341 | path: | |
| 342 | ~/.cargo/registry/index |
| 343 | ~/.cargo/registry/cache |
| 344 | apps/desktop/src-tauri/target/release |
| 345 | apps/desktop/src-tauri/target/x86_64-pc-windows-msvc/release |
| 346 | !apps/desktop/src-tauri/target/**/bundle |
| 347 | !apps/desktop/src-tauri/target/**/incremental |
| 348 | key: desktop-release-windows-${{ runner.os }}-${{ steps.keys.outputs.rust }}-${{ steps.keys.outputs.desktop }} |
| 349 | restore-keys: desktop-release-windows-${{ runner.os }}-${{ steps.keys.outputs.rust }}- |
| 350 | - name: Cache npm's downloads |
| 351 | uses: actions/cache/restore@v4 |
| 352 | with: |
| 353 | path: ~/.npm |
| 354 | key: npm-full-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 355 | restore-keys: npm-full-${{ runner.os }}- |
| 356 | - name: Install |
| 357 | run: node scripts/deploy/npm-ci.mjs --prefer-offline --no-audit --no-fund |
| 358 | - name: Build |
| 359 | working-directory: apps/desktop |
| 360 | run: | |
| 361 | rustup target add x86_64-pc-windows-msvc |
| 362 | npx tauri build --ci --runner cargo-xwin --target x86_64-pc-windows-msvc --no-bundle |
| 363 | # What the CRT and SDK came to, for the cache's 2 GB an entry may hold. |
| 364 | - name: How large the MSVC CRT is |
| 365 | run: du -sh ~/.cache/cargo-xwin || true |
| 366 | |
| 367 | # cli-release.yml's build of every platform, in the cargo-zigbuild image |
| 368 | # (scripts/cli-release.mjs). Built whole whenever its key is new (a new |
| 369 | # image or new dependencies), never started from an older entry: what |
| 370 | # zigbuild built cannot be listed by this machine's Cargo to prune it, so |
| 371 | # nothing old is carried in to begin with. |
| 372 | cli: |
| 373 | name: The CLI's release build |
| 374 | needs: look |
| 375 | if: ${{ needs.look.outputs.cli == 'true' }} |
| 376 | # The builder runs in Docker, which g1t's own machines give each job. |
| 377 | runs-on: g1t-4core |
| 378 | timeout-minutes: 60 |
| 379 | steps: |
| 380 | - uses: actions/checkout@v5 |
| 381 | - name: Cache keys |
| 382 | id: keys |
| 383 | run: node scripts/deploy/ci-cache.mjs keys |
| 384 | - name: Cache crates |
| 385 | uses: actions/cache/restore@v4 |
| 386 | with: |
| 387 | path: | |
| 388 | ~/.cargo/registry/index |
| 389 | ~/.cargo/registry/cache |
| 390 | key: cargo-crates-${{ runner.os }}-${{ steps.keys.outputs.cargo }} |
| 391 | restore-keys: cargo-crates-${{ runner.os }}- |
| 392 | - name: Cache the CLI's build |
| 393 | uses: actions/cache@v4 |
| 394 | with: |
| 395 | path: | |
| 396 | target/zig |
| 397 | !target/zig/**/incremental |
| 398 | key: cli-release-${{ runner.os }}-${{ steps.keys.outputs.zigbuild }}-${{ steps.keys.outputs.cargo }} |
| 399 | - name: Build |
| 400 | run: node scripts/cli-release.mjs build |
| 401 | - name: How large the build is |
| 402 | run: du -sh target/zig || true |