From d52095babb8dd70c350a5a012c6423d8ad753729 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sat, 30 Nov 2024 18:09:26 +0000 Subject: [PATCH] feat(builds): improve build speeds and use free arm64 runners Improves a few things: - Use the free macos-14 runners for arm64 builds. They are not as fast the macos-13-xlarge runners used before, but they are free for public repositories, meaning we can start doing nightly arm64 builds. - Use different nix install and cache actions which are faster, and uses a single action cache key, which avoids cache rate limit errors which was slowing down cache create/restore times. - Generally refactor and tidy up various bits and pieces in workflows. --- .github/workflows/_build.yml | 372 +++++++++------------------ .github/workflows/_build_emacs.yml | 240 +++++++++++++++++ .github/workflows/_prepare.yml | 67 +++-- .github/workflows/_release.yml | 14 +- .github/workflows/_update-casks.yml | 4 - .github/workflows/build.yml | 138 +--------- .github/workflows/nightly-master.yml | 129 ++-------- 7 files changed, 445 insertions(+), 519 deletions(-) create mode 100644 .github/workflows/_build_emacs.yml diff --git a/.github/workflows/_build.yml b/.github/workflows/_build.yml index c30fb25..e041bc9 100644 --- a/.github/workflows/_build.yml +++ b/.github/workflows/_build.yml @@ -1,283 +1,145 @@ --- -# Requires _prepare.yml re-usable workflow to have run. name: _build on: workflow_call: inputs: - should_run: - description: Whether or not to run the build job - type: boolean - default: false - artifact_prefix: - description: Artifact prefix - type: string - required: false - os: - description: GitHub Actions runner OS - type: string - required: false - default: "macos-12" - build_os: - description: Target OS to build for + git_ref: + description: Emacs git ref to build + required: true type: string + git_sha: + description: Override Emacs git commit SHA to build required: false - default: "macos-12" - git_ref: - description: Git ref to build type: string + builder_ref: + description: "Git ref to checkout of build-emacs-for-macos" required: true - git_sha: - description: Override git SHA to build type: string - required: false - build_args: + builder_args: description: Custom arguments passed to build script - type: string required: false + default: "" + type: string test_build_name: description: "Test build name" - type: string required: false + default: "" + type: string test_release_type: description: "prerelease or draft" + required: false + default: "" type: string + x86_64: + description: "Build x86_64 version of Emacs" required: false - default: "prerelease" - secrets: - APPLE_DEVELOPER_CERTIFICATE_P12_BASE64: - description: Base64 encoded Apple Developer Certificate - required: true - APPLE_DEVELOPER_CERTIFICATE_PASSWORD: - description: Password for Apple Developer Certificate - required: true - KEYCHAIN_PASSWORD: - description: Password to use for temporary local keychain on runner - required: true - AC_USERNAME: - description: Apple Connect Username - required: true - AC_PASSWORD: - description: Apple Connect Password - required: true - AC_PROVIDER: - description: Apple Connect Provider - required: true - AC_SIGN_IDENTITY: - description: Apple Connect Signing Identify - required: true - TAP_REPO_TOKEN: - description: Homebrew Tap Token - required: true - outputs: - package_created: - description: "Whether or not a package was created" - value: ${{ jobs.package.result == 'success' }} + default: true + type: boolean + arm64: + description: "Build arm64 version of Emacs" + required: false + default: true + type: boolean jobs: prepare: - runs-on: ${{ inputs.os }} - outputs: - builder_sha: ${{ steps.builder_sha.outputs.sha }} - emacs_sha_override: ${{ steps.emacs_sha.outputs.sha }} - test_plan_args: ${{ steps.test_plan_args.outputs.args }} - steps: - - name: Download emacs-builder git SHA artifact - uses: actions/download-artifact@v4 - with: - name: emacs-builder-git-sha - path: ./ - - name: Store builder Git SHA - id: builder_sha - run: >- - echo "sha=$(cat emacs-builder-git-sha.txt)" >> $GITHUB_OUTPUT - - name: Prepare plan test args - id: test_plan_args - if: ${{ inputs.test_build_name != '' }} - run: >- - echo "args=--test-build '${{ inputs.test_build_name }}' --test-release-type '${{ inputs.test_release_type }}'" >> $GITHUB_OUTPUT - - name: Set git SHA override - id: emacs_sha - if: ${{ inputs.git_sha != '' }} - run: >- - echo "sha=--sha '${{ inputs.git_sha }}'" >> $GITHUB_OUTPUT - plan: + name: Prepare + uses: ./.github/workflows/_prepare.yml + with: + builder_ref: ${{ inputs.builder_ref }} + + # ---------------------------------------------------------------------------- + # Build x86_64 version of Emacs + # ---------------------------------------------------------------------------- + + build_x86_64: + name: Build (x86_64) + if: inputs.x86_64 + uses: ./.github/workflows/_build_emacs.yml needs: [prepare] - runs-on: ${{ inputs.build_os }} - outputs: - check: ${{ steps.check.outputs.result }} - steps: - - name: Checkout build-emacs-for-macos repo - uses: actions/checkout@v4 - with: - repository: jimeh/build-emacs-for-macos - ref: ${{ needs.prepare.outputs.builder_sha }} - - uses: actions/setup-go@v5 - if: ${{ inputs.os != inputs.build_os }} - with: - go-version: "1.23" - - name: Build emacs-builder tool - if: ${{ inputs.os != inputs.build_os }} - run: make build - - name: Download pre-built emacs-builder artifact - if: ${{ inputs.os == inputs.build_os }} - uses: actions/download-artifact@v4 - with: - name: emacs-builder - path: bin - - name: Ensure emacs-builder is executable - if: ${{ inputs.os == inputs.build_os }} - run: chmod +x bin/emacs-builder - - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - - name: Plan build - run: >- - nix develop --command - bin/emacs-builder -l debug plan --output build-plan.yml - --output-dir '${{ github.workspace }}/builds' - ${{ needs.prepare.outputs.test_plan_args }} - ${{ needs.prepare.outputs.emacs_sha_override }} - '${{ inputs.git_ref }}' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Show plan - run: cat build-plan.yml - - name: Upload build-plan artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}build-plan - path: build-plan.yml - if-no-files-found: error - - name: Check if planned release and asset already exist - id: check - continue-on-error: true - run: | - echo "result=$((bin/emacs-builder -l debug release --plan build-plan.yml check && echo 'ok') || echo 'fail')" >> $GITHUB_OUTPUT - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: echo 'Planned release already seems to exist.' - if: ${{ steps.check.outputs.result == 'ok' }} + with: + builder_ref: ${{ needs.prepare.outputs.builder_sha }} + os: "macos-13" + build_os: "macos-13" # Only macos-13 and earlier are x86_64. + artifact_prefix: "x86_64-" + git_ref: ${{ inputs.git_ref }} + git_sha: ${{ inputs.git_sha }} + build_args: ${{ inputs.builder_args }} + test_build_name: ${{ inputs.test_build_name }} + test_release_type: ${{ inputs.test_release_type }} + secrets: inherit + + release_x86_64: + name: Release (x86_64) + uses: ./.github/workflows/_release.yml + # Depend on both build_x86_64 and build_arm64, but only run if build_x86_64 + # was successful and a package was created. This ensure wait for all builds + # to complete before running any release jobs. + needs: [prepare, build_x86_64, build_arm64] + if: | + always() && + needs.build_x86_64.result == 'success' && + needs.build_x86_64.outputs.package_created && + needs.build_arm64.result != 'failure' + with: + builder_ref: ${{ needs.prepare.outputs.builder_sha }} + os: "macos-13" # Only macos-13 and earlier are x86_64. + plan_artifact: x86_64-build-plan + dmg_artifact: x86_64-dmg - build: - runs-on: ${{ inputs.build_os }} - needs: [prepare, plan] - # Only run if check for existing release and asset failed. - if: ${{ needs.plan.outputs.check == 'fail' }} - steps: - - name: Checkout build-emacs-for-macos repo - uses: actions/checkout@v4 - with: - repository: jimeh/build-emacs-for-macos - ref: ${{ needs.prepare.outputs.builder_sha }} - path: builder - - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - - name: Download build-plan artifact - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}build-plan - path: ./builder/ - - name: Install dependencies - run: >- - nix develop - --command make bootstrap-ruby - working-directory: builder - env: - BUNDLE_WITHOUT: "development" - - name: Build Emacs - run: >- - nix develop - --command ./build-emacs-for-macos - --log-level debug - --plan build-plan.yml - --native-full-aot - --no-self-sign - ${{ inputs.build_args }} - working-directory: builder - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload unsigned app artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}unsigned-app - path: builds/*.tbz - if-no-files-found: error - - name: Upload Emacs source artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}emacs-source - path: builder/tarballs/*.tgz + # ---------------------------------------------------------------------------- + # Build arm64 version of Emacs + # ---------------------------------------------------------------------------- - package: - runs-on: ${{ inputs.os }} - needs: [prepare, plan, build] - steps: - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - name: Install dmgbuild - run: | - $(command -v pip3 || command -v pip) install --upgrade dmgbuild - - name: Download pre-built emacs-builder artifact - uses: actions/download-artifact@v4 - with: - name: emacs-builder - path: bin - - name: Ensure emacs-builder is executable - run: chmod +x bin/emacs-builder - - name: Download build-plan artifact - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}build-plan - path: ./ - - name: Download unsigned app artifact - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}unsigned-app - path: builds - - name: Extract unsigned app archive - run: | - find * -name '*.tbz' -exec tar xvjf "{}" \; - working-directory: builds - - name: Install the Apple signing certificate - run: | - # create variables - CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12" - KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" + build_arm64: + name: Build (arm64) + if: inputs.arm64 + uses: ./.github/workflows/_build_emacs.yml + needs: [prepare] + with: + builder_ref: ${{ needs.prepare.outputs.builder_sha }} + os: "macos-14" + build_os: "macos-14" # Only macos-14 and later are ARM64. + artifact_prefix: "arm64-" + git_ref: ${{ inputs.git_ref }} + git_sha: ${{ inputs.git_sha }} + build_args: ${{ inputs.builder_args }} + test_build_name: ${{ inputs.test_build_name }} + test_release_type: ${{ inputs.test_release_type }} + secrets: inherit - # import certificate and provisioning profile from secrets - echo -n "$CERT_BASE64" | base64 --decode > "$CERTIFICATE_PATH" + release_arm64: + name: Release (arm64) + uses: ./.github/workflows/_release.yml + # Depend on both build_arm64 and build_x86_64, but only run if build_arm64 + # was successful and a package was created. This ensure wait for all builds + # to complete before running any release jobs. + needs: [prepare, build_arm64, build_x86_64] + if: | + always() && + needs.build_arm64.result == 'success' && + needs.build_arm64.outputs.package_created && + needs.build_x86_64.result != 'failure' + with: + builder_ref: ${{ needs.prepare.outputs.builder_sha }} + os: "macos-14" # Only macos-14 and later are ARM64. + plan_artifact: arm64-build-plan + dmg_artifact: arm64-dmg - # create temporary keychain - security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + # ---------------------------------------------------------------------------- + # Trigger update casks workflow in homebrew tap + # ---------------------------------------------------------------------------- - # import certificate to keychain - security import "$CERTIFICATE_PATH" -P "$CERT_PASSWORD" -A \ - -t cert -f pkcs12 -k "$KEYCHAIN_PATH" - security list-keychain -d user -s "$KEYCHAIN_PATH" - env: - CERT_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} - CERT_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - - name: Sign, package and notarize build - run: >- - bin/emacs-builder package -v --plan build-plan.yml - --sign --remove-source-dir - env: - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - AC_PROVIDER: ${{ secrets.AC_PROVIDER }} - AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} - - name: Upload disk image artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ inputs.artifact_prefix }}dmg - path: | - builds/*.dmg - builds/*.sha* - if-no-files-found: error - - name: Clean up keychain used for signing certificate - if: ${{ always() }} - run: | - security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" + update_casks: + name: Update Casks + uses: ./.github/workflows/_update-casks.yml + # Depend on both release jobs, but only run if either of them was + # successful. This ensures we only run this job once all release jobs have + # been completed. + needs: [release_x86_64, release_arm64] + if: >- + always() && + inputs.test_build_name == '' && + contains(needs.*.result, 'success') && + !contains(needs.*.result, 'failure') + secrets: inherit diff --git a/.github/workflows/_build_emacs.yml b/.github/workflows/_build_emacs.yml new file mode 100644 index 0000000..2a06b5b --- /dev/null +++ b/.github/workflows/_build_emacs.yml @@ -0,0 +1,240 @@ +--- +# Requires _prepare.yml re-usable workflow to have run. +name: _build_emacs +on: + workflow_call: + inputs: + builder_ref: + description: Git ref of build-emacs-for-macos to use + type: string + required: true + os: + description: GitHub Actions runner OS + type: string + required: false + default: "macos-13" + build_os: + description: Target OS to build for + type: string + required: false + default: "macos-13" + artifact_prefix: + description: Artifact prefix for build_os + type: string + required: false + git_ref: + description: Git ref to build + type: string + required: true + git_sha: + description: Override git SHA to build + type: string + required: false + build_args: + description: Custom arguments passed to build script + type: string + required: false + test_build_name: + description: "Test build name" + type: string + required: false + test_release_type: + description: "prerelease or draft" + type: string + required: false + default: "prerelease" + outputs: + package_created: + description: "Whether or not a package was created" + value: ${{ jobs.package.result == 'success' }} + +jobs: + plan: + runs-on: ${{ inputs.build_os }} + outputs: + check: ${{ steps.check.outputs.result }} + steps: + - name: Checkout build-emacs-for-macos repo + uses: actions/checkout@v4 + with: + repository: jimeh/build-emacs-for-macos + ref: ${{ inputs.builder_ref }} + - name: Download pre-built emacs-builder artifact + uses: actions/download-artifact@v4 + with: + name: emacs-builder-${{ runner.arch }} + path: bin + - name: Ensure emacs-builder is executable + run: chmod +x bin/emacs-builder + - uses: nixbuild/nix-quick-install-action@v29 + - uses: nix-community/cache-nix-action@v5 + with: + primary-key: nix-${{ runner.arch }}-${{ hashFiles('**/flake.*') }} + - name: Install dependencies + run: nix develop --command nix flake metadata + - name: Prepare plan test args + id: test_plan_args + if: inputs.test_build_name != '' + run: >- + echo "args=--test-build '${{ inputs.test_build_name }}' --test-release-type '${{ inputs.test_release_type }}'" >> "$GITHUB_OUTPUT" + - name: Set git SHA override + id: emacs_sha + if: inputs.git_sha != '' + run: >- + echo "sha=--sha '${{ inputs.git_sha }}'" >> "$GITHUB_OUTPUT" + - name: Plan build + run: >- + nix develop --command + bin/emacs-builder -l debug plan --output build-plan.yml + --output-dir '${{ github.workspace }}/builds' + ${{ steps.test_plan_args.outputs.args }} + ${{ steps.emacs_sha.outputs.sha }} + '${{ inputs.git_ref }}' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Show plan + run: cat build-plan.yml + - name: Upload build-plan artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}build-plan + path: build-plan.yml + if-no-files-found: error + - name: Check if planned release and asset already exist + id: check + continue-on-error: true + run: | + echo "result=$((bin/emacs-builder -l debug release --plan build-plan.yml check && echo 'ok') || echo 'fail')" >> "$GITHUB_OUTPUT" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - run: echo 'Planned release already seems to exist.' + if: steps.check.outputs.result == 'ok' + + build: + runs-on: ${{ inputs.build_os }} + needs: [plan] + # Only run if check for existing release and asset failed. + if: needs.plan.outputs.check == 'fail' + steps: + - name: Checkout build-emacs-for-macos repo + uses: actions/checkout@v4 + with: + repository: jimeh/build-emacs-for-macos + ref: ${{ inputs.builder_ref }} + path: builder + - uses: nixbuild/nix-quick-install-action@v29 + - uses: nix-community/cache-nix-action@v5 + with: + primary-key: nix-${{ runner.arch }}-${{ hashFiles('**/flake.*') }} + - name: Download build-plan artifact + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}build-plan + path: ./builder/ + - name: Install dependencies + run: nix develop --command nix flake metadata + working-directory: builder + - name: Install Ruby dependencies + run: >- + nix develop --command make bootstrap-ruby + working-directory: builder + env: + BUNDLE_WITHOUT: "development" + - name: Build Emacs + run: >- + nix develop + --command ./build-emacs-for-macos + --log-level debug + --plan build-plan.yml + --native-full-aot + --no-self-sign + ${{ inputs.build_args }} + working-directory: builder + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload unsigned app artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}unsigned-app + path: builds/*.tbz + if-no-files-found: error + - name: Upload Emacs source artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}emacs-source + path: builder/tarballs/*.tgz + + package: + runs-on: ${{ inputs.os }} + needs: [plan, build] + steps: + - name: Download pre-built emacs-builder artifact + uses: actions/download-artifact@v4 + with: + name: emacs-builder-${{ runner.arch }} + path: bin + - name: Ensure emacs-builder is executable + run: chmod +x bin/emacs-builder + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install dmgbuild + run: | + $(command -v pip3 || command -v pip) install --upgrade dmgbuild + - name: Download build-plan artifact + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}build-plan + path: ./ + - name: Download unsigned app artifact + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}unsigned-app + path: builds + - name: Extract unsigned app archive + run: | + find * -name '*.tbz' -exec tar xvjf "{}" \; + working-directory: builds + - name: Install the Apple signing certificate + run: | + # create variables + CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12" + KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" + + # import certificate and provisioning profile from secrets + echo -n "$CERT_BASE64" | base64 --decode > "$CERTIFICATE_PATH" + + # create temporary keychain + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" + + # import certificate to keychain + security import "$CERTIFICATE_PATH" -P "$CERT_PASSWORD" -A \ + -t cert -f pkcs12 -k "$KEYCHAIN_PATH" + security list-keychain -d user -s "$KEYCHAIN_PATH" + env: + CERT_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} + CERT_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + - name: Sign, package and notarize build + run: >- + bin/emacs-builder package -v --plan build-plan.yml + --sign --remove-source-dir + env: + AC_USERNAME: ${{ secrets.AC_USERNAME }} + AC_PASSWORD: ${{ secrets.AC_PASSWORD }} + AC_PROVIDER: ${{ secrets.AC_PROVIDER }} + AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} + - name: Upload disk image artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.artifact_prefix }}dmg + path: | + builds/*.dmg + builds/*.sha* + if-no-files-found: error + - name: Clean up keychain used for signing certificate + if: always() + run: | + security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" diff --git a/.github/workflows/_prepare.yml b/.github/workflows/_prepare.yml index 000fdca..a42a785 100644 --- a/.github/workflows/_prepare.yml +++ b/.github/workflows/_prepare.yml @@ -3,24 +3,20 @@ name: _prepare on: workflow_call: inputs: - os: - description: GitHub Actions runner OS - type: string - required: false - default: "macos-12" builder_ref: description: Git ref to checkout of build-emacs-for-macos - required: false - type: string - default: "v0.6.50" - secrets: - TAP_REPO_TOKEN: - description: Personal Access Token for Homebrew Tap repo required: true + type: string + outputs: + builder_sha: + description: Git SHA of build-emacs-for-macos at builder_ref + value: ${{ jobs.builder-sha.outputs.sha }} jobs: - emacs-builder: - runs-on: ${{ inputs.os }} + builder-sha: + runs-on: "macos-13" + outputs: + sha: ${{ steps.builder_sha.outputs.sha }} steps: - name: Checkout build-emacs-for-macos repo uses: actions/checkout@v4 @@ -28,22 +24,57 @@ jobs: repository: jimeh/build-emacs-for-macos ref: ${{ inputs.builder_ref }} - name: Store builder Git SHA + id: builder_sha run: | - git rev-parse HEAD > emacs-builder-git-sha.txt + BUILDER_SHA="$(git rev-parse HEAD)" + echo "$BUILDER_SHA" > build-emacs-for-macos-git-sha.txt + echo "sha=$BUILDER_SHA" >> $GITHUB_OUTPUT + echo "Builder ref ${{ inputs.builder_ref }} resolved to" \ + "commit SHA: $BUILDER_SHA" - name: Upload builder git SHA artifact uses: actions/upload-artifact@v4 with: - name: emacs-builder-git-sha - path: emacs-builder-git-sha.txt + name: build-emacs-for-macos-git-sha + path: build-emacs-for-macos-git-sha.txt if-no-files-found: error - - uses: actions/setup-go@v5 + + emacs-builder: + needs: [builder-sha] + strategy: + matrix: + os: + - macos-13 # Only macos-13 and earlier are x86_64. + - macos-14 # Only macos-14 and later are ARM64. + runs-on: ${{ matrix.os }} + steps: + - name: Cache emacs-builder (${{ runner.arch }}) + id: cache + uses: actions/cache@v4 + with: + path: bin/emacs-builder + key: emacs-builder-${{ runner.arch }}-${{ needs.builder-sha.outputs.sha }}-bin + - name: Checkout build-emacs-for-macos repo + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/checkout@v4 + with: + repository: jimeh/build-emacs-for-macos + ref: ${{ inputs.builder_ref }} + fetch-depth: 0 + - name: Setup Go + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/setup-go@v5 with: go-version: "1.23" - name: Build emacs-builder tool + if: steps.cache.outputs.cache-hit != 'true' run: make build + - name: Ensure emacs-builder is executable + if: steps.cache.outputs.cache-hit != 'true' + run: chmod +x bin/emacs-builder + - run: bin/emacs-builder --version - name: Upload emacs-builder artifact uses: actions/upload-artifact@v4 with: - name: emacs-builder + name: emacs-builder-${{ runner.arch }} path: bin/emacs-builder if-no-files-found: error diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml index 853e0cf..73ff55d 100644 --- a/.github/workflows/_release.yml +++ b/.github/workflows/_release.yml @@ -7,6 +7,10 @@ concurrency: on: workflow_call: inputs: + builder_ref: + description: Git ref of build-emacs-for-macos to use + type: string + required: true os: description: GitHub Actions runner OS type: string @@ -20,10 +24,6 @@ on: description: Name of artifact containing a *.dmg files to release type: string required: true - secrets: - TAP_REPO_TOKEN: - description: Personal Access Token for Homebrew Tap repo - required: true jobs: github: @@ -32,7 +32,7 @@ jobs: - name: Download pre-built emacs-builder artifact uses: actions/download-artifact@v4 with: - name: emacs-builder + name: emacs-builder-${{ runner.arch }} path: bin - name: Ensure emacs-builder is executable run: chmod +x bin/emacs-builder @@ -49,11 +49,11 @@ jobs: name: ${{ inputs.dmg_artifact }} path: builds - name: Publish disk images to a GitHub Release - if: ${{ steps.dmg.outputs.result != 'fail' }} + if: steps.dmg.outputs.result != 'fail' run: >- bin/emacs-builder -l debug release --plan build-plan.yml publish $(find builds -name '*.dmg' -or -name '*.sha256') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: echo 'No DMG artifact available, was there a new commit to build?' - if: ${{ steps.dmg.outputs.result == 'fail' }} + if: steps.dmg.outputs.result == 'fail' diff --git a/.github/workflows/_update-casks.yml b/.github/workflows/_update-casks.yml index a850c2a..c13dc13 100644 --- a/.github/workflows/_update-casks.yml +++ b/.github/workflows/_update-casks.yml @@ -11,10 +11,6 @@ on: type: string required: false default: "ubuntu-latest" - secrets: - TAP_REPO_TOKEN: - description: Personal Access Token for Homebrew Tap repo - required: true jobs: emacs-builds: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29ab9a8..a43fd39 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,15 +13,11 @@ on: builder_ref: description: "Git ref to checkout of build-emacs-for-macos" required: true - default: "v0.6.50" + default: "v0.6.52" builder_args: description: Custom arguments passed to build script required: false default: "" - os: - description: 'Runner OS ("macos-13", "macos-14", or "macos-latest")' - required: true - default: "macos-13" test_build_name: description: "Test build name" required: false @@ -38,128 +34,20 @@ on: arm64: description: "Build arm64 version of Emacs" required: false - default: false + default: true type: boolean jobs: - prepare: - name: Prepare - uses: ./.github/workflows/_prepare.yml - with: - os: ${{ github.event.inputs.os }} - builder_ref: ${{ github.event.inputs.builder_ref }} - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - # ---------------------------------------------------------------------------- - # Build x86_64 version of Emacs - # ---------------------------------------------------------------------------- - - build_x86_64: - name: Build (x86_64) - if: ${{ github.event.inputs.x86_64 == 'true' }} + build: + name: Build uses: ./.github/workflows/_build.yml - needs: [prepare] - with: - os: ${{ github.event.inputs.os }} - build_os: "macos-13" - artifact_prefix: "x86_64-" - git_ref: ${{ github.event.inputs.git_ref }} - git_sha: ${{ github.event.inputs.git_sha }} - build_args: ${{ github.event.inputs.builder_args }} - test_build_name: ${{ github.event.inputs.test_build_name }} - test_release_type: ${{ github.event.inputs.test_release_type }} - secrets: - APPLE_DEVELOPER_CERTIFICATE_P12_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} - APPLE_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - AC_PROVIDER: ${{ secrets.AC_PROVIDER }} - AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - release_x86_64: - name: Release (x86_64) - uses: ./.github/workflows/_release.yml - # Depend on both build_x86_64 and build_arm64, but only run if build_x86_64 - # was successful and a package was created. This ensure wait for all builds - # to complete before running any release jobs. - needs: [build_x86_64, build_arm64] - if: | - always() && - needs.build_x86_64.result == 'success' && - needs.build_x86_64.outputs.package_created && - needs.build_arm64.result != 'failure' with: - os: ${{ github.event.inputs.os }} - plan_artifact: x86_64-build-plan - dmg_artifact: x86_64-dmg - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - # ---------------------------------------------------------------------------- - # Build arm64 version of Emacs - # ---------------------------------------------------------------------------- - - build_arm64: - name: Build (arm64) - if: ${{ github.event.inputs.arm64 == 'true' }} - uses: ./.github/workflows/_build.yml - needs: [prepare] - with: - os: ${{ github.event.inputs.os }} - build_os: "macos-13-xlarge" # Only macos-13-xlarge has arm64 support. - artifact_prefix: "arm64-" - git_ref: ${{ github.event.inputs.git_ref }} - git_sha: ${{ github.event.inputs.git_sha }} - build_args: ${{ github.event.inputs.builder_args }} - test_build_name: ${{ github.event.inputs.test_build_name }} - test_release_type: ${{ github.event.inputs.test_release_type }} - secrets: - APPLE_DEVELOPER_CERTIFICATE_P12_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} - APPLE_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - AC_PROVIDER: ${{ secrets.AC_PROVIDER }} - AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - release_arm64: - name: Release (arm64) - uses: ./.github/workflows/_release.yml - # Depend on both build_arm64 and build_x86_64, but only run if build_arm64 - # was successful and a package was created. This ensure wait for all builds - # to complete before running any release jobs. - needs: [build_arm64, build_x86_64] - if: | - always() && - needs.build_arm64.result == 'success' && - needs.build_arm64.outputs.package_created && - needs.build_x86_64.result != 'failure' - with: - os: ${{ github.event.inputs.os }} - plan_artifact: arm64-build-plan - dmg_artifact: arm64-dmg - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - # ---------------------------------------------------------------------------- - # Trigger update casks workflow in homebrew tap - # ---------------------------------------------------------------------------- - - update_casks: - name: Update Casks - uses: ./.github/workflows/_update-casks.yml - # Depend on both release jobs, but only run if either of them was - # successful. This ensures we only run this job once all release jobs have - # been completed. - needs: [release_x86_64, release_arm64] - if: >- - always() && - github.event.inputs.test_build_name == '' && - contains(needs.*.result, 'success') && - !contains(needs.*.result, 'failure') - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} + git_ref: ${{ inputs.git_ref }} + git_sha: ${{ inputs.git_sha }} + builder_ref: ${{ inputs.builder_ref }} + builder_args: ${{ inputs.builder_args }} + test_build_name: ${{ inputs.test_build_name }} + test_release_type: ${{ inputs.test_release_type }} + x86_64: ${{ inputs.x86_64 }} + arm64: ${{ inputs.arm64 }} + secrets: inherit diff --git a/.github/workflows/nightly-master.yml b/.github/workflows/nightly-master.yml index d8c1248..3e3be37 100644 --- a/.github/workflows/nightly-master.yml +++ b/.github/workflows/nightly-master.yml @@ -2,126 +2,35 @@ name: Nightly (master) on: schedule: - - cron: "0 23 1 * *" - - cron: "0 23 2-31 * *" + - cron: "0 23 * * *" workflow_dispatch: inputs: git_sha: description: Override Emacs git commit SHA to build required: false + builder_ref: + description: "Git ref to checkout of build-emacs-for-macos" + required: true + default: "v0.6.52" + x86_64: + description: "Build x86_64 version of Emacs" + required: false + default: true + type: boolean arm64: - description: "Build arm64 version of Emacs?" + description: "Build arm64 version of Emacs" required: false - default: false + default: true type: boolean jobs: - prepare: - name: Prepare - uses: ./.github/workflows/_prepare.yml - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - # ---------------------------------------------------------------------------- - # Build x86_64 version of Emacs - # ---------------------------------------------------------------------------- - - build_x86_64: - name: Build (x86_64) + build: + name: Build uses: ./.github/workflows/_build.yml - needs: [prepare] with: - build_os: "macos-13" - artifact_prefix: "x86_64-" git_ref: "master" - git_sha: ${{ github.event.inputs.git_sha }} - secrets: - APPLE_DEVELOPER_CERTIFICATE_P12_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} - APPLE_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - AC_PROVIDER: ${{ secrets.AC_PROVIDER }} - AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - release_x86_64: - name: Release (x86_64) - uses: ./.github/workflows/_release.yml - # Depend on both build_x86_64 and build_arm64, but only run if build_x86_64 - # was successful and a package was created. This ensure wait for all builds - # to complete before running any release jobs. - needs: [build_x86_64, build_arm64] - if: | - always() && - needs.build_x86_64.result == 'success' && - needs.build_x86_64.outputs.package_created && - needs.build_arm64.result != 'failure' - with: - plan_artifact: x86_64-build-plan - dmg_artifact: x86_64-dmg - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - # ---------------------------------------------------------------------------- - # Build arm64 version of Emacs - # ---------------------------------------------------------------------------- - - build_arm64: - name: Build (arm64) - if: >- - github.event.inputs.arm64 == 'true' || - github.event.schedule == '0 23 1 * *' - uses: ./.github/workflows/_build.yml - needs: [prepare] - with: - build_os: "macos-13-xlarge" # Only macos-13-xlarge has arm64 support. - artifact_prefix: "arm64-" - git_ref: "master" - git_sha: ${{ github.event.inputs.git_sha }} - secrets: - APPLE_DEVELOPER_CERTIFICATE_P12_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} - APPLE_DEVELOPER_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - AC_USERNAME: ${{ secrets.AC_USERNAME }} - AC_PASSWORD: ${{ secrets.AC_PASSWORD }} - AC_PROVIDER: ${{ secrets.AC_PROVIDER }} - AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - release_arm64: - name: Release (arm64) - uses: ./.github/workflows/_release.yml - # Depend on both build_arm64 and build_x86_64, but only run if build_arm64 - # was successful and a package was created. This ensure wait for all builds - # to complete before running any release jobs. - needs: [build_arm64, build_x86_64] - if: | - always() && - needs.build_arm64.result == 'success' && - needs.build_arm64.outputs.package_created && - needs.build_x86_64.result != 'failure' - with: - plan_artifact: arm64-build-plan - dmg_artifact: arm64-dmg - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} - - # ---------------------------------------------------------------------------- - # Trigger update casks workflow in homebrew tap - # ---------------------------------------------------------------------------- - - update_casks: - name: Update Casks - uses: ./.github/workflows/_update-casks.yml - # Depend on both release jobs, but only run if either of them was - # successful. This ensures we only run this job once all release jobs have - # been completed. - needs: [release_x86_64, release_arm64] - if: >- - always() && - github.event.inputs.test_build_name == '' && - contains(needs.*.result, 'success') && - !contains(needs.*.result, 'failure') - secrets: - TAP_REPO_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} + git_sha: ${{ inputs.git_sha }} + builder_ref: ${{ inputs.builder_ref }} + x86_64: ${{ inputs.x86_64 }} + arm64: ${{ inputs.arm64 }} + secrets: inherit