From 2674aa64b9177fa814c7d459a15acddca7456ea5 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Thu, 23 Apr 2026 03:54:07 -0400 Subject: [PATCH] ci: centralize build-image SHA and pre-seed node-gyp headers (41-x-y) (#51275) ci: centralize build-image SHA and pre-seed node-gyp headers (#51148) * ci: centralize build-image SHA and pre-seed node-gyp headers - Add .github/actions/build-image-sha as the single source of truth for the ghcr.io/electron/build (and arch-tagged electron/test) image SHA, with an optional override input for workflow_dispatch. - Refactor build.yml, apply-patches.yml, build-git-cache.yml, clean-src-cache.yml, clean-orphaned-cache-uploads.yml, and the three publish workflows to resolve the SHA via a small ubuntu-slim setup job instead of hardcoding it in each file. - Bump the image to daad061f (electron/build-images#68, which pre-warms the node-gyp header cache in the Linux images). - Run the build.yml setup job on ubuntu-slim instead of ubuntu-latest. - In install-dependencies (and the inline yarn installs in pipeline-electron-lint and generate-types), link deps with --mode=skip-build first, run `node-gyp install` with up to 3 retries (5s backoff) to populate the header cache, then run the build phase. This avoids the parallel-download race that intermittently fails the first native-addon configure with an empty common.gypi on cold macOS/Windows runners. * ci: skip node-gyp header pre-seed on Linux * ci: invoke node-gyp via its JS entrypoint for Windows compat (cherry picked from commit f7ba34064eb55aac0625bc4d98bd54e510bba153) --- .github/actions/build-image-sha/action.yml | 24 ++++++++++++++ .../actions/install-dependencies/action.yml | 21 ++++++++++-- .github/workflows/apply-patches.yml | 6 +++- .github/workflows/build.yml | 21 ++++++------ .github/workflows/linux-publish.yml | 33 ++++++++++++++----- .github/workflows/macos-publish.yml | 22 +++++++++++-- .github/workflows/windows-publish.yml | 26 +++++++++++---- 7 files changed, 123 insertions(+), 30 deletions(-) create mode 100644 .github/actions/build-image-sha/action.yml diff --git a/.github/actions/build-image-sha/action.yml b/.github/actions/build-image-sha/action.yml new file mode 100644 index 0000000000..dc60f2457c --- /dev/null +++ b/.github/actions/build-image-sha/action.yml @@ -0,0 +1,24 @@ +name: 'Build Image SHA' +description: 'Single source of truth for the ghcr.io/electron/build image SHA' +inputs: + override: + description: 'Optional override SHA (e.g. from a workflow_dispatch input)' + required: false + default: '' +outputs: + build-image-sha: + description: 'The electron/build image SHA to use' + value: ${{ steps.set.outputs.build-image-sha }} +runs: + using: 'composite' + steps: + - id: set + shell: bash + env: + OVERRIDE: ${{ inputs.override }} + run: | + if [ -n "$OVERRIDE" ]; then + echo "build-image-sha=$OVERRIDE" >> "$GITHUB_OUTPUT" + else + echo "build-image-sha=daad061f4b99a0ae1c841be4aa09188280a9c8a4" >> "$GITHUB_OUTPUT" + fi diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 0d2b4837ec..d034b7f587 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -21,11 +21,28 @@ runs: if [ "$TARGET_ARCH" = "x86" ]; then export npm_config_arch="ia32" fi - # if running on linux arm skip yarn Builds ARCH=$(uname -m) + node script/yarn.js install --immutable --mode=skip-build + # if running on linux arm skip yarn Builds if [ "$ARCH" = "armv7l" ]; then echo "Skipping yarn build on linux arm" - node script/yarn.js install --immutable --mode=skip-build else + # Pre-seed the node-gyp header cache so the parallel native-addon + # builds below don't race on a cold cache. Linux build containers + # already ship a warm cache (electron/build-images#68), so only do + # this on macOS / Windows runners. + if [ "$(uname -s)" != "Linux" ]; then + for i in 1 2 3; do + if node node_modules/node-gyp/bin/node-gyp.js install; then + break + fi + if [ "$i" = "3" ]; then + echo "node-gyp header pre-seed failed after 3 attempts" >&2 + exit 1 + fi + echo "node-gyp header pre-seed failed (attempt $i), retrying in 5s..." >&2 + sleep 5 + done + fi node script/yarn.js install --immutable fi diff --git a/.github/workflows/apply-patches.yml b/.github/workflows/apply-patches.yml index bfd40a58ba..8e9b70b828 100644 --- a/.github/workflows/apply-patches.yml +++ b/.github/workflows/apply-patches.yml @@ -18,6 +18,7 @@ jobs: pull-requests: read outputs: has-patches: ${{ steps.filter.outputs.patches }} + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: @@ -33,6 +34,9 @@ jobs: patches: - DEPS - 'patches/**' + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha apply-patches: needs: setup @@ -41,7 +45,7 @@ jobs: permissions: contents: read container: - image: ghcr.io/electron/build:a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root volumes: - /mnt/cross-instance-cache:/mnt/cross-instance-cache diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db42010c70..55355acb7c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,8 +6,8 @@ on: build-image-sha: type: string description: 'SHA for electron/build image' - default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb' - required: true + default: '' + required: false skip-macos: type: boolean description: 'Skip macOS builds' @@ -47,14 +47,15 @@ permissions: {} jobs: setup: - runs-on: ubuntu-latest + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim permissions: contents: read pull-requests: read outputs: docs: ${{ steps.filter.outputs.docs }} src: ${{ steps.filter.outputs.src }} - build-image-sha: ${{ steps.set-output.outputs.build-image-sha }} + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} docs-only: ${{ steps.set-output.outputs.docs-only }} steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 @@ -72,14 +73,14 @@ jobs: - CODE_OF_CONDUCT.md src: - '!docs/**' - - name: Set Outputs for Build Image SHA & Docs Only + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + - name: Set Docs Only id: set-output run: | - if [ -z "${{ inputs.build-image-sha }}" ]; then - echo "build-image-sha=a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb" >> "$GITHUB_OUTPUT" - else - echo "build-image-sha=${{ inputs.build-image-sha }}" >> "$GITHUB_OUTPUT" - fi echo "docs-only=${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.src == 'false' }}" >> "$GITHUB_OUTPUT" # Lint Jobs diff --git a/.github/workflows/linux-publish.yml b/.github/workflows/linux-publish.yml index eeea6e98e4..2860eda9f4 100644 --- a/.github/workflows/linux-publish.yml +++ b/.github/workflows/linux-publish.yml @@ -6,7 +6,8 @@ on: build-image-sha: type: string description: 'SHA for electron/build image' - default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb' + default: '' + required: false upload-to-storage: description: 'Uploads to Azure storage' required: false @@ -20,12 +21,28 @@ on: permissions: {} jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + checkout-linux: + needs: setup runs-on: electron-arc-centralus-linux-amd64-32core permissions: contents: read container: - image: ghcr.io/electron/build:${{ inputs.build-image-sha }} + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root volumes: - /mnt/cross-instance-cache:/mnt/cross-instance-cache @@ -49,11 +66,11 @@ jobs: attestations: write contents: read id-token: write - needs: checkout-linux + needs: [setup, checkout-linux] with: environment: production-release build-runs-on: electron-arc-centralus-linux-amd64-32core - build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + build-container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' target-platform: linux target-arch: x64 is-release: true @@ -69,11 +86,11 @@ jobs: attestations: write contents: read id-token: write - needs: checkout-linux + needs: [setup, checkout-linux] with: environment: production-release build-runs-on: electron-arc-centralus-linux-amd64-32core - build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + build-container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' target-platform: linux target-arch: arm is-release: true @@ -89,11 +106,11 @@ jobs: attestations: write contents: read id-token: write - needs: checkout-linux + needs: [setup, checkout-linux] with: environment: production-release build-runs-on: electron-arc-centralus-linux-amd64-32core - build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' + build-container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}' target-platform: linux target-arch: arm64 is-release: true diff --git a/.github/workflows/macos-publish.yml b/.github/workflows/macos-publish.yml index 0bc44aa434..9110f878d3 100644 --- a/.github/workflows/macos-publish.yml +++ b/.github/workflows/macos-publish.yml @@ -6,8 +6,8 @@ on: build-image-sha: type: string description: 'SHA for electron/build image' - default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb' - required: true + default: '' + required: false upload-to-storage: description: 'Uploads to Azure storage' required: false @@ -21,12 +21,28 @@ on: permissions: {} jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + checkout-macos: + needs: setup runs-on: electron-arc-centralus-linux-amd64-32core permissions: contents: read container: - image: ghcr.io/electron/build:${{ inputs.build-image-sha }} + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root volumes: - /mnt/cross-instance-cache:/mnt/cross-instance-cache diff --git a/.github/workflows/windows-publish.yml b/.github/workflows/windows-publish.yml index d82431bf46..c054ec039b 100644 --- a/.github/workflows/windows-publish.yml +++ b/.github/workflows/windows-publish.yml @@ -6,8 +6,8 @@ on: build-image-sha: type: string description: 'SHA for electron/build image' - default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb' - required: true + default: '' + required: false upload-to-storage: description: 'Uploads to Azure storage' required: false @@ -21,12 +21,28 @@ on: permissions: {} jobs: + setup: + if: github.repository == 'electron/electron' + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + build-image-sha: ${{ steps.build-image-sha.outputs.build-image-sha }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Set Build Image SHA + id: build-image-sha + uses: ./.github/actions/build-image-sha + with: + override: ${{ inputs.build-image-sha }} + checkout-windows: + needs: setup runs-on: electron-arc-centralus-linux-amd64-32core permissions: contents: read container: - image: ghcr.io/electron/build:${{ inputs.build-image-sha }} + image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }} options: --user root --device /dev/fuse --cap-add SYS_ADMIN volumes: - /mnt/win-cache:/mnt/win-cache @@ -36,8 +52,6 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_win=True' TARGET_OS: 'win' ELECTRON_DEPOT_TOOLS_WIN_TOOLCHAIN: '1' - outputs: - build-image-sha: ${{ inputs.build-image-sha }} steps: - name: Checkout Electron uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 @@ -53,7 +67,7 @@ jobs: # Build the patched siso binary in parallel with checkout-windows; the # publish-*-win jobs consume it via SISO_PATH. build-siso-windows: - if: github.repository == 'electron/electron' + needs: setup uses: ./.github/workflows/pipeline-segment-build-siso-windows.yml permissions: contents: read