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