Browse Source

Merge branch 'main' into roller/chromium/main

Alice Zhao 10 months ago
parent
commit
0aeebd8c93
78 changed files with 2600 additions and 1114 deletions
  1. 198 0
      .github/actions/build-electron/action.yml
  2. 154 0
      .github/actions/checkout/action.yml
  3. 61 0
      .github/actions/fix-sync-macos/action.yml
  4. 65 0
      .github/actions/free-space-macos/action.yml
  5. 11 0
      .github/actions/install-build-tools/action.yml
  6. 36 0
      .github/actions/restore-cache-aks/action.yml
  7. 51 0
      .github/actions/restore-cache-azcopy/action.yml
  8. 24 0
      .github/workflows/auto-close-pull-request.yml
  9. 205 0
      .github/workflows/build.yml
  10. 0 26
      .github/workflows/config/release/arm64/evm.mas.json
  11. 0 26
      .github/workflows/config/release/x64/evm.mas.json
  12. 0 25
      .github/workflows/config/testing/arm64/evm.mas.json
  13. 0 25
      .github/workflows/config/testing/x64/evm.mas.json
  14. 83 0
      .github/workflows/linux-publish.yml
  15. 0 765
      .github/workflows/macos-build.yml
  16. 52 9
      .github/workflows/macos-publish.yml
  17. 97 0
      .github/workflows/pipeline-electron-build-and-test-and-nan.yml
  18. 92 0
      .github/workflows/pipeline-electron-build-and-test.yml
  19. 43 0
      .github/workflows/pipeline-electron-docs-only.yml
  20. 77 0
      .github/workflows/pipeline-electron-lint.yml
  21. 202 0
      .github/workflows/pipeline-segment-electron-build.yml
  22. 138 0
      .github/workflows/pipeline-segment-electron-gn-check.yml
  23. 170 0
      .github/workflows/pipeline-segment-electron-test.yml
  24. 165 0
      .github/workflows/pipeline-segment-node-nan-test.yml
  25. 2 2
      .github/workflows/scorecards.yml
  26. 2 2
      .github/workflows/update_appveyor_image.yml
  27. 2 1
      .markdownlint-cli2.jsonc
  28. 9 6
      DEPS
  29. 1 1
      appveyor-woa.yml
  30. 1 1
      appveyor.yml
  31. 1 1
      docs/api/app.md
  32. 1 1
      docs/api/command-line-switches.md
  33. 1 1
      docs/api/dock.md
  34. 2 0
      docs/api/structures/cpu-usage.md
  35. 4 4
      docs/api/structures/trace-config.md
  36. 3 2
      docs/tutorial/electron-timelines.md
  37. 58 44
      docs/tutorial/mac-app-store-submission-guide.md
  38. 6 6
      docs/tutorial/security.md
  39. 4 4
      docs/tutorial/using-native-node-modules.md
  40. 2 2
      docs/tutorial/web-embeds.md
  41. 5 2
      lib/node/init.ts
  42. 1 3
      package.json
  43. 1 0
      patches/chromium/.patches
  44. 176 17
      patches/chromium/feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch
  45. 62 0
      patches/chromium/x11_use_localized_display_label_only_for_browser_process.patch
  46. 65 34
      patches/node/build_add_gn_build_files.patch
  47. 61 11
      script/actions/move-artifacts.sh
  48. 22 4
      script/actions/restore-artifacts.sh
  49. 7 0
      script/actions/run-tests.sh
  50. 0 2
      script/generate-deps-hash.js
  51. 12 8
      script/lib/util.py
  52. 7 13
      script/lib/utils.js
  53. 6 5
      script/nan-spec-runner.js
  54. 2 0
      script/node-disabled-tests.json
  55. 2 1
      script/release/ci-release-build.js
  56. 7 4
      script/release/prepare-release.js
  57. 32 0
      script/split-tests.js
  58. 11 4
      shell/browser/api/electron_api_app.cc
  59. 4 0
      shell/browser/api/electron_api_web_contents.cc
  60. 5 0
      shell/browser/browser.h
  61. 4 0
      shell/browser/browser_linux.cc
  62. 2 0
      shell/browser/browser_mac.mm
  63. 4 4
      shell/browser/electron_browser_main_parts_linux.cc
  64. 2 2
      shell/browser/hid/electron_hid_delegate.cc
  65. 3 6
      shell/browser/javascript_environment.cc
  66. 8 0
      shell/browser/mac/electron_application_delegate.mm
  67. 3 2
      shell/browser/ui/file_dialog_linux.cc
  68. 2 1
      shell/browser/usb/electron_usb_delegate.cc
  69. 9 2
      shell/common/api/electron_bindings.cc
  70. 5 0
      shell/common/gin_converters/net_converter.cc
  71. 1 1
      shell/common/platform_util_mac.mm
  72. 15 9
      shell/renderer/electron_renderer_client.cc
  73. 2 1
      spec/api-app-spec.ts
  74. 12 2
      spec/api-content-tracing-spec.ts
  75. 2 0
      spec/api-process-spec.ts
  76. 1 1
      spec/api-protocol-spec.ts
  77. 1 1
      spec/lib/codesign-helpers.ts
  78. 13 20
      yarn.lock

+ 198 - 0
.github/actions/build-electron/action.yml

@@ -0,0 +1,198 @@
+name: 'Build Electron'
+description: 'Builds Electron & Friends'
+inputs:
+  target-arch:
+    description: 'Target arch'
+    required: true
+  target-platform:
+    description: 'Target platform'
+    required: true
+  artifact-platform:
+    description: 'Artifact platform, should be linux, darwin or mas'
+    required: true
+  step-suffix:
+    description: 'Suffix for build steps'
+    required: false
+    default: ''
+  is-release:
+    description: 'Is release build'
+    required: true
+  generate-symbols:
+    description: 'Generate symbols'
+    required: true
+  upload-to-storage:
+    description: 'Upload to storage'
+    required: true
+runs:
+  using: "composite"
+  steps:
+    - name: Set GN_EXTRA_ARGS for MacOS x64 Builds
+      shell: bash
+      if: ${{ inputs.target-arch == 'x64' && inputs.target-platform == 'macos' }}
+      run: |
+        GN_APPENDED_ARGS="$GN_EXTRA_ARGS v8_snapshot_toolchain=\"//build/toolchain/mac:clang_x64\""
+        echo "GN_EXTRA_ARGS=$GN_APPENDED_ARGS" >> $GITHUB_ENV
+    - name: Build Electron ${{ inputs.step-suffix }}
+      shell: bash
+      run: |
+        rm -rf "src/out/Default/Electron Framework.framework"
+        rm -rf src/out/Default/Electron*.app
+
+        cd src/electron
+        # TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
+        git pack-refs
+        cd ..
+
+        if [ "`uname`" = "Darwin" ]; then
+          ulimit -n 10000
+          sudo launchctl limit maxfiles 65536 200000
+        fi
+
+        NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
+        cp out/Default/.ninja_log out/electron_ninja_log
+        node electron/script/check-symlinks.js
+    - name: Build Electron dist.zip ${{ inputs.step-suffix }}
+      shell: bash
+      run: |
+        cd src
+        e build electron:electron_dist_zip -j $NUMBER_OF_NINJA_PROCESSES
+        if [ "${{ env.CHECK_DIST_MANIFEST }}" = "true" ]; then
+          target_os=${{ inputs.target-platform == 'linux' && 'linux' || 'mac'}}
+          if [ "${{ inputs.artifact-platform }}" = "mas" ]; then
+            target_os="${target_os}_mas"
+          fi
+          electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ inputs.target-arch }}.manifest
+        fi
+    - name: Build Mksnapshot ${{ inputs.step-suffix }}
+      shell: bash
+      run: |
+        cd src
+        e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
+        gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
+        # Remove unused args from mksnapshot_args
+        SEDOPTION="-i"
+        if [ "`uname`" = "Darwin" ]; then
+          SEDOPTION="-i ''"
+        fi
+        sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
+        sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
+        sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
+
+        if [ "`uname`" = "Linux" ]; then
+          if [ "${{ inputs.target-arch }}" = "arm" ]; then
+            electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/mksnapshot
+            electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/v8_context_snapshot_generator
+          elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
+            electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/mksnapshot
+            electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/v8_context_snapshot_generator
+          else
+            electron/script/strip-binaries.py --file $PWD/out/Default/mksnapshot
+            electron/script/strip-binaries.py --file $PWD/out/Default/v8_context_snapshot_generator
+          fi
+        fi
+
+        e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
+        (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
+    - name: Generate Cross-Arch Snapshot (arm/arm64)  ${{ inputs.step-suffix }}
+      shell: bash
+      if: ${{ (inputs.target-arch == 'arm' || inputs.target-arch == 'arm64') && inputs.target-platform == 'linux' }}
+      run: |
+        cd src
+        if [ "${{ inputs.target-arch }}" = "arm" ]; then
+          MKSNAPSHOT_PATH="clang_x86_v8_arm"
+        elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
+          MKSNAPSHOT_PATH="clang_x64_v8_arm64"
+        fi
+
+        cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default
+        cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default
+        cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default
+
+        python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only
+        mkdir cross-arch-snapshots
+        cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots
+        # Clean up so that ninja does not get confused
+        rm -f out/Default/libffmpeg.so
+    - name: Build Chromedriver ${{ inputs.step-suffix }}
+      shell: bash
+      run: |
+        cd src
+        e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
+        e build electron:electron_chromedriver_zip
+    - name: Build Node.js headers ${{ inputs.step-suffix }}
+      shell: bash
+      run: |
+        cd src
+        e build electron:node_headers
+    - name: Generate & Zip Symbols ${{ inputs.step-suffix }}
+      shell: bash
+      run: |
+        # Generate breakpad symbols on release builds
+        if [ "${{ inputs.generate-symbols }}" = "true" ]; then
+          e build electron:electron_symbols
+        fi
+        cd src
+        export BUILD_PATH="$(pwd)/out/Default"
+        e build electron:licenses
+        e build electron:electron_version_file
+        if [ "${{ inputs.is-release }}" = "true" ]; then
+          DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
+        else
+          electron/script/zip-symbols.py -b $BUILD_PATH
+        fi
+    - name: Generate FFMpeg ${{ inputs.step-suffix }}
+      shell: bash
+      if: ${{ inputs.is-release == 'true' }}
+      run: |
+        cd src
+        gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true $GN_EXTRA_ARGS"
+        autoninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES
+    - name: Generate Hunspell Dictionaries ${{ inputs.step-suffix }}
+      shell: bash
+      if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }}
+      run: |
+        cd src
+        autoninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES
+    - name: Generate Libcxx ${{ inputs.step-suffix }}
+      shell: bash
+      if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }}
+      run: |
+        cd src
+        autoninja -C out/Default electron:libcxx_headers_zip -j $NUMBER_OF_NINJA_PROCESSES
+        autoninja -C out/Default electron:libcxxabi_headers_zip -j $NUMBER_OF_NINJA_PROCESSES
+        autoninja -C out/Default electron:libcxx_objects_zip -j $NUMBER_OF_NINJA_PROCESSES
+    - name: Generate TypeScript Definitions ${{ inputs.step-suffix }}
+      if: ${{ inputs.is-release == 'true' }}
+      shell: bash
+      run: |
+        cd src/electron
+        node script/yarn create-typescript-definitions
+    # TODO(vertedinde): These uploads currently point to a different Azure bucket & GitHub Repo
+    - name: Publish Electron Dist ${{ inputs.step-suffix }}
+      if: ${{ inputs.is-release == 'true' }}
+      shell: bash
+      run: |
+        rm -rf src/out/Default/obj
+        cd src/electron
+        if [ "${{ inputs.upload-to-storage }}" = "1" ]; then
+          echo 'Uploading Electron release distribution to Azure'
+          script/release/uploaders/upload.py --verbose --upload_to_storage
+        else
+          echo 'Uploading Electron release distribution to GitHub releases'
+          script/release/uploaders/upload.py --verbose
+        fi
+    # The current generated_artifacts_<< artifact.key >> name was taken from CircleCI
+    # to ensure we don't break anything, but we may be able to improve that.
+    - name: Move all Generated Artifacts to Upload Folder ${{ inputs.step-suffix }}
+      shell: bash
+      run: ./src/electron/script/actions/move-artifacts.sh
+    - name: Upload Generated Artifacts ${{ inputs.step-suffix }}
+      uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
+      with:
+        name: generated_artifacts_${{ inputs.artifact-platform }}_${{ env.TARGET_ARCH }}
+        path: ./generated_artifacts_${{ inputs.artifact-platform }}_${{ env.TARGET_ARCH }}
+    - name: Upload Src Artifacts ${{ inputs.step-suffix }}
+      uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
+      with:
+        name: src_artifacts_${{ inputs.artifact-platform }}_${{ env.TARGET_ARCH }}
+        path: ./src_artifacts_${{ inputs.artifact-platform }}_${{ env.TARGET_ARCH }}

+ 154 - 0
.github/actions/checkout/action.yml

@@ -0,0 +1,154 @@
+name: 'Checkout'
+description: 'Checks out Electron and stores it in the AKS Cache'
+inputs:
+  generate-sas-token:
+    description: 'Whether to generate and persist a SAS token for the item in the cache'
+    required: false
+    default: 'false'
+runs:
+  using: "composite"
+  steps:
+  - name: Set GIT_CACHE_PATH to make gclient to use the cache
+    shell: bash
+    run: |
+      echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV
+  - name: Install Dependencies
+    shell: bash
+    run: |
+      cd src/electron
+      node script/yarn install --frozen-lockfile
+  - name: Get Depot Tools
+    shell: bash
+    run: |
+      git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
+
+      sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+      # Remove swift-format dep from cipd on macOS until we send a patch upstream.
+      cd depot_tools
+      git apply --3way ../src/electron/.github/workflows/config/gclient.diff
+
+      # Ensure depot_tools does not update.
+      test -d depot_tools && cd depot_tools
+      touch .disable_auto_update
+  - name: Add Depot Tools to PATH
+    shell: bash
+    run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
+  - name: Generate DEPS Hash
+    shell: bash
+    run: |
+      node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
+      echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
+  - name: Generate SAS Key
+    if: ${{ inputs.generate-sas-token == 'true' }}
+    shell: bash
+    run: |
+      curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$DEPSHASH.tar" > sas-token
+  - name: Save SAS Key
+    if: ${{ inputs.generate-sas-token == 'true' }}
+    uses: actions/cache/save@v4
+    with:
+      path: |
+        sas-token
+      key: sas-key-${{ github.run_number }}-${{ github.run_attempt }}
+  - name: Check If Cache Exists
+    id: check-cache
+    shell: bash
+    run: |
+      cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
+      echo "Using cache key: $DEPSHASH"
+      echo "Checking for cache in: $cache_path"
+      if [ ! -f "$cache_path" ]; then
+        echo "cache_exists=false" >> $GITHUB_OUTPUT
+        echo "Cache Does Not Exist for $DEPSHASH"
+      else
+        echo "cache_exists=true" >> $GITHUB_OUTPUT
+        echo "Cache Already Exists for $DEPSHASH, Skipping.."
+      fi
+  - name: Gclient Sync
+    if: steps.check-cache.outputs.cache_exists == 'false'
+    shell: bash
+    run: |
+      gclient config \
+        --name "src/electron" \
+        --unmanaged \
+        ${GCLIENT_EXTRA_ARGS} \
+        "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
+
+      ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags -vvvvv
+      if [ "${{ inputs.is-release }}" != "true" ]; then
+        # Re-export all the patches to check if there were changes.
+        python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
+        cd src/electron
+        git update-index --refresh || true
+        if ! git diff-index --quiet HEAD --; then
+          # There are changes to the patches. Make a git commit with the updated patches
+          git add patches
+          GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>"
+          # Export it
+          mkdir -p ../../patches
+          git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
+          if (node ./script/push-patch.js 2> /dev/null > /dev/null); then
+            echo
+            echo "======================================================================"
+            echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch"
+            echo "A new CI job will kick off shortly"
+            echo "======================================================================"
+            exit 1
+          else
+            echo
+            echo "======================================================================"
+            echo "There were changes to the patches when applying."
+            echo "Check the CI artifacts for a patch you can apply to fix it."
+            echo "======================================================================"
+            exit 1
+          fi
+        fi
+      fi
+
+  # delete all .git directories under src/ except for
+  # third_party/angle/ and third_party/dawn/ because of build time generation of files
+  # gen/angle/commit.h depends on third_party/angle/.git/HEAD
+  # https://chromium-review.googlesource.com/c/angle/angle/+/2074924
+  # and dawn/common/Version_autogen.h depends on  third_party/dawn/.git/HEAD
+  # https://dawn-review.googlesource.com/c/dawn/+/83901
+  # TODO: maybe better to always leave out */.git/HEAD file for all targets ?
+  - name: Delete .git directories under src to free space
+    if: steps.check-cache.outputs.cache_exists == 'false'
+    shell: bash
+    run: |
+      cd src
+      ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf
+  - name: Minimize Cache Size for Upload
+    if: steps.check-cache.outputs.cache_exists == 'false'
+    shell: bash
+    run: |
+      rm -rf src/android_webview
+      rm -rf src/ios/chrome
+      rm -rf src/third_party/blink/web_tests
+      rm -rf src/third_party/blink/perf_tests
+      rm -rf src/chrome/test/data/xr/webvr_info
+      rm -rf src/third_party/angle/third_party/VK-GL-CTS/src
+      rm -rf src/third_party/swift-toolchain
+      rm -rf src/third_party/swiftshader/tests/regres/testlists
+      rm -rf src/electron
+  - name: Compress Src Directory
+    if: steps.check-cache.outputs.cache_exists == 'false'
+    shell: bash
+    run: |
+      echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')"
+      tar -cf $DEPSHASH.tar src
+      echo "Compressed src to $(du -sh $DEPSHASH.tar | cut -f1 -d' ')"
+      cp ./$DEPSHASH.tar /mnt/cross-instance-cache/
+  - name: Persist Src Cache
+    if: steps.check-cache.outputs.cache_exists == 'false'
+    shell: bash
+    run: |
+      final_cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
+      echo "Using cache key: $DEPSHASH"
+      echo "Checking path: $final_cache_path"
+      if [ ! -f "$final_cache_path" ]; then
+        echo "Cache key not found"
+        exit 1
+      else
+        echo "Cache key persisted in $final_cache_path"
+      fi

+ 61 - 0
.github/actions/fix-sync-macos/action.yml

