diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml new file mode 100644 index 0000000..6c642f0 --- /dev/null +++ b/.github/actions/cache/action.yml @@ -0,0 +1,28 @@ +name: cache +description: >- + Single-source wrapper around `actions/cache`. GitHub Actions can't + parameterize a `uses:` ref, so wrapping the step in a composite is the only + way to pin the action's SHA in ONE place across every rainix workflow that + caches build outputs. Each call site passes its own `path` / `key` / + `restore-keys` (the Foundry build cache, the npm cache, etc.). +inputs: + path: + description: A list of files, directories, and patterns to cache and restore. + required: true + key: + description: An explicit key for restoring and saving the cache. + required: true + restore-keys: + description: >- + An ordered multiline string listing the prefix-matched keys used to + restore a stale cache if no cache hit occurred for `key`. + required: false + default: '' +runs: + using: composite + steps: + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: ${{ inputs.path }} + key: ${{ inputs.key }} + restore-keys: ${{ inputs.restore-keys }} diff --git a/.github/actions/checkout/action.yml b/.github/actions/checkout/action.yml new file mode 100644 index 0000000..a16af6c --- /dev/null +++ b/.github/actions/checkout/action.yml @@ -0,0 +1,22 @@ +name: checkout +description: >- + Single-source wrapper around `actions/checkout`. GitHub Actions can't + parameterize a `uses:` ref (no `uses: ${{ env.X }}`), so the only way to pin + the checkout SHA in ONE place across every rainix workflow is to wrap it in a + composite. The `ssh-key` input covers the one call site (autopublish) that + needs a deploy-key checkout; every other site uses the default token checkout. +inputs: + ssh-key: + description: >- + Optional deploy key (e.g. `secrets.PUBLISH_PRIVATE_KEY`) for a checkout + whose pushes should trigger downstream workflows. A composite action + cannot read `secrets.*`, so the caller must plumb the secret through here. + Empty (the default) falls back to the standard GITHUB_TOKEN checkout. + required: false + default: '' +runs: + using: composite + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + ssh-key: ${{ inputs.ssh-key }} diff --git a/.github/actions/gh-release/action.yml b/.github/actions/gh-release/action.yml new file mode 100644 index 0000000..1d854a8 --- /dev/null +++ b/.github/actions/gh-release/action.yml @@ -0,0 +1,36 @@ +name: gh-release +description: >- + Single-source wrapper around `softprops/action-gh-release`. GitHub Actions + can't parameterize a `uses:` ref, so wrapping the step in a composite is the + only way to pin the action's SHA in ONE place across the (npm / soldeer) + GitHub Release steps in the autopublish workflow. Each call site passes its + own `tag-name` / `name` / `files`. +inputs: + tag-name: + description: The git tag to create the release against (passed to `tag_name`). + required: true + name: + description: The release title. + required: false + default: '' + files: + description: >- + Newline- or comma-separated globs of files to upload as release assets. + Empty (the default) creates a release with no attached assets. + required: false + default: '' + github-token: + description: >- + GitHub token used to create the release. A composite action cannot read + `secrets.*`, so the caller must plumb `secrets.GITHUB_TOKEN` through here. + required: true +runs: + using: composite + steps: + - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 + with: + tag_name: ${{ inputs.tag-name }} + name: ${{ inputs.name }} + files: ${{ inputs.files }} + env: + GITHUB_TOKEN: ${{ inputs.github-token }} diff --git a/.github/actions/nix-cachix-setup/action.yml b/.github/actions/nix-cachix-setup/action.yml new file mode 100644 index 0000000..8cfe1ff --- /dev/null +++ b/.github/actions/nix-cachix-setup/action.yml @@ -0,0 +1,84 @@ +name: nix-cachix-setup +description: >- + Shared 'nix + cachix CI' preamble for the rainix reusable workflows: checkout, + nix-quick-install, the Cachix substituter/pusher, and the cache-nix-action Nix + store restore/save. This composite is the single source of truth for the + pinned third-party action SHAs used by that preamble — each SHA lives here once + instead of being copy-pasted across the reusables. +inputs: + cachix-auth-token: + description: >- + Cachix auth token. A composite action cannot read `secrets.*`, so the + caller reusable must plumb `secrets.CACHIX_AUTH_TOKEN` through to here. + Empty (the default) degrades to a read-only/anonymous Cachix pull. + required: false + default: '' + cachix-name: + description: Cachix binary cache name to substitute from / push to. + required: false + default: rainlanguage + checkout: + description: >- + Run the bundled `actions/checkout` (default). Set to 'false' if the + caller needs a non-default checkout (e.g. an ssh-key deploy-key checkout) + and runs `actions/checkout` itself before calling this composite. + required: false + default: 'true' + cache-nix: + description: >- + Run the bundled `cache-nix-action` Nix store restore/save (default). Set + to 'false' if the caller pins a different cache-nix-action version and runs + it itself. + required: false + default: 'true' + gc-max-store-size-macos: + description: >- + Optional `gc-max-store-size-macos` for the bundled cache-nix-action. Left + empty (the action's own default) unless a caller needs to cap the macOS + store before saving. + required: false + default: '' +runs: + using: composite + steps: + # Fully qualified `rainlanguage/rainix/...@main`, NOT a `./` path: inside a + # composite a `./` ref resolves against the *caller's* repository (the + # downstream consumer running this preamble), where this `checkout` + # composite does not exist. The ref must name this repo explicitly, and + # `@main` is correct for real consumers (they run against merged main). + # + # Note this makes the whole composite un-runnable on a branch that hasn't + # yet merged `.github/actions/checkout` to main: GitHub resolves and + # downloads every transitively-referenced action up front (the `if:` only + # gates execution, not the download), so this `@main` ref is fetched — and + # fails — regardless of `inputs.checkout`. That is the one-time bootstrap + # cost of single-sourcing same-repo composites at `@main`; it clears the + # moment this PR lands on main. + - uses: rainlanguage/rainix/.github/actions/checkout@main + if: ${{ inputs.checkout == 'true' }} + - uses: nixbuild/nix-quick-install-action@5bb6a3b3abe66fd09bbf250dce8ada94f856a703 # v30 + with: + nix_conf: | + keep-env-derivations = true + keep-outputs = true + # Substitute prebuilt rainix derivations from the shared Cachix binary + # cache instead of rebuilding toolchain crates from source (rainix#196). + # Pushes new paths when the auth token is set; continue-on-error so a + # missing cache/token or a Cachix outage degrades to a normal build. + - uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 + continue-on-error: true + with: + name: ${{ inputs.cachix-name }} + authToken: ${{ inputs.cachix-auth-token }} + # No store-watching daemon: it checkpoints the nix DB + # concurrently with cache-nix-action and corrupts it ("database + # disk image is malformed"). Push happens once in the post step. + useDaemon: false + - name: Restore and save Nix store + if: ${{ inputs.cache-nix == 'true' }} + uses: nix-community/cache-nix-action@7df957e333c1e5da7721f60227dbba6d06080569 # v7 + with: + primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} + restore-prefixes-first-match: nix-${{ runner.os }}- + gc-max-store-size-linux: 8G + gc-max-store-size-macos: ${{ inputs.gc-max-store-size-macos }} diff --git a/.github/actions/rust-cache/action.yml b/.github/actions/rust-cache/action.yml new file mode 100644 index 0000000..b0eff56 --- /dev/null +++ b/.github/actions/rust-cache/action.yml @@ -0,0 +1,22 @@ +name: rust-cache +description: >- + Single-source wrapper around `Swatinem/rust-cache`. GitHub Actions can't + parameterize a `uses:` ref, so wrapping the step in a composite is the only + way to pin the action's SHA in ONE place across every rainix workflow that + caches Rust build artifacts. The `prefix-key` input covers the one call site + (vercel) that namespaces its cache per-workflow; every other site uses the + action's default key. +inputs: + prefix-key: + description: >- + Optional `prefix-key` for `Swatinem/rust-cache` (e.g. + `rust-${{ github.workflow }}`). Empty (the default) leaves the action's + own default prefix in place. + required: false + default: '' +runs: + using: composite + steps: + - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 + with: + prefix-key: ${{ inputs.prefix-key }} diff --git a/.github/workflows/check-shell.yml b/.github/workflows/check-shell.yml index 8dd8185..0b689ad 100644 --- a/.github/workflows/check-shell.yml +++ b/.github/workflows/check-shell.yml @@ -10,36 +10,26 @@ jobs: fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action). The pinned third-party action SHAs live ONCE in the + # composites; this self-test references them fully qualified at + # `rainlanguage/rainix/...@main`, exactly as downstream consumers do, so + # the self-test covers what consumers actually run and no third-party SHA + # is duplicated. + # + # BOOTSTRAP CAVEAT: the PR that first adds these composites is RED here + # until it merges. `@main` resolves against the tip of main, which does + # not yet contain `.github/actions/*`, so "Prepare all required actions" + # fails. It cannot be worked around on-branch without a regression (`./` + # would break downstream callers; a branch pin dangles post-merge; and + # GitHub downloads every transitively-referenced action up front, so even + # `checkout: 'false'` cannot dodge the preamble's internal `checkout@main` + # download). Once this PR lands on main the `@main` actions exist and this + # job is green — zero version skew, each third-party action still single- + # sourced. See the PR thread for the full analysis. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - # restore and save a cache using this key - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - # if there's no cache hit, restore a cache by this prefix - restore-prefixes-first-match: nix-${{ runner.os }}- - # collect garbage until the Nix store size (in bytes) is at most this number - # before trying to save a new cache - # 1G = 1073741824 - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} - run: NIXPKGS_ALLOW_INSECURE=1 nix flake check --impure - run: nix develop --command cargo release --version - run: nix develop --command flamegraph --help diff --git a/.github/workflows/rainix-autopublish.yaml b/.github/workflows/rainix-autopublish.yaml index 68f6059..01d4e62 100644 --- a/.github/workflows/rainix-autopublish.yaml +++ b/.github/workflows/rainix-autopublish.yaml @@ -49,7 +49,12 @@ jobs: id-token: write contents: write steps: - - uses: actions/checkout@v4 + # This job needs a deploy-key (ssh-key) checkout, so it runs the shared + # `checkout` composite itself with the key, then calls the nix+cachix + # preamble with `checkout: 'false'`. The pinned checkout / cache-nix / + # nix-quick-install / Cachix SHAs all live once in the composites. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/checkout@main with: # PUBLISH_PRIVATE_KEY is a deploy key whose push events trigger # downstream workflows (unlike GITHUB_TOKEN pushes which don't). @@ -57,30 +62,10 @@ jobs: # falls back to GITHUB_TOKEN over HTTPS — pushes still succeed, # they just won't trigger tag-listening workflows. ssh-key: ${{ secrets.PUBLISH_PRIVATE_KEY }} - - uses: nixbuild/nix-quick-install-action@v30 + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v6 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + checkout: 'false' # Resolve the crate list once (crates, else the back-compat singular crate). - name: Resolve crates run: | @@ -318,7 +303,7 @@ jobs: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - name: Publish to NPM if: ${{ inputs.npm-package != '' && steps.npm.outputs.changed == 'true' }} - uses: JS-DevTools/npm-publish@v3 + uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3 with: token: ${{ secrets.NPM_PUBLISH_PRIVATE_TOKEN }} access: public @@ -341,18 +326,16 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: GitHub Release (npm) if: ${{ inputs.npm-package != '' && steps.npm.outputs.changed == 'true' }} - uses: softprops/action-gh-release@v2 + uses: rainlanguage/rainix/.github/actions/gh-release@main with: - tag_name: npm-${{ env.NPM_VERSION }} + tag-name: npm-${{ env.NPM_VERSION }} name: NPM Package Release ${{ env.NPM_VERSION }} files: npm_package_${{ env.NPM_VERSION }}.tgz - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GITHUB_TOKEN }} - name: GitHub Release (soldeer) if: ${{ inputs.soldeer-package != '' && steps.soldeer.outputs.changed == 'true' }} - uses: softprops/action-gh-release@v2 + uses: rainlanguage/rainix/.github/actions/gh-release@main with: - tag_name: sol-v${{ steps.soldeer.outputs.next }} + tag-name: sol-v${{ steps.soldeer.outputs.next }} name: Soldeer Release sol-v${{ steps.soldeer.outputs.next }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/rainix-copy-artifacts.yaml b/.github/workflows/rainix-copy-artifacts.yaml index 593195a..f209385 100644 --- a/.github/workflows/rainix-copy-artifacts.yaml +++ b/.github/workflows/rainix-copy-artifacts.yaml @@ -5,30 +5,12 @@ jobs: copy-artifacts: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt derivations from the shared Cachix cache so the - # toolchain + any prelude build don't refetch crates from crates.io (whose - # download endpoint 403s nix's User-Agent). Pushes new paths when - # CACHIX_AUTH_TOKEN is set; continue-on-error degrades gracefully. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB concurrently - # with cache-nix-action and corrupts it. Push happens in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} # No Foundry build cache here on purpose: this is a clean-build determinism # check, so out/ must be regenerated fresh — and caching only cache/ (not # out/) gives no real speedup, since forge recompiles to rebuild the diff --git a/.github/workflows/rainix-manual-sol-artifacts.yaml b/.github/workflows/rainix-manual-sol-artifacts.yaml index 24ed9cd..b8503b0 100644 --- a/.github/workflows/rainix-manual-sol-artifacts.yaml +++ b/.github/workflows/rainix-manual-sol-artifacts.yaml @@ -12,35 +12,16 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} # 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 + uses: rainlanguage/rainix/.github/actions/cache@main with: path: | cache diff --git a/.github/workflows/rainix-rs-static.yaml b/.github/workflows/rainix-rs-static.yaml index cc618cb..b657907 100644 --- a/.github/workflows/rainix-rs-static.yaml +++ b/.github/workflows/rainix-rs-static.yaml @@ -5,32 +5,15 @@ jobs: rs-static: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action). The pinned action SHAs live in the composite. A + # reusable workflow must reference a sibling local action by its fully + # qualified owner/repo path (a bare `./` would resolve against the calling + # repo, not rainix), mirroring the github-chore action ref below. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G - - uses: Swatinem/rust-cache@v2 + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + - uses: rainlanguage/rainix/.github/actions/rust-cache@main - run: nix develop github:rainlanguage/rainix#rust-shell -c rainix-rs-static # Run the rainix pre-commit hook bundle (taplo, the nix hooks, yamlfmt, # shellcheck, rustfmt) over all files — the same hooks a local commit diff --git a/.github/workflows/rainix-rs-test.yaml b/.github/workflows/rainix-rs-test.yaml index 6061e63..d8dd043 100644 --- a/.github/workflows/rainix-rs-test.yaml +++ b/.github/workflows/rainix-rs-test.yaml @@ -9,31 +9,13 @@ jobs: fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + # This matrix runs on macOS too, so cap the macOS store before save. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} gc-max-store-size-macos: 1G - - uses: Swatinem/rust-cache@v2 + - uses: rainlanguage/rainix/.github/actions/rust-cache@main - run: nix develop github:rainlanguage/rainix#rust-shell -c cargo test diff --git a/.github/workflows/rainix-rs-wasm-test.yaml b/.github/workflows/rainix-rs-wasm-test.yaml index 4a5d522..9604fd1 100644 --- a/.github/workflows/rainix-rs-wasm-test.yaml +++ b/.github/workflows/rainix-rs-wasm-test.yaml @@ -5,30 +5,11 @@ jobs: rs-wasm-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G - - uses: Swatinem/rust-cache@v2 + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + - uses: rainlanguage/rainix/.github/actions/rust-cache@main - run: nix develop github:rainlanguage/rainix#rust-shell -c bash -c "CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-bindgen-test-runner cargo test --target wasm32-unknown-unknown --workspace" diff --git a/.github/workflows/rainix-rs-wasm.yaml b/.github/workflows/rainix-rs-wasm.yaml index 9362dbd..046b50f 100644 --- a/.github/workflows/rainix-rs-wasm.yaml +++ b/.github/workflows/rainix-rs-wasm.yaml @@ -5,30 +5,11 @@ jobs: rs-wasm: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G - - uses: Swatinem/rust-cache@v2 + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + - uses: rainlanguage/rainix/.github/actions/rust-cache@main - run: nix develop github:rainlanguage/rainix#rust-shell -c cargo build -r --target wasm32-unknown-unknown --lib --workspace diff --git a/.github/workflows/rainix-sol-legal.yaml b/.github/workflows/rainix-sol-legal.yaml index 6888ef0..34a2c9e 100644 --- a/.github/workflows/rainix-sol-legal.yaml +++ b/.github/workflows/rainix-sol-legal.yaml @@ -5,31 +5,12 @@ jobs: legal: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} - 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 cf1c05f..68d538c 100644 --- a/.github/workflows/rainix-sol-static.yaml +++ b/.github/workflows/rainix-sol-static.yaml @@ -5,35 +5,16 @@ jobs: static: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} # 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 + uses: rainlanguage/rainix/.github/actions/cache@main with: path: | cache diff --git a/.github/workflows/rainix-sol-test.yaml b/.github/workflows/rainix-sol-test.yaml index 43d9823..abf52ff 100644 --- a/.github/workflows/rainix-sol-test.yaml +++ b/.github/workflows/rainix-sol-test.yaml @@ -34,35 +34,16 @@ jobs: FLARE_RPC_URL: ${{ secrets.RPC_URL_FLARE_FORK || vars.RPC_URL_FLARE_FORK }} POLYGON_RPC_URL: ${{ secrets.RPC_URL_POLYGON_FORK || vars.RPC_URL_POLYGON_FORK }} steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} # 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 + uses: rainlanguage/rainix/.github/actions/cache@main with: path: | cache diff --git a/.github/workflows/rainix-subgraph-test.yaml b/.github/workflows/rainix-subgraph-test.yaml index 0d9df0f..22f5bed 100644 --- a/.github/workflows/rainix-subgraph-test.yaml +++ b/.github/workflows/rainix-subgraph-test.yaml @@ -5,27 +5,10 @@ jobs: subgraph-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action) — pinned action SHAs live in the composite. Fully + # qualified ref: a bare `./` would resolve against the calling repo. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache. Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error - # so a missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB concurrently - # with cache-nix-action and corrupts it. Push happens in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} - run: nix develop github:rainlanguage/rainix#subgraph-shell -c subgraph-test diff --git a/.github/workflows/rainix-vercel.yaml b/.github/workflows/rainix-vercel.yaml index cbb9bc8..400c49f 100644 --- a/.github/workflows/rainix-vercel.yaml +++ b/.github/workflows/rainix-vercel.yaml @@ -70,31 +70,24 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@v6 + # This workflow needs a Free-disk-space step between checkout and the nix + # install, so it runs its own checkout (composite `checkout: false`) and + # then calls the shared preamble for nix-quick-install + Cachix + + # cache-nix-action. The pinned action SHAs for those still live once in the + # composite. Fully qualified ref: a bare `./` would resolve against the + # calling repo. + - uses: rainlanguage/rainix/.github/actions/checkout@main - name: Free disk space - uses: jlumbroso/free-disk-space@v1.3.1 - - uses: nixbuild/nix-quick-install-action@v30 + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G - - uses: Swatinem/rust-cache@v2 + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} + checkout: 'false' + - uses: rainlanguage/rainix/.github/actions/rust-cache@main with: prefix-key: rust-${{ github.workflow }} - name: Cache npm - uses: actions/cache@v4 + uses: rainlanguage/rainix/.github/actions/cache@main with: path: ~/.npm key: npm-${{ runner.os }}-${{ github.workflow }}-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a34614f..2b4553f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,35 +29,34 @@ jobs: run: working-directory: test/fixture steps: - - uses: actions/checkout@v6 - - uses: nixbuild/nix-quick-install-action@v30 + # Shared nix + cachix CI preamble (checkout, nix-quick-install, Cachix, + # cache-nix-action). The pinned third-party action SHAs live ONCE in the + # composites; every call site — this self-test included — references them + # fully qualified at `rainlanguage/rainix/...@main`, exactly as downstream + # consumers do, so the self-test covers what consumers actually run and no + # third-party SHA is duplicated. + # + # BOOTSTRAP CAVEAT: the PR that first adds these composites is RED here + # until it merges. `@main` resolves against the tip of main, which does + # not yet contain `.github/actions/*`, so "Prepare all required actions" + # fails. This cannot be worked around on-branch without a regression: + # - `./` would resolve a composite's *internal* refs against the + # consumer repo, breaking every downstream caller; + # - a branch pin (`@`) dangles the instant the branch is deleted + # post-merge; + # - GitHub downloads every transitively-referenced action up front, so + # even `checkout: 'false'` cannot dodge the preamble's internal + # `checkout@main` download. + # Once this PR lands on main the `@main` actions exist and every job here + # is green — zero version skew, each third-party action still single- + # sourced. See the PR thread for the full analysis. + - uses: rainlanguage/rainix/.github/actions/nix-cachix-setup@main with: - nix_conf: | - keep-env-derivations = true - keep-outputs = true - # Substitute prebuilt rainix derivations from the shared Cachix binary - # cache instead of rebuilding toolchain crates from source (rainix#196). - # Pushes new paths when CACHIX_AUTH_TOKEN is set; continue-on-error so a - # missing cache/token or a Cachix outage degrades to a normal build. - - uses: cachix/cachix-action@v15 - continue-on-error: true - with: - name: rainlanguage - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - # No store-watching daemon: it checkpoints the nix DB - # concurrently with cache-nix-action and corrupts it ("database - # disk image is malformed"). Push happens once in the post step. - useDaemon: false - - name: Restore and save Nix store - uses: nix-community/cache-nix-action@v7 - with: - primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} - restore-prefixes-first-match: nix-${{ runner.os }}- - gc-max-store-size-linux: 8G + cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} # 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 + uses: rainlanguage/rainix/.github/actions/cache@main with: path: | cache