Browse Source

ci: update to CircleCI v2 config and APIs (#22330)

* build: update release build endpoint from /jobs to /job (#21232)

(cherry picked from commit 41f1569c465c85cb20edd34b95a69b25829e1a53)

* chore: workflows and pipeline state were split in the circle API (#21441)

(cherry picked from commit ec0edb757ae1734b48f4c918edfdce25d51dec15)

* ci: Update to CircleCI v2 config and APIs

This reverts commit e6807b387c9240dc4516c0fcaa5509db89bc5bda.

* fixup config.yml

* Add needed script

* Fixup circleci config

* Partial backport of e9114b3c00b7b50cab96d18b9dd187f37ba603e3

Needed for v2 circleci changes.

* Manually run update-external-binaries.py

* Use new cache key

* Move update external binaries to separate step

* Fix debug builds

* Download external binaries for release

Co-authored-by: Samuel Attard <[email protected]>
Co-authored-by: John Kleinschmidt <[email protected]>
trop[bot] 5 years ago
parent
commit
3b1a452406
4 changed files with 485 additions and 108 deletions
  1. 317 81
      .circleci/config.yml
  2. 10 8
      DEPS
  3. 120 19
      script/ci-release-build.js
  4. 38 0
      script/generate-deps-hash.js

+ 317 - 81
.circleci/config.yml

@@ -1,3 +1,46 @@
+version: 2.1
+
+parameters:
+  upload-to-s3:
+    type: string
+    default: '1'
+  
+  run-lint:
+    type: boolean
+    default: true
+
+  run-build-linux:
+    type: boolean
+    default: true
+
+  run-build-mac:
+    type: boolean
+    default: true
+
+  run-linux-x64-publish:
+    type: boolean
+    default: false
+
+  run-linux-ia32-publish:
+    type: boolean
+    default: false
+
+  run-linux-arm-publish:
+    type: boolean
+    default: false
+  
+  run-linux-arm64-publish:
+    type: boolean
+    default: false
+  
+  run-osx-publish:
+    type: boolean
+    default: false
+
+  run-mas-publish:
+    type: boolean
+    default: false
+
 # The config expects the following environment variables to be set:
 #  - "SLACK_WEBHOOK" Slack hook URL to send notifications.
 #
@@ -86,7 +129,7 @@ env-enable-sccache: &env-enable-sccache
 
 env-send-slack-notifications: &env-send-slack-notifications
   NOTIFY_SLACK: true
-  
+
 env-global: &env-global
   ELECTRON_OUT_DIR: Default
 
@@ -162,16 +205,15 @@ step-gclient-sync: &step-gclient-sync
   run:
     name: Gclient sync
     command: |
-      gclient config \
+      # If we did not restore a complete sync then we need to sync for realz
+      if [ ! -s "src/electron/.circle-sync-done" ]; then
+        gclient config \
         --name "src/electron" \
         --unmanaged \
         $GCLIENT_EXTRA_ARGS \
         "$CIRCLE_REPOSITORY_URL"
-
-      gclient sync --with_branch_heads --with_tags
-      
-      # Manually run update-external-binaries.py with system python
-      python src/electron/script/update-external-binaries.py
+        gclient sync --with_branch_heads --with_tags
+      fi
 
 step-setup-env-for-build: &step-setup-env-for-build
   run:
@@ -198,6 +240,13 @@ step-restore-brew-cache: &step-restore-brew-cache
     keys:
       - v1-brew-cache-{{ arch }}
 
+step-save-brew-cache: &step-save-brew-cache
+  save_cache:
+    paths:
+      - /usr/local/Homebrew
+    key: v1-brew-cache-{{ arch }}
+    name: Persisting brew cache
+
 step-get-more-space-on-mac: &step-get-more-space-on-mac
   run:
     name: Free up space on MacOS
@@ -237,11 +286,16 @@ step-fix-sync-on-mac: &step-fix-sync-on-mac
         # Fix Clang Install (wrong binary)
         rm -rf src/third_party/llvm-build
         python src/tools/clang/scripts/update.py
-        # Fix Framework Header Installs (symlinks not retained)
-        rm -rf src/electron/external_binaries
-        python src/electron/script/update-external-binaries.py
       fi
 
+# Manually run update-external-binaries.py with system python
+step-fixup-external-binaries: &step-fixup-external-binaries
+  run:
+    name: Update external binaries
+    command: |
+      rm -rf src/electron/external_binaries
+      python src/electron/script/update-external-binaries.py
+
 step-install-signing-cert-on-mac: &step-install-signing-cert-on-mac
   run:
     name: Import and trust self-signed codesigning cert on MacOS
@@ -554,6 +608,93 @@ step-fix-known-hosts-linux: &step-fix-known-hosts-linux
         ./src/electron/.circleci/fix-known-hosts.sh
       fi
 
+# Checkout Steps
+step-generate-deps-hash: &step-generate-deps-hash
+  run:
+    name: Generate DEPS Hash
+    command: node src/electron/script/generate-deps-hash.js
+
+step-touch-sync-done: &step-touch-sync-done
+  run:
+    name: Touch Sync Done
+    command: touch src/electron/.circle-sync-done
+
+# Restore exact src cache based on the hash of DEPS and patches/*
+# If no cache is matched EXACTLY then the .circle-sync-done file is empty
+# If a cache is matched EXACTLY then the .circle-sync-done file contains "done"
+step-maybe-restore-src-cache: &step-maybe-restore-src-cache
+  restore_cache:
+    paths:
+      - ./src
+    keys:
+      - v5-src-cache-{{ arch }}-{{ checksum "src/electron/.depshash" }}
+    name: Restoring src cache
+
+# Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done
+# If the src cache was restored above then this will match an empty cache
+# If the src cache was not restored above then this will match a close git cache
+step-maybe-restore-git-cache: &step-maybe-restore-git-cache
+  restore_cache:
+    paths:
+      - ~/.gclient-cache
+    keys:
+      - v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
+      - v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}
+    name: Conditionally restoring git cache
+
+step-set-git-cache-path: &step-set-git-cache-path
+  run:
+    name: Set GIT_CACHE_PATH to make gclient to use the cache
+    command: |
+      # CircleCI does not support interpolation when setting environment variables.
+      # https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-shell-command
+      echo 'export GIT_CACHE_PATH="$HOME/.gclient-cache"' >> $BASH_ENV
+
+# Persist the git cache based on the hash of DEPS and .circle-sync-done
+# If the src cache was restored above then this will persist an empty cache
+step-save-git-cache: &step-save-git-cache
+  save_cache:
+    paths:
+      - ~/.gclient-cache
+    key: v2-gclient-cache-{{ arch }}-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }}
+    name: Persisting git cache
+
+step-run-electron-only-hooks: &step-run-electron-only-hooks
+  run:
+    name: Run Electron Only Hooks
+    command: gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
+
+step-generate-deps-hash-cleanly: &step-generate-deps-hash-cleanly
+  run:
+    name: Generate DEPS Hash
+    command: (cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js
+
+# Mark the sync as done for future cache saving
+step-mark-sync-done: &step-mark-sync-done
+  run:
+    name: Mark Sync Done
+    command: echo DONE > src/electron/.circle-sync-done
+
+# Minimize the size of the cache
+step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-checkout
+  run:
+    name: Remove some unused data to avoid storing it in the workspace/cache
+    command: |
+      rm -rf src/android_webview
+      rm -rf src/ios
+      rm -rf src/third_party/blink/web_tests
+      rm -rf src/third_party/blink/perf_tests
+      rm -rf src/third_party/hunspell_dictionaries
+      rm -rf src/third_party/WebKit/LayoutTests
+
+# Save the src cache based on the deps hash
+step-save-src-cache: &step-save-src-cache
+  save_cache:
+    paths:
+      - ./src
+    key: v5-src-cache-{{ arch }}-{{ checksum "src/electron/.depshash" }}
+    name: Persisting src cache
+
 # Lists of steps.
 steps-lint: &steps-lint
   steps:
@@ -570,7 +711,7 @@ steps-lint: &steps-lint
           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
+          cipd ensure -ensure-file - -root . \<<-CIPD
           \$ServiceURL https://chrome-infra-packages.appspot.com/
           @Subdir buildtools/linux64
           gn/gn/linux-amd64 $gn_version
@@ -590,7 +731,7 @@ steps-lint: &steps-lint
           node script/yarn install
           node script/yarn lint
 
-steps-checkout: &steps-checkout
+steps-checkout-fast: &steps-checkout-fast
   steps:
     - *step-checkout-electron
     - *step-depot-tools-get
@@ -599,40 +740,57 @@ steps-checkout: &steps-checkout
     - *step-get-more-space-on-mac
     - *step-install-gnutar-on-mac
 
-    - restore_cache:
-        paths:
-          - ~/.gclient-cache
-        keys:
-          - v1-gclient-cache-{{ arch }}-{{ checksum "src/electron/DEPS" }}
-          - v1-gclient-cache-{{ arch }}-
-    - run:
-        name: Set GIT_CACHE_PATH to make gclient to use the cache
-        command: |
-          # CircleCI does not support interpolation when setting environment variables.
-          # https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-shell-command
-          echo 'export GIT_CACHE_PATH="$HOME/.gclient-cache"' >> $BASH_ENV
+    - *step-generate-deps-hash
+    - *step-touch-sync-done
+    - *step-maybe-restore-src-cache
+    - *step-maybe-restore-git-cache
+    - *step-set-git-cache-path
+    # This sync call only runs if .circle-sync-done is an EMPTY file
     - *step-gclient-sync
-    - save_cache:
-        paths:
-          - ~/.gclient-cache
-        key: v1-gclient-cache-{{ arch }}-{{ checksum "src/electron/DEPS" }}
-    - save_cache:
-        paths:
-          - /usr/local/Homebrew
-        key: v1-brew-cache-{{ arch }}
-
+    # These next few steps reset Electron to the correct commit regardless of which cache was restored
     - run:
-        name: Remove some unused data to avoid storing it in the workspace
-        command: |
-          rm -rf src/android_webview
-          rm -rf src/ios
-          rm -rf src/third_party/WebKit/LayoutTests
+        name: Wipe Electron
+        command: rm -rf src/electron
+    - *step-checkout-electron
+    - *step-run-electron-only-hooks
+    - *step-generate-deps-hash-cleanly
+    - *step-mark-sync-done
+    - *step-minimize-workspace-size-from-checkout
     - persist_to_workspace:
         root: .
         paths:
           - depot_tools
           - src
 
+steps-checkout-and-save-cache: &steps-checkout-and-save-cache
+  steps:
+    - *step-checkout-electron
+    - *step-depot-tools-get
+    - *step-depot-tools-add-to-path
+    - *step-restore-brew-cache
+    - *step-get-more-space-on-mac
+    - *step-install-gnutar-on-mac
+
+    - *step-generate-deps-hash
+    - *step-touch-sync-done
+    - *step-maybe-restore-src-cache
+    - *step-maybe-restore-git-cache
+    - *step-set-git-cache-path
+    # This sync call only runs if .circle-sync-done is an EMPTY file
+    - *step-gclient-sync
+    - *step-save-git-cache
+    # These next few steps reset Electron to the correct commit regardless of which cache was restored
+    - run:
+        name: Wipe Electron
+        command: rm -rf src/electron
+    - *step-checkout-electron
+    - *step-run-electron-only-hooks
+    - *step-generate-deps-hash-cleanly
+    - *step-mark-sync-done
+    - *step-minimize-workspace-size-from-checkout
+    - *step-save-src-cache
+    - *step-save-brew-cache
+
 steps-electron-gn-check: &steps-electron-gn-check
   steps:
     - attach_workspace:
@@ -648,6 +806,7 @@ steps-electron-build: &steps-electron-build
         at: .
     - *step-depot-tools-add-to-path
     - *step-setup-env-for-build
+    - *step-fixup-external-binaries
     - *step-gn-gen-default
 
     # Electron app
@@ -671,6 +830,7 @@ steps-electron-build-for-tests: &steps-electron-build-for-tests
     - *step-get-more-space-on-mac
     - *step-install-npm-deps-on-mac
     - *step-fix-sync-on-mac
+    - *step-fixup-external-binaries
     - *step-gn-gen-default
     - *step-delete-git-directories
 
@@ -716,6 +876,7 @@ steps-electron-build-for-publish: &steps-electron-build-for-publish
     - *step-restore-brew-cache
     - *step-get-more-space-on-mac
     - *step-gclient-sync
+    - *step-fixup-external-binaries
     - *step-setup-env-for-build
     - *step-gn-gen-default
     - *step-delete-git-directories
@@ -758,6 +919,7 @@ steps-chromedriver-build: &steps-chromedriver-build
     - *step-depot-tools-add-to-path
     - *step-setup-env-for-build
     - *step-fix-sync-on-mac
+    - *step-fixup-external-binaries
     - *step-gn-gen-default
 
     - *step-electron-chromedriver-build
@@ -866,7 +1028,6 @@ chromium-upgrade-branches: &chromium-upgrade-branches
   /chromium\-upgrade\/[0-9]+/
 
 # List of all jobs.
-version: 2
 jobs:
   # Layer 0: Lint. Standalone.
   lint:
@@ -876,33 +1037,47 @@ jobs:
     <<: *steps-lint
 
   # Layer 1: Checkout.
-  linux-checkout:
+  linux-checkout-fast:
     <<: *machine-linux-2xlarge
     environment:
       <<: *env-linux-2xlarge
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
-    <<: *steps-checkout
+    <<: *steps-checkout-fast
+
+  linux-checkout-and-save-cache:
+    <<: *machine-linux-2xlarge
+    environment:
+      <<: *env-linux-2xlarge
+      GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
+    <<: *steps-checkout-and-save-cache
 
   linux-checkout-for-native-tests:
     <<: *machine-linux-2xlarge
     environment:
       <<: *env-linux-2xlarge
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_pyyaml=True'
-    <<: *steps-checkout
+    <<: *steps-checkout-fast
 
   linux-checkout-for-native-tests-with-no-patches:
     <<: *machine-linux-2xlarge
     environment:
       <<: *env-linux-2xlarge
       GCLIENT_EXTRA_ARGS: '--custom-var=apply_patches=False --custom-var=checkout_pyyaml=True'
-    <<: *steps-checkout
+    <<: *steps-checkout-fast
+
+  mac-checkout-fast:
+    <<: *machine-linux-2xlarge
+    environment:
+      <<: *env-linux-2xlarge
+      GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
+    <<: *steps-checkout-fast
 
-  mac-checkout:
+  mac-checkout-and-save-cache:
     <<: *machine-linux-2xlarge
     environment:
       <<: *env-linux-2xlarge
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
-    <<: *steps-checkout
+    <<: *steps-checkout-and-save-cache
 
   # Layer 2: Builds.
   linux-x64-debug:
@@ -959,6 +1134,8 @@ jobs:
       <<: *env-linux-2xlarge-release
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
       <<: *env-release-build
+      <<: *env-enable-sccache
+      UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
     <<: *steps-electron-build-for-publish
 
   linux-ia32-debug:
@@ -1006,6 +1183,8 @@ jobs:
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
       <<: *env-ia32
       <<: *env-release-build
+      <<: *env-enable-sccache
+      UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
     <<: *steps-electron-build-for-publish
 
   linux-arm-debug:
@@ -1053,7 +1232,9 @@ jobs:
       <<: *env-linux-2xlarge-release
       <<: *env-arm
       <<: *env-release-build
+      <<: *env-enable-sccache
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_boto=True --custom-var=checkout_requests=True'
+      UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
     <<: *steps-electron-build-for-publish
 
   linux-arm64-debug:
@@ -1117,7 +1298,9 @@ jobs:
       <<: *env-linux-2xlarge-release
       <<: *env-arm64
       <<: *env-release-build
+      <<: *env-enable-sccache
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm64=True --custom-var=checkout_boto=True --custom-var=checkout_requests=True'
+      UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
     <<: *steps-electron-build-for-publish
 
   osx-testing:
@@ -1172,7 +1355,9 @@ jobs:
     environment:
       <<: *env-mac-large-release
       <<: *env-release-build
+      <<: *env-enable-sccache
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
+      UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
     <<: *steps-electron-build-for-publish
 
   mas-testing:
@@ -1233,7 +1418,9 @@ jobs:
       <<: *env-mac-large-release
       <<: *env-mas
       <<: *env-release-build
+      <<: *env-enable-sccache
       GCLIENT_EXTRA_ARGS: '--custom-var=checkout_boto=True --custom-var=checkout_requests=True'
+      UPLOAD_TO_S3: << pipeline.parameters.upload-to-s3 >>
     <<: *steps-electron-build-for-publish
 
   # Layer 3: Tests.
@@ -1455,78 +1642,127 @@ jobs:
 
 workflows:
   version: 2
+
+  # The publish workflows below each contain one job so that they are 
+  # compatible with how sudowoodo works today.  If these workflows are
+  # changed to have multiple jobs, then scripts/release/ci-release-build.js
+  # will need to be updated and there will most likely need to be changes to
+  # sudowoodo
+
+  publish-x64-linux:
+    when: << pipeline.parameters.run-linux-x64-publish >>
+    jobs:
+    - linux-x64-publish:
+        context: release-env
+
+  publish-ia32-linux:
+    when: << pipeline.parameters.run-linux-ia32-publish >>
+    jobs:
+    - linux-ia32-publish:
+        context: release-env
+
+  publish-arm-linux:
+    when: << pipeline.parameters.run-linux-arm-publish >>
+    jobs:
+    - linux-arm-publish:
+        context: release-env
+  
+  publish-arm64-linux:
+    when: << pipeline.parameters.run-linux-arm64-publish >>
+    jobs:
+    - linux-arm64-publish:
+        context: release-env
+  
+  publish-osx:
+    when: << pipeline.parameters.run-osx-publish >>
+    jobs:
+    - osx-publish:
+        context: release-env
+
+  publish-mas:
+    when: << pipeline.parameters.run-mas-publish >>
+    jobs:
+    - mas-publish:
+        context: release-env
+
   lint:
+    when: << pipeline.parameters.run-lint >>
     jobs:
       - lint
 
   build-linux:
+    when: << pipeline.parameters.run-build-linux >>
     jobs:
-      - linux-checkout
+      - linux-checkout-fast
+      - linux-checkout-and-save-cache
 
       - linux-x64-debug:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-x64-debug-gn-check:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-x64-testing:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-x64-testing-gn-check:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-x64-testing-tests:
           requires:
             - linux-x64-testing
 
       - linux-ia32-debug:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-ia32-testing:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-ia32-testing-tests:
           requires:
             - linux-ia32-testing
 
       - linux-arm-debug:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm-testing:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
 
       - linux-arm64-debug:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm64-debug-gn-check:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm64-testing:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm64-testing-gn-check:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
 
   build-mac:
+    when: << pipeline.parameters.run-build-mac >>
     jobs:
-      - mac-checkout
+      - mac-checkout-fast
+      - mac-checkout-and-save-cache
+
       - osx-testing:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - osx-debug:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - osx-debug-gn-check:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - osx-testing-gn-check:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - osx-testing-tests:
           requires:
@@ -1534,19 +1770,19 @@ workflows:
 
       - mas-testing:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - mas-debug:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - mas-debug-gn-check:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - mas-testing-gn-check:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
 
       - mas-testing-tests:
           requires:
@@ -1562,11 +1798,11 @@ workflows:
                 - master
                 - *chromium-upgrade-branches
     jobs:
-      - linux-checkout
+      - linux-checkout-fast
 
       - linux-x64-release:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-x64-release-tests:
           requires:
             - linux-x64-release
@@ -1578,7 +1814,7 @@ workflows:
             - linux-x64-release
       - linux-x64-chromedriver:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-x64-release-summary:
           requires:
             - linux-x64-release
@@ -1588,7 +1824,7 @@ workflows:
 
       - linux-ia32-release:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-ia32-release-tests:
           requires:
             - linux-ia32-release
@@ -1600,7 +1836,7 @@ workflows:
             - linux-ia32-release
       - linux-ia32-chromedriver:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-ia32-release-summary:
           requires:
             - linux-ia32-release
@@ -1610,10 +1846,10 @@ workflows:
 
       - linux-arm-release:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm-chromedriver:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm-release-summary:
           requires:
             - linux-arm-release
@@ -1622,10 +1858,10 @@ workflows:
 
       - linux-arm64-release:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm64-chromedriver:
           requires:
-            - linux-checkout
+            - linux-checkout-fast
       - linux-arm64-release-summary:
           requires:
             - linux-arm64-release
@@ -1641,11 +1877,11 @@ workflows:
                 - master
                 - *chromium-upgrade-branches
     jobs:
-      - mac-checkout
+      - mac-checkout-fast
 
       - osx-release:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
       - osx-release-tests:
           requires:
             - osx-release
@@ -1657,7 +1893,7 @@ workflows:
             - osx-release
       - osx-chromedriver:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
       - osx-release-summary:
           requires:
           - osx-release
@@ -1667,7 +1903,7 @@ workflows:
 
       - mas-release:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
       - mas-release-tests:
           requires:
             - mas-release
@@ -1679,7 +1915,7 @@ workflows:
             - mas-release
       - mas-chromedriver:
           requires:
-            - mac-checkout
+            - mac-checkout-fast
       - mas-release-summary:
           requires:
           - mas-release

+ 10 - 8
DEPS

@@ -47,6 +47,8 @@ vars = {
   # Python "requests" module is used for releases only.
   'checkout_requests': False,
 
+  # To allow running hooks without parsing the DEPS tree
+  'process_deps': True,
   # It is always needed for normal Electron builds,
   # but might be impossible for custom in-house builds.
   'download_external_binaries': False,
@@ -68,30 +70,30 @@ vars = {
 deps = {
   'src': {
     'url': (Var("chromium_git")) + '/chromium/src.git@' + (Var("chromium_version")),
-    'condition': 'checkout_chromium',
+    'condition': 'checkout_chromium and process_deps',
   },
   'src/third_party/electron_node': {
     'url': (Var("nodejs_git")) + '/node.git@' + (Var("node_version")),
-    'condition': 'checkout_node',
+    'condition': 'checkout_node and process_deps',
   },
   'src/electron/vendor/pyyaml': {
     'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")),
-    'condition': 'checkout_pyyaml',
+    'condition': 'checkout_pyyaml and process_deps',
   },
   'src/electron/vendor/boto': {
     'url': Var('boto_git') + '/boto.git' + '@' +  Var('boto_version'),
-    'condition': 'checkout_boto',
+    'condition': 'checkout_boto and process_deps',
   },
   'src/electron/vendor/requests': {
     'url': Var('requests_git') + '/requests.git' + '@' +  Var('requests_version'),
-    'condition': 'checkout_requests',
+    'condition': 'checkout_requests and process_deps',
   },
 }
 
 hooks = [
   {
     'name': 'patch_chromium',
-    'condition': 'checkout_chromium and apply_patches',
+    'condition': '(checkout_chromium and apply_patches) and process_deps',
     'pattern': 'src/electron',
     'action': [
       'python',
@@ -130,7 +132,7 @@ hooks = [
   {
     'name': 'setup_boto',
     'pattern': 'src/electron',
-    'condition': 'checkout_boto',
+    'condition': 'checkout_boto and process_deps',
     'action': [
       'python',
       '-c',
@@ -140,7 +142,7 @@ hooks = [
   {
     'name': 'setup_requests',
     'pattern': 'src/electron',
-    'condition': 'checkout_requests',
+    'condition': 'checkout_requests and process_deps',
     'action': [
       'python',
       '-c',

+ 120 - 19
script/ci-release-build.js

@@ -2,8 +2,11 @@ if (!process.env.CI) require('dotenv-safe').load()
 
 const assert = require('assert')
 const request = require('request')
-const buildAppVeyorURL = 'https://ci.appveyor.com/api/builds'
-const vstsURL = 'https://github.visualstudio.com/electron/_apis/build'
+
+const BUILD_APPVEYOR_URL = 'https://ci.appveyor.com/api/builds'
+const CIRCLECI_PIPELINE_URL = 'https://circleci.com/api/v2/project/gh/electron/electron/pipeline'
+const VSTS_URL = 'https://github.visualstudio.com/electron/_apis/build'
+const CIRCLECI_WAIT_TIME = process.env.CIRCLECI_WAIT_TIME || 30000
 
 const appVeyorJobs = {
   'electron-x64': 'electron-x64-release',
@@ -55,30 +58,129 @@ async function makeRequest (requestOptions, parseResponse) {
   })
 }
 
-async function circleCIcall (buildUrl, targetBranch, job, options) {
+async function circleCIcall (targetBranch, job, options) {
   console.log(`Triggering CircleCI to run build job: ${job} on branch: ${targetBranch} with release flag.`)
   const buildRequest = {
-    'build_parameters': {
-      'CIRCLE_JOB': job
+    'branch': targetBranch,
+    'parameters': {
+      'run-lint': false,
+      'run-build-linux': false,
+      'run-build-mac': false
     }
   }
-
-  if (!options.ghRelease) {
-    buildRequest.build_parameters.UPLOAD_TO_S3 = 1
+  if (options.ghRelease) {
+    buildRequest.parameters['upload-to-s3'] = '0'
+  } else {
+    buildRequest.parameters['upload-to-s3'] = '1'
   }
+  buildRequest.parameters[`run-${job}`] = true
   jobRequestedCount++
-  const circleResponse = await makeRequest({
-    method: 'POST',
-    url: buildUrl,
+  // The logic below expects that the CircleCI workflows for releases each
+  // contain only one job in order to maintain compatibility with sudowoodo.
+  // If the workflows are changed in the CircleCI config.yml, this logic will
+  // also need to be changed as well as possibly changing sudowoodo.
+  try {
+    const circleResponse = await circleCIRequest(CIRCLECI_PIPELINE_URL, 'POST', buildRequest)
+    console.log(`CircleCI release build pipeline ${circleResponse.id} for ${job} triggered.`)
+    const pipelineInfoUrl = `https://circleci.com/api/v2/pipeline/${circleResponse.id}`
+    const workflowId = await getCircleCIWorkflowId(circleResponse.id)
+    if (workflowId === -1) {
+      return
+    }
+    console.log(`CircleCI release build workflow running at https://circleci.com/workflow-run/${workflowId} for ${job}.`)
+    const jobNumber = await getCircleCIJobNumber(workflowId)
+    if (jobNumber === -1) {
+      return
+    }
+    const jobUrl = `https://circleci.com/gh/electron/electron/${jobNumber}`
+    console.log(`CircleCI release build request for ${job} successful.  Check ${jobUrl} for status.`)
+  } catch (err) {
+    console.log('Error calling CircleCI: ', err)
+  }
+}
+
+async function getCircleCIWorkflowId (pipelineId) {
+  const pipelineInfoUrl = `https://circleci.com/api/v2/pipeline/${pipelineId}`
+  let workflowId = 0
+  while (workflowId === 0) {
+    const pipelineInfo = await circleCIRequest(pipelineInfoUrl, 'GET')
+    switch (pipelineInfo.state) {
+      case 'created': {
+        const workflows = await circleCIRequest(`${pipelineInfoUrl}/workflow`, 'GET')
+        if (workflows.items.length === 1) {
+          workflowId = workflows.items[0].id
+          break
+        }
+        console.log('Unxpected number of workflows, response was:', pipelineInfo)
+        workflowId = -1
+        break
+      }
+      case 'error': {
+        console.log('Error retrieving workflows, response was:', pipelineInfo)
+        workflowId = -1
+        break
+      }
+    }
+    await new Promise(resolve => setTimeout(resolve, CIRCLECI_WAIT_TIME))
+  }
+  return workflowId
+}
+
+async function getCircleCIJobNumber (workflowId) {
+  const jobInfoUrl = `https://circleci.com/api/v2/workflow/${workflowId}/job`
+  let jobNumber = 0
+  while (jobNumber === 0) {
+    const jobInfo = await circleCIRequest(jobInfoUrl, 'GET')
+    if (!jobInfo.items) {
+      continue
+    }
+    if (jobInfo.items.length !== 1) {
+      console.log('Unxpected number of jobs, response was:', jobInfo)
+      jobNumber = -1
+      break
+    }
+
+    switch (jobInfo.items[0].status) {
+      case 'not_running':
+      case 'queued':
+      case 'running': {
+        if (jobInfo.items[0].job_number && !isNaN(jobInfo.items[0].job_number)) {
+          jobNumber = jobInfo.items[0].job_number
+        }
+        break
+      }
+      case 'canceled':
+      case 'error':
+      case 'infrastructure_fail':
+      case 'timedout':
+      case 'not_run':
+      case 'failed': {
+        console.log(`Error job returned a status of ${jobInfo.items[0].status}, response was:`, jobInfo)
+        jobNumber = -1
+        break
+      }
+    }
+    await new Promise(resolve => setTimeout(resolve, CIRCLECI_WAIT_TIME))
+  }
+  return jobNumber
+}
+
+async function circleCIRequest (url, method, requestBody) {
+  return makeRequest({
+    auth: {
+      username: process.env.CIRCLE_TOKEN,
+      password: ''
+    },
+    method,
+    url,
     headers: {
       'Content-Type': 'application/json',
       'Accept': 'application/json'
     },
-    body: JSON.stringify(buildRequest)
+    body: requestBody ? JSON.stringify(requestBody) : null
   }, true).catch(err => {
     console.log('Error calling CircleCI:', err)
   })
-  console.log(`CircleCI release build request for ${job} successful.  Check ${circleResponse.build_url} for status.`)
 }
 
 function buildAppVeyor (targetBranch, options) {
@@ -102,7 +204,7 @@ async function callAppVeyor (targetBranch, job, options) {
   }
 
   const requestOpts = {
-    url: buildAppVeyorURL,
+    url: BUILD_APPVEYOR_URL,
     auth: {
       bearer: process.env.APPVEYOR_CLOUD_TOKEN
     },
@@ -126,12 +228,11 @@ async function callAppVeyor (targetBranch, job, options) {
 }
 
 function buildCircleCI (targetBranch, options) {
-  const circleBuildUrl = `https://circleci.com/api/v1.1/project/github/electron/electron/tree/${targetBranch}?circle-token=${process.env.CIRCLE_TOKEN}`
   if (options.job) {
     assert(circleCIJobs.includes(options.job), `Unknown CircleCI job name: ${options.job}. Valid values are: ${circleCIJobs}.`)
-    circleCIcall(circleBuildUrl, targetBranch, options.job, options)
+    circleCIcall(targetBranch, options.job, options)
   } else {
-    circleCIJobs.forEach((job) => circleCIcall(circleBuildUrl, targetBranch, job, options))
+    circleCIJobs.forEach((job) => circleCIcall(targetBranch, job, options))
   }
 }
 
@@ -158,7 +259,7 @@ async function buildVSTS (targetBranch, options) {
   }
 
   const requestOpts = {
-    url: `${vstsURL}/definitions?api-version=4.1`,
+    url: `${VSTS_URL}/definitions?api-version=4.1`,
     auth: {
       user: '',
       password: process.env.VSTS_TOKEN
@@ -184,7 +285,7 @@ async function callVSTSBuild (build, targetBranch, environmentVariables) {
     buildBody.parameters = JSON.stringify(environmentVariables)
   }
   const requestOpts = {
-    url: `${vstsURL}/builds?api-version=4.1`,
+    url: `${VSTS_URL}/builds?api-version=4.1`,
     auth: {
       user: '',
       password: process.env.VSTS_TOKEN

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

@@ -0,0 +1,38 @@
+const crypto = require('crypto')
+const fs = require('fs')
+const path = require('path')
+
+// Fallback to blow away old cache keys
+const HASH_VERSION = 1
+
+// Base files to hash
+const filesToHash = [
+  path.resolve(__dirname, '../DEPS'),
+  path.resolve(__dirname, '../yarn.lock')
+]
+
+const addAllFiles = (dir) => {
+  for (const child of fs.readdirSync(dir).sort()) {
+    const childPath = path.resolve(dir, child)
+    if (fs.statSync(childPath).isDirectory()) {
+      addAllFiles(childPath)
+    } else {
+      filesToHash.push(childPath)
+    }
+  }
+}
+
+// Add all patch files to the hash
+addAllFiles(path.resolve(__dirname, '../patches'))
+
+// Create Hash
+const hasher = crypto.createHash('SHA256')
+for (const file of filesToHash) {
+  hasher.update(fs.readFileSync(file))
+}
+
+// Add the GCLIENT_EXTRA_ARGS variable to the hash
+hasher.update(process.env.GCLIENT_EXTRA_ARGS || 'no_extra_args')
+
+// Write the hash to disk
+fs.writeFileSync(path.resolve(__dirname, '../.depshash'), hasher.digest('hex'))