@@ -0,0 +1,61 @@
+name: 'Fix Sync macOS'
+description: 'Checks out Electron and stores it in the AKS Cache'
+runs:
+  using: "composite"
+  steps:
+    - name: Fix Sync
+      shell: bash
+      # This step is required to correct for differences between "gclient sync"
+      # on Linux and the expected state on macOS. This requires:
+      # 1. Fixing Clang Install (wrong binary)
+      # 2. Fixing esbuild (wrong binary)
+      # 3. Fixing rustc (wrong binary)
+      # 4. Fixing gn (wrong binary)
+      # 5. Fix reclient (wrong binary)
+      # 6. Fixing dsymutil (wrong binary)
+      # 7. Ensuring we are using the correct ninja and adding it to PATH
+      # 8. Fixing angle (wrong remote)
+      run : |
+        SEDOPTION="-i ''"
+        rm -rf src/third_party/llvm-build
+        python3 src/tools/clang/scripts/update.py
+
+        echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file
+        # Remove extra output from calling gclient getdep which always calls update_depot_tools
+        sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file
+        cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file
+
+        rm -rf src/third_party/rust-toolchain
+        python3 src/tools/rust/update_rust.py
+        
+        # Prevent calling gclient getdep which always calls update_depot_tools
+        echo 'gn/gn/mac-${arch}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/mac:gn/gn/mac-${arch}'` > gn_ensure_file
+        sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
+        cipd ensure --root src/buildtools/mac -ensure-file gn_ensure_file
+
+        # Prevent calling gclient getdep which always calls update_depot_tools
+        echo 'infra/rbe/client/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/reclient:infra/rbe/client/${platform}'` > gn_ensure_file
+        sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
+        cipd ensure --root src/buildtools/reclient -ensure-file gn_ensure_file
+        python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch
+
+        if  [ "${{ env.TARGET_ARCH }}" == "arm64" ]; then
+          DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1
+        else
+          DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.x64.sha1
+        fi
+        python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil
+
+        echo 'infra/3pp/tools/ninja/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/third_party/ninja:infra/3pp/tools/ninja/${platform}'` > ninja_ensure_file
+        sed $SEDOPTION "s/Updating depot_tools... //g" ninja_ensure_file
+        cipd ensure --root src/third_party/ninja -ensure-file ninja_ensure_file
+
+        echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH
+
+        cd src/third_party/angle
+        rm -f .git/objects/info/alternates
+        git remote set-url origin https://chromium.googlesource.com/angle/angle.git
+        cp .git/config .git/config.backup
+        git remote remove origin
+        mv .git/config.backup .git/config
+        git fetch

+ 65 - 0
.github/actions/free-space-macos/action.yml

@@ -0,0 +1,65 @@
+name: 'Free Space macOS'
+description: 'Checks out Electron and stores it in the AKS Cache'
+runs:
+  using: "composite"
+  steps:
+    - name: Free Space on MacOS
+      shell: bash
+      run: |
+        sudo mkdir -p $TMPDIR/del-target
+
+        tmpify() {
+          if [ -d "$1" ]; then
+            sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1)
+          fi
+        }
+
+        strip_universal_deep() {
+          opwd=$(pwd)
+          cd $1
+          f=$(find . -perm +111 -type f)
+          for fp in $f
+          do
+            if [[ $(file "$fp") == *"universal binary"* ]]; then
+              if [ "`arch`" == "arm64" ]; then
+                if [[ $(file "$fp") == *"x86_64"* ]]; then
+                  sudo lipo -remove x86_64 "$fp" -o "$fp" || true
+                fi
+              else
+                if [[ $(file "$fp") == *"arm64e)"* ]]; then
+                  sudo lipo -remove arm64e "$fp" -o "$fp" || true
+                fi
+                if [[ $(file "$fp") == *"arm64)"* ]]; then
+                  sudo lipo -remove arm64 "$fp" -o "$fp" || true
+                fi
+              fi
+            fi
+          done
+
+          cd $opwd
+        }
+
+        tmpify /Library/Developer/CoreSimulator
+        tmpify ~/Library/Developer/CoreSimulator
+        tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform
+        tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform
+        tmpify $(xcode-select -p)/Platforms/WatchOS.platform
+        tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform
+        tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform
+        tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform
+        tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios
+        tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
+        tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0
+        tmpify ~/.rubies
+        tmpify ~/Library/Caches/Homebrew
+        tmpify /usr/local/Homebrew
+
+        sudo rm -rf $TMPDIR/del-target
+
+        sudo rm -rf /Applications/Safari.app
+        sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data
+        sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS
+
+        # lipo off some huge binaries arm64 versions to save space
+        strip_universal_deep $(xcode-select -p)/../SharedFrameworks
+        # strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr

+ 11 - 0
.github/actions/install-build-tools/action.yml

@@ -0,0 +1,11 @@
+name: 'Install Build Tools'
+description: 'Installs an exact SHA of build tools'
+runs:
+  using: "composite"
+  steps:
+  - name: Install Build Tools
+    shell: bash
+    run: |
+      export BUILD_TOOLS_SHA=ff3e40a9a2ebb735c18b6450ecd5ddaa8bb364a9
+      npm i -g @electron/build-tools
+      e auto-update disable

+ 36 - 0
.github/actions/restore-cache-aks/action.yml

@@ -0,0 +1,36 @@
+name: 'Restore Cache AKS'
+description: 'Restores Electron src cache via AKS'
+runs:
+  using: "composite"
+  steps:
+  - name: Restore and Ensure Src Cache
+    shell: bash
+    run: |
+      cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
+      echo "Using cache key: $DEPSHASH"
+      echo "Checking for cache in: $cache_path"
+      if [ ! -f "$cache_path" ]; then
+        echo "Cache Does Not Exist for $DEPSHASH - exiting"
+        exit 1
+      else
+        echo "Found Cache for $DEPSHASH at $cache_path"
+      fi
+
+      echo "Persisted cache is $(du -sh $cache_path | cut -f1)"
+      mkdir temp-cache
+      tar -xf $cache_path -C temp-cache
+      echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
+
+      if [ -d "temp-cache/src" ]; then
+        echo "Relocating Cache"
+        rm -rf src
+        mv temp-cache/src src
+      fi
+
+      if [ ! -d "src/third_party/blink" ]; then
+        echo "Cache was not correctly restored - exiting"
+        exit 1
+      fi
+
+      echo "Wiping Electron Directory"
+      rm -rf src/electron

+ 51 - 0
.github/actions/restore-cache-azcopy/action.yml

@@ -0,0 +1,51 @@
+name: 'Restore Cache AZCopy'
+description: 'Restores Electron src cache via AZCopy'
+runs:
+  using: "composite"
+  steps:
+  - name: Obtain SAS Key
+    uses: actions/cache/restore@v4
+    with:
+      path: |
+        sas-token
+      key: sas-key-${{ github.run_number }}-${{ github.run_attempt }}
+  - name: Download Src Cache from AKS
+    # The cache will always exist here as a result of the checkout job
+    # Either it was uploaded to Azure in the checkout job for this commit
+    # or it was uploaded in the checkout job for a previous commit.
+    uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
+    with:
+      timeout_minutes: 20
+      max_attempts: 3
+      retry_on: error
+      command: |
+        sas_token=$(cat sas-token)
+        azcopy copy \
+          "https://${{ env.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}.file.core.windows.net/${{ env.AZURE_AKS_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar
+  - name: Clean SAS Key
+    shell: bash
+    run: rm -f sas-token
+  - name: Unzip and Ensure Src Cache
+    shell: bash
+    run: |
+      echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)"
+      mkdir temp-cache
+      tar -xf $DEPSHASH.tar -C temp-cache
+      echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
+
+      if [ -d "temp-cache/src" ]; then
+        echo "Relocating Cache"
+        rm -rf src
+        mv temp-cache/src src
+
+        echo "Deleting zip file"
+        rm -rf $DEPSHASH.tar
+      fi
+
+      if [ ! -d "src/third_party/blink" ]; then
+        echo "Cache was not correctly restored - exiting"
+        exit 1
+      fi
+
+      echo "Wiping Electron Directory"
+      rm -rf src/electron

+ 24 - 0
.github/workflows/auto-close-pull-request.yml

@@ -0,0 +1,24 @@
+name: Auto Close Pull Request
+
+on:
+  pull_request_target:
+    paths:
+      - 'yarn.lock'
+      - 'spec/yarn.lock'
+
+permissions: {}
+
+jobs:
+  auto-close-dependency-pull-request:
+    name: Auto close non-maintainer dependency pull request
+    if: ${{ !contains(fromJSON('["MEMBER", "OWNER"]'), github.event.pull_request.author_association) && github.event.pull_request.user.type != 'Bot' && !github.event.pull_request.draft }}
+    permissions:
+      pull-requests: write
+    runs-on: ubuntu-latest
+    steps:
+      - name: Close pull request
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          PR_URL: ${{ github.event.pull_request.html_url }}
+        run: |
+          gh pr close $PR_URL --comment 'Hello @${{ github.event.pull_request.user.login }}! It looks like this pull request touches one of our dependency files, and per [our contribution policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy) we do not accept these types of PRs, so this PR will be closed.'

+ 205 - 0
.github/workflows/build.yml

@@ -0,0 +1,205 @@
+name: Build
+
+on:
+  workflow_dispatch:
+    inputs:
+      build-image-sha:
+        type: string
+        description: 'SHA for electron/build image'
+        default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
+        required: true
+      skip-macos:
+        type: boolean
+        description: 'Skip macOS builds'
+        default: false
+        required: false
+      skip-linux:
+        type: boolean
+        description: 'Skip Linux builds'
+        default: false
+        required: false
+      skip-lint:
+        type: boolean
+        description: 'Skip lint check'
+        default: false
+        required: false
+  # push:
+  # pull_request:
+
+jobs:
+  changes:
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: read
+    outputs:
+        docs: ${{ steps.filter.outputs.docs }}
+        src: ${{ steps.filter.outputs.src }}
+    steps:
+    - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.0.2
+    - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
+      id: filter
+      with:
+        filters: |
+          docs:
+            - 'docs/**'
+          src:
+            - '!docs/**'
+
+  # Lint Jobs
+  lint:
+    if: ${{ !inputs.skip-lint }}
+    uses: ./.github/workflows/pipeline-electron-lint.yml
+    with:
+      container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root"}'
+    secrets: inherit
+
+  # Docs Only Jobs
+  docs-only:
+    needs: changes
+    if: ${{ needs.changes.outputs.docs == 'true' && needs.changes.outputs.src == 'false'}}
+    uses: ./.github/workflows/pipeline-electron-docs-only.yml
+    with:
+      container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root"}'
+    secrets: inherit
+
+  # Checkout Jobs
+  checkout-macos:
+    needs: changes
+    if: ${{ needs.changes.outputs.src == 'true' && !inputs.skip-macos}}
+    runs-on: aks-linux-large
+    container:
+      image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
+      options: --user root
+      volumes:
+        - /mnt/cross-instance-cache:/mnt/cross-instance-cache
+        - /var/run/sas:/var/run/sas
+    env:
+      GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Checkout & Sync & Save
+      uses: ./src/electron/.github/actions/checkout
+      with:
+        generate-sas-token: 'true'
+
+  checkout-linux:
+    needs: changes
+    if: ${{ needs.changes.outputs.src == 'true' && !inputs.skip-linux}}
+    runs-on: aks-linux-large
+    container:
+      image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
+      options: --user root
+      volumes:
+        - /mnt/cross-instance-cache:/mnt/cross-instance-cache
+        - /var/run/sas:/var/run/sas
+    env:
+      GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Checkout & Sync & Save
+      uses: ./src/electron/.github/actions/checkout
+
+  # Build Jobs - These cascade into testing jobs
+  macos-x64:
+    permissions:
+      contents: read
+      issues: read
+      pull-requests: read
+    uses: ./.github/workflows/pipeline-electron-build-and-test.yml
+    needs: checkout-macos
+    with:
+      build-runs-on: macos-14-xlarge
+      test-runs-on: macos-13
+      target-platform: macos
+      target-arch: x64
+      is-release: false
+      gn-build-type: testing
+      generate-symbols: false
+      upload-to-storage: '0'
+    secrets: inherit
+  
+  macos-arm64:
+    permissions:
+      contents: read
+      issues: read
+      pull-requests: read
+    uses: ./.github/workflows/pipeline-electron-build-and-test.yml
+    needs: checkout-macos
+    with:
+      build-runs-on: macos-14-xlarge
+      test-runs-on: macos-14
+      target-platform: macos
+      target-arch: arm64
+      is-release: false
+      gn-build-type: testing
+      generate-symbols: false
+      upload-to-storage: '0'
+    secrets: inherit
+
+  linux-x64:
+    permissions:
+      contents: read
+      issues: read
+      pull-requests: read
+    uses: ./.github/workflows/pipeline-electron-build-and-test-and-nan.yml
+    needs: checkout-linux
+    with:
+      build-runs-on: aks-linux-large
+      test-runs-on: aks-linux-medium
+      build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      test-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root --privileged --init"}'
+      target-platform: linux
+      target-arch: x64
+      is-release: false
+      gn-build-type: testing
+      generate-symbols: false
+      upload-to-storage: '0'
+    secrets: inherit
+  
+  linux-arm:
+    permissions:
+      contents: read
+      issues: read
+      pull-requests: read
+    uses: ./.github/workflows/pipeline-electron-build-and-test.yml
+    needs: checkout-linux
+    with:
+      build-runs-on: aks-linux-large
+      test-runs-on: aks-linux-arm-medium
+      build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ inputs.build-image-sha }}","options":"--user root --privileged --init","volumes":["/home/runner/externals:/mnt/runner-externals"]}'
+      target-platform: linux
+      target-arch: arm
+      is-release: false
+      gn-build-type: testing
+      generate-symbols: false
+      upload-to-storage: '0'
+    secrets: inherit
+  
+  linux-arm64:
+    permissions:
+      contents: read
+      issues: read
+      pull-requests: read
+    uses: ./.github/workflows/pipeline-electron-build-and-test.yml
+    needs: checkout-linux
+    with:
+      build-runs-on: aks-linux-large
+      test-runs-on: aks-linux-arm-medium
+      build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ inputs.build-image-sha }}","options":"--user root --privileged --init"}'
+      target-platform: linux
+      target-arch: arm64
+      is-release: false
+      gn-build-type: testing
+      generate-symbols: false
+      upload-to-storage: '0'
+    secrets: inherit

+ 0 - 26
.github/workflows/config/release/arm64/evm.mas.json

@@ -1,26 +0,0 @@
-{
-  "root": "/Users/runner/work/electron/electron/",
-  "remotes": {
-    "electron": {
-      "origin": "https://github.com/electron/electron.git"
-    }
-  },
-  "gen": {
-    "args": [
-      "import(\"//electron/build/args/release.gn\")",
-      "use_remoteexec = true",
-      "target_cpu = \"arm64\"",
-      "is_mas_build = true"
-    ],
-    "out": "Default"
-  },
-  "env": {
-    "CHROMIUM_BUILDTOOLS_PATH": "/Users/runner/work/electron/electron/src/buildtools",
-    "GIT_CACHE_PATH": "/Users/runner/work/electron/electron/.git-cache"
-  },
-  "$schema": "file:///home/builduser/.electron_build_tools/evm-config.schema.json",
-  "configValidationLevel": "strict",
-  "reclient": "remote_exec",
-  "goma": "none",
-  "preserveXcode": 5
-}

+ 0 - 26
.github/workflows/config/release/x64/evm.mas.json

@@ -1,26 +0,0 @@
-{
-  "root": "/Users/runner/work/electron/electron/",
-  "remotes": {
-    "electron": {
-      "origin": "https://github.com/electron/electron.git"
-    }
-  },
-  "gen": {
-    "args": [
-      "import(\"//electron/build/args/release.gn\")",
-      "use_remoteexec = true",
-      "target_cpu = \"x64\"",
-      "is_mas_build = true"
-    ],
-    "out": "Default"
-  },
-  "env": {
-    "CHROMIUM_BUILDTOOLS_PATH": "/Users/runner/work/electron/electron/src/buildtools",
-    "GIT_CACHE_PATH": "/Users/runner/work/electron/electron/.git-cache"
-  },
-  "$schema": "file:///home/builduser/.electron_build_tools/evm-config.schema.json",
-  "configValidationLevel": "strict",
-  "reclient": "remote_exec",
-  "goma": "none",
-  "preserveXcode": 5
-}

+ 0 - 25
.github/workflows/config/testing/arm64/evm.mas.json

@@ -1,25 +0,0 @@
-{
-  "root": "/Users/runner/work/electron/electron/",
-  "remotes": {
-    "electron": {
-      "origin": "https://github.com/electron/electron.git"
-    }
-  },
-  "gen": {
-    "args": [
-      "import(\"//electron/build/args/testing.gn\")",
-      "use_remoteexec = true",
-      "is_mas_build = true"
-    ],
-    "out": "Default"
-  },
-  "env": {
-    "CHROMIUM_BUILDTOOLS_PATH": "/Users/runner/work/electron/electron/src/buildtools",
-    "GIT_CACHE_PATH": "/Users/runner/work/electron/electron/.git-cache"
-  },
-  "$schema": "file:///home/builduser/.electron_build_tools/evm-config.schema.json",
-  "configValidationLevel": "strict",
-  "reclient": "remote_exec",
-  "goma": "none",
-  "preserveXcode": 5
-}

+ 0 - 25
.github/workflows/config/testing/x64/evm.mas.json

@@ -1,25 +0,0 @@
-{
-  "root": "/Users/runner/work/electron/electron/",
-  "remotes": {
-    "electron": {
-      "origin": "https://github.com/electron/electron.git"
-    }
-  },
-  "gen": {
-    "args": [
-      "import(\"//electron/build/args/testing.gn\")",
-      "use_remoteexec = true",
-      "is_mas_build = true"
-    ],
-    "out": "Default"
-  },
-  "env": {
-    "CHROMIUM_BUILDTOOLS_PATH": "/Users/runner/work/electron/electron/src/buildtools",
-    "GIT_CACHE_PATH": "/Users/runner/work/electron/electron/.git-cache"
-  },
-  "$schema": "file:///home/builduser/.electron_build_tools/evm-config.schema.json",
-  "configValidationLevel": "strict",
-  "reclient": "remote_exec",
-  "goma": "none",
-  "preserveXcode": 5
-}

+ 83 - 0
.github/workflows/linux-publish.yml

@@ -0,0 +1,83 @@
+name: Publish Linux
+
+on:
+  workflow_dispatch:
+    inputs:
+      build-image-sha:
+        type: string
+        description: 'SHA for electron/build image'
+        default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
+      upload-to-storage:
+        description: 'Uploads to Azure storage'
+        required: false
+        default: '1'
+        type: string
+      run-linux-publish:
+        description: 'Run the publish jobs vs just the build jobs'
+        type: boolean
+        default: false
+
+jobs:
+  checkout-linux:
+    runs-on: aks-linux-large
+    container:
+      image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
+      options: --user root
+      volumes:
+        - /mnt/cross-instance-cache:/mnt/cross-instance-cache
+        - /var/run/sas:/var/run/sas
+    env:
+      GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Checkout & Sync & Save
+      uses: ./src/electron/.github/actions/checkout
+
+  publish-x64:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    needs: checkout-linux
+    with:
+      environment: production-release
+      build-runs-on: aks-linux-large
+      build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      target-platform: linux
+      target-arch: x64
+      is-release: true
+      gn-build-type: release
+      generate-symbols: true
+      upload-to-storage: ${{ inputs.upload-to-storage }}
+    secrets: inherit
+
+  publish-arm:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    needs: checkout-linux
+    with:
+      environment: production-release
+      build-runs-on: aks-linux-large
+      build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      target-platform: linux
+      target-arch: arm
+      is-release: true
+      gn-build-type: release
+      generate-symbols: true
+      upload-to-storage: ${{ inputs.upload-to-storage }}
+    secrets: inherit
+
+  publish-arm64:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    needs: checkout-linux
+    with:
+      environment: production-release
+      build-runs-on: aks-linux-large
+      build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
+      target-platform: linux
+      target-arch: arm64
+      is-release: true
+      gn-build-type: release
+      generate-symbols: true
+      upload-to-storage: ${{ inputs.upload-to-storage }}
+    secrets: inherit

+ 0 - 765
.github/workflows/macos-build.yml

@@ -1,765 +0,0 @@
-name: Build MacOS
-
-# TODO: change to 'pull_request' and 'push' 
-# when we are ready to enable this for PRs.
-on:
-  workflow_call:
-    inputs:
-      IS_RELEASE:
-        required: true
-        type: boolean
-        default: false
-      GN_CONFIG:
-        required: false
-        type: string
-        default: //electron/build/args/testing.gn
-      GN_BUILD_TYPE:
-        required: false
-        type: string
-        default: release
-      GENERATE_SYMBOLS: 
-        required: false
-        type: boolean
-        default: false
-      UPLOAD_TO_STORAGE: 
-        required: false
-        type: string
-        default: '0'
-
-concurrency:
-  group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: true
-
-env:
-  AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
-  AZURE_STORAGE_KEY: ${{ secrets.AZURE_STORAGE_KEY }}
-  AZURE_STORAGE_CONTAINER_NAME: ${{ secrets.AZURE_STORAGE_CONTAINER_NAME }}
-  ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
-  ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
-  ELECTRON_GITHUB_TOKEN: ${{ secrets.ELECTRON_GITHUB_TOKEN }}
-  GN_CONFIG: ${{ inputs.GN_CONFIG }}
-  # Disable pre-compiled headers to reduce out size - only useful for rebuilds
-  GN_BUILDFLAG_ARGS: 'enable_precompiled_headers = false'
-  GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
-  CHECK_DIST_MANIFEST: '1'
-  IS_GHA_RELEASE: true
-  ELECTRON_OUT_DIR: Default
-
-jobs:
-  checkout:
-    runs-on: LargeLinuxRunner
-    steps:
-    - name: Checkout Electron
-      uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
-      with:
-        path: src/electron
-        fetch-depth: 0
-    - name: Set GIT_CACHE_PATH to make gclient to use the cache
-      run: |
-        echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV
-    - name: Setup Node.js/npm
-      uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
-      with:
-        node-version: 20.11.x
-        cache: yarn
-        cache-dependency-path: src/electron/yarn.lock
-    - name: Install Dependencies
-      run: |
-        cd src/electron
-        node script/yarn install
-    - name: Get Depot Tools
-      timeout-minutes: 5
-      run: |
-        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
-        if [ "`uname`" == "Darwin" ]; then
-          # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
-          sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
-        else
-          sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
-          # Remove swift-format dep from cipd on macOS until we send a patch upstream.
-          cd depot_tools
-          git apply --3way ../src/electron/.github/workflows/config/gclient.diff
-        fi
-        # Ensure depot_tools does not update.
-        test -d depot_tools && cd depot_tools
-        touch .disable_auto_update
-    - name: Add Depot Tools to PATH
-      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
-    - name: Generate DEPS Hash
-      run: |
-        node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
-        echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
-    - name: Check If Cache Exists
-      id: check-cache
-      run: |
-        exists_json=$(az storage blob exists \
-          --account-name $AZURE_STORAGE_ACCOUNT \
-          --account-key $AZURE_STORAGE_KEY \
-          --container-name $AZURE_STORAGE_CONTAINER_NAME \
-          --name $DEPSHASH)
-
-        cache_exists=$(echo $exists_json | jq -r '.exists')
-        echo "cache_exists=$cache_exists" >> $GITHUB_OUTPUT
-
-        if (test "$cache_exists" = "true"); then
-          echo "Cache Exists for $DEPSHASH"
-        else
-          echo "Cache Does Not Exist for $DEPSHASH"
-        fi
-    - name: Gclient Sync
-      # If there is no existing src cache, we need to do a full gclient sync.
-      # TODO(codebytere): Add stale patch handling for non-release builds.
-      if: steps.check-cache.outputs.cache_exists == 'false'
-      run: |
-        gclient config \
-          --name "src/electron" \
-          --unmanaged \
-          ${GCLIENT_EXTRA_ARGS} \
-          "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
-
-        ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags -vvvvv
-        if [ ${{ inputs.IS_RELEASE }} != "true" ]; then
-          # Re-export all the patches to check if there were changes.
-          python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
-          cd src/electron
-          git update-index --refresh || true
-          if ! git diff-index --quiet HEAD --; then
-            # There are changes to the patches. Make a git commit with the updated patches
-            git add patches
-            GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>"
-            # Export it
-            mkdir -p ../../patches
-            git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
-            if (node ./script/push-patch.js 2> /dev/null > /dev/null); then
-              echo
-              echo "======================================================================"
-              echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch"
-              echo "A new CI job will kick off shortly"
-              echo "======================================================================"
-              exit 1
-            else
-              echo
-              echo "======================================================================"
-              echo "There were changes to the patches when applying."
-              echo "Check the CI artifacts for a patch you can apply to fix it."
-              echo "======================================================================"
-              exit 1
-            fi
-          fi
-        fi
-
-    # delete all .git directories under src/ except for
-    # third_party/angle/ and third_party/dawn/ because of build time generation of files
-    # gen/angle/commit.h depends on third_party/angle/.git/HEAD
-    # https://chromium-review.googlesource.com/c/angle/angle/+/2074924
-    # and dawn/common/Version_autogen.h depends on  third_party/dawn/.git/HEAD
-    # https://dawn-review.googlesource.com/c/dawn/+/83901
-    # TODO: maybe better to always leave out */.git/HEAD file for all targets ?
-    - name: Delete .git directories under src to free space
-      if: steps.check-cache.outputs.cache_exists == 'false'
-      run: |
-        cd src
-        ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf
-    - name: Minimize Cache Size for Upload
-      if: steps.check-cache.outputs.cache_exists == 'false'
-      run: |
-        rm -rf src/android_webview
-        rm -rf src/ios/chrome
-        rm -rf src/third_party/blink/web_tests
-        rm -rf src/third_party/blink/perf_tests
-        rm -rf src/chrome/test/data/xr/webvr_info
-        rm -rf src/third_party/angle/third_party/VK-GL-CTS/src
-        rm -rf src/third_party/swift-toolchain
-        rm -rf src/third_party/swiftshader/tests/regres/testlists
-        rm -rf src/electron
-    - name: Compress Src Directory
-      if: steps.check-cache.outputs.cache_exists == 'false'
-      run: |
-        echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')"
-        tar -cvf $DEPSHASH.tar src
-        echo "Compressed src to $(du -sh $DEPSHASH.tar | cut -f1 -d' ')"
-    - name: Upload Compressed Src Cache to Azure
-      if: steps.check-cache.outputs.cache_exists == 'false'
-      run: |
-        az storage blob upload \
-          --account-name $AZURE_STORAGE_ACCOUNT \
-          --account-key $AZURE_STORAGE_KEY \
-          --container-name $AZURE_STORAGE_CONTAINER_NAME \
-          --file $DEPSHASH.tar \
-          --name $DEPSHASH \
-          --debug
-  build:
-    strategy:
-      fail-fast: false
-      matrix:
-        build-arch: [ arm64, x64 ]
-    # macos-large is x64, macos-xlarge is arm64
-    # More runner information: https://github.com/actions/runner-images/blob/main/README.md#available-images
-    runs-on: macos-14-xlarge
-    needs: checkout
-    steps:
-    - name: Load Build Tools
-      run: |
-        export BUILD_TOOLS_SHA=2bb63e2e7877491b52f972532b52adc979a6ec2f
-        npm i -g @electron/build-tools
-        e init --root=$(pwd) --out=Default ${{ inputs.GN_BUILD_TYPE }} --import ${{ inputs.GN_BUILD_TYPE }} --target-cpu ${{ matrix.build-arch}}
-        e use ${{ inputs.GN_BUILD_TYPE }}
-    - name: Checkout Electron
-      uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
-      with:
-        path: src/electron
-        fetch-depth: 0
-    - name: Setup Node.js/npm
-      uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
-      with:
-        node-version: 20.11.x
-        cache: yarn
-        cache-dependency-path: src/electron/yarn.lock
-    - name: Install Dependencies
-      run: |
-        cd src/electron
-        node script/yarn install
-    - name: Load Target Arch & CPU
-      run: |
-        echo "TARGET_ARCH=${{ matrix.build-arch }}" >> $GITHUB_ENV
-        echo "target_cpu=${{ matrix.build-arch }}" >> $GITHUB_ENV
-        echo "host_cpu=${{ matrix.build-arch }}" >> $GITHUB_ENV
-    - name: Get Depot Tools
-      timeout-minutes: 5
-      run: |
-        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
-        if [ "`uname`" == "Darwin" ]; then
-          # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
-          sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
-        else
-          sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
-          # Remove swift-format dep from cipd on macOS until we send a patch upstream.
-          cd depot_tools
-          git apply --3way ../src/electron/.github/workflows/config/gclient.diff
-        fi
-        # Ensure depot_tools does not update.
-        test -d depot_tools && cd depot_tools
-        touch .disable_auto_update
-    - name: Add Depot Tools to PATH
-      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
-    - name: Generate DEPS Hash
-      run: |
-        node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
-        echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
-    - name: Download Src Cache
-      # The cache will always exist here as a result of the checkout job
-      # Either it was uploaded to Azure in the checkout job for this commit
-      # or it was uploaded in the checkout job for a previous commit.
-      uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
-      with:
-        timeout_minutes: 20
-        max_attempts: 3
-        retry_on: error
-        command: |
-          az storage blob download \
-            --account-name $AZURE_STORAGE_ACCOUNT \
-            --account-key $AZURE_STORAGE_KEY \
-            --container-name $AZURE_STORAGE_CONTAINER_NAME \
-            --name $DEPSHASH \
-            --file $DEPSHASH.tar \
-    - name: Unzip and Ensure Src Cache
-      run: |
-        echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)"
-        mkdir temp-cache
-        tar -xvf $DEPSHASH.tar -C temp-cache
-        echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
-
-        if [ -d "temp-cache/src" ]; then
-          echo "Relocating Cache"
-          rm -rf src
-          mv temp-cache/src src
-
-          echo "Deleting zip file"
-          rm -rf $DEPSHASH.tar
-        fi
-
-        if [ ! -d "src/third_party/blink" ]; then
-          echo "Cache was not correctly restored - exiting"
-          exit 1
-        fi
-
-        echo "Wiping Electron Directory"
-        rm -rf src/electron
-    - name: Checkout Electron
-      uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
-      with:
-        path: src/electron
-        fetch-depth: 0
-    - name: Run Electron Only Hooks
-      run: |
-        echo "Running Electron Only Hooks"
-        gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
-    - name: Regenerate DEPS Hash
-      run: |
-        (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
-        echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
-    - name: Add CHROMIUM_BUILDTOOLS_PATH to env
-      run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
-    - name: Fix Sync
-      # This step is required to correct for differences between "gclient sync"
-      # on Linux and the expected state on macOS. This requires:
-      # 1. Fixing Clang Install (wrong binary)
-      # 2. Fixing esbuild (wrong binary)
-      # 3. Fixing rustc (wrong binary)
-      # 4. Fixing gn (wrong binary)
-      # 5. Fix reclient (wrong binary)
-      # 6. Fixing dsymutil (wrong binary)
-      # 7. Ensuring we are using the correct ninja and adding it to PATH
-      # 8. Fixing angle (wrong remote)
-      run : |
-        SEDOPTION="-i ''"
-        rm -rf src/third_party/llvm-build
-        python3 src/tools/clang/scripts/update.py
-
-        echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file
-        # Remove extra output from calling gclient getdep which always calls update_depot_tools
-        sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file
-        cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file
-
-        rm -rf src/third_party/rust-toolchain
-        python3 src/tools/rust/update_rust.py
-        
-        # Prevent calling gclient getdep which always calls update_depot_tools
-        echo 'gn/gn/mac-${arch}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/mac:gn/gn/mac-${arch}'` > gn_ensure_file
-        sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
-        cipd ensure --root src/buildtools/mac -ensure-file gn_ensure_file
-
-        # Prevent calling gclient getdep which always calls update_depot_tools
-        echo 'infra/rbe/client/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/reclient:infra/rbe/client/${platform}'` > gn_ensure_file
-        sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
-        cipd ensure --root src/buildtools/reclient -ensure-file gn_ensure_file
-        python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch
-
-        if  [ "$TARGET_ARCH" == "arm64" ]; then
-          DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1
-        else
-          DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.x64.sha1
-        fi
-        python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil
-
-        echo 'infra/3pp/tools/ninja/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/third_party/ninja:infra/3pp/tools/ninja/${platform}'` > ninja_ensure_file
-        sed $SEDOPTION "s/Updating depot_tools... //g" ninja_ensure_file
-        cipd ensure --root src/third_party/ninja -ensure-file ninja_ensure_file
-
-        echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH
-
-        cd src/third_party/angle
-        rm -f .git/objects/info/alternates
-        git remote set-url origin https://chromium.googlesource.com/angle/angle.git
-        cp .git/config .git/config.backup
-        git remote remove origin
-        mv .git/config.backup .git/config
-        git fetch
-    - name: Install build-tools & Setup RBE
-      run: |
-        echo "NUMBER_OF_NINJA_PROCESSES=200" >> $GITHUB_ENV
-        cd ~/.electron_build_tools
-        npx yarn --ignore-engines
-        # Pull down credential helper and print status
-        node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
-        HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
-        $HELPER login
-        echo 'RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $GITHUB_ENV
-        echo 'RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $GITHUB_ENV
-        echo 'RBE_experimental_credentials_helper_args=print' >> $GITHUB_ENV
-    - name: Free Space on MacOS
-      run: |
-        sudo mkdir -p $TMPDIR/del-target
-
-        tmpify() {
-          if [ -d "$1" ]; then
-            sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1)
-          fi
-        }
-
-        strip_universal_deep() {
-          opwd=$(pwd)
-          cd $1
-          f=$(find . -perm +111 -type f)
-          for fp in $f
-          do
-            if [[ $(file "$fp") == *"universal binary"* ]]; then
-              if [ "`arch`" == "arm64" ]; then
-                if [[ $(file "$fp") == *"x86_64"* ]]; then
-                  sudo lipo -remove x86_64 "$fp" -o "$fp" || true
-                fi
-              else
-                if [[ $(file "$fp") == *"arm64e)"* ]]; then
-                  sudo lipo -remove arm64e "$fp" -o "$fp" || true
-                fi
-                if [[ $(file "$fp") == *"arm64)"* ]]; then
-                  sudo lipo -remove arm64 "$fp" -o "$fp" || true
-                fi
-              fi
-            fi
-          done
-
-          cd $opwd
-        }
-
-        tmpify /Library/Developer/CoreSimulator
-        tmpify ~/Library/Developer/CoreSimulator
-        tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform
-        tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform
-        tmpify $(xcode-select -p)/Platforms/WatchOS.platform
-        tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform
-        tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform
-        tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform
-        tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios
-        tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
-        tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0
-        tmpify ~/.rubies
-        tmpify ~/Library/Caches/Homebrew
-        tmpify /usr/local/Homebrew
-
-        # the contents of build/linux/strip_binary.gni aren't used, but
-        # https://chromium-review.googlesource.com/c/chromium/src/+/4278307
-        # needs the file to exist.
-        # mv ~/project/src/build/linux/strip_binary.gni "${TMPDIR}"/
-        # tmpify ~/project/src/build/linux/
-        # mkdir -p ~/project/src/build/linux
-        # mv "${TMPDIR}/strip_binary.gni" ~/project/src/build/linux/
-
-        sudo rm -rf $TMPDIR/del-target
-
-        # sudo rm -rf "/System/Library/Desktop Pictures"
-        # sudo rm -rf /System/Library/Templates/Data
-        # sudo rm -rf /System/Library/Speech/Voices
-        # sudo rm -rf "/System/Library/Screen Savers"
-        # sudo rm -rf /System/Volumes/Data/Library/Developer/CommandLineTools/SDKs
-        # sudo rm -rf "/System/Volumes/Data/Library/Application Support/Apple/Photos/Print Products"
-        # sudo rm -rf /System/Volumes/Data/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/
-        # sudo rm -rf /System/Volumes/Data/Library/Java
-        # sudo rm -rf /System/Volumes/Data/Library/Ruby
-        # sudo rm -rf /System/Volumes/Data/Library/Printers
-        # sudo rm -rf /System/iOSSupport
-        # sudo rm -rf /System/Applications/*.app
-        # sudo rm -rf /System/Applications/Utilities/*.app
-        # sudo rm -rf /System/Library/LinguisticData
-        # sudo rm -rf /System/Volumes/Data/private/var/db/dyld/*
-        # sudo rm -rf /System/Library/Fonts/*
-        # sudo rm -rf /System/Library/PreferencePanes
-        # sudo rm -rf /System/Library/AssetsV2/*
-        sudo rm -rf /Applications/Safari.app
-        sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data
-        sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS
-
-        # lipo off some huge binaries arm64 versions to save space
-        strip_universal_deep $(xcode-select -p)/../SharedFrameworks
-        # strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr
-    - name: Build Electron (darwin)
-      run: |
-        cd src/electron
-        # TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
-        git pack-refs
-        cd ..
-        ulimit -n 10000
-        sudo launchctl limit maxfiles 65536 200000
-
-        NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
-        cp out/Default/.ninja_log out/electron_ninja_log
-        node electron/script/check-symlinks.js
-    - name: Build Electron dist.zip (darwin)
-      run: |
-        cd src
-        e build electron:electron_dist_zip -j $NUMBER_OF_NINJA_PROCESSES
-        if [ "$CHECK_DIST_MANIFEST" == "1" ]; then
-          target_os=mac
-          electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ env.TARGET_ARCH }}.manifest
-        fi
-    - name: Build Mksnapshot (darwin)
-      run: |
-        cd src
-        e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
-        gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
-        # Remove unused args from mksnapshot_args
-        SEDOPTION="-i ''"
-        sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
-        sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
-        sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
-        e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
-        (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
-    - name: Build Chromedriver (darwin)
-      run: |
-        cd src
-        e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
-        e build electron:electron_chromedriver_zip
-    # NOTE (vertedinde): We strip binaries/symbols on the Linux job, not the Mac job
-    - name: Generate & Zip Symbols (darwin)
-      run: |
-        # Generate breakpad symbols on release builds
-        if [ ${{ inputs.GENERATE_SYMBOLS }} == "true" ]; then
-          e build electron:electron_symbols
-        fi
-        cd src
-        export BUILD_PATH="$(pwd)/out/Default"
-        e build electron:licenses
-        e build electron:electron_version_file
-        if [ ${{ inputs.IS_RELEASE }} == "true" ]; then
-          DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
-        else
-          electron/script/zip-symbols.py -b $BUILD_PATH
-        fi
-    - name: Generate FFMpeg
-      if: ${{ inputs.IS_RELEASE == true }}
-      run: |
-        cd src
-        gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true $GN_EXTRA_ARGS"
-        autoninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES
-    - name: Generate Hunspell Dictionaries
-      if: ${{ inputs.IS_RELEASE == true }}
-      run: |
-        cd src
-        autoninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES
-    - name: Generate TypeScript Definitions
-      if: ${{ inputs.IS_RELEASE == true }}
-      run: |
-        cd src/electron
-        node script/yarn create-typescript-definitions
-    # TODO(vertedinde): These uploads currently point to a different Azure bucket & GitHub Repo
-    - name: Publish Electron Dist
-      run: |
-        rm -rf src/out/Default/obj
-        cd src/electron
-        if [ ${{ inputs.UPLOAD_TO_STORAGE }} == "1" ]; then
-          echo 'Uploading Electron release distribution to Azure'
-          script/release/uploaders/upload.py --verbose --upload_to_storage
-        else
-          echo 'Uploading Electron release distribution to GitHub releases'
-          script/release/uploaders/upload.py --verbose
-        fi
-    # The current generated_artifacts_<< artifact.key >> name was taken from CircleCI
-    # to ensure we don't break anything, but we may be able to improve that.
-    - name: Move all Generated Artifacts to Upload Folder
-      run: ./src/electron/script/actions/move-artifacts.sh
-    - name: Upload Generated Artifacts
-      uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
-      with:
-        name: generated_artifacts_darwin_${{ env.TARGET_ARCH }}
-        path: ./generated_artifacts_darwin_${{ env.TARGET_ARCH }}
-    - name: Persist Build Artifacts
-      uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
-      with:
-        path: |
-          src/out/Default/gen/node_headers
-          src/out/Default/overlapped-checker
-          src/electron
-          src/third_party/electron_node
-          src/third_party/nan
-          src/cross-arch-snapshots
-          src/third_party/llvm-build
-          src/build/linux
-          src/buildtools/mac
-          src/buildtools/third_party/libc++
-          src/buildtools/third_party/libc++abi
-          src/third_party/libc++
-          src/third_party/libc++abi
-          src/out/Default/obj/buildtools/third_party
-          src/v8/tools/builtins-pgo
-        key: ${{ runner.os }}-build-artifacts-darwin-${{ env.TARGET_ARCH }}-${{ github.sha }}
-    - name: Create MAS Config
-      run: |
-        mv src/electron/.github/workflows/config/${{ inputs.GN_BUILD_TYPE }}/${{ matrix.build-arch }}/evm.mas.json $HOME/.electron_build_tools/configs/evm.mas.json
-        echo "MAS_BUILD=true" >> $GITHUB_ENV
-        e use mas
-    - name: Build Electron (mas)
-      run: |
-        rm -rf "src/out/Default/Electron Framework.framework"
-        rm -rf src/out/Default/Electron*.app
-
-        cd src/electron
-        # TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
-        git pack-refs
-        cd ..
-
-        ulimit -n 10000
-        sudo launchctl limit maxfiles 65536 200000
-        NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
-        cp out/Default/.ninja_log out/electron_ninja_log
-        node electron/script/check-symlinks.js
-    - name: Build Electron dist.zip (mas)
-      run: |
-        cd src
-        e build electron:electron_dist_zip -j $NUMBER_OF_NINJA_PROCESSES
-        if [ "$CHECK_DIST_MANIFEST" == "1" ]; then
-          target_os=mac_mas
-          electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ env.TARGET_ARCH }}.manifest
-        fi
-    - name: Build Mksnapshot (mas)
-      run: |
-        cd src
-        e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
-        gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
-        # Remove unused args from mksnapshot_args
-        SEDOPTION="-i ''"
-        sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
-        sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
-        sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
-        e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
-        (cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
-    - name: Build Chromedriver (mas)
-      run: |
-        cd src
-        e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
-        e build electron:electron_chromedriver_zip
-    - name: Build Node Headers
-      run: |
-        cd src
-        e build electron:node_headers
-    - name: Generate & Zip Symbols (mas)
-      run: |
-        if [ ${{ inputs.GENERATE_SYMBOLS }}  == "true" ]; then
-          e build electron:electron_symbols
-        fi
-        cd src
-        export BUILD_PATH="$(pwd)/out/Default"
-        e build electron:licenses
-        e build electron:electron_version_file
-        if [ ${{ inputs.IS_RELEASE }} == "true" ]; then
-          DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
-        else
-          electron/script/zip-symbols.py -b $BUILD_PATH
-        fi
-    # TODO(vertedinde): These uploads currently point to a different Azure bucket & GitHub Repo
-    - name: Publish Electron Dist
-      run: |
-        rm -rf src/out/Default/obj
-        cd src/electron
-        if [ ${{ inputs.UPLOAD_TO_STORAGE }} == "1" ]; then
-          echo 'Uploading Electron release distribution to Azure'
-          script/release/uploaders/upload.py --verbose --upload_to_storage
-        else
-          echo 'Uploading Electron release distribution to GitHub releases'
-          script/release/uploaders/upload.py --verbose
-        fi
-    - name: Move all Generated Artifacts to Upload Folder (mas)
-      run: ./src/electron/script/actions/move-artifacts.sh
-    - name: Upload Generated Artifacts
-      uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
-      with:
-        name: generated_artifacts_mas_${{ env.TARGET_ARCH }}
-        path: ./generated_artifacts_mas_${{ env.TARGET_ARCH }}
-    - name: Persist Build Artifacts
-      uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
-      with:
-        path: |
-          src/out/Default/gen/node_headers
-          src/out/Default/overlapped-checker
-          src/out/Default/ffmpeg
-          src/out/Default/hunspell_dictionaries
-          src/electron
-          src/third_party/electron_node
-          src/third_party/nan
-          src/cross-arch-snapshots
-          src/third_party/llvm-build
-          src/build/linux
-          src/buildtools/mac
-          src/buildtools/third_party/libc++
-          src/buildtools/third_party/libc++abi
-          src/third_party/libc++
-          src/third_party/libc++abi
-          src/out/Default/obj/buildtools/third_party
-          src/v8/tools/builtins-pgo
-        key: ${{ runner.os }}-build-artifacts-mas-${{ env.TARGET_ARCH }}-${{ github.sha }}
-  test:
-    if: ${{ inputs.IS_RELEASE == false }}
-    runs-on: macos-14-xlarge
-    needs: build
-    strategy:
-      fail-fast: false
-      matrix:
-        build-type: [ darwin, mas ]
-    env:
-      BUILD_TYPE: ${{ matrix.build-type }}
-    steps:
-    - name: Load Build Tools
-      run: |
-        export BUILD_TOOLS_SHA=2bb63e2e7877491b52f972532b52adc979a6ec2f
-        npm i -g @electron/build-tools
-        e init --root=$(pwd) --out=Default ${{ inputs.GN_BUILD_TYPE }}
-    - name: Checkout Electron
-      uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
-      with:
-        path: src/electron
-        fetch-depth: 0
-    - name: Setup Node.js/npm
-      uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
-      with:
-        node-version: 20.11.x
-        cache: yarn
-        cache-dependency-path: src/electron/yarn.lock
-    - name: Install Dependencies
-      run: |
-        cd src/electron
-        node script/yarn install
-    - name: Get Depot Tools
-      timeout-minutes: 5
-      run: |
-        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
-        if [ "`uname`" == "Darwin" ]; then
-          # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
-          sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
-        else
-          sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
-          # Remove swift-format dep from cipd on macOS until we send a patch upstream.
-          cd depot_tools
-          git apply --3way ../src/electron/.github/workflows/config/gclient.diff
-        fi
-        # Ensure depot_tools does not update.
-        test -d depot_tools && cd depot_tools
-        touch .disable_auto_update
-    - name: Add Depot Tools to PATH
-      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
-    - name: Download Generated Artifacts
-      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
-      with:
-        name: generated_artifacts_${{ matrix.build-type }}
-        path: ./generated_artifacts_${{ matrix.build-type }}
-    - name: Restore Persisted Build Artifacts
-      uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
-      with:
-        path: |
-          src/out/Default/gen/node_headers
-          src/out/Default/overlapped-checker
-          src/electron
-          src/third_party/electron_node
-          src/third_party/nan
-          src/cross-arch-snapshots
-          src/third_party/llvm-build
-          src/build/linux
-          src/buildtools/mac
-          src/buildtools/third_party/libc++
-          src/buildtools/third_party/libc++abi
-          src/third_party/libc++
-          src/third_party/libc++abi
-          src/out/Default/obj/buildtools/third_party
-          src/v8/tools/builtins-pgo
-        key: ${{ runner.os }}-build-artifacts-${{ matrix.build-type }}-${{ github.sha }}
-    - name: Restore Generated Artifacts
-      run: ./src/electron/script/actions/restore-artifacts.sh
-    - name: Unzip Dist, Mksnapshot & Chromedriver
-      run: |
-        cd src/out/Default
-        unzip -:o dist.zip
-        unzip -:o chromedriver.zip
-        unzip -:o mksnapshot.zip
-    - name: Import & Trust Self-Signed Codesigning Cert on MacOS
-      run: |
-        sudo security authorizationdb write com.apple.trust-settings.admin allow
-        cd src/electron
-        ./script/codesign/generate-identity.sh
-    - name: Run Electron Tests
-      env:
-        MOCHA_REPORTER: mocha-multi-reporters
-        ELECTRON_TEST_RESULTS_DIR: junit
-        MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
-        ELECTRON_DISABLE_SECURITY_WARNINGS: 1
-        ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
-      run: |
-        cd src/electron
-        node script/yarn test --runners=main --trace-uncaught --enable-logging

+ 52 - 9
.github/workflows/macos-publish.yml

@@ -3,9 +3,14 @@ name: Publish MacOS
 on:
   workflow_dispatch:
     inputs:
+      build-image-sha:
+        type: string
+        description: 'SHA for electron/build image'
+        default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
+        required: true
       upload-to-storage:
         description: 'Uploads to Azure storage'
-        required: false 
+        required: false
         default: '1'
         type: string
       run-macos-publish:
@@ -14,13 +19,51 @@ on:
         default: false
 
 jobs:
-  publish:
-  # TODO(vertedinde): Change this to main before merge
-    uses: electron/electron/.github/workflows/macos-build.yml@gh-actions-mac-publish
+  checkout-macos:
+    runs-on: aks-linux-large
+    container:
+      image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
+      options: --user root
+      volumes:
+        - /mnt/cross-instance-cache:/mnt/cross-instance-cache
+        - /var/run/sas:/var/run/sas
+    env:
+      GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Checkout & Sync & Save
+      uses: ./src/electron/.github/actions/checkout
+      with:
+        generate-sas-token: 'true'
+
+  publish-x64:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    needs: checkout-macos
+    with:
+      environment: production-release
+      build-runs-on: macos-14-xlarge
+      target-platform: macos
+      target-arch: x64
+      is-release: true
+      gn-build-type: release
+      generate-symbols: true
+      upload-to-storage: ${{ inputs.upload-to-storage }}
+    secrets: inherit
+
+  publish-arm64:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    needs: checkout-macos
     with:
-      IS_RELEASE: true
-      GN_CONFIG: //electron/build/args/release.gn
-      GN_BUILD_TYPE: release
-      GENERATE_SYMBOLS: true
-      UPLOAD_TO_STORAGE: ${{ inputs.upload-to-storage }}
+      environment: production-release
+      build-runs-on: macos-14-xlarge
+      target-platform: macos
+      target-arch: arm64
+      is-release: true
+      gn-build-type: release
+      generate-symbols: true
+      upload-to-storage: ${{ inputs.upload-to-storage }}
     secrets: inherit

+ 97 - 0
.github/workflows/pipeline-electron-build-and-test-and-nan.yml

@@ -0,0 +1,97 @@
+name: Electron Build & Test (+ Node + NaN) Pipeline
+
+on:
+  workflow_call:
+    inputs:
+      target-platform:
+        type: string
+        description: 'Platform to run on, can be macos or linux'
+        required: true
+      target-arch:
+        type: string
+        description: 'Arch to build for, can be x64, arm64 or arm'
+        required: true
+      build-runs-on:
+        type: string
+        description: 'What host to run the build'
+        required: true
+      test-runs-on:
+        type: string
+        description: 'What host to run the tests on'
+        required: true
+      build-container:
+        type: string
+        description: 'JSON container information for aks runs-on'
+        required: false
+        default: '{"image":null}'
+      test-container:
+        type: string
+        description: 'JSON container information for testing'
+        required: false
+        default: '{"image":null}'
+      is-release:
+        description: 'Whether this build job is a release job'
+        required: true
+        type: boolean
+        default: false
+      gn-build-type:
+        description: 'The gn build type - testing or release'
+        required: true
+        type: string
+        default: testing
+      generate-symbols: 
+        description: 'Whether or not to generate symbols'
+        required: true
+        type: boolean
+        default: false
+      upload-to-storage: 
+        description: 'Whether or not to upload build artifacts to external storage'
+        required: true
+        type: string
+        default: '0'
+
+concurrency:
+  group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
+
+jobs:
+  build:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    with:
+      build-runs-on: ${{ inputs.build-runs-on }}
+      build-container: ${{ inputs.build-container }}
+      target-platform: ${{ inputs.target-platform }}
+      target-arch: ${{ inputs.target-arch }}
+      is-release: ${{ inputs.is-release }}
+      gn-build-type: ${{ inputs.gn-build-type }}
+      generate-symbols: ${{ inputs.generate-symbols }}
+      upload-to-storage: ${{ inputs.upload-to-storage }}
+    secrets: inherit
+  gn-check:
+    uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
+    with:
+      target-platform: ${{ inputs.target-platform }}
+      target-arch: ${{ inputs.target-arch }}
+      check-runs-on: ${{ inputs.build-runs-on }}
+      check-container: ${{ inputs.build-container }}
+      gn-build-type: ${{ inputs.gn-build-type }}
+    secrets: inherit
+  test:
+    uses: ./.github/workflows/pipeline-segment-electron-test.yml
+    needs: build
+    with:
+      target-arch: ${{ inputs.target-arch }}
+      target-platform: ${{ inputs.target-platform }}
+      test-runs-on: ${{ inputs.test-runs-on }}
+      test-container: ${{ inputs.test-container }}
+    secrets: inherit
+  nn-test:
+    uses: ./.github/workflows/pipeline-segment-node-nan-test.yml
+    needs: build
+    with:
+      target-arch: ${{ inputs.target-arch }}
+      target-platform: ${{ inputs.target-platform }}
+      test-runs-on: ${{ inputs.test-runs-on }}
+      test-container: ${{ inputs.test-container }}
+      gn-build-type: ${{ inputs.gn-build-type }}
+    secrets: inherit

+ 92 - 0
.github/workflows/pipeline-electron-build-and-test.yml

@@ -0,0 +1,92 @@
+name: Electron Build & Test Pipeline
+
+on:
+  workflow_call:
+    inputs:
+      target-platform:
+        type: string
+        description: 'Platform to run on, can be macos or linux'
+        required: true
+      target-arch:
+        type: string
+        description: 'Arch to build for, can be x64, arm64 or arm'
+        required: true
+      build-runs-on:
+        type: string
+        description: 'What host to run the build'
+        required: true
+      test-runs-on:
+        type: string
+        description: 'What host to run the tests on'
+        required: true
+      build-container:
+        type: string
+        description: 'JSON container information for aks runs-on'
+        required: false
+        default: '{"image":null}'
+      test-container:
+        type: string
+        description: 'JSON container information for testing'
+        required: false
+        default: '{"image":null}'
+      is-release:
+        description: 'Whether this build job is a release job'
+        required: true
+        type: boolean
+        default: false
+      gn-build-type:
+        description: 'The gn build type - testing or release'
+        required: true
+        type: string
+        default: testing
+      generate-symbols: 
+        description: 'Whether or not to generate symbols'
+        required: true
+        type: boolean
+        default: false
+      upload-to-storage: 
+        description: 'Whether or not to upload build artifacts to external storage'
+        required: true
+        type: string
+        default: '0'
+
+concurrency:
+  group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
+
+permissions:
+  contents: read
+  issues: read
+  pull-requests: read  
+
+jobs:
+  build:
+    uses: ./.github/workflows/pipeline-segment-electron-build.yml
+    with:
+      build-runs-on: ${{ inputs.build-runs-on }}
+      build-container: ${{ inputs.build-container }}
+      target-platform: ${{ inputs.target-platform }}
+      target-arch: ${{ inputs.target-arch }}
+      is-release: ${{ inputs.is-release }}
+      gn-build-type: ${{ inputs.gn-build-type }}
+      generate-symbols: ${{ inputs.generate-symbols }}
+      upload-to-storage: ${{ inputs.upload-to-storage }}
+    secrets: inherit
+  gn-check:
+    uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
+    with:
+      target-platform: ${{ inputs.target-platform }}
+      target-arch: ${{ inputs.target-arch }}
+      check-runs-on: ${{ inputs.build-runs-on }}
+      check-container: ${{ inputs.build-container }}
+      gn-build-type: ${{ inputs.gn-build-type }}
+    secrets: inherit
+  test:
+    uses: ./.github/workflows/pipeline-segment-electron-test.yml
+    needs: build
+    with:
+      target-arch: ${{ inputs.target-arch }}
+      target-platform: ${{ inputs.target-platform }}
+      test-runs-on: ${{ inputs.test-runs-on }}
+      test-container: ${{ inputs.test-container }}
+    secrets: inherit

+ 43 - 0
.github/workflows/pipeline-electron-docs-only.yml

@@ -0,0 +1,43 @@
+name: Electron Docs Compile
+
+on:
+  workflow_call:
+    inputs:
+      container:
+        required: true
+        description: 'Container to run the docs-only ts compile in'
+        type: string
+
+concurrency:
+  group: electron-docs-only-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  docs-only:
+    name: Docs Only Compile
+    runs-on: aks-linux-medium
+    timeout-minutes: 20
+    container: ${{ fromJSON(inputs.container) }}
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Dependencies
+      run: |
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+    - name: Run TS/JS compile
+      shell: bash
+      run: |
+        cd src/electron
+        node script/yarn create-typescript-definitions
+        node script/yarn tsc -p tsconfig.default_app.json --noEmit
+        for f in build/webpack/*.js
+        do
+            out="${f:29}"
+            if [ "$out" != "base.js" ]; then
+            node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development
+            fi
+        done

+ 77 - 0
.github/workflows/pipeline-electron-lint.yml

@@ -0,0 +1,77 @@
+name: Electron Lint
+
+on:
+  workflow_call:
+    inputs:
+      container:
+        required: true
+        description: 'Container to run lint in'
+        type: string
+
+concurrency:
+  group: electron-lint-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
+
+jobs:
+  lint:
+    name: Lint
+    runs-on: aks-linux-medium
+    timeout-minutes: 20
+    container: ${{ fromJSON(inputs.container) }}
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Dependencies
+      run: |
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+    - name: Setup third_party Depot Tools
+      shell: bash
+      run: |
+        # "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
+        git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
+        echo "$(pwd)/src/third_party/depot_tools" >> $GITHUB_PATH
+    - name: Download GN Binary
+      shell: bash
+      run: |
+        chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
+        gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
+
+        cipd ensure -ensure-file - -root . <<-CIPD
+        \$ServiceURL https://chrome-infra-packages.appspot.com/
+        @Subdir src/buildtools/linux64
+        gn/gn/linux-amd64 $gn_version
+        CIPD
+
+        buildtools_path="$(pwd)/src/buildtools"
+        echo "CHROMIUM_BUILDTOOLS_PATH=$buildtools_path" >> $GITHUB_ENV
+    - name: Download clang-format Binary
+      shell: bash
+      run: |
+        chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
+
+        mkdir -p src/buildtools
+        curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/buildtools/DEPS?format=TEXT" | base64 -d > src/buildtools/DEPS
+
+        gclient runhooks --spec="solutions=[{'name':'src/buildtools','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':True},'managed':False}]"
+    - name: Run Lint
+      shell: bash
+      run: |
+        # gn.py tries to find a gclient root folder starting from the current dir.
+        # When it fails and returns "None" path, the whole script fails. Let's "fix" it.
+        touch .gclient
+        # Another option would be to checkout "buildtools" inside the Electron checkout,
+        # but then we would lint its contents (at least gn format), and it doesn't pass it.
+
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+        node script/yarn lint
+    - name: Run Script Typechecker
+      shell: bash
+      run: |
+        cd src/electron
+        node script/yarn tsc -p tsconfig.script.json
+    

+ 202 - 0
.github/workflows/pipeline-segment-electron-build.yml

@@ -0,0 +1,202 @@
+name: Pipeline Segment - Electron Build
+
+on:
+  workflow_call:
+    inputs:
+      environment:
+        description: using the production or testing environment
+        required: false
+        type: string
+      target-platform:
+        type: string
+        description: 'Platform to run on, can be macos or linux'
+        required: true
+      target-arch:
+        type: string
+        description: 'Arch to build for, can be x64, arm64 or arm'
+        required: true
+      build-runs-on:
+        type: string
+        description: 'What host to run the build'
+        required: true
+      build-container:
+        type: string
+        description: 'JSON container information for aks runs-on'
+        required: false
+        default: '{"image":null}'
+      is-release:
+        description: 'Whether this build job is a release job'
+        required: true
+        type: boolean
+        default: false
+      gn-build-type:
+        description: 'The gn build type - testing or release'
+        required: true
+        type: string
+        default: testing
+      generate-symbols: 
+        description: 'Whether or not to generate symbols'
+        required: true
+        type: boolean
+        default: false
+      upload-to-storage: 
+        description: 'Whether or not to upload build artifacts to external storage'
+        required: true
+        type: string
+        default: '0'
+
+
+concurrency:
+  group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
+
+env:
+  AZURE_AKS_CACHE_STORAGE_ACCOUNT: ${{ secrets.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}
+  AZURE_AKS_CACHE_SHARE_NAME: ${{ secrets.AZURE_AKS_CACHE_SHARE_NAME }}
+  ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
+  ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
+  ELECTRON_GITHUB_TOKEN: ${{ secrets.ELECTRON_GITHUB_TOKEN }}
+  GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
+  # Only disable this in the Asan build
+  CHECK_DIST_MANIFEST: true
+  IS_GHA_RELEASE: true
+  ELECTRON_OUT_DIR: Default
+
+jobs:
+  build:
+    runs-on: ${{ inputs.build-runs-on }}
+    container: ${{ fromJSON(inputs.build-container) }}
+    environment: ${{ inputs.environment }}
+    env:
+      TARGET_ARCH: ${{ inputs.target-arch }}
+    steps:
+    - name: Create src dir
+      run: mkdir src
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Setup Node.js/npm
+      if: ${{ inputs.target-platform == 'macos' }}
+      uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
+      with:
+        node-version: 20.11.x
+        cache: yarn
+        cache-dependency-path: src/electron/yarn.lock
+    - name: Install Dependencies
+      run: |
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+    - name: Install AZCopy
+      if: ${{ inputs.target-platform == 'macos' }}
+      run: brew install azcopy
+    - name: Set GN_EXTRA_ARGS for Linux
+      if: ${{ inputs.target-platform == 'linux' }}
+      run: |
+        if [ "${{ inputs.target-arch  }}" = "arm" ]; then
+          if [ "${{ inputs.is-release  }}" = true ]; then
+            GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false symbol_level=1'
+          else
+            GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false'
+          fi
+        elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
+          GN_EXTRA_ARGS='target_cpu="arm64" fatal_linker_warnings=false enable_linux_installer=false'
+        fi
+        echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
+    - name: Get Depot Tools
+      timeout-minutes: 5
+      run: |
+        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
+
+        SEDOPTION="-i"
+        if [ "`uname`" = "Darwin" ]; then
+          SEDOPTION="-i ''"
+        fi
+
+        # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
+        sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+
+        # Ensure depot_tools does not update.
+        test -d depot_tools && cd depot_tools
+        if [ "`uname`" = "Linux" ]; then
+          git apply --3way ../src/electron/.github/workflows/config/gclient.diff
+        fi
+        touch .disable_auto_update
+    - name: Add Depot Tools to PATH
+      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
+    - name: Generate DEPS Hash
+      run: |
+        node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
+        DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
+        echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
+        echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
+    - name: Restore src cache via AZCopy
+      if: ${{ inputs.target-platform == 'macos' }}
+      uses: ./src/electron/.github/actions/restore-cache-azcopy
+    - name: Restore src cache via AKS
+      if: ${{ inputs.target-platform == 'linux' }}
+      uses: ./src/electron/.github/actions/restore-cache-aks
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Build Tools
+      uses: ./src/electron/.github/actions/install-build-tools
+    - name: Init Build Tools
+      run: |
+        e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk
+    - name: Run Electron Only Hooks
+      run: |
+        gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
+    - name: Regenerate DEPS Hash
+      run: |
+        (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
+        echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
+    - name: Add CHROMIUM_BUILDTOOLS_PATH to env
+      run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
+    - name: Fix Sync (macOS)
+      if: ${{ inputs.target-platform == 'macos' }}
+      uses: ./src/electron/.github/actions/fix-sync-macos
+    - name: Install build-tools & Setup RBE
+      run: |
+        echo "NUMBER_OF_NINJA_PROCESSES=${{ inputs.target-platform == 'linux' && '300' || '200' }}" >> $GITHUB_ENV
+        cd ~/.electron_build_tools
+        npx yarn --ignore-engines
+        # Pull down credential helper and print status
+        node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
+        HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
+        $HELPER login
+        echo 'RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $GITHUB_ENV
+        echo 'RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $GITHUB_ENV
+        echo 'RBE_experimental_credentials_helper_args=print' >> $GITHUB_ENV
+    - name: Free up space (macOS)
+      if: ${{ inputs.target-platform == 'macos' }}
+      uses: ./src/electron/.github/actions/free-space-macos
+    - name: Build Electron
+      uses: ./src/electron/.github/actions/build-electron
+      with:
+        target-arch: ${{ inputs.target-arch }}
+        target-platform: ${{ inputs.target-platform }}
+        artifact-platform: ${{ inputs.target-platform == 'linux' && 'linux' || 'darwin' }}
+        is-release: '${{ inputs.is-release }}'
+        generate-symbols: '${{ inputs.generate-symbols }}'
+        upload-to-storage: '${{ inputs.upload-to-storage }}'
+    - name: Set GN_EXTRA_ARGS for MAS Build
+      if: ${{ inputs.target-platform == 'macos' }}
+      run: |
+        echo "MAS_BUILD=true" >> $GITHUB_ENV
+        GN_EXTRA_ARGS='is_mas_build=true'
+        echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
+    - name: Build Electron (MAS)
+      if: ${{ inputs.target-platform == 'macos' }}
+      uses: ./src/electron/.github/actions/build-electron
+      with:
+        target-arch: ${{ inputs.target-arch }}
+        target-platform: ${{ inputs.target-platform }}
+        artifact-platform: 'mas'
+        is-release: '${{ inputs.is-release }}'
+        generate-symbols: '${{ inputs.generate-symbols }}'
+        upload-to-storage: '${{ inputs.upload-to-storage }}'
+        step-suffix: '(mas)'

+ 138 - 0
.github/workflows/pipeline-segment-electron-gn-check.yml

@@ -0,0 +1,138 @@
+name: Pipeline Segment - Electron GN Check
+
+on:
+  workflow_call:
+    inputs:
+      target-platform:
+        type: string
+        description: 'Platform to run on, can be macos or linux'
+        required: true
+      target-arch:
+        type: string
+        description: 'Arch to build for, can be x64, arm64 or arm'
+        required: true
+      check-runs-on:
+        type: string
+        description: 'What host to run the tests on'
+        required: true
+      check-container:
+        type: string
+        description: 'JSON container information for aks runs-on'
+        required: false
+        default: '{"image":null}'
+      gn-build-type:
+        description: 'The gn build type - testing or release'
+        required: true
+        type: string
+        default: testing
+
+concurrency:
+  group: electron-gn-check-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
+  cancel-in-progress: true
+
+env:
+  AZURE_AKS_CACHE_STORAGE_ACCOUNT: ${{ secrets.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}
+  AZURE_AKS_CACHE_SHARE_NAME: ${{ secrets.AZURE_AKS_CACHE_SHARE_NAME }}
+  ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
+  GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
+  ELECTRON_OUT_DIR: Default
+  TARGET_ARCH: ${{ inputs.target-arch }}
+
+jobs:
+  gn-check:
+    # TODO(codebytere): Change this to medium VM
+    runs-on: ${{ inputs.check-runs-on }}
+    container: ${{ fromJSON(inputs.check-container) }}
+    env:
+      TARGET_ARCH: ${{ inputs.target-arch }}
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Build Tools
+      uses: ./src/electron/.github/actions/install-build-tools
+    - name: Init Build Tools
+      run: |
+        e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk
+    - name: Get Depot Tools
+      timeout-minutes: 5
+      run: |
+        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
+
+        SEDOPTION="-i"
+        if [ "`uname`" = "Darwin" ]; then
+          SEDOPTION="-i ''"
+        fi
+
+        # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
+        sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+
+        # Ensure depot_tools does not update.
+        test -d depot_tools && cd depot_tools
+        if [ "`uname`" = "Linux" ]; then
+          git apply --3way ../src/electron/.github/workflows/config/gclient.diff
+        fi
+        touch .disable_auto_update
+    - name: Add Depot Tools to PATH
+      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
+    - name: Set GN_EXTRA_ARGS for Linux
+      if: ${{ inputs.target-platform == 'linux' }}
+      run: |
+        if [ "${{ inputs.target-arch  }}" = "arm" ]; then
+          GN_EXTRA_ARGS='build_tflite_with_xnnpack=false'
+        elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
+          GN_EXTRA_ARGS='fatal_linker_warnings=false enable_linux_installer=false'
+        fi
+        echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
+    - name: Generate DEPS Hash
+      run: |
+        node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
+        DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
+        echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
+        echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
+    - name: Restore src cache via AZCopy
+      if: ${{ inputs.target-platform == 'macos' }}
+      uses: ./src/electron/.github/actions/restore-cache-azcopy
+    - name: Restore src cache via AKS
+      if: ${{ inputs.target-platform == 'linux' }}
+      uses: ./src/electron/.github/actions/restore-cache-aks
+    - name: Run Electron Only Hooks
+      run: |
+        gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
+    - name: Regenerate DEPS Hash
+      run: |
+        (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
+        echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
+    - name: Add CHROMIUM_BUILDTOOLS_PATH to env
+      run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Default GN gen
+      run: |
+        cd src/electron
+        git pack-refs
+        cd ..
+
+        e build --only-gen
+    - name: Run GN Check
+      run: |
+        cd src
+        gn check out/Default //electron:electron_lib
+        gn check out/Default //electron:electron_app
+        gn check out/Default //electron/shell/common/api:mojo
+
+        # Check the hunspell filenames
+        node electron/script/gen-hunspell-filenames.js --check
+        node electron/script/gen-libc++-filenames.js --check
+    - name: Wait for active SSH sessions
+      if: always() && !cancelled()
+      run: |
+        while [ -f /var/.ssh-lock ]
+        do
+          sleep 60
+        done

+ 170 - 0
.github/workflows/pipeline-segment-electron-test.yml

@@ -0,0 +1,170 @@
+name: Pipeline Segment - Electron Test
+
+on:
+  workflow_call:
+    inputs:
+      target-platform:
+        type: string
+        description: 'Platform to run on, can be macos or linux'
+        required: true
+      target-arch:
+        type: string
+        description: 'Arch to build for, can be x64, arm64 or arm'
+        required: true
+      test-runs-on:
+        type: string
+        description: 'What host to run the tests on'
+        required: true
+      test-container:
+        type: string
+        description: 'JSON container information for aks runs-on'
+        required: false
+        default: '{"image":null}'
+
+concurrency:
+  group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
+
+permissions:
+  contents: read
+  issues: read
+  pull-requests: read
+
+env:
+  ELECTRON_OUT_DIR: Default
+  ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
+  ELECTRON_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+jobs:
+  test:
+    runs-on: ${{ inputs.test-runs-on }}
+    container: ${{ fromJSON(inputs.test-container) }}
+    strategy:
+      fail-fast: false
+      matrix:
+        build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || fromJSON('["linux"]') }}
+        shard: ${{ inputs.target-platform == 'macos' && fromJSON('[1, 2]') || fromJSON('[1, 2, 3]') }}
+    env:
+      BUILD_TYPE: ${{ matrix.build-type }}
+      TARGET_ARCH: ${{ inputs.target-arch }}
+    steps:
+    - name: Fix node20 on arm32 runners
+      if: ${{ inputs.target-arch == 'arm' }}
+      run: |
+        cp $(which node) /mnt/runner-externals/node20/bin/
+    - name: Add TCC permissions on macOS
+      if: ${{ inputs.target-platform == 'macos' }}
+      run: |
+        configure_user_tccdb () {
+          local values=$1
+          local dbPath="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
+          local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);"
+          sqlite3 "$dbPath" "$sqlQuery"
+        }
+
+        configure_sys_tccdb () {
+          local values=$1
+          local dbPath="/Library/Application Support/com.apple.TCC/TCC.db"
+          local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);"
+          sudo sqlite3 "$dbPath" "$sqlQuery"
+        }
+
+        userValuesArray=(
+            "'kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
+            "'kTCCServiceCamera','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
+            "'kTCCServiceBluetoothAlways','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
+        )
+        for values in "${userValuesArray[@]}"; do
+          # Sonoma and higher have a few extra values
+          # Ref: https://github.com/actions/runner-images/blob/main/images/macos/scripts/build/configure-tccdb-macos.sh
+          if [ "$OSTYPE" = "darwin23" ]; then
+            configure_user_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}"
+            configure_sys_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}"
+          else
+            configure_user_tccdb "$values"
+            configure_sys_tccdb "$values"
+          fi
+        done
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Dependencies
+      run: |
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+    - name: Get Depot Tools
+      timeout-minutes: 5
+      run: |
+        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
+        if [ "`uname`" = "Darwin" ]; then
+          # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
+          sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+        else
+          sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+          # Remove swift-format dep from cipd on macOS until we send a patch upstream.
+          cd depot_tools
+          git apply --3way ../src/electron/.github/workflows/config/gclient.diff
+        fi
+        # Ensure depot_tools does not update.
+        test -d depot_tools && cd depot_tools
+        touch .disable_auto_update
+    - name: Add Depot Tools to PATH
+      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
+    - name: Download Generated Artifacts
+      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
+      with:
+        name: generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
+        path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
+    - name: Download Src Artifacts
+      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
+      with:
+        name: src_artifacts_${{ matrix.build-type }}_${{ env.TARGET_ARCH }}
+        path: ./src_artifacts_${{ matrix.build-type }}_${{ env.TARGET_ARCH }}
+    - name: Restore Generated Artifacts
+      run: ./src/electron/script/actions/restore-artifacts.sh
+    - name: Unzip Dist, Mksnapshot & Chromedriver
+      run: |
+        cd src/out/Default
+        unzip -:o dist.zip
+        unzip -:o chromedriver.zip
+        unzip -:o mksnapshot.zip
+    # - name: Import & Trust Self-Signed Codesigning Cert on MacOS
+    #   if: ${{ inputs.target-platform == 'macos' }}
+    #   run: |
+    #     sudo security authorizationdb write com.apple.trust-settings.admin allow
+    #     cd src/electron
+    #     ./script/codesign/generate-identity.sh
+    - name: Run Electron Tests
+      shell: bash
+      env:
+        MOCHA_REPORTER: mocha-multi-reporters
+        ELECTRON_TEST_RESULTS_DIR: junit
+        MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
+        ELECTRON_DISABLE_SECURITY_WARNINGS: 1
+        ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
+        DISPLAY: ':99.0'
+      run: |
+        cd src/electron
+        # Get which tests are on this shard
+        tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ inputs.target-platform == 'macos' && 2 || 3 }})
+
+        # Run tests
+        if [ "`uname`" = "Darwin" ]; then
+          echo "About to start tests"
+          node script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
+        else
+          chown :builduser .. && chmod g+w ..
+          chown -R :builduser . && chmod -R g+w .
+          chmod 4755 ../out/Default/chrome-sandbox
+          runuser -u builduser -- git config --global --add safe.directory $(pwd)
+          runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
+        fi
+    - name: Wait for active SSH sessions
+      if: always() && !cancelled()
+      run: |
+        while [ -f /var/.ssh-lock ]
+        do
+          sleep 60
+        done

+ 165 - 0
.github/workflows/pipeline-segment-node-nan-test.yml

@@ -0,0 +1,165 @@
+name: Pipeline Segment - Node/Nan Test
+
+on:
+  workflow_call:
+    inputs:
+      target-platform:
+        type: string
+        description: 'Platform to run on, can be macos or linux'
+        required: true
+      target-arch:
+        type: string
+        description: 'Arch to build for, can be x64, arm64 or arm'
+        required: true
+      test-runs-on:
+        type: string
+        description: 'What host to run the tests on'
+        required: true
+      test-container:
+        type: string
+        description: 'JSON container information for aks runs-on'
+        required: false
+        default: '{"image":null}'
+      gn-build-type:
+        description: 'The gn build type - testing or release'
+        required: true
+        type: string
+        default: testing
+
+concurrency:
+  group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
+  cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
+
+env:
+  ELECTRON_OUT_DIR: Default
+  ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
+
+jobs:
+  node-tests:
+    name: Run Node.js Tests
+    runs-on: aks-linux-medium-plus
+    timeout-minutes: 20
+    env: 
+      TARGET_ARCH: ${{ inputs.target-arch }}
+      BUILD_TYPE: linux
+    container: ${{ fromJSON(inputs.test-container) }}
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Build Tools
+      uses: ./src/electron/.github/actions/install-build-tools
+    - name: Init Build Tools
+      run: |
+        e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }}
+    - name: Install Dependencies
+      run: |
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+    - name: Get Depot Tools
+      timeout-minutes: 5
+      run: |
+        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
+        sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+        cd depot_tools
+        git apply --3way ../src/electron/.github/workflows/config/gclient.diff
+        # Ensure depot_tools does not update.
+        test -d depot_tools && cd depot_tools
+        touch .disable_auto_update
+    - name: Add Depot Tools to PATH
+      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
+    - name: Download Generated Artifacts
+      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
+      with:
+        name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
+        path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
+    - name: Download Src Artifacts
+      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
+      with:
+        name: src_artifacts_linux_${{ env.TARGET_ARCH }}
+        path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
+    - name: Restore Generated Artifacts
+      run: ./src/electron/script/actions/restore-artifacts.sh
+    - name: Unzip Dist
+      run: |
+        cd src/out/Default
+        unzip -:o dist.zip
+    - name: Setup Linux for Headless Testing
+      run: sh -e /etc/init.d/xvfb start
+    - name: Run Node.js Tests
+      run: |
+        cd src
+        node electron/script/node-spec-runner.js --default --jUnitDir=junit
+    - name: Wait for active SSH sessions
+      if: always() && !cancelled()
+      run: |
+        while [ -f /var/.ssh-lock ]
+        do
+          sleep 60
+        done
+  nan-tests:
+    name: Run Nan Tests
+    runs-on: aks-linux-medium
+    timeout-minutes: 20
+    env: 
+      TARGET_ARCH: ${{ inputs.target-arch }}
+      BUILD_TYPE: linux
+    container: ${{ fromJSON(inputs.test-container) }}
+    steps:
+    - name: Checkout Electron
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
+      with:
+        path: src/electron
+        fetch-depth: 0
+    - name: Install Build Tools
+      uses: ./src/electron/.github/actions/install-build-tools
+    - name: Init Build Tools
+      run: |
+        e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }}
+    - name: Install Dependencies
+      run: |
+        cd src/electron
+        node script/yarn install --frozen-lockfile
+    - name: Get Depot Tools
+      timeout-minutes: 5
+      run: |
+        git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
+        sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
+        cd depot_tools
+        git apply --3way ../src/electron/.github/workflows/config/gclient.diff
+        # Ensure depot_tools does not update.
+        test -d depot_tools && cd depot_tools
+        touch .disable_auto_update
+    - name: Add Depot Tools to PATH
+      run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
+    - name: Download Generated Artifacts
+      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
+      with:
+        name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
+        path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
+    - name: Download Src Artifacts
+      uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
+      with:
+        name: src_artifacts_linux_${{ env.TARGET_ARCH }}
+        path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
+    - name: Restore Generated Artifacts
+      run: ./src/electron/script/actions/restore-artifacts.sh
+    - name: Unzip Dist
+      run: |
+        cd src/out/Default
+        unzip -:o dist.zip
+    - name: Setup Linux for Headless Testing
+      run: sh -e /etc/init.d/xvfb start
+    - name: Run Node.js Tests
+      run: |
+        cd src
+        node electron/script/nan-spec-runner.js
+    - name: Wait for active SSH sessions
+      if: always() && !cancelled()
+      run: |
+        while [ -f /var/.ssh-lock ]
+        do
+          sleep 60
+        done

+ 2 - 2
.github/workflows/scorecards.yml

@@ -22,7 +22,7 @@ jobs:
 
     steps:
       - name: "Checkout code"
-        uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
+        uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
         with:
           persist-credentials: false
 
@@ -50,6 +50,6 @@ jobs:
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7
+        uses: github/codeql-action/upload-sarif@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10
         with:
           sarif_file: results.sarif

+ 2 - 2
.github/workflows/update_appveyor_image.yml

@@ -19,7 +19,7 @@ jobs:
       with:
         creds: ${{ secrets.APPVEYOR_UPDATER_GH_APP_CREDS }}
     - name: Checkout
-      uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
+      uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
       with:
         fetch-depth: 0
         token: ${{ steps.generate-token.outputs.token }}
@@ -39,7 +39,7 @@ jobs:
         fi
     - name: (Optionally) Update Appveyor Image
       if: ${{ env.APPVEYOR_IMAGE_VERSION }}
-      uses: mikefarah/yq@557dcb87b8efe786f89a12c09e9046b4753ab72e # v4.44.1
+      uses: mikefarah/yq@f15500b20a1c991c8729870ba60a4dc3524b6a94 # v4.44.2
       with:
         cmd: |
           yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml"

+ 2 - 1
.markdownlint-cli2.jsonc

@@ -19,7 +19,8 @@
         "Tabs",
         "TabItem"
       ]
-    }
+    },
+    "no-newline-in-links": true
   },
   "customRules": [
     "@electron/lint-roller/markdownlint-rules/"

+ 9 - 6
DEPS

@@ -48,6 +48,9 @@ vars = {
   # It's only needed to parse the native tests configurations.
   'checkout_pyyaml': False,
 
+  # Can be used to disable the sysroot hooks.
+  'install_sysroot': True,
+
   'use_rts': False,
 
   'mac_xcode_version': 'default',
@@ -164,7 +167,7 @@ hooks = [
   {
     'name': 'sysroot_arm',
     'pattern': '.',
-    'condition': 'checkout_linux and checkout_arm',
+    'condition': 'install_sysroot and checkout_linux and checkout_arm',
     'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py',
                '--sysroots-json-path=' + Var('sysroots_json_path'),
                '--arch=arm'],
@@ -172,7 +175,7 @@ hooks = [
   {
     'name': 'sysroot_arm64',
     'pattern': '.',
-    'condition': 'checkout_linux and checkout_arm64',
+    'condition': 'install_sysroot and checkout_linux and checkout_arm64',
     'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py',
                '--sysroots-json-path=' + Var('sysroots_json_path'),
                '--arch=arm64'],
@@ -180,7 +183,7 @@ hooks = [
   {
     'name': 'sysroot_x86',
     'pattern': '.',
-    'condition': 'checkout_linux and (checkout_x86 or checkout_x64)',
+    'condition': 'install_sysroot and checkout_linux and (checkout_x86 or checkout_x64)',
     'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py',
                '--sysroots-json-path=' + Var('sysroots_json_path'),
                '--arch=x86'],
@@ -188,7 +191,7 @@ hooks = [
   {
     'name': 'sysroot_mips',
     'pattern': '.',
-    'condition': 'checkout_linux and checkout_mips',
+    'condition': 'install_sysroot and checkout_linux and checkout_mips',
     'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py',
                '--sysroots-json-path=' + Var('sysroots_json_path'),
                '--arch=mips'],
@@ -196,7 +199,7 @@ hooks = [
   {
     'name': 'sysroot_mips64',
     'pattern': '.',
-    'condition': 'checkout_linux and checkout_mips64',
+    'condition': 'install_sysroot and checkout_linux and checkout_mips64',
     'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py',
                '--sysroots-json-path=' + Var('sysroots_json_path'),
                '--arch=mips64el'],
@@ -204,7 +207,7 @@ hooks = [
   {
     'name': 'sysroot_x64',
     'pattern': '.',
-    'condition': 'checkout_linux and checkout_x64',
+    'condition': 'install_sysroot and checkout_linux and checkout_x64',
     'action': ['python3', 'src/build/linux/sysroot_scripts/install-sysroot.py',
                '--sysroots-json-path=' + Var('sysroots_json_path'),
                '--arch=x64'],

+ 1 - 1
appveyor-woa.yml

@@ -29,7 +29,7 @@
 
 version: 1.0.{build}
 build_cloud: electronhq-16-core
-image: e-126.0.6445.0
+image: e-127.0.6521.0
 environment:
   GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
   ELECTRON_OUT_DIR: Default

+ 1 - 1
appveyor.yml

@@ -29,7 +29,7 @@
 
 version: 1.0.{build}
 build_cloud: electronhq-16-core
-image: e-126.0.6445.0
+image: e-127.0.6521.0
 environment:
   GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache
   ELECTRON_OUT_DIR: Default

+ 1 - 1
docs/api/app.md

@@ -1265,7 +1265,7 @@ Returns `Object`:
 
 * `openAtLogin` boolean - `true` if the app is set to open at login.
 * `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up.
-* `wasOpenedAtLogin` boolean _macOS_ _Deprecated_ - `true` if the app was opened at login automatically. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
+* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
 * `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
 * `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
 * `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.

+ 1 - 1
docs/api/command-line-switches.md

@@ -279,7 +279,7 @@ Aliased to `--debug[=[host:]port`.
 
 Specify ways of the inspector web socket url exposure.
 
-By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list.
+By default inspector websocket url is available in stderr and under /json/list endpoint on `http://host:port/json/list`.
 
 ### `--no-deprecation`
 

+ 1 - 1
docs/api/dock.md

@@ -80,4 +80,4 @@ Returns `Menu | null` - The application's [dock menu][dock-menu].
 
 Sets the `image` associated with this dock icon.
 
-[dock-menu]: https://developer.apple.com/macos/human-interface-guidelines/menus/dock-menus/
+[dock-menu]: https://developer.apple.com/design/human-interface-guidelines/dock-menus

+ 2 - 0
docs/api/structures/cpu-usage.md

@@ -2,6 +2,8 @@
 
 * `percentCPUUsage` number - Percentage of CPU used since the last call to getCPUUsage.
   First call returns 0.
+* `cumulativeCPUUsage` number (optional) - Total seconds of CPU time used since process
+  startup.
 * `idleWakeupsPerSecond` number - The number of average idle CPU wakeups per second
   since the last call to getCPUUsage. First call returns 0. Will always return 0 on
   Windows.

+ 4 - 4
docs/api/structures/trace-config.md

@@ -7,8 +7,8 @@
   recording buffer in events.
 * `enable_argument_filter` boolean (optional) - if true, filter event data
   according to a specific list of events that have been manually vetted to not
-  include any PII. See [the implementation in
-  Chromium][trace_event_args_allowlist.cc] for specifics.
+  include any PII. See [the implementation in Chromium][trace_event_args_allowlist.cc]
+  for specifics.
 * `included_categories` string[] (optional) - a list of tracing categories to
   include. Can include glob-like patterns using `*` at the end of the category
   name. See [tracing categories][] for the list of categories.
@@ -21,8 +21,8 @@
   with the trace.
 * `memory_dump_config` Record\<string, any\> (optional) - if the
   `disabled-by-default-memory-infra` category is enabled, this contains
-  optional additional configuration for data collection. See the [Chromium
-  memory-infra docs][memory-infra docs] for more information.
+  optional additional configuration for data collection. See the
+  [Chromium memory-infra docs][memory-infra docs] for more information.
 
 An example TraceConfig that roughly matches what Chrome DevTools records:
 

+ 3 - 2
docs/tutorial/electron-timelines.md

@@ -9,10 +9,11 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
 
 | Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
 | ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
-| 31.0.0 |  2024-Apr-18 | 2024-May-15 | 2024-Jun-11 | 2025-Jan-07 | M126 | TBD | ✅ |
+| 32.0.0 |  2024-Jun-14 | 2024-Jul-24 | 2024-Aug-20 | 2025-Mar-04 | M128 | TBD | ✅ |
+| 31.0.0 |  2024-Apr-18 | 2024-May-15 | 2024-Jun-11 | 2025-Jan-07 | M126 | v20.14 | ✅ |
 | 30.0.0 |  2024-Feb-22 | 2024-Mar-20 | 2024-Apr-16 | 2024-Oct-15 | M124 | v20.11 | ✅ |
 | 29.0.0 |  2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v20.9 | ✅ |
-| 28.0.0 |  2023-Oct-11 | 2023-Nov-06 | 2023-Dec-05 | 2024-Jun-11 | M120 | v18.18 |  |
+| 28.0.0 |  2023-Oct-11 | 2023-Nov-06 | 2023-Dec-05 | 2024-Jun-11 | M120 | v18.18 | 🚫 |
 | 27.0.0 |  2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | 2024-Apr-16 | M118 | v18.17 | 🚫 |
 | 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | 🚫 |
 | 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2023-Dec-05 | M114 | v18.15 | 🚫 |

+ 58 - 44
docs/tutorial/mac-app-store-submission-guide.md

@@ -20,7 +20,7 @@ You also have to register an Apple Developer account and join the
 
 Electron apps can be distributed through Mac App Store or outside it. Each way
 requires different ways of signing and testing. This guide focuses on
-distribution via Mac App Store, but will also mention other methods.
+distribution via Mac App Store.
 
 The following steps describe how to get the certificates from Apple, how to sign
 Electron apps, and how to test them.
@@ -104,26 +104,15 @@ the App Sandbox. The standard darwin build of Electron will fail to launch
 when run under App Sandbox.
 
 When signing the app with `@electron/osx-sign`, it will automatically add the
-necessary entitlements to your app's entitlements, but if you are using custom
-entitlements, you must ensure App Sandbox capacity is added:
+necessary entitlements to your app's entitlements.
 
-```xml
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-  <dict>
-    <key>com.apple.security.app-sandbox</key>
-    <true/>
-  </dict>
-</plist>
-```
-
-#### Extra steps without `electron-osx-sign`
+<details>
+<summary>Extra steps without `electron-osx-sign`</summary>
 
 If you are signing your app without using `@electron/osx-sign`, you must ensure
 the app bundle's entitlements have at least following keys:
 
-```xml
+```xml title='entitlements.plist'
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
@@ -174,6 +163,7 @@ When using `@electron/osx-sign` the `ElectronTeamID` key will be added
 automatically by extracting the Team ID from the certificate's name. You may
 need to manually add this key if `@electron/osx-sign` could not find the correct
 Team ID.
+</details>
 
 ### Sign apps for development
 
@@ -181,8 +171,14 @@ To sign an app that can run on your development machine, you must sign it with
 the "Apple Development" certificate and pass the provisioning profile to
 `@electron/osx-sign`.
 
-```bash
-electron-osx-sign YourApp.app --identity='Apple Development' --provisioning-profile=/path/to/yourapp.provisionprofile
+```js @ts-nocheck
+const { signAsync } = require('@electron/osx-sign')
+
+signAsync({
+  app: '/path/to/your.app',
+  identity: 'Apple Development',
+  provisioningProfile: '/path/to/your.provisionprofile'
+})
 ```
 
 If you are signing without `@electron/osx-sign`, you must place the provisioning
@@ -198,30 +194,16 @@ To sign an app that will be submitted to Mac App Store, you must sign it with
 the "Apple Distribution" certificate. Note that apps signed with this
 certificate will not run anywhere, unless it is downloaded from Mac App Store.
 
-```bash
-electron-osx-sign YourApp.app --identity='Apple Distribution'
-```
-
-### Sign apps for distribution outside the Mac App Store
+```js @ts-nocheck
+const { signAsync } = require('@electron/osx-sign')
 
-If you don't plan to submit the app to Mac App Store, you can sign it the
-"Developer ID Application" certificate. In this way there is no requirement on
-App Sandbox, and you should use the normal darwin build of Electron if you don't
-use App Sandbox.
-
-```bash
-electron-osx-sign YourApp.app --identity='Developer ID Application' --no-gatekeeper-assess
+signAsync({
+  app: 'path/to/your.app',
+  identity: 'Apple Distribution'
+})
 ```
 
-By passing `--no-gatekeeper-assess`, `@electron/osx-sign` will skip the macOS
-GateKeeper check as your app usually has not been notarized yet by this step.
-
-<!-- TODO(zcbenz): Add a chapter about App Notarization -->
-This guide does not cover [App Notarization][app-notarization], but you might
-want to do it otherwise Apple may prevent users from using your app outside Mac
-App Store.
-
-## Submit Apps to the Mac App Store
+## Submit apps to the Mac App Store
 
 After signing the app with the "Apple Distribution" certificate, you can
 continue to submit it to Mac App Store.
@@ -263,10 +245,43 @@ more information.
 
 ### Additional entitlements
 
+Every app running under the App Sandbox will run under a limited set of permissions,
+which limits potential damage from malicious code.
 Depending on which Electron APIs your app uses, you may need to add additional
 entitlements to your app's entitlements file. Otherwise, the App Sandbox may
 prevent you from using them.
 
+Entitlements are specified using a file with format like
+property list (`.plist`) or XML. You must provide an entitlement file for the
+application bundle itself and a child entitlement file which basically describes
+an inheritance of properties, specified for all other enclosing executable files
+like binaries, frameworks (`.framework`), and dynamically linked libraries (`.dylib`).
+
+A full list of entitlements is available in the [App Sandbox][app-sandboxing]
+documentation, but below are a few entitlements you might need for your
+MAS app.
+
+With `@electron/osx-sign`, you can set custom entitlements per file as such:
+
+```js @ts-nocheck
+const { signAsync } = require('@electron/osx-sign')
+
+function getEntitlementsForFile (filePath) {
+  if (filePath.startsWith('my-path-1')) {
+    return './my-path-1.plist'
+  } else {
+    return './alternate.plist'
+  }
+}
+
+signAsync({
+  optionsForFile: (filePath) => ({
+    // Ensure you return the right entitlements path here based on the file being signed.
+    entitlements: getEntitlementsForFile(filePath)
+  })
+})
+```
+
 #### Network access
 
 Enable outgoing network connections to allow your app to connect to a server:
@@ -342,12 +357,11 @@ Electron uses following cryptographic algorithms:
 
 [developer-program]: https://developer.apple.com/support/compare-memberships/
 [@electron/osx-sign]: https://github.com/electron/osx-sign
-[app-sandboxing]: https://developer.apple.com/app-sandboxing/
-[app-notarization]: https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution
-[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
-[create-record]: https://help.apple.com/app-store-connect/#/dev2cd126805
+[app-sandboxing]: https://developer.apple.com/documentation/security/app_sandbox
+[submitting-your-app]: https://help.apple.com/xcode/mac/current/#/dev067853c94
+[create-record]: https://developer.apple.com/help/app-store-connect/create-an-app-record/add-a-new-app
 [apple-transporter]: https://help.apple.com/itc/transporteruserguide/en.lproj/static.html
-[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
+[submit-for-review]: https://developer.apple.com/help/app-store-connect/manage-submissions-to-app-review/submit-for-review
 [export-compliance]: https://help.apple.com/app-store-connect/#/devc3f64248f
 [user-selected]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW6
 [network-access]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW9

+ 6 - 6
docs/tutorial/security.md

@@ -121,8 +121,8 @@ To automate the detection of misconfigurations and insecure patterns, it is
 possible to use
 [Electronegativity](https://github.com/doyensec/electronegativity). For
 additional details on potential weaknesses and implementation bugs when
-developing applications using Electron, please refer to this [guide for
-developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf).
+developing applications using Electron, please refer to this
+[guide for developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf).
 
 ### 1. Only load secure content
 
@@ -246,7 +246,7 @@ and prevent the use of Node primitives `contextIsolation` **must** also be used.
 :::info
 For more information on what `contextIsolation` is and how to enable it please
 see our dedicated [Context Isolation](context-isolation.md) document.
-:::info
+:::
 
 ### 4. Enable process sandboxing
 
@@ -259,7 +259,7 @@ content in an unsandboxed process, including the main process, is not advised.
 :::info
 For more information on what Process Sandboxing is and how to enable it please
 see our dedicated [Process Sandboxing](sandbox.md) document.
-:::info
+:::
 
 ### 5. Handle session permission requests from remote content
 
@@ -644,8 +644,8 @@ windows at runtime.
 
 #### How?
 
-[`webContents`][web-contents] will delegate to its [window open
-handler][window-open-handler] before creating new windows. The handler will
+[`webContents`][web-contents] will delegate to its
+[window open handler][window-open-handler] before creating new windows. The handler will
 receive, amongst other parameters, the `url` the window was requested to open
 and the options used to create it. We recommend that you register a handler to
 monitor the creation of windows, and deny any unexpected window creation.

+ 4 - 4
docs/tutorial/using-native-node-modules.md

@@ -40,8 +40,8 @@ npm install --save-dev @electron/rebuild
 .\node_modules\.bin\electron-rebuild.cmd
 ```
 
-For more information on usage and integration with other tools such as [Electron
-Packager][electron-packager], consult the project's README.
+For more information on usage and integration with other tools such as
+[Electron Packager][electron-packager], consult the project's README.
 
 ### Using `npm`
 
@@ -108,8 +108,8 @@ the following things:
 On Windows, by default, `node-gyp` links native modules against `node.dll`.
 However, in Electron 4.x and higher, the symbols needed by native modules are
 exported by `electron.exe`, and there is no `node.dll`. In order to load native
-modules on Windows, `node-gyp` installs a [delay-load
-hook](https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification?view=msvc-170#notification-hooks) that triggers
+modules on Windows, `node-gyp` installs a
+[delay-load hook](https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification?view=msvc-170#notification-hooks) that triggers
 when the native module is loaded, and redirects the `node.dll` reference to use
 the loading executable instead of looking for `node.dll` in the library search
 path (which would turn up nothing). As such, on Electron 4.x and higher,

+ 2 - 2
docs/tutorial/web-embeds.md

@@ -23,8 +23,8 @@ and only allow the capabilities you want to support.
 [we do not recommend you to use WebViews](../api/webview-tag.md#warning),
 as this tag undergoes dramatic architectural changes that may affect stability
 of your application. Consider switching to alternatives, like `iframe` and
-Electron's `BrowserView`, or an architecture that avoids embedded content
-by design.
+Electron's [`WebContentsView`](../api/web-contents-view.md), or an architecture
+that avoids embedded content by design.
 
 [WebViews](../api/webview-tag.md) are based on Chromium's WebViews and are not
 explicitly supported by Electron. We do not guarantee that the WebView API will

+ 5 - 2
lib/node/init.ts

@@ -3,8 +3,11 @@ import { wrapFsWithAsar } from './asar-fs-wrapper';
 wrapFsWithAsar(require('fs'));
 
 // See ElectronRendererClient::DidCreateScriptContext.
-if ((globalThis as any).blinkFetch) {
-  globalThis.fetch = (globalThis as any).blinkFetch;
+if ((globalThis as any).blinkfetch) {
+  const keys = ['fetch', 'Response', 'FormData', 'Request', 'Headers'];
+  for (const key of keys) {
+    (globalThis as any)[key] = (globalThis as any)[`blink${key}`];
+  }
 }
 
 // Hook child_process.fork.

+ 1 - 3
package.json

@@ -9,7 +9,7 @@
     "@electron/docs-parser": "^1.2.0",
     "@electron/fiddle-core": "^1.0.4",
     "@electron/github-app-auth": "^2.0.0",
-    "@electron/lint-roller": "^2.1.0",
+    "@electron/lint-roller": "^2.2.0",
     "@electron/typescript-definitions": "^8.15.2",
     "@octokit/rest": "^19.0.7",
     "@primer/octicons": "^10.0.0",
@@ -20,7 +20,6 @@
     "@types/dirty-chai": "^2.0.2",
     "@types/express": "^4.17.13",
     "@types/fs-extra": "^9.0.1",
-    "@types/klaw": "^3.0.1",
     "@types/minimist": "^1.2.0",
     "@types/mocha": "^7.0.2",
     "@types/node": "^20.9.0",
@@ -54,7 +53,6 @@
     "fs-extra": "^9.0.1",
     "got": "^11.8.5",
     "husky": "^8.0.1",
-    "klaw": "^3.0.0",
     "lint": "^1.1.2",
     "lint-staged": "^10.2.11",
     "markdownlint-cli2": "^0.13.0",

+ 1 - 0
patches/chromium/.patches

@@ -129,3 +129,4 @@ feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch
 fix_font_face_resolution_when_renderer_is_blocked.patch
 feat_enable_passing_exit_code_on_service_process_crash.patch
 chore_remove_reference_to_chrome_browser_themes.patch
+x11_use_localized_display_label_only_for_browser_process.patch

+ 176 - 17
patches/chromium/feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch

@@ -186,24 +186,10 @@ index 129979e844581e68fdecde87bd52f3344f88022a..5e02a36e5e9eb4db84700dd9a0b8765d
  }
  
 diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
-index 53ae15f14c45ee72abdae172fc4555c9e4b3ff9a..af181afd9db1351cd886ba24dd651c7bf2f8a716 100644
+index 53ae15f14c45ee72abdae172fc4555c9e4b3ff9a..ee19c3f399a1d060d5e9bd0dc5f1b3828381e8df 100644
 --- a/ui/gtk/select_file_dialog_linux_gtk.h
 +++ b/ui/gtk/select_file_dialog_linux_gtk.h
-@@ -15,6 +15,13 @@
- 
- namespace gtk {
- 
-+struct ExtraSettings {
-+  std::string button_label;
-+  bool show_overwrite_confirmation = true;
-+  bool show_hidden = false;
-+  bool allow_multiple_selection = false;
-+};
-+
- // Implementation of SelectFileDialog that shows a Gtk common dialog for
- // choosing a file or folder. This acts as a modal dialog.
- class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
-@@ -90,19 +97,23 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
+@@ -90,19 +90,23 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
    GtkWidget* CreateSelectFolderDialog(Type type,
                                        const std::string& title,
                                        const base::FilePath& default_path,
@@ -231,7 +217,7 @@ index 53ae15f14c45ee72abdae172fc4555c9e4b3ff9a..af181afd9db1351cd886ba24dd651c7b
  
    // Removes and returns the |params| associated with |dialog| from
    // |params_map_|.
-@@ -121,7 +132,8 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
+@@ -121,7 +125,8 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
    // Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
    GtkWidget* CreateFileOpenHelper(const std::string& title,
                                    const base::FilePath& default_path,
@@ -241,3 +227,176 @@ index 53ae15f14c45ee72abdae172fc4555c9e4b3ff9a..af181afd9db1351cd886ba24dd651c7b
  
    // Callback for when the user responds to a Save As or Open File dialog.
    void OnSelectSingleFileDialogResponse(GtkWidget* dialog, int response_id);
+diff --git a/ui/shell_dialogs/select_file_dialog_linux.h b/ui/shell_dialogs/select_file_dialog_linux.h
+index 20ad001988831afca73315c577f90c824a36e282..57a8d35ace583eaafb526f70935d21c0f8fd1078 100644
+--- a/ui/shell_dialogs/select_file_dialog_linux.h
++++ b/ui/shell_dialogs/select_file_dialog_linux.h
+@@ -26,6 +26,13 @@ class SHELL_DIALOGS_EXPORT SelectFileDialogLinux : public SelectFileDialog {
+   SelectFileDialogLinux(const SelectFileDialogLinux&) = delete;
+   SelectFileDialogLinux& operator=(const SelectFileDialogLinux&) = delete;
+ 
++  struct ExtraSettings {
++    std::string button_label;
++    bool show_overwrite_confirmation = true;
++    bool show_hidden = false;
++    bool allow_multiple_selection = false;
++  };
++
+   // Returns true if the SelectFileDialog class returned by
+   // NewSelectFileDialogImplKDE will actually work.
+   static bool CheckKDEDialogWorksOnUIThread(std::string& kdialog_version);
+diff --git a/ui/shell_dialogs/select_file_dialog_linux_kde.cc b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
+index c79fb47bfba9233da7d2c1438d1e26600684fc78..d7cc7cd70653aaa5b628ef456dcb48a2eef5ec5e 100644
+--- a/ui/shell_dialogs/select_file_dialog_linux_kde.cc
++++ b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
+@@ -480,6 +480,9 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
+   int title_message_id = (type == SELECT_UPLOAD_FOLDER)
+                              ? IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE
+                              : IDS_SELECT_FOLDER_DIALOG_TITLE;
++  ExtraSettings extra_settings;
++  if (params)
++    extra_settings = *(static_cast<ExtraSettings*>(params));
+   pipe_task_runner_->PostTaskAndReplyWithResult(
+       FROM_HERE,
+       base::BindOnce(
+@@ -487,7 +490,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
+           KDialogParams(
+               "--getexistingdirectory", GetTitle(title, title_message_id),
+               default_path.empty() ? *last_opened_path() : default_path, parent,
+-              false, false)),
++              false, extra_settings.allow_multiple_selection)),
+       base::BindOnce(
+           &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
+           parent, params));
+diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
+index 65727489ddecb755eeabbd194ce843ca9eaa59c9..b15bace56639d2f914f8f76edfa1b28e33165b48 100644
+--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc
++++ b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
+@@ -219,6 +219,10 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
+   info_->main_task_runner = base::SequencedTaskRunner::GetCurrentDefault();
+   listener_params_ = params;
+ 
++  ExtraSettings extra_settings;
++  if (params)
++    extra_settings = *(static_cast<ExtraSettings*>(params));
++
+   if (owning_window) {
+     if (auto* root = owning_window->GetRootWindow()) {
+       if (auto* host = root->GetNativeWindowProperty(
+@@ -246,7 +250,7 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
+             host_->GetAcceleratedWidget(),
+             base::BindOnce(
+                 &SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle,
+-                this, title, default_path, filter_set, default_extension))) {
++                this, title, default_path, filter_set, default_extension, extra_settings))) {
+       // Return early to skip the fallback below.
+       return;
+     } else {
+@@ -256,7 +260,7 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
+ 
+   // No parent, so just use a blank parent handle.
+   SelectFileImplWithParentHandle(title, default_path, filter_set,
+-                                 default_extension, "");
++                                 default_extension, extra_settings, "");
+ }
+ 
+ bool SelectFileDialogLinuxPortal::HasMultipleFileTypeChoicesImpl() {
+@@ -453,6 +457,7 @@ void SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle(
+     base::FilePath default_path,
+     PortalFilterSet filter_set,
+     base::FilePath::StringType default_extension,
++    const ExtraSettings& settings,
+     std::string parent_handle) {
+   bool default_path_exists = CallDirectoryExistsOnUIThread(default_path);
+   dbus_thread_linux::GetTaskRunner()->PostTask(
+@@ -461,7 +466,7 @@ void SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle(
+           &SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread,
+           info_, std::move(title), std::move(default_path), default_path_exists,
+           std::move(filter_set), std::move(default_extension),
+-          std::move(parent_handle)));
++          std::move(parent_handle), std::move(settings)));
+ }
+ 
+ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
+@@ -470,7 +475,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
+     const bool default_path_exists,
+     PortalFilterSet filter_set,
+     base::FilePath::StringType default_extension,
+-    std::string parent_handle) {
++    std::string parent_handle,
++    const ExtraSettings& settings) {
+   DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
+   dbus::Bus* bus = AcquireBusOnBusThread();
+   if (!bus->Connect())
+@@ -516,7 +522,7 @@ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
+       base::StringPrintf("handle_%d", handle_token_counter_++);
+ 
+   AppendOptions(&writer, response_handle_token, default_path,
+-                default_path_exists, filter_set);
++                default_path_exists, filter_set, settings);
+ 
+   // The sender part of the handle object contains the D-Bus connection name
+   // without the prefix colon and with all dots replaced with underscores.
+@@ -546,7 +552,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
+     const std::string& response_handle_token,
+     const base::FilePath& default_path,
+     const bool default_path_exists,
+-    const SelectFileDialogLinuxPortal::PortalFilterSet& filter_set) {
++    const SelectFileDialogLinuxPortal::PortalFilterSet& filter_set,
++    const ExtraSettings& settings) {
+   dbus::MessageWriter options_writer(nullptr);
+   writer->OpenArray("{sv}", &options_writer);
+ 
+@@ -554,8 +561,10 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
+                      response_handle_token);
+ 
+   if (type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER) {
+-    AppendStringOption(&options_writer, kFileChooserOptionAcceptLabel,
+-                       l10n_util::GetStringUTF8(
++    const std::string accept_label = settings.button_label.empty()
++                            ? kFileChooserOptionAcceptLabel
++                            : settings.button_label;
++    AppendStringOption(&options_writer, accept_label, l10n_util::GetStringUTF8(
+                            IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON));
+   }
+ 
+@@ -563,6 +572,7 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
+       type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER ||
+       type == SelectFileDialog::Type::SELECT_EXISTING_FOLDER) {
+     AppendBoolOption(&options_writer, kFileChooserOptionDirectory, true);
++    AppendBoolOption(&options_writer, kFileChooserOptionMultiple, settings.allow_multiple_selection);
+   } else if (type == SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE) {
+     AppendBoolOption(&options_writer, kFileChooserOptionMultiple, true);
+   }
+diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.h b/ui/shell_dialogs/select_file_dialog_linux_portal.h
+index c487f7da19e2d05696a8eb72f2fa3e12972149f3..02a40c571570974dcc61e1b1f7ed95fbfc2bedf2 100644
+--- a/ui/shell_dialogs/select_file_dialog_linux_portal.h
++++ b/ui/shell_dialogs/select_file_dialog_linux_portal.h
+@@ -115,7 +115,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
+                                    const bool default_path_exists,
+                                    PortalFilterSet filter_set,
+                                    base::FilePath::StringType default_extension,
+-                                   std::string parent_handle);
++                                   std::string parent_handle,
++                                   const ExtraSettings& settings);
+     Type type;
+     // The task runner the SelectFileImpl method was called on.
+     scoped_refptr<base::SequencedTaskRunner> main_task_runner;
+@@ -143,7 +144,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
+                        const std::string& response_handle_token,
+                        const base::FilePath& default_path,
+                        const bool derfault_path_exists,
+-                       const PortalFilterSet& filter_set);
++                       const PortalFilterSet& filter_set,
++                       const ExtraSettings& settings);
+     void AppendFilterStruct(dbus::MessageWriter* writer,
+                             const PortalFilter& filter);
+     std::vector<base::FilePath> ConvertUrisToPaths(
+@@ -190,6 +192,7 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
+       base::FilePath default_path,
+       PortalFilterSet filter_set,
+       base::FilePath::StringType default_extension,
++      const ExtraSettings& settings,
+       std::string parent_handle);
+ 
+   void DialogCreatedOnMainThread();

+ 62 - 0
patches/chromium/x11_use_localized_display_label_only_for_browser_process.patch

@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: deepak1556 <[email protected]>
+Date: Mon, 17 Jun 2024 18:05:47 +0000
+Subject: Use localized display label only for browser process
+
+With https://crrev.com/c/5098130, GetPrimaryDisplayRefreshIntervalFromXrandr uses BuildDisplaysFromXRandRInfo
+to calculate the primary display frequency. In software compositing mode --disable-gpu-compositing,
+this code path will be called from the gpu process via SoftwareOutputSurface::SwapBuffers and
+can trigger a crash when attempting to set localized string. This is because on linux,
+gpu process does not have access to the resource bundle.
+
+Bug: none
+Change-Id: I9d66b98c07a1a8671369546d4fc685213904a84f
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5631219
+Auto-Submit: Deepak Mohan (Robo) <[email protected]>
+Reviewed-by: Thomas Anderson <[email protected]>
+Reviewed-by: Scott Violet <[email protected]>
+Commit-Queue: Scott Violet <[email protected]>
+Cr-Commit-Position: refs/heads/main@{#1315980}
+
+diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
+index ffaea4fef9931050f1c1888674bf2f7498c578da..faf59929eb7e291502c449631e54f3841582bd9e 100644
+--- a/ui/base/x/x11_display_util.cc
++++ b/ui/base/x/x11_display_util.cc
+@@ -299,6 +299,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+     const display::DisplayConfig& display_config,
+     size_t* primary_display_index_out) {
+   DCHECK(primary_display_index_out);
++  auto* command_line = base::CommandLine::ForCurrentProcess();
+   const float primary_scale = display_config.primary_scale;
+ 
+   auto* connection = x11::Connection::Get();
+@@ -348,7 +349,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+   connection->Flush();
+ 
+   std::vector<x11::Future<x11::GetPropertyReply>> icc_futures{n_iccs};
+-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) {
++  if (!command_line->HasSwitch(switches::kHeadless)) {
+     for (size_t monitor = 0; monitor < n_iccs; ++monitor) {
+       icc_futures[monitor] = GetIccProfileFuture(connection, monitor);
+     }
+@@ -446,11 +447,18 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+     }
+ 
+     const std::string name(output_info->name.begin(), output_info->name.end());
++    auto process_type =
++        command_line->GetSwitchValueASCII("type");
+     if (base::StartsWith(name, "eDP") || base::StartsWith(name, "LVDS")) {
+       display::SetInternalDisplayIds({display_id});
+-      // Use localized variant of "Built-in display" for internal displays.
++      // For browser process which has access to resource bundle,
++      // use localized variant of "Built-in display" for internal displays.
+       // This follows the ozone DRM behavior (i.e. ChromeOS).
+-      display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
++      if (process_type.empty()) {
++        display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
++      } else {
++        display.set_label("Built-in display");
++      }
+     } else {
+       display.set_label(edid_parser.display_name());
+     }

+ 65 - 34
patches/node/build_add_gn_build_files.patch

@@ -1256,10 +1256,10 @@ index 0000000000000000000000000000000000000000..af9cbada10203b387fb9732b346583b1
 +}
 diff --git a/filenames.json b/filenames.json
 new file mode 100644
-index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e112101ec
+index 0000000000000000000000000000000000000000..fd42e2a5e6163ff70db0f716d2f9a32f13cdf668
 --- /dev/null
 +++ b/filenames.json
-@@ -0,0 +1,739 @@
+@@ -0,0 +1,734 @@
 +// This file is automatically generated by generate_gn_filenames_json.py
 +// DO NOT EDIT
 +{
@@ -1292,7 +1292,7 @@ index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e
 +      ]
 +    },
 +    {
-+      "dest_dir": "include/node//",
++      "dest_dir": "include/node/./",
 +      "files": [
 +        "//v8/include/v8-array-buffer.h",
 +        "//v8/include/v8-callbacks.h",
@@ -1346,11 +1346,12 @@ index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e
 +        "//v8/include/v8-wasm.h",
 +        "//v8/include/v8-weak-callback-info.h",
 +        "//v8/include/v8.h",
-+        "//v8/include/v8config.h"
++        "//v8/include/v8config.h",
++        "deps/uv/include/uv.h"
 +      ]
 +    },
 +    {
-+      "dest_dir": "include/node//libplatform/",
++      "dest_dir": "include/node/libplatform/",
 +      "files": [
 +        "//v8/include/libplatform/libplatform-export.h",
 +        "//v8/include/libplatform/libplatform.h",
@@ -1358,7 +1359,7 @@ index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e
 +      ]
 +    },
 +    {
-+      "dest_dir": "include/node//cppgc/",
++      "dest_dir": "include/node/cppgc/",
 +      "files": [
 +        "//v8/include/cppgc/allocation.h",
 +        "//v8/include/cppgc/common.h",
@@ -1391,7 +1392,7 @@ index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e
 +      ]
 +    },
 +    {
-+      "dest_dir": "include/node//cppgc/internal/",
++      "dest_dir": "include/node/cppgc/internal/",
 +      "files": [
 +        "//v8/include/cppgc/internal/api-constants.h",
 +        "//v8/include/cppgc/internal/atomic-entry-flag.h",
@@ -1410,13 +1411,7 @@ index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e
 +      ]
 +    },
 +    {
-+      "dest_dir": "include/node//",
-+      "files": [
-+        "deps/uv/include/uv.h"
-+      ]
-+    },
-+    {
-+      "dest_dir": "include/node//uv/",
++      "dest_dir": "include/node/uv/",
 +      "files": [
 +        "deps/uv/include/uv/aix.h",
 +        "deps/uv/include/uv/bsd.h",
@@ -1891,7 +1886,7 @@ index 0000000000000000000000000000000000000000..1a9cba024f1762b0dfe31da92213b51e
 +    "src/dataqueue/queue.h",
 +    "src/debug_utils.h",
 +    "src/debug_utils-inl.h",
-+    "src/embeded_data.h",
++    "src/embedded_data.h",
 +    "src/encoding_binding.h",
 +    "src/env_properties.h",
 +    "src/env.h",
@@ -2243,10 +2238,10 @@ index 75a7f3dd89e096d13ad7d70ed29d301cd56315b5..9a20a275fbe5df9f384b7b1d1d26806e
  // bootstrap scripts, whose source are bundled into the binary as static data.
 diff --git a/tools/generate_gn_filenames_json.py b/tools/generate_gn_filenames_json.py
 new file mode 100755
-index 0000000000000000000000000000000000000000..7848ddb1841b6d4f36e9376c73564eb4ff6d7c08
+index 0000000000000000000000000000000000000000..37c16859003e61636fe2f1a4040b1e904c472d0b
 --- /dev/null
 +++ b/tools/generate_gn_filenames_json.py
-@@ -0,0 +1,90 @@
+@@ -0,0 +1,117 @@
 +#!/usr/bin/env python3
 +import json
 +import os
@@ -2276,6 +2271,14 @@ index 0000000000000000000000000000000000000000..7848ddb1841b6d4f36e9376c73564eb4
 +// DO NOT EDIT
 +'''.lstrip()
 +
++SRC_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', '..'))
++
++def get_out_dir():
++  out_dir = 'Testing'
++  override = os.environ.get('ELECTRON_OUT_DIR')
++  if override is not None:
++    out_dir = override
++  return os.path.join(SRC_DIR, 'out', out_dir)
 +
 +if __name__ == '__main__':
 +  node_root_dir = os.path.dirname(os.path.dirname(__file__))
@@ -2294,18 +2297,25 @@ index 0000000000000000000000000000000000000000..7848ddb1841b6d4f36e9376c73564eb4
 +  }
 +
 +  def filter_v8_files(files):
-+    if any(f.startswith('deps/v8/') for f in files):
-+      files = [f.replace('deps/v8/', '../../v8/', 1) if f.endswith('js') else f.replace('deps/v8/', '//v8/') for f in files]
-+
-+    if any(f == '<@(node_builtin_shareable_builtins)' for f in files):
-+      files.remove('<@(node_builtin_shareable_builtins)')
++    v8_files = [f for f in files if f.startswith('deps/v8/')]
++    other_files = [f for f in files if not f.startswith('deps/v8/')]
++
++    for i, f in enumerate(v8_files):
++        if not f.startswith('deps/v8/tools'):
++            if f.endswith('js'):
++                v8_files[i] = f.replace('deps/v8/', '../../v8/', 1)
++            else:
++                v8_files[i] = f.replace('deps/v8/', '//v8/')
++
++    if any(f == '<@(node_builtin_shareable_builtins)' for f in other_files):
++      other_files.remove('<@(node_builtin_shareable_builtins)')
 +      shared_builtins = ['deps/cjs-module-lexer/lexer.js', 'deps/cjs-module-lexer/dist/lexer.js', 'deps/undici/undici.js']
-+      files.extend(shared_builtins)
++      other_files.extend(shared_builtins)
 +
-+    return files
++    return v8_files + other_files
 +
 +  def filter_fs_files(files):
-+    return [f for f in files if f.startswith('lib/internal/fs/')] + ['lib/fs.js']
++    return [f for f in files if f.startswith('lib/internal/fs/')] + ['lib/fs.js'] + ['lib/fs/promises.js']
 +
 +  lib_files = SearchFiles('lib', 'js')
 +  out['library_files'] = filter_v8_files(lib_files)
@@ -2322,17 +2332,29 @@ index 0000000000000000000000000000000000000000..7848ddb1841b6d4f36e9376c73564eb4
 +  out['node_sources'] += filter_v8_files(blocklisted_sources)
 +
 +  out['headers'] = []
-+  def add_headers(files, dest_dir):
++  def add_headers(options, files, dest_dir):
 +    if 'src/node.h' in files:
 +      files = [f for f in files if f.endswith('.h') and f != 'src/node_version.h']
 +    elif any(f.startswith('../../v8/') for f in files):
 +      files = [f.replace('../../v8/', '//v8/', 1) for f in files]
 +    if files:
-+      hs = {'files': sorted(files), 'dest_dir': dest_dir}
-+      out['headers'].append(hs)
-+
-+  install.variables = {'node_shared_libuv': 'false'}
-+  install.headers(add_headers)
++      dir_index = next((i for i, d in enumerate(out['headers']) if d['dest_dir'] == dest_dir), -1)
++      if (dir_index != -1):
++        out['headers'][dir_index]['files'] += sorted(files)
++      else:
++        hs = {'files': sorted(files), 'dest_dir': dest_dir}
++        out['headers'].append(hs)
++
++  config_gypi_path = os.path.join(get_out_dir(), 'gen', 'config.gypi')
++  root_gen_dir = os.path.join(node_root_dir, 'out', 'Release', 'gen')
++
++  options = install.parse_options(['install', '--v8-dir', '../../v8', '--config-gypi-path', config_gypi_path, '--headers-only'])
++  options.variables['node_use_openssl'] = 'false'
++  options.variables['node_shared_libuv'] = 'false'
++  # We generate zlib headers in Electron's BUILD.gn.
++  options.variables['node_shared_zlib'] = ''
++
++  install.headers(options, add_headers)
 +  with open(os.path.join(node_root_dir, 'filenames.json'), 'w') as f:
 +    f.write(FILENAMES_JSON_HEADER)
 +    f.write(json.dumps(out, sort_keys=True, indent=2, separators=(',', ': ')))
@@ -2363,18 +2385,27 @@ index 0000000000000000000000000000000000000000..9be3ac447f9a4dde23fefc26e0b922b4
 +      transformed_f.write(transformed_contents)
 +
 diff --git a/tools/install.py b/tools/install.py
-index b132c7bf26c02886a7ab341a1973bf449744ba0f..171b383a4b6c2528d11dd5f89a6837fd071bcf4b 100755
+index b132c7bf26c02886a7ab341a1973bf449744ba0f..757e3e60a7be01fac55c5fbb010dbbae00b1bfca 100755
 --- a/tools/install.py
 +++ b/tools/install.py
-@@ -284,6 +284,7 @@ def headers(options, action):
+@@ -264,6 +264,7 @@ def headers(options, action):
+       'include/v8-forward.h',
+       'include/v8-function-callback.h',
+       'include/v8-function.h',
++      'include/v8-handle-base.h',
+       'include/v8-initialization.h',
+       'include/v8-internal.h',
+       'include/v8-isolate.h',
+@@ -284,6 +285,8 @@ def headers(options, action):
        'include/v8-promise.h',
        'include/v8-proxy.h',
        'include/v8-regexp.h',
 +      "include/v8-sandbox.h",
++      "include/v8-source-location.h",
        'include/v8-script.h',
        'include/v8-snapshot.h',
        'include/v8-statistics.h',
-@@ -390,7 +391,7 @@ def parse_options(args):
+@@ -390,7 +393,7 @@ def parse_options(args):
    parser.add_argument('--build-dir', help='the location of built binaries',
                        default='out/Release')
    parser.add_argument('--v8-dir', help='the location of V8',

+ 61 - 11
script/actions/move-artifacts.sh

@@ -1,34 +1,82 @@
-#!/bin/sh
+#!/bin/bash
 
-set -eo pipefail
-
-if [ -z "$MAS_BUILD" ]; then
-  BUILD_TYPE="darwin"
+if [ "`uname`" == "Darwin" ]; then
+  if [ -z "$MAS_BUILD" ]; then
+    BUILD_TYPE="darwin"
+  else
+    BUILD_TYPE="mas"
+  fi
+elif [ "`uname`" == "Linux" ]; then
+  BUILD_TYPE="linux"
 else
-  BUILD_TYPE="mas"
+  echo "Unsupported platform"
+  exit 1
 fi
 
-echo Creating generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}...
-rm -rf generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}
-mkdir generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}
+GENERATED_ARTIFACTS="generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
+
+echo Creating $GENERATED_ARTIFACTS...
+rm -rf $GENERATED_ARTIFACTS
+mkdir $GENERATED_ARTIFACTS
+
+SRC_ARTIFACTS="src_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
+
+echo Creating $SRC_ARTIFACTS...
+rm -rf $SRC_ARTIFACTS
+mkdir $SRC_ARTIFACTS
 
 mv_if_exist() {
   if [ -f "$1" ] || [ -d "$1" ]; then
     echo Storing $1
-    mv $1 generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}
+    mv $1 $GENERATED_ARTIFACTS
   else
     echo Skipping $1 - It is not present on disk
   fi
 }
+
 cp_if_exist() {
   if [ -f "$1" ] || [ -d "$1" ]; then
     echo Storing $1
-    cp $1 generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}
+    cp $1 $GENERATED_ARTIFACTS
   else
     echo Skipping $1 - It is not present on disk
   fi
 }
 
+move_src_dirs_if_exist() {
+  mkdir src_artifacts
+
+  for dir in \
+    src/out/Default/gen/node_headers \
+    src/out/Default/overlapped-checker \
+    src/out/Default/ffmpeg \
+    src/out/Default/hunspell_dictionaries \
+    src/third_party/electron_node \
+    src/third_party/nan \
+    src/cross-arch-snapshots \
+    src/third_party/llvm-build \
+    src/build/linux \
+    src/buildtools/mac \
+    src/buildtools/third_party/libc++ \
+    src/buildtools/third_party/libc++abi \
+    src/third_party/libc++ \
+    src/third_party/libc++abi \
+    src/out/Default/obj/buildtools/third_party \
+    src/v8/tools/builtins-pgo
+  do
+    if [ -d "$dir" ]; then
+      mkdir -p src_artifacts/$(dirname $dir)
+      cp -r $dir/ src_artifacts/$dir
+    fi      
+  done
+
+  tar -C src_artifacts -cf src_artifacts.tar ./
+
+  echo Storing src_artifacts.tar
+  mv src_artifacts.tar $SRC_ARTIFACTS
+}
+
+# Generated Artifacts
 mv_if_exist src/out/Default/dist.zip
 mv_if_exist src/out/Default/gen/node_headers.tar.gz
 mv_if_exist src/out/Default/symbols.zip
@@ -39,3 +87,5 @@ mv_if_exist src/out/Default/hunspell_dictionaries.zip
 mv_if_exist src/cross-arch-snapshots
 cp_if_exist src/out/electron_ninja_log
 cp_if_exist src/out/Default/.ninja_log
+
+move_src_dirs_if_exist

+ 22 - 4
script/actions/restore-artifacts.sh

@@ -1,17 +1,30 @@
 #!/bin/bash
 
-set -eo pipefail
+GENERATED_ARTIFACTS="generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
+SRC_ARTIFACTS="src_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
 
 mv_if_exist() {
-  if [ -f "generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}/$1" ] || [ -d "generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}/$1" ]; then
+  if [ -f "${GENERATED_ARTIFACTS}/$1" ] || [ -d "${GENERATED_ARTIFACTS}/$1" ]; then
     echo Restoring $1 to $2
     mkdir -p $2
-    mv generated_artifacts_${BUILD_TYPE_${TARGET_ARCH}}/$1 $2
+    mv $GENERATED_ARTIFACTS/$1 $2
   else
     echo Skipping $1 - It is not present on disk
   fi
 }
 
+untar_if_exist() {
+  if [ -f "${SRC_ARTIFACTS}/$1" ] || [ -d "${SRC_ARTIFACTS}/$1" ]; then
+    echo Restoring $1 to current directory
+    tar -xf ${SRC_ARTIFACTS}/$1
+  else
+    echo Skipping $1 - It is not present on disk
+  fi
+}
+
+echo Restoring artifacts from $GENERATED_ARTIFACTS
+
+# Restore generated artifacts
 mv_if_exist dist.zip src/out/Default
 mv_if_exist node_headers.tar.gz src/out/Default/gen
 mv_if_exist symbols.zip src/out/Default
@@ -19,4 +32,9 @@ mv_if_exist mksnapshot.zip src/out/Default
 mv_if_exist chromedriver.zip src/out/Default
 mv_if_exist ffmpeg.zip src/out/ffmpeg
 mv_if_exist hunspell_dictionaries.zip src/out/Default
-mv_if_exist cross-arch-snapshots src
+mv_if_exist cross-arch-snapshots src
+
+echo Restoring artifacts from $SRC_ARTIFACTS
+
+# Restore src artifacts
+untar_if_exist src_artifacts.tar

+ 7 - 0
script/actions/run-tests.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+set -euo pipefail
+
+export DISPLAY=:99
+Xvfb :99 -screen 0 1024x768x16 -ac &
+XVFB_PID=$!
+node "$@"

+ 0 - 2
script/generate-deps-hash.js

@@ -36,12 +36,10 @@ addAllFiles(path.resolve(__dirname, '../patches'));
 // Create Hash
 const hasher = crypto.createHash('SHA256');
 const addToHashAndLog = (s) => {
-  console.log('Hashing:', s);
   return hasher.update(s);
 };
 addToHashAndLog(`HASH_VERSION:${HASH_VERSIONS[process.platform] || FALLBACK_HASH_VERSION}`);
 for (const file of filesToHash) {
-  console.log('Hashing Content:', file, crypto.createHash('SHA256').update(fs.readFileSync(file)).digest('hex'));
   hasher.update(fs.readFileSync(file));
 }
 

+ 12 - 8
script/lib/util.py

@@ -4,6 +4,7 @@ import contextlib
 import errno
 import json
 import os
+import platform
 import shutil
 import subprocess
 import sys
@@ -158,7 +159,7 @@ def azput(prefix, key_prefix, files):
   print(output)
 
 def get_out_dir():
-  out_dir = 'Debug'
+  out_dir = 'Default'
   override = os.environ.get('ELECTRON_OUT_DIR')
   if override is not None:
     out_dir = override
@@ -184,13 +185,16 @@ def get_electron_exec():
 
 def get_buildtools_executable(name):
   buildtools = os.path.realpath(os.path.join(ELECTRON_DIR, '..', 'buildtools'))
-  chromium_platform = {
-    'darwin': 'mac',
-    'linux': 'linux64',
-    'linux2': 'linux64',
-    'win32': 'win',
-    'cygwin': 'win',
-  }[sys.platform]
+
+  if sys.platform == 'darwin':
+    chromium_platform = 'mac_arm64' if platform.machine() == 'arm64' else 'mac'
+  elif sys.platform in ['win32', 'cygwin']:
+    chromium_platform = 'win'
+  elif sys.platform in ['linux', 'linux2']:
+    chromium_platform = 'linux64'
+  else:
+    raise Exception(f"Unsupported platform: {sys.platform}")
+
   if name == 'clang-format':
     path = os.path.join(buildtools, f"{chromium_platform}-format", name)  
   else:

+ 7 - 13
script/lib/utils.js

@@ -1,6 +1,5 @@
 const { GitProcess } = require('dugite');
 const fs = require('node:fs');
-const klaw = require('klaw');
 const os = require('node:os');
 const path = require('node:path');
 
@@ -130,18 +129,13 @@ function chunkFilenames (filenames, offset = 0) {
  * @returns {Promise<string[]>}
 */
 async function findMatchingFiles (top, test) {
-  return new Promise(resolve => {
-    const matches = [];
-    klaw(top, {
-      filter: f => path.basename(f) !== '.bin'
-    })
-      .on('end', () => resolve(matches))
-      .on('data', item => {
-        if (test(item.path)) {
-          matches.push(item.path);
-        }
-      });
-  });
+  return fs.promises.readdir(top, { encoding: 'utf8', recursive: true })
+    .then(files => {
+      return files
+        .filter(name => path.basename(name) !== '.bin')
+        .filter(name => test(name))
+        .map(name => path.join(top, name));
+    });
 }
 
 module.exports = {

+ 6 - 5
script/nan-spec-runner.js

@@ -90,16 +90,16 @@ async function main () {
     env.LDFLAGS = ldflags;
   }
 
-  const { status: buildStatus } = cp.spawnSync(NPX_CMD, ['node-gyp', 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
+  const { status: buildStatus, signal } = cp.spawnSync(NPX_CMD, ['node-gyp', 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
     env,
     cwd: NAN_DIR,
     stdio: 'inherit',
     shell: process.platform === 'win32'
   });
 
-  if (buildStatus !== 0) {
+  if (buildStatus !== 0 || signal != null) {
     console.error('Failed to build nan test modules');
-    return process.exit(buildStatus);
+    return process.exit(buildStatus !== 0 ? buildStatus : signal);
   }
 
   const { status: installStatus } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], {
@@ -108,9 +108,10 @@ async function main () {
     stdio: 'inherit',
     shell: process.platform === 'win32'
   });
-  if (installStatus !== 0) {
+
+  if (installStatus !== 0 || signal != null) {
     console.error('Failed to install nan node_modules');
-    return process.exit(installStatus);
+    return process.exit(installStatus !== 0 ? installStatus : signal);
   }
 
   const onlyTests = args.only && args.only.split(',');

+ 2 - 0
script/node-disabled-tests.json

@@ -4,6 +4,8 @@
   "parallel/test-bootstrap-modules",
   "parallel/test-child-process-fork-exec-path",
   "parallel/test-code-cache",
+  "parallel/test-cluster-primary-error",
+  "parallel/test-cluster-primary-kill",
   "parallel/test-crypto-aes-wrap",
   "parallel/test-crypto-authenticated-stream",
   "parallel/test-crypto-des3-wrap",

+ 2 - 1
script/release/ci-release-build.js

@@ -33,6 +33,7 @@ const circleCIPublishIndividualArches = {
 };
 
 const ghActionsPublishWorkflows = [
+  'linux-publish',
   'macos-publish'
 ];
 
@@ -92,7 +93,7 @@ async function githubActionsCall (targetBranch, workflowName, options) {
     }
 
     await octokit.request(`POST ${GH_ACTIONS_API_URL}/workflows/${workflowName}.yml/dispatches`, {
-      ref: buildRequest.branch,
+      ref: `refs/tags/${options.newVersion}`,
       inputs: {
         ...buildRequest.parameters
       },

+ 7 - 4
script/release/prepare-release.js

@@ -158,9 +158,10 @@ async function pushRelease (branch) {
   }
 }
 
-async function runReleaseBuilds (branch) {
+async function runReleaseBuilds (branch, newVersion) {
   await ciReleaseBuild(branch, {
-    ghRelease: true
+    ghRelease: true,
+    newVersion
   });
 }
 
@@ -190,6 +191,8 @@ async function verifyNewVersion () {
     console.log(`${fail} Aborting release of ${newVersion}`);
     process.exit();
   }
+
+  return newVersion;
 }
 
 async function promptForVersion (version) {
@@ -225,10 +228,10 @@ async function prepareRelease (isBeta, notesOnly) {
     } else {
       const changes = await changesToRelease();
       if (changes) {
-        await verifyNewVersion();
+        const newVersion = await verifyNewVersion();
         await createRelease(currentBranch, isBeta);
         await pushRelease(currentBranch);
-        await runReleaseBuilds(currentBranch);
+        await runReleaseBuilds(currentBranch, newVersion);
       } else {
         console.log('There are no new changes to this branch since the last release, aborting release.');
         process.exit(1);

+ 32 - 0
script/split-tests.js

@@ -0,0 +1,32 @@
+const fs = require('node:fs');
+const glob = require('glob');
+
+const currentShard = parseInt(process.argv[2], 10);
+const shardCount = parseInt(process.argv[3], 10);
+
+const specFiles = glob.sync('spec/*-spec.ts');
+
+const buckets = [];
+
+for (let i = 0; i < shardCount; i++) {
+  buckets.push([]);
+}
+
+const testsInSpecFile = Object.create(null);
+for (const specFile of specFiles) {
+  const testContent = fs.readFileSync(specFile, 'utf8');
+  testsInSpecFile[specFile] = testContent.split('it(').length;
+}
+
+specFiles.sort((a, b) => {
+  return testsInSpecFile[b] - testsInSpecFile[a];
+});
+
+let shard = 0;
+for (const specFile of specFiles) {
+  buckets[shard].push(specFile);
+  shard++;
+  if (shard === shardCount) shard = 0;
+}
+
+console.log(buckets[currentShard - 1].join(' '));

+ 11 - 4
shell/browser/api/electron_api_app.cc

@@ -1270,10 +1270,17 @@ std::vector<gin_helper::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
     auto pid_dict = gin_helper::Dictionary::CreateEmpty(isolate);
     auto cpu_dict = gin_helper::Dictionary::CreateEmpty(isolate);
 
-    double usage =
-        process_metric.second->metrics->GetPlatformIndependentCPUUsage()
-            .value_or(0);
-    cpu_dict.Set("percentCPUUsage", usage / processor_count);
+    // Default usage percentage to 0 for compatibility
+    double usagePercent = 0;
+    if (auto usage = process_metric.second->metrics->GetCumulativeCPUUsage();
+        usage.has_value()) {
+      cpu_dict.Set("cumulativeCPUUsage", usage->InSecondsF());
+      usagePercent =
+          process_metric.second->metrics->GetPlatformIndependentCPUUsage(
+              *usage);
+    }
+
+    cpu_dict.Set("percentCPUUsage", usagePercent / processor_count);
 
 #if !BUILDFLAG(IS_WIN)
     cpu_dict.Set("idleWakeupsPerSecond",

+ 4 - 0
shell/browser/api/electron_api_web_contents.cc

@@ -1893,6 +1893,8 @@ void WebContents::OnFirstNonEmptyLayout(
   }
 }
 
+namespace {
+
 // This object wraps the InvokeCallback so that if it gets GC'd by V8, we can
 // still call the callback and send an error. Not doing so causes a Mojo DCHECK,
 // since Mojo requires callbacks to be called before they are destroyed.
@@ -1949,6 +1951,8 @@ class ReplyChannel : public gin::Wrappable<ReplyChannel> {
 
 gin::WrapperInfo ReplyChannel::kWrapperInfo = {gin::kEmbedderNativeGin};
 
+}  // namespace
+
 gin::Handle<gin_helper::internal::Event> WebContents::MakeEventWithSender(
     v8::Isolate* isolate,
     content::RenderFrameHost* frame,

+ 5 - 0
shell/browser/browser.h

@@ -236,6 +236,10 @@ class Browser : private WindowListObserver {
   // Set docks' icon.
   void DockSetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon);
 
+  void SetLaunchedAtLogin(bool launched_at_login) {
+    was_launched_at_login_ = launched_at_login;
+  }
+
 #endif  // BUILDFLAG(IS_MAC)
 
   void ShowAboutPanel();
@@ -370,6 +374,7 @@ class Browser : private WindowListObserver {
 #if BUILDFLAG(IS_MAC)
   std::unique_ptr<ui::ScopedPasswordInputEnabler> password_input_enabler_;
   base::Time last_dock_show_;
+  bool was_launched_at_login_;
 #endif
 
   base::Value::Dict about_panel_options_;

+ 4 - 0
shell/browser/browser_linux.cc

@@ -25,6 +25,8 @@
 
 namespace electron {
 
+namespace {
+
 const char kXdgSettings[] = "xdg-settings";
 const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler";
 
@@ -84,6 +86,8 @@ bool SetDefaultWebClient(const std::string& protocol) {
   return ran_ok && exit_code == EXIT_SUCCESS;
 }
 
+}  // namespace
+
 void Browser::AddRecentDocument(const base::FilePath& path) {}
 
 void Browser::ClearRecentDocuments() {}

+ 2 - 0
shell/browser/browser_mac.mm

@@ -392,6 +392,7 @@ v8::Local<v8::Value> Browser::GetLoginItemSettings(
       platform_util::GetLoginItemEnabled(options.type, options.service_name);
   settings.open_at_login =
       status == "enabled" || status == "enabled-deprecated";
+  settings.opened_at_login = was_launched_at_login_;
   if (@available(macOS 13, *))
     settings.status = status;
 #else
@@ -405,6 +406,7 @@ v8::Local<v8::Value> Browser::GetLoginItemSettings(
       settings = settings_deprecated;
     } else {
       settings.open_at_login = status == "enabled";
+      settings.opened_at_login = was_launched_at_login_;
       settings.status = status;
     }
   } else {

+ 4 - 4
shell/browser/electron_browser_main_parts_linux.cc

@@ -18,6 +18,10 @@
 #include "shell/common/thread_restrictions.h"
 #endif
 
+namespace electron {
+
+namespace {
+
 constexpr std::string_view kElectronOzonePlatformHint{
     "ELECTRON_OZONE_PLATFORM_HINT"};
 
@@ -55,10 +59,6 @@ bool HasWaylandDisplay(base::Environment* env) {
 constexpr char kPlatformX11[] = "x11";
 #endif
 
-namespace electron {
-
-namespace {
-
 // Evaluates the environment and returns the effective platform name for the
 // given |ozone_platform_hint|.
 // For the "auto" value, returns "wayland" if the XDG session type is "wayland",

+ 2 - 2
shell/browser/hid/electron_hid_delegate.cc

@@ -46,8 +46,8 @@ class ElectronHidDelegate::ContextObservation
   ContextObservation(ElectronHidDelegate* parent,
                      content::BrowserContext* browser_context)
       : parent_(parent), browser_context_(browser_context) {
-    auto* chooser_context = GetChooserContext(browser_context_);
-    device_observation_.Observe(chooser_context);
+    if (auto* chooser_context = GetChooserContext(browser_context_))
+      device_observation_.Observe(chooser_context);
   }
 
   ContextObservation(ContextObservation&) = delete;

+ 3 - 6
shell/browser/javascript_environment.cc

@@ -124,13 +124,10 @@ JavascriptEnvironment::~JavascriptEnvironment() {
 v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
                                                bool setup_wasm_streaming) {
   auto* cmd = base::CommandLine::ForCurrentProcess();
-
   // --js-flags.
-  std::string js_flags =
-      cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags);
-  js_flags.append(" --no-freeze-flags-after-init");
-  if (!js_flags.empty())
-    v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
+  std::string js_flags = "--no-freeze-flags-after-init ";
+  js_flags.append(cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags));
+  v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
 
   // The V8Platform of gin relies on Chromium's task schedule, which has not
   // been started at this point, so we have to rely on Node's V8Platform.

+ 8 - 0
shell/browser/mac/electron_application_delegate.mm

@@ -84,6 +84,14 @@ static NSDictionary* UNNotificationResponseToNSDictionary(
     }
   }
 
+  NSAppleEventDescriptor* event =
+      NSAppleEventManager.sharedAppleEventManager.currentAppleEvent;
+  BOOL launched_as_login_item =
+      (event.eventID == kAEOpenApplication &&
+       [event paramDescriptorForKeyword:keyAEPropData].enumCodeValue ==
+           keyAELaunchedAsLogInItem);
+  electron::Browser::Get()->SetLaunchedAtLogin(launched_as_login_item);
+
   electron::Browser::Get()->DidFinishLaunching(
       electron::NSDictionaryToValue(notification_info));
 }

+ 3 - 2
shell/browser/ui/file_dialog_linux.cc

@@ -67,8 +67,9 @@ class FileChooserDialog : public ui::SelectFileDialog::Listener {
 
   ~FileChooserDialog() override = default;
 
-  gtk::ExtraSettings GetExtraSettings(const DialogSettings& settings) {
-    gtk::ExtraSettings extra;
+  ui::SelectFileDialogLinux::ExtraSettings GetExtraSettings(
+      const DialogSettings& settings) {
+    ui::SelectFileDialogLinux::ExtraSettings extra;
     extra.button_label = settings.button_label;
     extra.show_overwrite_confirmation =
         settings.properties & SAVE_DIALOG_SHOW_OVERWRITE_CONFIRMATION;

+ 2 - 1
shell/browser/usb/electron_usb_delegate.cc

@@ -94,7 +94,8 @@ class ElectronUsbDelegate::ContextObservation
                      content::BrowserContext* browser_context)
       : parent_(parent), browser_context_(browser_context) {
     auto* chooser_context = GetChooserContext(browser_context_);
-    device_observation_.Observe(chooser_context);
+    if (chooser_context)
+      device_observation_.Observe(chooser_context);
   }
   ContextObservation(ContextObservation&) = delete;
   ContextObservation& operator=(ContextObservation&) = delete;

+ 9 - 2
shell/common/api/electron_bindings.cc

@@ -274,8 +274,15 @@ v8::Local<v8::Value> ElectronBindings::GetCPUUsage(
     v8::Isolate* isolate) {
   auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
   int processor_count = base::SysInfo::NumberOfProcessors();
-  double usage = metrics->GetPlatformIndependentCPUUsage().value_or(0);
-  dict.Set("percentCPUUsage", usage / processor_count);
+
+  // Default usage percentage to 0 for compatibility
+  double usagePercent = 0;
+  if (auto usage = metrics->GetCumulativeCPUUsage(); usage.has_value()) {
+    dict.Set("cumulativeCPUUsage", usage->InSecondsF());
+    usagePercent = metrics->GetPlatformIndependentCPUUsage(*usage);
+  }
+
+  dict.Set("percentCPUUsage", usagePercent / processor_count);
 
   // NB: This will throw NOTIMPLEMENTED() on Windows
   // For backwards compatibility, we'll return 0

+ 5 - 0
shell/common/gin_converters/net_converter.cc

@@ -250,6 +250,8 @@ bool Converter<net::HttpRequestHeaders>::FromV8(v8::Isolate* isolate,
   return true;
 }
 
+namespace {
+
 class ChunkedDataPipeReadableStream
     : public gin::Wrappable<ChunkedDataPipeReadableStream> {
  public:
@@ -489,9 +491,12 @@ class ChunkedDataPipeReadableStream
   v8::Global<v8::ArrayBufferView> buf_;
   gin_helper::Promise<int> promise_;
 };
+
 gin::WrapperInfo ChunkedDataPipeReadableStream::kWrapperInfo = {
     gin::kEmbedderNativeGin};
 
+}  // namespace
+
 // static
 v8::Local<v8::Value> Converter<network::ResourceRequestBody>::ToV8(
     v8::Isolate* isolate,

+ 1 - 1
shell/common/platform_util_mac.mm

@@ -111,7 +111,7 @@ std::string GetLaunchStringForError(NSError* error) {
         return "The specified path doesn't exist or the helper tool at the "
                "specified path isn't valid";
       default:
-        return "Failed to register the login item";
+        return base::SysNSStringToUTF8([error localizedDescription]);
     }
   }
 

+ 15 - 9
shell/renderer/electron_renderer_client.cc

@@ -110,19 +110,25 @@ void ElectronRendererClient::DidCreateScriptContext(
       base::BindRepeating(&ElectronRendererClient::UndeferLoad,
                           base::Unretained(this), render_frame));
 
-  v8::Local<v8::Object> global = renderer_context->Global();
-  v8::MaybeLocal<v8::Value> fetch =
-      global->Get(renderer_context, gin::StringToV8(env->isolate(), "fetch"));
-
   // We need to use the Blink implementation of fetch in the renderer process
   // Node.js deletes the global fetch function when their fetch implementation
   // is disabled, so we need to save and re-add it after the Node.js environment
   // is loaded. See corresponding change in node/init.ts.
-  if (!fetch.IsEmpty()) {
-    global
-        ->Set(renderer_context, gin::StringToV8(env->isolate(), "blinkFetch"),
-              fetch.ToLocalChecked())
-        .Check();
+  v8::Isolate* isolate = env->isolate();
+  v8::Local<v8::Object> global = renderer_context->Global();
+
+  std::vector<std::string> keys = {"fetch", "Response", "FormData", "Request",
+                                   "Headers"};
+  for (const auto& key : keys) {
+    v8::MaybeLocal<v8::Value> value =
+        global->Get(renderer_context, gin::StringToV8(isolate, key.c_str()));
+    if (!value.IsEmpty()) {
+      std::string blink_key = "blink" + key;
+      global
+          ->Set(renderer_context, gin::StringToV8(isolate, blink_key.c_str()),
+                value.ToLocalChecked())
+          .Check();
+    }
   }
 
   // If we have disabled the site instance overrides we should prevent loading

+ 2 - 1
spec/api-app-spec.ts

@@ -595,7 +595,7 @@ describe('app module', () => {
     });
   });
 
-  ifdescribe(process.platform !== 'linux' && !process.mas)('app.get/setLoginItemSettings API', function () {
+  ifdescribe(process.platform !== 'linux' && !process.mas && (process.platform !== 'darwin' || process.arch === 'arm64'))('app.get/setLoginItemSettings API', function () {
     const isMac = process.platform === 'darwin';
     const isWin = process.platform === 'win32';
 
@@ -1442,6 +1442,7 @@ describe('app module', () => {
 
         types.push(entry.type);
         expect(entry.cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number');
+        expect(entry.cpu).to.have.ownProperty('cumulativeCPUUsage').that.is.a('number');
         expect(entry.cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number');
 
         expect(entry.memory).to.have.property('workingSetSize').that.is.greaterThan(0);

+ 12 - 2
spec/api-content-tracing-spec.ts

@@ -25,7 +25,12 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
   });
 
   describe('startRecording', function () {
-    this.timeout(5e3);
+    if (process.platform === 'win32' && process.arch === 'arm64') {
+      // WOA needs more time
+      this.timeout(10e3);
+    } else {
+      this.timeout(5e3);
+    }
 
     const getFileSizeInKiloBytes = (filePath: string) => {
       const stats = fs.statSync(filePath);
@@ -84,7 +89,12 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
   });
 
   describe('stopRecording', function () {
-    this.timeout(5e3);
+    if (process.platform === 'win32' && process.arch === 'arm64') {
+      // WOA needs more time
+      this.timeout(10e3);
+    } else {
+      this.timeout(5e3);
+    }
 
     it('does not crash on empty string', async () => {
       const options = {

+ 2 - 0
spec/api-process-spec.ts

@@ -26,6 +26,7 @@ describe('process module', () => {
       it('returns a cpu usage object', async () => {
         const cpuUsage = await w.webContents.executeJavaScript('process.getCPUUsage()');
         expect(cpuUsage.percentCPUUsage).to.be.a('number');
+        expect(cpuUsage.cumulativeCPUUsage).to.be.a('number');
         expect(cpuUsage.idleWakeupsPerSecond).to.be.a('number');
       });
     });
@@ -124,6 +125,7 @@ describe('process module', () => {
       it('returns a cpu usage object', () => {
         const cpuUsage = process.getCPUUsage();
         expect(cpuUsage.percentCPUUsage).to.be.a('number');
+        expect(cpuUsage.cumulativeCPUUsage).to.be.a('number');
         expect(cpuUsage.idleWakeupsPerSecond).to.be.a('number');
       });
     });

+ 1 - 1
spec/api-protocol-spec.ts

@@ -1749,7 +1749,7 @@ describe('protocol module', () => {
         const end = Date.now();
         return end - begin;
       })();
-      expect(interceptedTime).to.be.lessThan(rawTime * 1.5);
+      expect(interceptedTime).to.be.lessThan(rawTime * 1.6);
     });
   });
 });

+ 1 - 1
spec/lib/codesign-helpers.ts

@@ -8,7 +8,7 @@ const fixturesPath = path.resolve(__dirname, '..', 'fixtures');
 
 export const shouldRunCodesignTests =
     process.platform === 'darwin' &&
-    !(process.env.CI && process.arch === 'arm64') &&
+    !process.env.CI &&
     !process.mas &&
     !features.isComponentBuild();
 

+ 13 - 20
yarn.lock

@@ -199,10 +199,10 @@
     "@octokit/auth-app" "^4.0.13"
     "@octokit/rest" "^19.0.11"
 
-"@electron/lint-roller@^2.1.0":
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/@electron/lint-roller/-/lint-roller-2.1.0.tgz#984ec017c8d512e77e34749e7f6dc965aec8de06"
-  integrity sha512-Oxt7CHq7FNujOi5g0nYq3hwVvspnDk/DCp7C+52pHi3Ez7P85K8dY3QlGtm9Dpswm3t7SJmk6m1pfFzXWre1dg==
+"@electron/lint-roller@^2.2.0":
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/@electron/lint-roller/-/lint-roller-2.2.0.tgz#3390ea37868b1ac35863cd393ddf776d049a2e3c"
+  integrity sha512-gYOwL7p3vXJjzndzW0ewnYuBz+WcNOGCbqNBJLmoVwimHGdNJ7cdh9/AwAggcjHEPO/zpRMfpfhUM7shNPagCQ==
   dependencies:
     "@dsanders11/vscode-markdown-languageservice" "^0.3.0"
     balanced-match "^2.0.0"
@@ -880,13 +880,6 @@
   dependencies:
     "@types/node" "*"
 
-"@types/klaw@^3.0.1":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@types/klaw/-/klaw-3.0.1.tgz#29f90021c0234976aa4eb97efced9cb6db9fa8b3"
-  integrity sha512-acnF3n9mYOr1aFJKFyvfNX0am9EtPUsYPq22QUCGdJE+MVt6UyAN1jwo+PmOPqXD4K7ZS9MtxDEp/un0lxFccA==
-  dependencies:
-    "@types/node" "*"
-
 "@types/linkify-it@*":
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806"
@@ -3348,7 +3341,7 @@ got@^11.8.5:
     p-cancelable "^2.0.0"
     responselike "^2.0.0"
 
-graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
   version "4.2.10"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
   integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
@@ -4016,13 +4009,6 @@ kind-of@^6.0.2:
   resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
   integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
 
-klaw@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146"
-  integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==
-  dependencies:
-    graceful-fs "^4.1.9"
-
 kleur@^4.0.3:
   version "4.1.5"
   resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
@@ -6609,7 +6595,7 @@ stringify-object@^3.3.0:
     is-obj "^1.0.1"
     is-regexp "^1.0.0"
 
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
   integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -6630,6 +6616,13 @@ strip-ansi@^6.0.0:
   dependencies:
     ansi-regex "^5.0.0"
 
+strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
 strip-ansi@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.0.tgz#1dc49b980c3a4100366617adac59327eefdefcb0"