GHA: Create yarn-install action for improved caching (#119481)

* Use .github/actions/yarn-install workflow everywhere

de-emoji-ify

* Update CODEOWNERS

* add yarn-install-validation job
This commit is contained in:
Josh Hunt
2026-03-04 12:58:44 +00:00
committed by GitHub
parent d9d472117c
commit 2bc94fe2ac
15 changed files with 259 additions and 118 deletions
+1
View File
@@ -1240,6 +1240,7 @@ embed.go @grafana/grafana-as-code
/.github/actions/build-package @grafana/grafana-developer-enablement-squad
/.github/actions/change-detection @grafana/grafana-developer-enablement-squad
/.github/actions/setup-node @grafana/grafana-frontend-platform
/.github/actions/yarn-install/action.yml @grafana/grafana-frontend-platform
/.github/workflows/actionlint-format.txt @grafana/grafana-developer-enablement-squad
/.github/workflows/actionlint.yml @grafana/grafana-developer-enablement-squad
/.github/workflows/add-to-whats-new.yml @grafana/docs-tooling
@@ -14,6 +14,9 @@ outputs:
frontend:
description: Whether the frontend or self has changed in any way
value: ${{ steps.changed-files.outputs.frontend_any_changed || 'true' }}
frontend-dependencies:
description: Whether the frontend dependencies or self have changed in any way
value: ${{ steps.changed-files.outputs.frontend_dependencies_any_changed || 'true' }}
frontend-packages:
description: Whether any frontend packages have changed
value: ${{ steps.changed-files.outputs.frontend_packages_any_changed || 'true' }}
@@ -101,6 +104,9 @@ runs:
- '.yarn/**'
- 'apps/dashboard/pkg/migration/**'
- '${{ inputs.self }}'
frontend_dependencies:
- 'yarn.lock'
- 'package.json'
frontend_packages:
- '.github/actions/checkout/**'
- '.github/actions/change-detection/**'
+13 -3
View File
@@ -1,11 +1,21 @@
name: Setup Node.js
description: Sets up a node.js environment with presets for the Grafana repository.
inputs:
cache:
description: Whether to cache the yarn dependencies. Note, its recommended to use .github/actions/yarn-install instead as it has better caching.
required: false
default: 'false'
cwd:
description: "Changes node's process.cwd() if the project is not located on the root. Default to process.cwd()"
required: false
default: '.'
runs:
using: "composite"
steps:
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'yarn'
cache-dependency-path: 'yarn.lock'
node-version-file: '${{ inputs.cwd }}/.nvmrc'
cache: ${{ inputs.cache == 'true' && 'yarn' || '' }}
cache-dependency-path: ${{ inputs.cache == 'true' && format('{0}/yarn.lock', inputs.cwd) || '' }}
+125
View File
@@ -0,0 +1,125 @@
# From https://gist.github.com/belgattitude/042f9caf10d029badbde6cf9d43e400a
########################################################################################
# "yarn install" composite action for yarn 3/4+ and "nodeLinker: node-modules" #
#--------------------------------------------------------------------------------------#
# Requirement: ./.github/actions/setup-node should be run before #
# #
# Usage in workflows steps: #
# #
# - name: Monorepo install #
# uses: ./.github/actions/yarn-nm-install #
# with: #
# enable-corepack: false # (default = 'false') #
# cwd: ${{ github.workspace }}/apps/my-app # (default = '.') #
# cache-prefix: add cache key prefix # (default = 'default') #
# cache-node-modules: false # (default = 'false') #
# cache-install-state: false # (default = 'false') #
# #
# Reference: #
# - latest: https://gist.github.com/belgattitude/042f9caf10d029badbde6cf9d43e400a #
########################################################################################
name: 'Monorepo install (yarn)'
description: 'Run yarn install with node_modules linker and cache enabled'
inputs:
cwd:
description: "Changes node's process.cwd() if the project is not located on the root. Default to process.cwd()"
required: false
default: '.'
cache-prefix:
description: 'Add a specific cache-prefix'
required: false
default: 'default'
cache-npm-cache:
description: 'Cache npm global cache folder often used by node-gyp, prebuild binaries (invalidated on lock/os/node-version)'
required: false
default: 'true'
cache-node-modules:
description: 'Cache node_modules, might speed up link step (invalidated lock/os/node-version/branch)'
required: false
default: 'false'
cache-install-state:
description: 'Cache yarn install state, might speed up resolution step when node-modules cache is activated (invalidated lock/os/node-version/branch)'
required: false
default: 'false'
enable-corepack:
description: 'Enable corepack'
required: false
default: 'true'
hardened-mode:
description: "Enable yarn hardened mode. 'auto' disables it for internal PRs, 'true' always enables it. Fork PRs always use hardened mode regardless."
required: false
default: 'auto'
runs:
using: 'composite'
steps:
- name: ⚙️ Enable Corepack
if: inputs.enable-corepack == 'true'
shell: bash
working-directory: ${{ inputs.cwd }}
run: corepack enable
- name: ⚙️ Expose yarn config as "$GITHUB_OUTPUT"
id: yarn-config
shell: bash
working-directory: ${{ inputs.cwd }}
env:
YARN_ENABLE_GLOBAL_CACHE: 'false'
run: |
echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
echo "CURRENT_NODE_VERSION="node-$(node --version)"" >> $GITHUB_OUTPUT
echo "CURRENT_BRANCH=$(echo ${GITHUB_REF#refs/heads/} | sed -r 's,/,-,g')" >> $GITHUB_OUTPUT
echo "NPM_GLOBAL_CACHE_FOLDER=$(npm config get cache)" >> $GITHUB_OUTPUT
- name: Restore yarn cache
uses: actions/cache@v5
id: yarn-download-cache
with:
path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}
key: yarn-download-cache-${{ inputs.cache-prefix }}-${{ hashFiles(format('{0}/yarn.lock', inputs.cwd), format('{0}/.yarnrc.yml', inputs.cwd)) }}
restore-keys: |
yarn-download-cache-${{ inputs.cache-prefix }}-
- name: Restore node_modules
if: inputs.cache-node-modules == 'true'
id: yarn-nm-cache
uses: actions/cache@v5
with:
path: |
${{ inputs.cwd }}/**/node_modules
!${{ inputs.cwd }}/**/node_modules/.cache
key: yarn-nm-cache-${{ inputs.cache-prefix }}-${{ runner.os }}-${{ steps.yarn-config.outputs.CURRENT_NODE_VERSION }}-${{ steps.yarn-config.outputs.CURRENT_BRANCH }}-${{ hashFiles(format('{0}/yarn.lock', inputs.cwd), format('{0}/.yarnrc.yml', inputs.cwd)) }}
- name: Restore global npm cache folder
if: inputs.cache-npm-cache == 'true'
id: npm-global-cache
uses: actions/cache@v5
with:
path: ${{ steps.yarn-config.outputs.NPM_GLOBAL_CACHE_FOLDER }}
key: yarn-npm-global-cache-${{ inputs.cache-prefix }}-${{ runner.os }}-${{ steps.yarn-config.outputs.CURRENT_NODE_VERSION }}-${{ hashFiles(format('{0}/yarn.lock', inputs.cwd), format('{0}/.yarnrc.yml', inputs.cwd)) }}
- name: Restore yarn install state
if: inputs.cache-install-state == 'true' && inputs.cache-node-modules == 'true'
id: yarn-install-state-cache
uses: actions/cache@v5
with:
path: ${{ inputs.cwd }}/.yarn/install-state.gz
key: yarn-install-state-cache-${{ inputs.cache-prefix }}-${{ runner.os }}-${{ steps.yarn-config.outputs.CURRENT_NODE_VERSION }}-${{ steps.yarn-config.outputs.CURRENT_BRANCH }}-${{ hashFiles(format('{0}/yarn.lock', inputs.cwd), format('{0}/.yarnrc.yml', inputs.cwd)) }}
- name: Install dependencies
shell: bash
working-directory: ${{ inputs.cwd }}
run: yarn install --immutable --inline-builds
env:
# Overrides/align yarnrc.yml options (v3, v4) for a CI context
YARN_ENABLE_GLOBAL_CACHE: 'false' # Use local cache folder to keep downloaded archives
YARN_ENABLE_MIRROR: 'false' # Prevent populating global cache for caches misses (local cache only)
YARN_NM_MODE: 'hardlinks-local' # Reduce node_modules size
YARN_INSTALL_STATE_PATH: '.yarn/install-state.gz' # Might speed up resolution step when node_modules present
YARN_ENABLE_HARDENED_MODE: ${{ (github.event.pull_request.head.repo.fork == true || inputs.hardened-mode == 'true') && '1' || '0' }} # Always enabled for forks; for internal PRs, enabled when hardened-mode is 'true'
# Skip big post-install dependencies
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
@@ -120,7 +120,7 @@ jobs:
run: |
TEAMS='${{ needs.setup.outputs.opted-in-teams }}'
TEAM_LIST=$(echo "$TEAMS" | jq -r '.[] | "- `" + . + "`"' | tr '\n' '\n')
{
echo "message<<EOF"
echo "## ⚠️ Frontend Test Coverage Checks Skipped"
@@ -192,7 +192,7 @@ jobs:
uses: ./.github/actions/setup-node
- name: Install dependencies for manifest generation
run: yarn install --immutable
run: yarn install --immutable # TODO: switch to ./.github/actions/yarn-install for better caching
env:
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
@@ -220,7 +220,7 @@ jobs:
- name: Install dependencies
if: steps.check-affected.outputs.affected == 'true'
run: yarn install --immutable
run: yarn install --immutable # TODO: switch to ./.github/actions/yarn-install for better caching
env:
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
@@ -273,7 +273,7 @@ jobs:
uses: ./.github/actions/setup-node
- name: Install dependencies for manifest and comparison
run: yarn install --immutable
run: yarn install --immutable # TODO: switch to ./.github/actions/yarn-install for better caching
env:
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
@@ -347,7 +347,7 @@ jobs:
else
echo "passed=false" >> "$GITHUB_OUTPUT"
fi
# Always capture the markdown output
{
echo "markdown<<EOF"
@@ -38,11 +38,8 @@ jobs:
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Install dependencies
env:
# If the PR isn't from a fork then don't use the slower yarn checks
YARN_ENABLE_HARDENED_MODE: ${{ github.event.pull_request.head.repo.fork == false && '1' || '0' }}
run: yarn install --immutable
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Build storybook
run: yarn storybook:build
+2 -2
View File
@@ -55,8 +55,8 @@ jobs:
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Install dependencies
run: yarn install --immutable
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Build storybook
run: yarn storybook:build
@@ -34,25 +34,15 @@ jobs:
path: './pr'
persist-credentials: false
- uses: actions/setup-node@v6
- name: Setup Node
uses: ./pr/.github/actions/setup-node
with:
node-version-file: './pr/.nvmrc'
cwd: './pr'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- name: Restore yarn cache
uses: actions/cache@v4
id: yarn-cache
- name: Install yarn dependencies
uses: ./pr/.github/actions/yarn-install
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-cache-folder-${{ hashFiles('**/yarn.lock', '.yarnrc.yml') }}
restore-keys: |
yarn-cache-folder-
- name: Install dependencies
run: yarn install --immutable
cwd: './pr'
- name: Build packages
run: yarn packages:build
@@ -80,31 +70,27 @@ jobs:
working-directory: './base'
steps:
# We need to check out the PR's branch to get actions from the same branch, so if they change in a PR this action can pick up those changes
- uses: actions/checkout@v5
with:
path: './pr'
persist-credentials: false
- uses: actions/checkout@v5
with:
path: './base'
ref: ${{ github.event.pull_request.base.ref }}
persist-credentials: false
- uses: actions/setup-node@v6
- name: Setup Node
uses: ./pr/.github/actions/setup-node # run the action from the PR, pointing to the base checkout
with:
node-version-file: './base/.nvmrc'
cwd: './base'
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- name: Restore yarn cache
uses: actions/cache@v4
id: yarn-cache
- name: Install yarn dependencies
uses: ./pr/.github/actions/yarn-install # run the action from the PR, pointing to the base checkout
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: yarn-cache-folder-${{ hashFiles('**/yarn.lock', '.yarnrc.yml') }}
restore-keys: |
yarn-cache-folder-
- name: Install dependencies
run: yarn install --immutable
cwd: './base'
- name: Build packages
run: yarn packages:build
+59 -20
View File
@@ -18,6 +18,7 @@ jobs:
changed: ${{ steps.detect-changes.outputs.frontend }}
prettier: ${{ steps.detect-changes.outputs.frontend == 'true' || steps.detect-changes.outputs.docs == 'true' }}
changed-frontend-packages: ${{ steps.detect-changes.outputs.frontend-packages }}
changed-frontend-dependencies: ${{ steps.detect-changes.outputs.frontend-dependencies }}
steps:
- uses: actions/checkout@v5
with:
@@ -43,9 +44,10 @@ jobs:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Node
- name: Setup Node.js
uses: ./.github/actions/setup-node
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run prettier:check
- run: yarn run lint
lint-frontend-prettier-enterprise:
@@ -61,13 +63,14 @@ jobs:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Node
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Setup Enterprise
uses: ./.github/actions/setup-enterprise
with:
github-app-name: 'grafana-ci-bot'
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run prettier:check
- run: yarn run lint
lint-frontend-typecheck:
@@ -84,9 +87,10 @@ jobs:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Node
- name: Setup Node.js
uses: ./.github/actions/setup-node
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run typecheck
lint-frontend-typecheck-enterprise:
needs: detect-changes
@@ -107,7 +111,8 @@ jobs:
uses: ./.github/actions/setup-enterprise
with:
github-app-name: 'grafana-ci-bot'
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run typecheck
lint-frontend-api-clients:
permissions:
@@ -124,7 +129,8 @@ jobs:
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Generate API clients
run: |
extract_error_message='ERROR! API client generation failed!'
@@ -154,7 +160,8 @@ jobs:
node-version-file: '.nvmrc'
cache: 'yarn'
cache-dependency-path: 'yarn.lock'
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Free up disk space
run: |
sudo rm -rf /usr/local/lib/android || true
@@ -174,7 +181,7 @@ jobs:
echo "$file_diff"
echo "${uncommited_error_message}"
exit 1
fi
fi
lint-frontend-api-clients-enterprise:
permissions:
contents: read
@@ -193,7 +200,8 @@ jobs:
uses: ./.github/actions/setup-enterprise
with:
github-app-name: 'grafana-ci-bot'
- run: yarn install --immutable --check-cache
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Generate API clients
run: |
extract_error_message='ERROR! API client generation failed!'
@@ -222,8 +230,8 @@ jobs:
persist-credentials: false
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install dependencies
run: yarn install --immutable
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Build and pack packages
run: |
yarn run packages:build
@@ -243,12 +251,18 @@ jobs:
uses: actions/checkout@v5
with:
persist-credentials: false
path: './pr'
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install dependencies
run: yarn install --immutable
uses: ./pr/.github/actions/setup-node
with:
cwd: './pr'
- name: Install yarn dependencies
uses: ./pr/.github/actions/yarn-install
with:
cwd: './pr'
- name: Check circular dependencies on PR
# the first sed command is used to clean the output
working-directory: ./pr
run: |
yarn lint:circular &> /tmp/pr-circular.txt || true
sed -n '/.*Found \([0-9]*\) circular.*/,$p' /tmp/pr-circular.txt > /tmp/pr-circular-clean.txt
@@ -261,11 +275,17 @@ jobs:
persist-credentials: false
repository: 'grafana/grafana'
ref: 'main'
path: './main'
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install dependencies
run: yarn install --immutable
uses: ./pr/.github/actions/setup-node # run the action from the PR, pointing to the base checkout
with:
cwd: './main'
- name: Install yarn dependencies
uses: ./pr/.github/actions/yarn-install # run the action from the PR, pointing to the base checkout
with:
cwd: './main'
- name: Check circular dependencies on main
working-directory: ./main
# the first sed command is used to clean the output
run: |
yarn lint:circular &> /tmp/main-circular.txt || true
@@ -284,4 +304,23 @@ jobs:
echo "Diff between main and PR:"
diff -u /tmp/main-circular-clean.txt /tmp/pr-circular-clean.txt || true
exit 1
fi
fi
yarn-install-validation:
needs:
- detect-changes
if: needs.detect-changes.outputs.changed-frontend-dependencies == 'true'
runs-on: ubuntu-x64-small
name: Validate yarn install
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Setup Node.js
uses: ./.github/actions/setup-node
# Deliberately not using the yarn-install action for exact control over the command for extra checks
- name: Install yarn dependencies
run: yarn install --immutable --check-cache
env:
YARN_ENABLE_HARDENED_MODE: 1
+2 -5
View File
@@ -39,11 +39,8 @@ jobs:
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Yarn install
run: yarn install --immutable
env:
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Install Playwright browsers
run: yarn playwright install chromium --with-deps
+2 -2
View File
@@ -40,8 +40,8 @@ jobs:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
run: yarn install --immutable
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Lint docs
run: yarn run prettier:checkDocs
+8 -26
View File
@@ -88,11 +88,8 @@ jobs:
path: apps/dashboard/pkg/migration
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Yarn install
run: yarn install --immutable
env:
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run test:ci
env:
TEST_MAX_WORKERS: 4
@@ -130,13 +127,8 @@ jobs:
path: apps/dashboard/pkg/migration
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Yarn install
run: yarn install --immutable
env:
# Switch from default hardened mode to faster mode for internal PRs
YARN_ENABLE_HARDENED_MODE: ${{ github.event.pull_request.head.repo.fork == false && '1' || '0' }}
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run test:ci
env:
TEST_MAX_WORKERS: 4
@@ -155,13 +147,8 @@ jobs:
persist-credentials: false
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Yarn install
run: yarn install --immutable
env:
# Switch from default hardened mode to faster mode for internal PRs
YARN_ENABLE_HARDENED_MODE: ${{ github.event.pull_request.head.repo.fork == false && '1' || '0' }}
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run plugin:test:ci
frontend-packages-unit-tests:
@@ -176,13 +163,8 @@ jobs:
persist-credentials: false
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Yarn install
run: yarn install --immutable
env:
# Switch from default hardened mode to faster mode for internal PRs
YARN_ENABLE_HARDENED_MODE: ${{ github.event.pull_request.head.repo.fork == false && '1' || '0' }}
PUPPETEER_SKIP_DOWNLOAD: true
CYPRESS_INSTALL_BINARY: 0
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- run: yarn run packages:test:ci
# This is the job that is actually required by rulesets.
+4 -2
View File
@@ -99,8 +99,10 @@ jobs:
- name: Update npm
run: npm install -g npm@^11.5.1
- name: Install dependencies
run: yarn install --immutable
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
with:
hardened-mode: 'true'
- name: Typecheck packages
run: yarn run packages:typecheck
+4 -6
View File
@@ -26,12 +26,10 @@ jobs:
with:
go-version-file: 'go.mod'
- run: go version
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
run: yarn install --immutable
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Install Playwright browsers
run: yarn playwright install --with-deps chromium
- name: Build grafana
+8 -10
View File
@@ -39,11 +39,10 @@ jobs:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
package-manager-cache: false # too large for GH's cache limits :-(
- run: yarn install --immutable --check-cache
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Start Storybook
@@ -69,11 +68,10 @@ jobs:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
package-manager-cache: false # too large for GH's cache limits :-(
- run: yarn install --immutable --check-cache
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Install yarn dependencies
uses: ./.github/actions/yarn-install
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Start Storybook