From b38211469a9d6095fc7aff390774dd0bfe8346cd Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Sat, 12 Sep 2026 23:02:41 +0000 Subject: [PATCH 1/2] Cache the pnpm store between CI runs The lockfile is not committed so the usual lockfile hash key does not work. Instead the store is snapshotted whenever a package.json changes or a week passes, and every run restores the most recent snapshot through a prefix restore key. pnpm still resolves the latest versions within the ranges; the cache only saves the tarball downloads. A composite action holds the setup so the four jobs share it. Co-Authored-By: Claude Fable 5.1 --- .github/actions/pnpm-install/action.yml | 36 +++++++++++++++++++++++++ .github/workflows/node.js.yml | 21 +++++---------- 2 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 .github/actions/pnpm-install/action.yml diff --git a/.github/actions/pnpm-install/action.yml b/.github/actions/pnpm-install/action.yml new file mode 100644 index 00000000..3f310773 --- /dev/null +++ b/.github/actions/pnpm-install/action.yml @@ -0,0 +1,36 @@ +name: Install dependencies +description: Set up pnpm and Node.js, restore the pnpm store from the cache and run pnpm install + +inputs: + node-version: + description: Node.js version passed to actions/setup-node + required: true + +runs: + using: composite + steps: + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v7 + with: + node-version: ${{ inputs.node-version }} + + # The lockfile is not committed, so the usual lockfile hash key does not + # apply. Instead a new store snapshot is saved whenever a package.json + # changes or a week passes, and every run restores the most recent one. + - id: store + shell: bash + run: | + echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT" + echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT" + - uses: actions/cache@v6 + with: + path: ${{ steps.store.outputs.path }} + key: pnpm-store-${{ runner.os }}-${{ steps.store.outputs.week }}-${{ hashFiles('**/package.json', 'pnpm-workspace.yaml') }} + restore-keys: pnpm-store-${{ runner.os }}- + + - shell: bash + run: pnpm i --no-frozen-lockfile + # Drop packages the restored store had but this install did not use, so + # the snapshot does not grow with every version bump. + - shell: bash + run: pnpm store prune diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f465f8f7..caa9a1a0 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -31,13 +31,10 @@ jobs: steps: - uses: actions/checkout@v7 - - uses: pnpm/action-setup@v6 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v7 + - name: Prepare and install + uses: ./.github/actions/pnpm-install with: node-version: ${{ matrix.node-version }} - - name: Prepare and install - run: pnpm i --no-frozen-lockfile - name: Use Factorio ${{ matrix.factorio-version }} run: wget -q -O factorio.tar.gz https://www.factorio.com/get-download/${{ matrix.factorio-version }}/headless/linux64 && tar -xf factorio.tar.gz && rm factorio.tar.gz - name: Run tests @@ -78,12 +75,10 @@ jobs: steps: - uses: actions/checkout@v7 - - uses: pnpm/action-setup@v6 - - uses: actions/setup-node@v7 + - name: Prepare and install + uses: ./.github/actions/pnpm-install with: node-version: ${{ env.NODE_VERSION }} - - name: Prepare and install - run: pnpm i --no-frozen-lockfile - name: Build run: pnpm run build - name: Test ${{ matrix.controller }} controller with ${{ matrix.host }} host @@ -98,11 +93,9 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v7 - - uses: pnpm/action-setup@v6 - - uses: actions/setup-node@v7 + - uses: ./.github/actions/pnpm-install with: node-version: ${{ env.NODE_VERSION }} - - run: pnpm i --no-frozen-lockfile - run: pnpm run lint build: @@ -110,11 +103,9 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v7 - - uses: pnpm/action-setup@v6 - - uses: actions/setup-node@v7 + - uses: ./.github/actions/pnpm-install with: node-version: ${{ env.NODE_VERSION }} - - run: pnpm i --no-frozen-lockfile - run: pnpm run build-mod # Upload build to artifacts - name: Upload build to artifacts From 992fc0fed7c3d219a5b526900b295688951d95b8 Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Sat, 12 Sep 2026 23:16:12 +0000 Subject: [PATCH 2/2] Cache build output and skip builds where unused The prepare scripts (tsc --build and webpack) are most of the install time in every job, so their output is cached between runs. tsc's tsbuildinfo tracks file hashes and webpack's filesystem cache keeps its node_modules modules, so a restored cache makes both incremental. The lint and build-mod jobs never read the compiled output: eslint is not type-aware here and build_mod.js is plain JavaScript. They now install with --ignore-scripts. Co-Authored-By: Claude Fable 5.1 --- .github/actions/pnpm-install/action.yml | 21 +++++++++++++++++++-- .github/workflows/node.js.yml | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/actions/pnpm-install/action.yml b/.github/actions/pnpm-install/action.yml index 3f310773..b4225457 100644 --- a/.github/actions/pnpm-install/action.yml +++ b/.github/actions/pnpm-install/action.yml @@ -1,10 +1,13 @@ name: Install dependencies -description: Set up pnpm and Node.js, restore the pnpm store from the cache and run pnpm install +description: Set up pnpm and Node.js, restore caches and run pnpm install inputs: node-version: description: Node.js version passed to actions/setup-node required: true + ignore-scripts: + description: Skip the prepare scripts that build the workspace packages + default: "false" runs: using: composite @@ -28,8 +31,22 @@ runs: key: pnpm-store-${{ runner.os }}-${{ steps.store.outputs.week }}-${{ hashFiles('**/package.json', 'pnpm-workspace.yaml') }} restore-keys: pnpm-store-${{ runner.os }}- + # The prepare scripts run tsc --build and webpack, both incremental when + # their previous output is present. Every run saves its output and the + # next run starts from the most recent one. + - if: inputs.ignore-scripts != 'true' + uses: actions/cache@v6 + with: + path: | + packages/*/dist + plugins/*/dist + packages/*/node_modules/.cache + plugins/*/node_modules/.cache + key: build-${{ runner.os }}-${{ github.sha }} + restore-keys: build-${{ runner.os }}- + - shell: bash - run: pnpm i --no-frozen-lockfile + run: pnpm i --no-frozen-lockfile ${{ inputs.ignore-scripts == 'true' && '--ignore-scripts' || '' }} # Drop packages the restored store had but this install did not use, so # the snapshot does not grow with every version bump. - shell: bash diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index caa9a1a0..8b321f19 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -96,6 +96,7 @@ jobs: - uses: ./.github/actions/pnpm-install with: node-version: ${{ env.NODE_VERSION }} + ignore-scripts: true - run: pnpm run lint build: @@ -106,6 +107,7 @@ jobs: - uses: ./.github/actions/pnpm-install with: node-version: ${{ env.NODE_VERSION }} + ignore-scripts: true - run: pnpm run build-mod # Upload build to artifacts - name: Upload build to artifacts