Files
emacs-builds/.github/workflows/_build.yml
Jim Myhrberg ff1b573f43 feat(build): allow running build job on separate OS
This should help reduce costs for Apple Silicon builds, as they are not
available on any form of free tier of GitHub Actions at the moment.

The build step that actually runs Emacs' configure script, and compiles
Emacs, is the only step that actually needs to run on the target
hardware architecture. The rest should be architecture agnostic.
2023-11-19 22:26:46 +00:00

277 lines
9.5 KiB
YAML

---
# Requires _prepare.yml re-usable workflow to have run.
name: _build
on:
workflow_call:
inputs:
artifact_prefix:
description: Artifact prefix
type: string
required: false
os:
description: GitHub Actions runner OS
type: string
required: false
default: "macos-11"
build_os:
description: Target OS to build for
type: string
required: false
default: "macos-11"
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"
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
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@v3
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:
needs: [prepare]
runs-on: ${{ inputs.build_os }}
outputs:
check: ${{ steps.check.outputs.result }}
steps:
- name: Checkout build-emacs-for-macos repo
if: ${{ inputs.os != inputs.build_os }}
uses: actions/checkout@v4
with:
repository: jimeh/build-emacs-for-macos
ref: ${{ needs.prepare.outputs.builder_sha }}
- uses: actions/setup-go@v4
if: ${{ inputs.os != inputs.build_os }}
with:
go-version: "1.21"
- 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@v3
with:
name: emacs-builder
path: bin
- name: Ensure emacs-builder is executable
if: ${{ inputs.os == inputs.build_os }}
run: chmod +x bin/emacs-builder
- name: Plan build
run: >-
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@v3
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 == 'fail' }}
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: ruby/setup-ruby@v1
with:
ruby-version: "3.2"
- name: Update homebrew
run: brew update
- name: Fix system python breaking homebrew
run: >-
find "$(brew --prefix)/bin" -type l
-ilname '*/Library/Frameworks/Python.framework/*'
-delete
- name: Install dependencies
run: make bootstrap-ci
working-directory: builder
- name: Download build-plan artifact
uses: actions/download-artifact@v3
with:
name: ${{ inputs.artifact_prefix }}build-plan
path: ./
- name: Build Emacs
run: >-
./builder/build-emacs-for-macos
--log-level debug
--plan build-plan.yml
--native-full-aot
--no-self-sign
${{ inputs.build_args }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload unsigned app artifact
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.artifact_prefix }}unsigned-app
path: builds/*.tbz
if-no-files-found: error
- name: Upload Emacs source artifact
uses: actions/upload-artifact@v3
with:
name: ${{ inputs.artifact_prefix }}emacs-source
path: builder/tarballs/*.tgz
package:
runs-on: ${{ inputs.os }}
needs: [prepare, plan, build]
# Only run if check for existing release and asset failed.
steps:
- uses: actions/setup-python@v4
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@v3
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@v3
with:
name: ${{ inputs.artifact_prefix }}build-plan
path: ./
- name: Download unsigned app artifact
uses: actions/download-artifact@v3
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 --output "$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 -l debug 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@v3
with:
name: 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"