From ad8628773ee2b3b86ee42993f895bf14a2cef9da Mon Sep 17 00:00:00 2001 From: John Wright Date: Sun, 22 Mar 2026 10:54:46 +0000 Subject: [PATCH 1/4] feat: better caching strategy --- .github/workflows/yarn-cache.yml | 91 ++++++++++++++++++++----------- actions/yarn-cache-key/action.yml | 36 +++++++++--- actions/yarn-cache/action.yml | 42 ++++++++++++-- 3 files changed, 122 insertions(+), 47 deletions(-) diff --git a/.github/workflows/yarn-cache.yml b/.github/workflows/yarn-cache.yml index cec6f51..49a252a 100644 --- a/.github/workflows/yarn-cache.yml +++ b/.github/workflows/yarn-cache.yml @@ -1,33 +1,70 @@ name: Yarn Cache +# description: | #markdown +# Similar idea to the yarn-cache action, but makes sure that only one workflow +# can create the cache at a time. EG: + +# ```yaml +# jobs: +# cache: +# uses: johngeorgewright/workflows/workflows/yarn-cache@main +# test: +# needs: [cache] +# runs-on: dmg-arc-ubuntu +# steps: +# - uses: actions/checkout@v6 +# +# # OPTION 1: manually download the cache +# - uses: actions/cache/restore@v5 +# with: +# key: ${\{ needs.cache.outputs.key }} +# path: ${\{ needs.cache.outputs.path }} +# restore-keys: ${\{ needs.cache.outputs.restore-keys }} +# +# # OPTION 2: let the key be discovered automatically +# - uses: actions/setup-node@v6 +# - uses: johngeorgewright/workflows/actions/yarn-cache@main +# ``` + on: workflow_call: inputs: + cache-path: + description: The cache paths + required: false + type: string + default: | + ~/.cache + .yarn/unplugged + .yarn/install-state.gz + runs-on: - default: ubuntu-latest + default: dmg-arc-ubuntu required: false type: string description: Use runs-on to define the type of machine to run the job on. + working-directory: + description: Optional directory to execute yarn command in + required: false + type: string + default: ${{ github.workspace }} + outputs: key: value: ${{ jobs.key.outputs.cache-key }} path: value: ${{ jobs.prime.outputs.cache-path }} + restore-keys: + value: ${{ jobs.key.outputs.cache-restore-keys }} jobs: - deprecate: - name: Deprecated - runs-on: ${{ inputs.runs-on }} - steps: - - name: Message - run: echo "::warning title=Deprecated workflow::The johngeorgewright/workflows/.github/workflows/yarn-cache.yml is dperecated. Please use johngeorgewright/workflows/yarn-cache.yml instead." - key: name: Key runs-on: ${{ inputs.runs-on }} outputs: - cache-key: ${{ steps.key.outputs.cache_key }} + cache-key: ${{ steps.key.outputs.cache-key }} + cache-restore-keys: ${{ steps.key.outputs.cache-restore-keys }} steps: - name: Checkout project uses: actions/checkout@v6 @@ -36,46 +73,36 @@ jobs: id: node uses: actions/setup-node@v6 with: - node-version-file: .nvmrc + node-version-file: ${{ inputs.working-directory }}/.nvmrc + + - run: corepack enable - name: Key id: key - run: | - corepack enable - echo "cache_key=${{ runner.os }}-node-${{ steps.node.outputs.node-version }}-yarn-$(yarn --version)-${{ hashFiles('**/yarn.lock') }}" >> $GITHUB_OUTPUT + uses: johngeorgewright/workflows/actions/yarn-cache-key@main + with: + working-directory: ${{ inputs.working-directory }} prime: name: Prime needs: [key] runs-on: ${{ inputs.runs-on }} - env: - CACHE_PATH: | - ~/.cache - .yarn/unplugged - .yarn/install-state.gz concurrency: group: ${{ needs.key.outputs.cache-key }} outputs: - cache-path: ${{ env.CACHE_PATH }} + cache-path: ${{ inputs.cache-path }} steps: - name: Checkout project uses: actions/checkout@v6 - name: Install Node.js - id: node uses: actions/setup-node@v6 with: - node-version-file: .nvmrc + node-version-file: ${{ inputs.working-directory }}/.nvmrc - - name: Cache - id: cache - uses: actions/cache@v5 - with: - path: ${{ env.CACHE_PATH }} - key: ${{ needs.key.outputs.cache-key }} + - run: corepack enable - - name: Install Depedencies - if: steps.cache.outputs.cache-hit != 'true' - run: | - corepack enable - yarn --immutable + - uses: johngeorgewright/workflows/actions/yarn-cache@main + with: + cache-path: ${{ inputs.cache-path }} + working-directory: ${{ inputs.working-directory }} diff --git a/actions/yarn-cache-key/action.yml b/actions/yarn-cache-key/action.yml index 21ed38c..1b60bb5 100644 --- a/actions/yarn-cache-key/action.yml +++ b/actions/yarn-cache-key/action.yml @@ -1,25 +1,43 @@ name: Yarn Cache Key -author: johngeorgewright +author: DMG Ads -description: Create the Yarn dependency cache key. +description: Create a cache key for you Yarn dependencies inputs: working-directory: - description: An optional working directory to discover the cache key + description: Optional directory to execute in required: false outputs: - cache-key: + cache-key: description: The cache key value: ${{ steps.key.outputs.cache-key }} + cache-restore-keys: + description: Fallback/restore keys + value: ${{ steps.key.outputs.cache-restore-keys }} runs: using: composite steps: - - shell: bash - id: key + - id: key working-directory: ${{ inputs.working-directory }} - run: | - corepack enable - echo "cache-key=${{ runner.os }}-node-$(node --version)-yarn-$(yarn --version)-${{ hashFiles('**/yarn.lock') }}" >> $GITHUB_OUTPUT + shell: bash + run: | # shell + os='${{ runner.os }}' + node_version=$( node --version ) + yarn_version=$( yarn --version ) + deps_hash=$(sed -n 's/ resolution: "\(.*\)@npm:.*/\1/p' yarn.lock \ + | sort -u \ + | sha256sum \ + | cut -d ' ' -f 1) + + echo "cache-key=deps-${os}-${node_version}-${yarn_version}-${deps_hash}-${{ hashFiles('**/yarn.lock') }}" >> $GITHUB_OUTPUT + + echo "cache-restore-keys<> $GITHUB_OUTPUT + echo "deps-${os}-${node_version}-${yarn_version}-${deps_hash}-" >> $GITHUB_OUTPUT + echo "deps-${os}-${node_version}-${yarn_version}-" >> $GITHUB_OUTPUT + echo "deps-${os}-${node_version}-" >> $GITHUB_OUTPUT + echo "deps-${os}-" >> $GITHUB_OUTPUT + echo "deps-" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT diff --git a/actions/yarn-cache/action.yml b/actions/yarn-cache/action.yml index 5e520ca..bf9d589 100644 --- a/actions/yarn-cache/action.yml +++ b/actions/yarn-cache/action.yml @@ -1,12 +1,13 @@ name: Yarn Cache -author: johngeorgewright +author: DMG Ads description: Speed up your Node.js builds by caching the Yarn dependencies. inputs: - cache_path: + cache-path: description: The cache paths + required: false default: | ~/.cache .yarn/unplugged @@ -15,19 +16,48 @@ inputs: description: Optional directory to execute in required: false +outputs: + cache-key: + description: The cache key + value: ${{ steps.key.outputs.cache-key }} + cache-hit: + description: Whether the cache was used + value: ${{ steps.cache.outputs.cache-hit }} + cache-restore-keys: + description: Fallback/restore keys + value: ${{ steps.key.outputs.cache-restore-keys }} + runs: using: composite steps: - id: key uses: johngeorgewright/workflows/actions/yarn-cache-key@main + with: + working-directory: ${{ inputs.working-directory }} - - id: cache - uses: actions/cache@v4 + - name: Restore Cache + id: cache + uses: actions/cache/restore@v5 with: - path: ${{ inputs.cache_path }} key: ${{ steps.key.outputs.cache-key }} + path: ${{ inputs.cache-path }} + restore-keys: ${{ steps.key.outputs.cache-restore-keys }} - - if: steps.cache.outputs.cache-hit != 'true' + - name: Clean Stale Install State + if: steps.cache.outputs.cache-matched-key != '' && steps.cache.outputs.cache-matched-key != steps.key.outputs.cache-key + working-directory: ${{ inputs.working-directory }} + shell: bash + run: rm -f .yarn/install-state.gz + + - name: Install Dependencies + if: steps.cache.outputs.cache-hit != 'true' working-directory: ${{ inputs.working-directory }} shell: bash run: yarn --immutable + + - name: Save Cache + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v5 + with: + path: ${{ inputs.cache-path }} + key: ${{ steps.key.outputs.cache-key }} From 1a4a3b357be9da4f3cf07a98d2d2f0723deeda6b Mon Sep 17 00:00:00 2001 From: John Wright Date: Sun, 22 Mar 2026 12:24:07 +0000 Subject: [PATCH 2/4] feat: better caching --- .github/workflows/test-action-yarn-cache.yml | 68 ++++++++++++---- actions/yarn-cache/action.yml | 2 +- yarn-cache.yml | 82 ++++++++++++++------ 3 files changed, 115 insertions(+), 37 deletions(-) diff --git a/.github/workflows/test-action-yarn-cache.yml b/.github/workflows/test-action-yarn-cache.yml index 7cec3d0..a6833d9 100644 --- a/.github/workflows/test-action-yarn-cache.yml +++ b/.github/workflows/test-action-yarn-cache.yml @@ -1,8 +1,14 @@ -name: Test Yarn Cache Action +name: Test Yarn Cache on: pull_request: - paths: [actions/yarn-cache/**] + paths: + - .github/actions/yarn-cache/** + - .github/actions/yarn-cache-key/** + +concurrency: + group: test-action-yarn-cache-${{ github.head_ref }} + cancel-in-progress: true env: CACHE_PATH: | @@ -12,29 +18,65 @@ env: WORKING_DIR: ./test/actions/yarn-cache jobs: - first-cache: - runs-on: ubuntu-latest + create-cache: + uses: ./.github/workflows/yarn-cache.yml + with: + cache-path: | + ~/.cache + test/actions/yarn-cache/.yarn/unplugged + test/actions/yarn-cache/.yarn/install-state.gz + working-directory: ./test/actions/yarn-cache + + use-exact-cache: + needs: [create-cache] + runs-on: dmg-arc-ubuntu steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: - node-version-file: test/actions/yarn-cache/.nvmrc + node-version-file: ${{ env.WORKING_DIR }}/.nvmrc - run: corepack enable - - uses: ./actions/yarn-cache + - uses: ./.github/actions/yarn-cache + id: cache with: - cache_path: ${{ env.CACHE_PATH }} + cache-path: ${{ env.CACHE_PATH }} working-directory: ${{ env.WORKING_DIR }} + - if: steps.cache.outputs.cache-hit != 'true' + run: | + echo "::error::The cache wasn't used" + exit 1 - second-cache: - needs: [first-cache] - runs-on: ubuntu-latest + use-partial-cache: + needs: [create-cache] + runs-on: dmg-arc-ubuntu steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 with: - node-version-file: test/actions/yarn-cache/.nvmrc + node-version-file: ${{ env.WORKING_DIR }}/.nvmrc - run: corepack enable - - uses: ./actions/yarn-cache + - working-directory: ${{ env.WORKING_DIR }} + run: yarn add express@^5.2.1 + - uses: ./.github/actions/yarn-cache-key + id: key + with: + working-directory: ${{ env.WORKING_DIR }} + - uses: ./.github/actions/yarn-cache + id: cache with: - cache_path: ${{ env.CACHE_PATH }} + cache-path: ${{ env.CACHE_PATH }} working-directory: ${{ env.WORKING_DIR }} + - if: steps.cache.outputs.cache-hit == 'true' + run: | # shell + echo "::error::Expected a restore-key match, not an exact cache hit" + exit 1 + + clean-up: + needs: [create-cache, use-exact-cache, use-partial-cache] + if: always() + runs-on: dmg-arc-ubuntu + steps: + - env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + run: gh cache delete --all diff --git a/actions/yarn-cache/action.yml b/actions/yarn-cache/action.yml index bf9d589..3dd2fa9 100644 --- a/actions/yarn-cache/action.yml +++ b/actions/yarn-cache/action.yml @@ -31,7 +31,7 @@ runs: using: composite steps: - id: key - uses: johngeorgewright/workflows/actions/yarn-cache-key@main + uses: johngeorgewright/workflows/actions/yarn-cache-key@yarn-cache with: working-directory: ${{ inputs.working-directory }} diff --git a/yarn-cache.yml b/yarn-cache.yml index fa728d6..c1ceba5 100644 --- a/yarn-cache.yml +++ b/yarn-cache.yml @@ -1,19 +1,62 @@ name: Yarn Cache +# description: | #markdown +# Similar idea to the yarn-cache action, but makes sure that only one workflow +# can create the cache at a time. EG: + +# ```yaml +# jobs: +# cache: +# uses: johngeorgewright/workflows/workflows/yarn-cache@main +# test: +# needs: [cache] +# runs-on: dmg-arc-ubuntu +# steps: +# - uses: actions/checkout@v6 +# +# # OPTION 1: manually download the cache +# - uses: actions/cache/restore@v5 +# with: +# key: ${\{ needs.cache.outputs.key }} +# path: ${\{ needs.cache.outputs.path }} +# restore-keys: ${\{ needs.cache.outputs.restore-keys }} +# +# # OPTION 2: let the key be discovered automatically +# - uses: actions/setup-node@v6 +# - uses: johngeorgewright/workflows/actions/yarn-cache@main +# ``` + on: workflow_call: inputs: - runs-on: - default: ubuntu-latest + cache-path: + description: The cache paths + required: false + type: string + default: | + ~/.cache + .yarn/unplugged + .yarn/install-state.gz + + runs-on: + default: dmg-arc-ubuntu required: false type: string description: Use runs-on to define the type of machine to run the job on. + working-directory: + description: Optional directory to execute yarn command in + required: false + type: string + default: ${{ github.workspace }} + outputs: key: value: ${{ jobs.key.outputs.cache-key }} path: value: ${{ jobs.prime.outputs.cache-path }} + restore-keys: + value: ${{ jobs.key.outputs.cache-restore-keys }} jobs: key: @@ -21,6 +64,7 @@ jobs: runs-on: ${{ inputs.runs-on }} outputs: cache-key: ${{ steps.key.outputs.cache-key }} + cache-restore-keys: ${{ steps.key.outputs.cache-restore-keys }} steps: - name: Checkout project uses: actions/checkout@v6 @@ -29,44 +73,36 @@ jobs: id: node uses: actions/setup-node@v6 with: - node-version-file: .nvmrc + node-version-file: ${{ inputs.working-directory }}/.nvmrc + + - run: corepack enable - name: Key id: key - uses: johngeorgewright/workflows/actions/yarn-cache-key.yml@main + uses: johngeorgewright/workflows/actions/yarn-cache-key@yarn-cache + with: + working-directory: ${{ inputs.working-directory }} prime: name: Prime needs: [key] runs-on: ${{ inputs.runs-on }} - env: - CACHE_PATH: | - ~/.cache - .yarn/unplugged - .yarn/install-state.gz concurrency: group: ${{ needs.key.outputs.cache-key }} outputs: - cache-path: ${{ env.CACHE_PATH }} + cache-path: ${{ inputs.cache-path }} steps: - name: Checkout project uses: actions/checkout@v6 - name: Install Node.js - id: node uses: actions/setup-node@v6 with: - node-version-file: .nvmrc + node-version-file: ${{ inputs.working-directory }}/.nvmrc - - name: Cache - id: cache - uses: actions/cache@v4 - with: - path: ${{ env.CACHE_PATH }} - key: ${{ needs.key.outputs.cache-key }} + - run: corepack enable - - name: Install Depedencies - if: steps.cache.outputs.cache-hit != 'true' - run: | - corepack enable - yarn --immutable + - uses: johngeorgewright/workflows/actions/yarn-cache@yarn-cache + with: + cache-path: ${{ inputs.cache-path }} + working-directory: ${{ inputs.working-directory }} From 6254bc1145deaf0f9eba797263ee3a42c33ac7b1 Mon Sep 17 00:00:00 2001 From: John Wright Date: Sun, 22 Mar 2026 12:25:13 +0000 Subject: [PATCH 3/4] test: correct paths --- .github/workflows/test-action-yarn-cache.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-action-yarn-cache.yml b/.github/workflows/test-action-yarn-cache.yml index a6833d9..39a678c 100644 --- a/.github/workflows/test-action-yarn-cache.yml +++ b/.github/workflows/test-action-yarn-cache.yml @@ -3,8 +3,10 @@ name: Test Yarn Cache on: pull_request: paths: - - .github/actions/yarn-cache/** - - .github/actions/yarn-cache-key/** + - .github/workflows/yarn-cache.yml + - actions/yarn-cache/** + - actions/yarn-cache-key/** + - yarn-cache.yml concurrency: group: test-action-yarn-cache-${{ github.head_ref }} From 34b9c48710b58686b8923fb971c0b01bf3718b89 Mon Sep 17 00:00:00 2001 From: John Wright Date: Sun, 22 Mar 2026 12:26:44 +0000 Subject: [PATCH 4/4] fix: correct runs-on --- .github/workflows/test-action-yarn-cache.yml | 6 +++--- .github/workflows/yarn-cache.yml | 4 ++-- yarn-cache.yml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-action-yarn-cache.yml b/.github/workflows/test-action-yarn-cache.yml index 39a678c..143630d 100644 --- a/.github/workflows/test-action-yarn-cache.yml +++ b/.github/workflows/test-action-yarn-cache.yml @@ -31,7 +31,7 @@ jobs: use-exact-cache: needs: [create-cache] - runs-on: dmg-arc-ubuntu + runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 @@ -50,7 +50,7 @@ jobs: use-partial-cache: needs: [create-cache] - runs-on: dmg-arc-ubuntu + runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 @@ -76,7 +76,7 @@ jobs: clean-up: needs: [create-cache, use-exact-cache, use-partial-cache] if: always() - runs-on: dmg-arc-ubuntu + runs-on: ubuntu-latest steps: - env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/yarn-cache.yml b/.github/workflows/yarn-cache.yml index 49a252a..7bc3ad7 100644 --- a/.github/workflows/yarn-cache.yml +++ b/.github/workflows/yarn-cache.yml @@ -10,7 +10,7 @@ name: Yarn Cache # uses: johngeorgewright/workflows/workflows/yarn-cache@main # test: # needs: [cache] -# runs-on: dmg-arc-ubuntu +# runs-on: ubuntu-latest # steps: # - uses: actions/checkout@v6 # @@ -39,7 +39,7 @@ on: .yarn/install-state.gz runs-on: - default: dmg-arc-ubuntu + default: ubuntu-latest required: false type: string description: Use runs-on to define the type of machine to run the job on. diff --git a/yarn-cache.yml b/yarn-cache.yml index c1ceba5..3e7f85d 100644 --- a/yarn-cache.yml +++ b/yarn-cache.yml @@ -10,7 +10,7 @@ name: Yarn Cache # uses: johngeorgewright/workflows/workflows/yarn-cache@main # test: # needs: [cache] -# runs-on: dmg-arc-ubuntu +# runs-on: ubuntu-latest # steps: # - uses: actions/checkout@v6 # @@ -39,7 +39,7 @@ on: .yarn/install-state.gz runs-on: - default: dmg-arc-ubuntu + default: ubuntu-latest required: false type: string description: Use runs-on to define the type of machine to run the job on.