Files
vscode/.github/workflows/pr-node-modules.yml
T
Alexandru DimaandCopilot fe721a5460 ci: only warm missing node_modules caches on main (#342747)
* ci: only warm missing node_modules caches on main

Every push to main started six cache warming jobs on 1ES and macOS runners, which found their caches present and exited in about 30 seconds in 93 of the last 100 runs, while waiting up to 29 minutes for runners shared with pull request jobs.

A job on a GitHub-hosted runner now computes the cache keys of each job, including the CRLF checkouts of the Windows runners, and lists the caches on main. Jobs only run when one of their caches is missing, and all jobs run when the detection fails. At most one run is in progress so that concurrent pushes don't install the same missing dependencies several times.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ci: also match cache versions when detecting missing caches

actions/cache only restores a cache whose key and version both match, and the version depends on the cache path, compression method and OS. Detecting caches by key alone could skip warming a cache that the jobs can no longer restore, for example after a runner image changes its home directory.

The detection now also compares the cache versions, mirroring actions/cache with the cache paths of the runners. A cache with another version counts as missing, so the job runs and saves a compatible one.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-20 02:59:32 +02:00

436 lines
16 KiB
YAML

name: Code OSS (node_modules)
on:
push:
branches:
- main
permissions: {}
# Warming a missing cache takes up to 15 minutes, and the pushes in the meantime need the same
# caches. Allow one running and one pending run: GitHub replaces the pending run with the newest
# push, which then skips the caches the running one saved. Don't cancel in-progress runs, or
# frequent pushes may keep a slow cache from ever being saved.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
# Most pushes don't change the dependencies. Each job below only runs when one of the caches
# it keeps warm is missing (see .github/actions/detect-missing-caches/detect.ts), for example
# after a dependency change or a cache eviction. Jobs also run when the detection fails.
caches:
name: Detect Missing Caches
runs-on: ubuntu-24.04
permissions:
actions: read
contents: read
outputs:
compile: ${{ steps.detect.outputs.compile }}
linux: ${{ steps.detect.outputs.linux }}
macOS: ${{ steps.detect.outputs.macOS }}
windows: ${{ steps.detect.outputs.windows }}
copilot-linux: ${{ steps.detect.outputs.copilot-linux }}
copilot-windows: ${{ steps.detect.outputs.copilot-windows }}
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Detect missing caches
id: detect
uses: ./.github/actions/detect-missing-caches
with:
token: ${{ secrets.GITHUB_TOKEN }}
compile:
name: Compile
needs: caches
if: ${{ !cancelled() && (needs.caches.result != 'success' || needs.caches.outputs.compile == 'true') }}
runs-on: [ self-hosted, 1ES.Pool=1es-vscode-oss-ubuntu-22.04-x64, "JobId=compile-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" ]
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
- name: Restore node_modules cache
id: cache-node-modules
uses: ./.github/actions/restore-node-modules
with:
key-prefix: node_modules-compile
key-args: "compile $(node -p process.arch)"
- name: Install build tools
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: sudo apt update -y && sudo apt install -y build-essential pkg-config libx11-dev libx11-xcb-dev libxkbfile-dev libnotify-bin libkrb5-dev
- name: Install Electron headers
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: node build/npm/preinstall.ts
- name: Install dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: |
set -e
for i in {1..5}; do # try 5 times
npm ci && break
if [ $i -eq 5 ]; then
echo "Npm install failed too many times" >&2
exit 1
fi
echo "Npm install failed $i, trying again..."
done
env:
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
- name: Save node_modules cache
if: steps.cache-node-modules.outputs.cache-hit != 'true'
uses: ./.github/actions/save-node-modules
- name: Prepare built-in extensions cache key
run: |
set -e
mkdir -p .build
node build/azure-pipelines/common/computeBuiltInDepsCacheKey.ts > .build/builtindepshash
- name: Restore built-in extensions cache
id: cache-builtin-extensions
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
enableCrossOsArchive: true
path: .build/builtInExtensions
key: "builtin-extensions-${{ hashFiles('.build/builtindepshash') }}"
- name: Download built-in extensions
if: steps.cache-builtin-extensions.outputs.cache-hit != 'true'
run: node build/lib/builtInExtensions.ts
env:
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
linux:
name: Linux
needs: caches
if: ${{ !cancelled() && (needs.caches.result != 'success' || needs.caches.outputs.linux == 'true') }}
runs-on: [ self-hosted, 1ES.Pool=1es-vscode-oss-ubuntu-22.04-x64, "JobId=linux-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" ]
env:
NPM_ARCH: x64
VSCODE_ARCH: x64
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
- name: Check Electron cache
id: cache-electron
uses: ./.github/actions/setup-electron
with:
arch: ${{ env.VSCODE_ARCH }}
lookup-only: 'true'
- name: Restore node_modules cache
id: cache-node-modules
uses: ./.github/actions/restore-node-modules
with:
key-prefix: node_modules-linux
key-args: "linux ${{ env.VSCODE_ARCH }} $(node -p process.arch)"
lookup-only: ${{ steps.cache-electron.outputs.cache-hit == 'true' }}
- name: Install build dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
working-directory: build
run: |
set -e
for i in {1..5}; do # try 5 times
npm ci && break
if [ $i -eq 5 ]; then
echo "Npm install failed too many times" >&2
exit 1
fi
echo "Npm install failed $i, trying again..."
done
env:
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
- name: Install dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: |
set -e
source ./build/azure-pipelines/linux/setup-env.sh
for i in {1..5}; do # try 5 times
npm ci && break
if [ $i -eq 5 ]; then
echo "Npm install failed too many times" >&2
exit 1
fi
echo "Npm install failed $i, trying again..."
done
env:
npm_config_arch: ${{ env.NPM_ARCH }}
VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
- name: Verify native optional dependency binaries
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: node build/azure-pipelines/common/checkNativeOptionalDeps.ts
- name: Save node_modules cache
if: steps.cache-node-modules.outputs.cache-hit != 'true'
uses: ./.github/actions/save-node-modules
- name: Setup Electron
if: steps.cache-electron.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-electron
with:
arch: ${{ env.VSCODE_ARCH }}
save-cache: 'true'
env:
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
macOS:
name: macOS
needs: caches
if: ${{ !cancelled() && (needs.caches.result != 'success' || needs.caches.outputs.macOS == 'true') }}
runs-on: macos-26-xlarge
env:
NPM_ARCH: arm64
VSCODE_ARCH: arm64
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
- name: Check Electron cache
id: cache-electron
uses: ./.github/actions/setup-electron
with:
arch: ${{ env.VSCODE_ARCH }}
lookup-only: 'true'
- name: Restore node_modules cache
id: cache-node-modules
uses: ./.github/actions/restore-node-modules
with:
key-prefix: node_modules-macos
key-args: "darwin ${{ env.VSCODE_ARCH }} $(node -p process.arch)"
lookup-only: ${{ steps.cache-electron.outputs.cache-hit == 'true' }}
- name: Install dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: |
set -e
c++ --version
xcode-select -print-path
python3 -m pip install --break-system-packages setuptools
for i in {1..5}; do # try 5 times
npm ci && break
if [ $i -eq 5 ]; then
echo "Npm install failed too many times" >&2
exit 1
fi
echo "Npm install failed $i, trying again..."
done
env:
npm_config_arch: ${{ env.NPM_ARCH }}
VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
# Avoid using dlopen to load Kerberos on macOS which can cause missing libraries
# https://github.com/mongodb-js/kerberos/commit/04044d2814ad1d01e77f1ce87f26b03d86692cf2
# flipped the default to support legacy linux distros which shouldn't happen
# on macOS.
GYP_DEFINES: "kerberos_use_rtld=false"
- name: Verify native optional dependency binaries
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: node build/azure-pipelines/common/checkNativeOptionalDeps.ts
- name: Save node_modules cache
if: steps.cache-node-modules.outputs.cache-hit != 'true'
uses: ./.github/actions/save-node-modules
- name: Setup Electron
if: steps.cache-electron.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-electron
with:
arch: ${{ env.VSCODE_ARCH }}
save-cache: 'true'
env:
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
windows:
name: Windows
needs: caches
if: ${{ !cancelled() && (needs.caches.result != 'success' || needs.caches.outputs.windows == 'true') }}
runs-on: [ self-hosted, 1ES.Pool=1es-vscode-oss-windows-2022-x64, "JobId=windows-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" ]
env:
NPM_ARCH: x64
VSCODE_ARCH: x64
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
- name: Check Electron cache
id: cache-electron
uses: ./.github/actions/setup-electron
with:
arch: ${{ env.VSCODE_ARCH }}
lookup-only: 'true'
- name: Restore node_modules cache
id: node-modules-cache
uses: ./.github/actions/restore-node-modules
with:
key-prefix: node_modules-windows
key-args: "win32 ${{ env.VSCODE_ARCH }} $(node -p process.arch)"
lookup-only: ${{ steps.cache-electron.outputs.cache-hit == 'true' }}
- name: Install dependencies
if: steps.node-modules-cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
. build/azure-pipelines/win32/exec.ps1
$ErrorActionPreference = "Stop"
for ($i = 1; $i -le 5; $i++) {
try {
exec { npm ci }
break
}
catch {
if ($i -eq 5) {
Write-Error "npm ci failed after 5 attempts"
throw
}
Write-Host "npm ci failed attempt $i, retrying..."
Start-Sleep -Seconds 2
}
}
env:
npm_config_arch: ${{ env.NPM_ARCH }}
npm_config_foreground_scripts: "true"
VSCODE_ARCH: ${{ env.VSCODE_ARCH }}
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
- name: Verify native optional dependency binaries
if: steps.node-modules-cache.outputs.cache-hit != 'true'
run: node build/azure-pipelines/common/checkNativeOptionalDeps.ts
- name: Save node_modules cache
if: steps.node-modules-cache.outputs.cache-hit != 'true'
uses: ./.github/actions/save-node-modules
- name: Setup Electron
if: steps.cache-electron.outputs.cache-hit != 'true'
uses: ./.github/actions/setup-electron
with:
arch: ${{ env.VSCODE_ARCH }}
save-cache: 'true'
env:
GITHUB_TOKEN: ${{ secrets.VSCODE_OSS }}
# The Windows smoke tests install this WSL release, see pr-win32-test.yml
- name: Cache WSL installer
continue-on-error: true
uses: ./.github/actions/restore-wsl-installer
with:
save-cache: 'true'
copilot-linux:
name: Copilot (Linux)
needs: caches
if: ${{ !cancelled() && (needs.caches.result != 'success' || needs.caches.outputs.copilot-linux == 'true') }}
runs-on: [ self-hosted, 1ES.Pool=1es-vscode-oss-ubuntu-22.04-x64, "JobId=copilot-linux-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" ]
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: extensions/copilot/.nvmrc
- name: Restore node_modules cache
id: cache-node-modules
uses: ./.github/actions/restore-node-modules
with:
key-prefix: copilot-node_modules-linux
key-args: "$(node -p process.platform) $(node -p process.arch)"
lookup-only: 'true'
- name: Install root dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci --ignore-scripts --no-workspaces
- name: Install copilot dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
working-directory: extensions/copilot
run: npm ci
- name: Save node_modules cache
if: steps.cache-node-modules.outputs.cache-hit != 'true'
uses: ./.github/actions/save-node-modules
copilot-windows:
name: Copilot (Windows)
needs: caches
if: ${{ !cancelled() && (needs.caches.result != 'success' || needs.caches.outputs.copilot-windows == 'true') }}
runs-on: [ self-hosted, 1ES.Pool=1es-vscode-oss-windows-2022-x64, "JobId=copilot-windows-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}" ]
steps:
- name: Checkout microsoft/vscode
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: extensions/copilot/.nvmrc
- name: Restore node_modules cache
id: cache-node-modules
uses: ./.github/actions/restore-node-modules
with:
key-prefix: copilot-node_modules-windows
key-args: "$(node -p process.platform) $(node -p process.arch)"
lookup-only: 'true'
- name: Install root dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci --ignore-scripts --no-workspaces
- name: Install copilot dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
working-directory: extensions/copilot
run: npm ci
- name: Save node_modules cache
if: steps.cache-node-modules.outputs.cache-hit != 'true'
uses: ./.github/actions/save-node-modules