From f052e485ba519c0c81f30f9cddd7ece7189e1ce3 Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 27 May 2026 17:47:56 +0000 Subject: [PATCH 1/2] CI: cache Foundry build (cache/ + out/) to skip recompiling unchanged contracts forge build is the dominant cost in the sol workflows (~105s in copy-artifacts). Cache Foundry's incremental compilation cache + artifacts keyed on the sol sources + foundry.toml + soldeer.lock, with a restore-keys prefix fallback so forge only recompiles changed files. copy-artifacts caches cache/ but NOT out/: it is a clean-build determinism check, so out/ is regenerated fresh each run while cache/ still speeds recompilation. The other sol workflows (sol-test, sol-static, build-pointers, manual-sol-artifacts, rainix test.yml) cache both for the full speedup. --- .github/workflows/rainix-build-pointers.yaml | 11 +++++++++++ .github/workflows/rainix-copy-artifacts.yaml | 10 ++++++++++ .github/workflows/rainix-manual-sol-artifacts.yaml | 11 +++++++++++ .github/workflows/rainix-sol-static.yaml | 11 +++++++++++ .github/workflows/rainix-sol-test.yaml | 11 +++++++++++ .github/workflows/test.yml | 11 +++++++++++ 6 files changed, 65 insertions(+) diff --git a/.github/workflows/rainix-build-pointers.yaml b/.github/workflows/rainix-build-pointers.yaml index 4d6ba13..a45f009 100644 --- a/.github/workflows/rainix-build-pointers.yaml +++ b/.github/workflows/rainix-build-pointers.yaml @@ -30,6 +30,17 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G + # Cache Foundry's incremental compilation cache + artifacts so unchanged + # contracts aren't recompiled (forge build is the dominant CI cost). + - name: Cache Foundry build + uses: actions/cache@v4 + with: + path: | + cache + out + key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} + restore-keys: | + foundry-${{ runner.os }}- # Use rainix's sol-shell directly (slim — no rust/node/chromium). # Mixed-language consumers can ship their heavy default devShell without # paying for it on this purely Solidity-side check. diff --git a/.github/workflows/rainix-copy-artifacts.yaml b/.github/workflows/rainix-copy-artifacts.yaml index bbfd073..92d54ed 100644 --- a/.github/workflows/rainix-copy-artifacts.yaml +++ b/.github/workflows/rainix-copy-artifacts.yaml @@ -29,6 +29,16 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G + # Cache Foundry's incremental compilation cache only (NOT out/): out/ is + # regenerated fresh each run so the committed-artifact assert stays a true + # clean-build check, while cache/ still speeds recompilation. + - name: Cache Foundry build + uses: actions/cache@v4 + with: + path: cache + key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} + restore-keys: | + foundry-${{ runner.os }}- - name: Install soldeer dependencies if: hashFiles('soldeer.lock') != '' run: nix develop github:rainlanguage/rainix#sol-shell -c forge soldeer install diff --git a/.github/workflows/rainix-manual-sol-artifacts.yaml b/.github/workflows/rainix-manual-sol-artifacts.yaml index b8d4689..74f894b 100644 --- a/.github/workflows/rainix-manual-sol-artifacts.yaml +++ b/.github/workflows/rainix-manual-sol-artifacts.yaml @@ -37,6 +37,17 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G + # Cache Foundry's incremental compilation cache + artifacts so unchanged + # contracts aren't recompiled (forge build is the dominant CI cost). + - name: Cache Foundry build + uses: actions/cache@v4 + with: + path: | + cache + out + key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} + restore-keys: | + foundry-${{ runner.os }}- - name: Install soldeer dependencies if: hashFiles('soldeer.lock') != '' run: nix develop github:rainlanguage/rainix#sol-shell -c forge soldeer install diff --git a/.github/workflows/rainix-sol-static.yaml b/.github/workflows/rainix-sol-static.yaml index 78ce9ad..593ca3a 100644 --- a/.github/workflows/rainix-sol-static.yaml +++ b/.github/workflows/rainix-sol-static.yaml @@ -30,6 +30,17 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G + # Cache Foundry's incremental compilation cache + artifacts so unchanged + # contracts aren't recompiled (forge build is the dominant CI cost). + - name: Cache Foundry build + uses: actions/cache@v4 + with: + path: | + cache + out + key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} + restore-keys: | + foundry-${{ runner.os }}- - name: Install soldeer dependencies if: hashFiles('soldeer.lock') != '' run: nix develop github:rainlanguage/rainix#sol-shell -c forge soldeer install diff --git a/.github/workflows/rainix-sol-test.yaml b/.github/workflows/rainix-sol-test.yaml index dd0c1df..305e925 100644 --- a/.github/workflows/rainix-sol-test.yaml +++ b/.github/workflows/rainix-sol-test.yaml @@ -59,6 +59,17 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G + # Cache Foundry's incremental compilation cache + artifacts so unchanged + # contracts aren't recompiled (forge build is the dominant CI cost). + - name: Cache Foundry build + uses: actions/cache@v4 + with: + path: | + cache + out + key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} + restore-keys: | + foundry-${{ runner.os }}- - name: Install soldeer dependencies if: hashFiles('soldeer.lock') != '' run: nix develop github:rainlanguage/rainix#sol-shell -c forge soldeer install diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 38f9188..d018b1e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,6 +54,17 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G + # Cache Foundry's incremental compilation cache + artifacts so unchanged + # contracts aren't recompiled (forge build is the dominant CI cost). + - name: Cache Foundry build + uses: actions/cache@v4 + with: + path: | + cache + out + key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} + restore-keys: | + foundry-${{ runner.os }}- - run: nix develop ../.. --command forge soldeer install - name: Run ${{ matrix.task }} env: From 90043bbe6d762dc083b7b524e0df48f84283ef1b Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 27 May 2026 17:52:00 +0000 Subject: [PATCH 2/2] build-pointers: cache cache/ only, not out/ (determinism check) Like copy-artifacts, build-pointers asserts committed artifacts match a fresh build, so out/ must be regenerated each run; cache/ alone still speeds recompilation. --- .github/workflows/rainix-build-pointers.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rainix-build-pointers.yaml b/.github/workflows/rainix-build-pointers.yaml index a45f009..2b49b16 100644 --- a/.github/workflows/rainix-build-pointers.yaml +++ b/.github/workflows/rainix-build-pointers.yaml @@ -30,14 +30,14 @@ jobs: primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 8G - # Cache Foundry's incremental compilation cache + artifacts so unchanged - # contracts aren't recompiled (forge build is the dominant CI cost). + # Cache Foundry's incremental compilation cache only (NOT out/): this is a + # clean-build determinism check (assert committed pointers match a fresh + # BuildPointers run), so out/ is regenerated fresh each run while cache/ + # still speeds recompilation. - name: Cache Foundry build uses: actions/cache@v4 with: - path: | - cache - out + path: cache key: foundry-${{ runner.os }}-${{ hashFiles('src/**/*.sol', 'test/**/*.sol', 'script/**/*.sol', 'foundry.toml', 'soldeer.lock', 'remappings.txt') }} restore-keys: | foundry-${{ runner.os }}-