├── .gitignore ├── img └── EmacsLG1.png ├── .github └── workflows │ ├── nightly-master.yml │ ├── _update-casks.yml │ ├── update-metadata.yml │ ├── build.yml │ ├── _release.yml │ ├── _prepare.yml │ ├── _build.yml │ └── _build_emacs.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | plan.yml 2 | -------------------------------------------------------------------------------- /img/EmacsLG1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimeh/emacs-builds/HEAD/img/EmacsLG1.png -------------------------------------------------------------------------------- /.github/workflows/nightly-master.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Nightly (master) 3 | on: 4 | schedule: 5 | - cron: "0 23 * * *" 6 | workflow_dispatch: 7 | inputs: 8 | git_sha: 9 | description: Override Emacs git commit SHA to build 10 | required: false 11 | 12 | jobs: 13 | build: 14 | name: Build 15 | uses: ./.github/workflows/_build.yml 16 | with: 17 | git_ref: "master" 18 | git_sha: ${{ inputs.git_sha }} 19 | secrets: inherit 20 | -------------------------------------------------------------------------------- /.github/workflows/_update-casks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: _update-casks 3 | concurrency: 4 | group: _update-casks 5 | cancel-in-progress: false 6 | on: 7 | workflow_call: 8 | inputs: 9 | os: 10 | description: GitHub Actions runner OS 11 | type: string 12 | required: false 13 | default: "ubuntu-latest" 14 | 15 | jobs: 16 | emacs-builds: 17 | runs-on: ${{ inputs.os }} 18 | steps: 19 | - name: Trigger update casks workflow in homebrew tap 20 | run: >- 21 | gh workflow run --repo jimeh/homebrew-emacs-builds update-casks.yml 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.TAP_REPO_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/workflows/update-metadata.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Update Metadata 3 | concurrency: jimeh/emacs-builds/update-metadata 4 | on: 5 | schedule: 6 | - cron: "0 0 * * *" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | update-metadata: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout meta branch 14 | uses: actions/checkout@v4 15 | with: 16 | ref: meta 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version: "1.23" 20 | - name: update total downloads shield JSON 21 | run: >- 22 | go run . badges downloads 23 | --output total-downloads/shield.json 24 | --cache total-downloads/.cache.json 25 | env: 26 | GITHUB_TOKEN: ${{ github.token }} 27 | - name: commit and push changes to meta branch 28 | uses: stefanzweifel/git-auto-commit-action@v5 29 | with: 30 | commit_message: "chore(meta): update metadata files" 31 | commit_user_name: github-actions[bot] 32 | commit_user_email: github-actions[bot]@users.noreply.github.com 33 | commit_author: >- 34 | github-actions[bot] 35 | skip_dirty_check: false 36 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Build 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | git_ref: 7 | description: Emacs git ref to build 8 | required: true 9 | default: "master" 10 | git_sha: 11 | description: Override Emacs git commit SHA to build 12 | required: false 13 | builder_ref: 14 | description: "Override git ref to checkout of build-emacs-for-macos" 15 | required: false 16 | default: "" 17 | builder_args: 18 | description: Custom arguments passed to build script 19 | required: false 20 | default: "" 21 | test_build_name: 22 | description: "Test build name" 23 | required: false 24 | default: "" 25 | test_release_type: 26 | description: "prerelease or draft" 27 | required: false 28 | default: "" 29 | build_variant: 30 | description: "Optional build number used as version suffix" 31 | required: false 32 | type: string 33 | x86_64: 34 | description: "Build x86_64 version of Emacs" 35 | required: false 36 | default: true 37 | type: boolean 38 | arm64: 39 | description: "Build arm64 version of Emacs" 40 | required: false 41 | default: true 42 | type: boolean 43 | 44 | jobs: 45 | build: 46 | name: Build 47 | uses: ./.github/workflows/_build.yml 48 | with: 49 | git_ref: ${{ inputs.git_ref }} 50 | git_sha: ${{ inputs.git_sha }} 51 | builder_ref: ${{ inputs.builder_ref }} 52 | builder_args: ${{ inputs.builder_args }} 53 | build_variant: ${{ inputs.build_variant }} 54 | test_build_name: ${{ inputs.test_build_name }} 55 | test_release_type: ${{ inputs.test_release_type }} 56 | x86_64: ${{ inputs.x86_64 }} 57 | arm64: ${{ inputs.arm64 }} 58 | secrets: inherit 59 | -------------------------------------------------------------------------------- /.github/workflows/_release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Requires _prepare.yml and _build.yml re-usable workflows to have run. 3 | name: _release 4 | concurrency: 5 | group: _release 6 | cancel-in-progress: false 7 | on: 8 | workflow_call: 9 | inputs: 10 | builder_ref: 11 | description: Git ref of build-emacs-for-macos to use 12 | type: string 13 | required: true 14 | os: 15 | description: GitHub Actions runner OS 16 | type: string 17 | required: false 18 | default: "macos-15" 19 | plan_artifact: 20 | description: Name of artifact containing a emacs-builder plan yaml file 21 | type: string 22 | required: true 23 | dmg_artifact: 24 | description: Name of artifact containing a *.dmg files to release 25 | type: string 26 | required: true 27 | 28 | jobs: 29 | github: 30 | runs-on: ${{ inputs.os }} 31 | steps: 32 | - name: Download pre-built emacs-builder artifact 33 | uses: actions/download-artifact@v4 34 | with: 35 | name: emacs-builder-${{ runner.arch }} 36 | path: bin 37 | - name: Ensure emacs-builder is executable 38 | run: chmod +x bin/emacs-builder 39 | - name: Download build-plan.yml artifact 40 | uses: actions/download-artifact@v4 41 | with: 42 | name: ${{ inputs.plan_artifact }} 43 | path: ./ 44 | - name: Download disk image artifacts 45 | id: dmg 46 | continue-on-error: true 47 | uses: actions/download-artifact@v4 48 | with: 49 | name: ${{ inputs.dmg_artifact }} 50 | path: builds 51 | - name: Publish disk images to a GitHub Release 52 | if: steps.dmg.outcome != 'failure' 53 | run: >- 54 | bin/emacs-builder -l debug release --plan build-plan.yml publish 55 | $(find builds -name '*.dmg' -or -name '*.sha256') 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | - run: echo 'No DMG artifact available, was there a new commit to build?' 59 | if: steps.dmg.outcome == 'failure' 60 | -------------------------------------------------------------------------------- /.github/workflows/_prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: _prepare 3 | on: 4 | workflow_call: 5 | inputs: 6 | builder_ref: 7 | description: Git ref to checkout of build-emacs-for-macos 8 | required: false 9 | type: string 10 | default: "" 11 | outputs: 12 | builder_ref: 13 | description: Git ref of build-emacs-for-macos at builder_ref 14 | value: ${{ jobs.builder-sha.outputs.ref }} 15 | builder_sha: 16 | description: Git commit SHA of build-emacs-for-macos at builder_ref 17 | value: ${{ jobs.builder-sha.outputs.sha }} 18 | 19 | jobs: 20 | builder-sha: 21 | runs-on: "macos-15" 22 | outputs: 23 | ref: ${{ steps.ref.outputs.ref }} 24 | sha: ${{ steps.sha.outputs.sha }} 25 | steps: 26 | - name: Default git ref check 27 | id: ref 28 | run: | 29 | DEFAULT_BUILDER_REF="v0.6.63" 30 | BUILDER_REF="${{ inputs.builder_ref }}" 31 | echo "ref=${BUILDER_REF:-$DEFAULT_BUILDER_REF}" >> "$GITHUB_OUTPUT" 32 | - name: Checkout build-emacs-for-macos repo 33 | uses: actions/checkout@v4 34 | with: 35 | repository: jimeh/build-emacs-for-macos 36 | ref: ${{ steps.ref.outputs.ref }} 37 | - name: Store builder Git SHA 38 | id: sha 39 | run: | 40 | BUILDER_SHA="$(git rev-parse HEAD)" 41 | echo "$BUILDER_SHA" > build-emacs-for-macos-git-sha.txt 42 | echo "sha=$BUILDER_SHA" >> "$GITHUB_OUTPUT" 43 | echo "Builder ref ${{ inputs.builder_ref }} resolved to" \ 44 | "commit SHA: $BUILDER_SHA" 45 | - name: Upload builder git SHA artifact 46 | uses: actions/upload-artifact@v4 47 | with: 48 | name: build-emacs-for-macos-git-sha 49 | path: build-emacs-for-macos-git-sha.txt 50 | if-no-files-found: error 51 | 52 | emacs-builder: 53 | needs: [builder-sha] 54 | strategy: 55 | matrix: 56 | os: 57 | - macos-15 58 | - macos-15-intel 59 | runs-on: ${{ matrix.os }} 60 | steps: 61 | - name: Cache emacs-builder (${{ runner.arch }}) 62 | id: cache 63 | uses: actions/cache@v4 64 | with: 65 | path: bin/emacs-builder 66 | key: emacs-builder-${{ runner.arch }}-${{ needs.builder-sha.outputs.sha }}-bin 67 | - name: Checkout build-emacs-for-macos repo 68 | if: steps.cache.outputs.cache-hit != 'true' 69 | uses: actions/checkout@v4 70 | with: 71 | repository: jimeh/build-emacs-for-macos 72 | ref: ${{ needs.builder-sha.outputs.ref }} 73 | fetch-depth: 0 74 | - name: Setup Go 75 | if: steps.cache.outputs.cache-hit != 'true' 76 | uses: actions/setup-go@v5 77 | with: 78 | go-version: "1.23" 79 | - name: Build emacs-builder tool 80 | if: steps.cache.outputs.cache-hit != 'true' 81 | run: make build 82 | - name: Ensure emacs-builder is executable 83 | if: steps.cache.outputs.cache-hit != 'true' 84 | run: chmod +x bin/emacs-builder 85 | - run: bin/emacs-builder --version 86 | - name: Upload emacs-builder artifact 87 | uses: actions/upload-artifact@v4 88 | with: 89 | name: emacs-builder-${{ runner.arch }} 90 | path: bin/emacs-builder 91 | if-no-files-found: error 92 | -------------------------------------------------------------------------------- /.github/workflows/_build.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: _build 3 | on: 4 | workflow_call: 5 | inputs: 6 | git_ref: 7 | description: Emacs git ref to build 8 | required: true 9 | type: string 10 | git_sha: 11 | description: Override Emacs git commit SHA to build 12 | required: false 13 | type: string 14 | builder_ref: 15 | description: "Git ref to checkout of build-emacs-for-macos" 16 | required: false 17 | type: string 18 | builder_args: 19 | description: Custom arguments passed to build script 20 | required: false 21 | default: "" 22 | type: string 23 | build_variant: 24 | description: "Optional build number used as version suffix" 25 | required: false 26 | type: string 27 | test_build_name: 28 | description: "Test build name" 29 | required: false 30 | default: "" 31 | type: string 32 | test_release_type: 33 | description: "prerelease or draft" 34 | required: false 35 | default: "" 36 | type: string 37 | x86_64: 38 | description: "Build x86_64 version of Emacs" 39 | required: false 40 | default: true 41 | type: boolean 42 | arm64: 43 | description: "Build arm64 version of Emacs" 44 | required: false 45 | default: true 46 | type: boolean 47 | 48 | jobs: 49 | prepare: 50 | name: Prepare 51 | uses: ./.github/workflows/_prepare.yml 52 | with: 53 | builder_ref: ${{ inputs.builder_ref }} 54 | 55 | # ---------------------------------------------------------------------------- 56 | # Build x86_64 version of Emacs 57 | # ---------------------------------------------------------------------------- 58 | 59 | build_x86_64: 60 | name: Build (x86_64) 61 | if: inputs.x86_64 62 | uses: ./.github/workflows/_build_emacs.yml 63 | needs: [prepare] 64 | with: 65 | builder_ref: ${{ needs.prepare.outputs.builder_sha }} 66 | os: "macos-15-intel" 67 | build_os: "macos-15-intel" 68 | artifact_prefix: "x86_64-" 69 | git_ref: ${{ inputs.git_ref }} 70 | git_sha: ${{ inputs.git_sha }} 71 | build_args: ${{ inputs.builder_args }} 72 | build_variant: ${{ inputs.build_variant }} 73 | test_build_name: ${{ inputs.test_build_name }} 74 | test_release_type: ${{ inputs.test_release_type }} 75 | secrets: inherit 76 | 77 | release_x86_64: 78 | name: Release (x86_64) 79 | uses: ./.github/workflows/_release.yml 80 | # Depend on both build_x86_64 and build_arm64, but only run if build_x86_64 81 | # was successful and a package was created. This ensure wait for all builds 82 | # to complete before running any release jobs. 83 | needs: [prepare, build_x86_64, build_arm64] 84 | if: | 85 | always() && 86 | needs.build_x86_64.result == 'success' && 87 | needs.build_x86_64.outputs.package_created && 88 | needs.build_arm64.result != 'failure' 89 | with: 90 | builder_ref: ${{ needs.prepare.outputs.builder_sha }} 91 | os: "macos-15-intel" 92 | plan_artifact: x86_64-build-plan 93 | dmg_artifact: x86_64-dmg 94 | 95 | # ---------------------------------------------------------------------------- 96 | # Build arm64 version of Emacs 97 | # ---------------------------------------------------------------------------- 98 | 99 | build_arm64: 100 | name: Build (arm64) 101 | if: inputs.arm64 102 | uses: ./.github/workflows/_build_emacs.yml 103 | needs: [prepare] 104 | with: 105 | builder_ref: ${{ needs.prepare.outputs.builder_sha }} 106 | os: "macos-15" 107 | build_os: "macos-15" 108 | artifact_prefix: "arm64-" 109 | git_ref: ${{ inputs.git_ref }} 110 | git_sha: ${{ inputs.git_sha }} 111 | build_args: ${{ inputs.builder_args }} 112 | build_variant: ${{ inputs.build_variant }} 113 | test_build_name: ${{ inputs.test_build_name }} 114 | test_release_type: ${{ inputs.test_release_type }} 115 | secrets: inherit 116 | 117 | release_arm64: 118 | name: Release (arm64) 119 | uses: ./.github/workflows/_release.yml 120 | # Depend on both build_arm64 and build_x86_64, but only run if build_arm64 121 | # was successful and a package was created. This ensure wait for all builds 122 | # to complete before running any release jobs. 123 | needs: [prepare, build_arm64, build_x86_64] 124 | if: | 125 | always() && 126 | needs.build_arm64.result == 'success' && 127 | needs.build_arm64.outputs.package_created && 128 | needs.build_x86_64.result != 'failure' 129 | with: 130 | builder_ref: ${{ needs.prepare.outputs.builder_sha }} 131 | os: "macos-15" 132 | plan_artifact: arm64-build-plan 133 | dmg_artifact: arm64-dmg 134 | 135 | # ---------------------------------------------------------------------------- 136 | # Trigger update casks workflow in homebrew tap 137 | # ---------------------------------------------------------------------------- 138 | 139 | update_casks: 140 | name: Update Casks 141 | uses: ./.github/workflows/_update-casks.yml 142 | # Depend on both release jobs, but only run if either of them was 143 | # successful. This ensures we only run this job once all release jobs have 144 | # been completed. 145 | needs: [release_x86_64, release_arm64] 146 | if: >- 147 | always() && 148 | inputs.test_build_name == '' && 149 | contains(needs.*.result, 'success') && 150 | !contains(needs.*.result, 'failure') 151 | secrets: inherit 152 | -------------------------------------------------------------------------------- /.github/workflows/_build_emacs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Requires _prepare.yml re-usable workflow to have run. 3 | name: _build_emacs 4 | on: 5 | workflow_call: 6 | inputs: 7 | builder_ref: 8 | description: Git ref of build-emacs-for-macos to use 9 | type: string 10 | required: true 11 | os: 12 | description: GitHub Actions runner OS 13 | type: string 14 | required: false 15 | default: "macos-15" 16 | build_os: 17 | description: Target OS to build for 18 | type: string 19 | required: false 20 | default: "macos-15" 21 | artifact_prefix: 22 | description: Artifact prefix for build_os 23 | type: string 24 | required: false 25 | git_ref: 26 | description: Git ref to build 27 | type: string 28 | required: true 29 | git_sha: 30 | description: Override git SHA to build 31 | type: string 32 | required: false 33 | build_args: 34 | description: Custom arguments passed to build script 35 | type: string 36 | required: false 37 | build_variant: 38 | description: "Optional build number used as version suffix" 39 | type: string 40 | required: false 41 | test_build_name: 42 | description: "Test build name" 43 | type: string 44 | required: false 45 | test_release_type: 46 | description: "prerelease or draft" 47 | type: string 48 | required: false 49 | default: "prerelease" 50 | outputs: 51 | package_created: 52 | description: "Whether or not a package was created" 53 | value: ${{ jobs.package.result == 'success' }} 54 | 55 | jobs: 56 | plan: 57 | runs-on: ${{ inputs.build_os }} 58 | outputs: 59 | check: ${{ steps.check.outputs.result }} 60 | steps: 61 | - name: Checkout build-emacs-for-macos repo 62 | uses: actions/checkout@v4 63 | with: 64 | repository: jimeh/build-emacs-for-macos 65 | ref: ${{ inputs.builder_ref }} 66 | - name: Download pre-built emacs-builder artifact 67 | uses: actions/download-artifact@v4 68 | with: 69 | name: emacs-builder-${{ runner.arch }} 70 | path: bin 71 | - name: Ensure emacs-builder is executable 72 | run: chmod +x bin/emacs-builder 73 | - uses: nixbuild/nix-quick-install-action@v32 74 | - uses: nix-community/cache-nix-action@v6 75 | with: 76 | primary-key: nix-${{ runner.arch }}-${{ hashFiles('**/flake.*') }} 77 | - name: Install dependencies 78 | run: nix develop --command nix flake metadata 79 | - name: Prepare plan test args 80 | id: test_plan_args 81 | if: inputs.test_build_name != '' 82 | run: >- 83 | echo "args=--test-build '${{ inputs.test_build_name }}' --test-release-type '${{ inputs.test_release_type }}'" >> "$GITHUB_OUTPUT" 84 | - name: Prepare build variant args 85 | id: build_variant_args 86 | if: inputs.build_variant != '' 87 | run: >- 88 | echo "args=--build-variant ${{ inputs.build_variant }}" >> "$GITHUB_OUTPUT" 89 | - name: Set git SHA override 90 | id: emacs_sha 91 | if: inputs.git_sha != '' 92 | run: >- 93 | echo "sha=--sha '${{ inputs.git_sha }}'" >> "$GITHUB_OUTPUT" 94 | - name: Plan build 95 | run: >- 96 | nix develop --command 97 | bin/emacs-builder -l debug plan --output build-plan.yml 98 | --output-dir '${{ github.workspace }}/builds' 99 | ${{ steps.build_variant_args.outputs.args }} 100 | ${{ steps.test_plan_args.outputs.args }} 101 | ${{ steps.emacs_sha.outputs.sha }} 102 | '${{ inputs.git_ref }}' 103 | env: 104 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 105 | - name: Show plan 106 | run: cat build-plan.yml 107 | - name: Upload build-plan artifact 108 | uses: actions/upload-artifact@v4 109 | with: 110 | name: ${{ inputs.artifact_prefix }}build-plan 111 | path: build-plan.yml 112 | if-no-files-found: error 113 | - name: Check if planned release and asset already exist 114 | id: check 115 | continue-on-error: true 116 | run: | 117 | echo "result=$((bin/emacs-builder -l debug release --plan build-plan.yml check && echo 'ok') || echo 'fail')" >> "$GITHUB_OUTPUT" 118 | env: 119 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 120 | - run: echo 'Planned release already seems to exist.' 121 | if: steps.check.outputs.result == 'ok' 122 | 123 | build: 124 | runs-on: ${{ inputs.build_os }} 125 | needs: [plan] 126 | # Only run if check for existing release and asset failed. 127 | if: needs.plan.outputs.check == 'fail' 128 | steps: 129 | - name: Checkout build-emacs-for-macos repo 130 | uses: actions/checkout@v4 131 | with: 132 | repository: jimeh/build-emacs-for-macos 133 | ref: ${{ inputs.builder_ref }} 134 | path: builder 135 | - uses: nixbuild/nix-quick-install-action@v32 136 | - uses: nix-community/cache-nix-action@v6 137 | with: 138 | primary-key: nix-${{ runner.arch }}-${{ hashFiles('**/flake.*') }} 139 | - name: Download build-plan artifact 140 | uses: actions/download-artifact@v4 141 | with: 142 | name: ${{ inputs.artifact_prefix }}build-plan 143 | path: ./builder/ 144 | - name: Install dependencies 145 | run: nix develop --command nix flake metadata 146 | working-directory: builder 147 | - name: Install Ruby dependencies 148 | run: >- 149 | nix develop --command make bootstrap-ruby 150 | working-directory: builder 151 | env: 152 | BUNDLE_WITHOUT: "development" 153 | - name: Build Emacs 154 | run: >- 155 | nix develop 156 | --command ./build-emacs-for-macos 157 | --log-level debug 158 | --plan build-plan.yml 159 | --native-full-aot 160 | --no-self-sign 161 | --icon-uri 'https://github.com/jimeh/emacs-liquid-glass-icons/releases/download/v1.0.1/EmacsLG1-Default.icns' 162 | --tahoe-icon-uri 'https://github.com/jimeh/emacs-liquid-glass-icons/releases/download/v1.0.1/Assets.car' 163 | --tahoe-icon-name EmacsLG1 164 | ${{ inputs.build_args }} 165 | working-directory: builder 166 | env: 167 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 168 | - name: Upload unsigned app artifact 169 | uses: actions/upload-artifact@v4 170 | with: 171 | name: ${{ inputs.artifact_prefix }}unsigned-app 172 | path: builds/*.tbz 173 | if-no-files-found: error 174 | - name: Upload Emacs source artifact 175 | uses: actions/upload-artifact@v4 176 | with: 177 | name: ${{ inputs.artifact_prefix }}emacs-source 178 | path: builder/tarballs/*.tgz 179 | 180 | package: 181 | runs-on: ${{ inputs.os }} 182 | needs: [plan, build] 183 | steps: 184 | - name: Download pre-built emacs-builder artifact 185 | uses: actions/download-artifact@v4 186 | with: 187 | name: emacs-builder-${{ runner.arch }} 188 | path: bin 189 | - name: Ensure emacs-builder is executable 190 | run: chmod +x bin/emacs-builder 191 | - uses: actions/setup-python@v5 192 | with: 193 | python-version: "3.11" 194 | - name: Install dmgbuild 195 | run: | 196 | $(command -v pip3 || command -v pip) install --upgrade dmgbuild 197 | - name: Download build-plan artifact 198 | uses: actions/download-artifact@v4 199 | with: 200 | name: ${{ inputs.artifact_prefix }}build-plan 201 | path: ./ 202 | - name: Download unsigned app artifact 203 | uses: actions/download-artifact@v4 204 | with: 205 | name: ${{ inputs.artifact_prefix }}unsigned-app 206 | path: builds 207 | - name: Extract unsigned app archive 208 | run: | 209 | find * -name '*.tbz' -exec tar xvjf "{}" \; 210 | working-directory: builds 211 | - name: Install the Apple signing certificate 212 | run: | 213 | # create variables 214 | CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12" 215 | KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db" 216 | 217 | # import certificate and provisioning profile from secrets 218 | echo -n "$CERT_BASE64" | base64 --decode > "$CERTIFICATE_PATH" 219 | 220 | # create temporary keychain 221 | security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" 222 | security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" 223 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" 224 | 225 | # import certificate to keychain 226 | security import "$CERTIFICATE_PATH" -P "$CERT_PASSWORD" -A \ 227 | -t cert -f pkcs12 -k "$KEYCHAIN_PATH" 228 | security list-keychain -d user -s "$KEYCHAIN_PATH" 229 | env: 230 | CERT_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} 231 | CERT_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} 232 | KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} 233 | - name: Sign, package and notarize build 234 | run: >- 235 | bin/emacs-builder package -v --plan build-plan.yml 236 | --sign --remove-source-dir 237 | env: 238 | AC_USERNAME: ${{ secrets.AC_USERNAME }} 239 | AC_PASSWORD: ${{ secrets.AC_PASSWORD }} 240 | AC_PROVIDER: ${{ secrets.AC_PROVIDER }} 241 | AC_SIGN_IDENTITY: ${{ secrets.AC_SIGN_IDENTITY }} 242 | - name: Upload disk image artifacts 243 | uses: actions/upload-artifact@v4 244 | with: 245 | name: ${{ inputs.artifact_prefix }}dmg 246 | path: | 247 | builds/*.dmg 248 | builds/*.sha* 249 | if-no-files-found: error 250 | - name: Clean up keychain used for signing certificate 251 | if: always() 252 | run: | 253 | security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" 254 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | Logo 4 | 5 | # Emacs Builds 6 | 7 | [![GitHub release (stable)](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjimeh%2Fhomebrew-emacs-builds%2Fmeta%2FCasks%2Femacs-app%2Fshield.json)](https://github.com/jimeh/emacs-builds/releases/latest) 8 | [![GitHub release (pretest)](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjimeh%2Fhomebrew-emacs-builds%2Fmeta%2FCasks%2Femacs-app-pretest%2Fshield.json)](https://github.com/jimeh/emacs-builds/releases?q=pretest&expanded=true) 9 | [![GitHub release (nightly)](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjimeh%2Fhomebrew-emacs-builds%2Fmeta%2FCasks%2Femacs-app-nightly%2Fshield.json)](https://github.com/jimeh/emacs-builds/releases?q=master&expanded=true) 10 | [![GitHub release (monthly)](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjimeh%2Fhomebrew-emacs-builds%2Fmeta%2FCasks%2Femacs-app-monthly%2Fshield.json)](https://github.com/jimeh/emacs-builds/releases?q=master&expanded=true) 11 | [![GitHub release (known good nightly)](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjimeh%2Fhomebrew-emacs-builds%2Fmeta%2FCasks%2Femacs-app-good%2Fshield.json)](https://github.com/jimeh/emacs-builds/issues/7) 12 | [![GitHub issues](https://img.shields.io/github/issues-raw/jimeh/emacs-builds?style=flat&logo=github&logoColor=white)](https://github.com/jimeh/emacs-builds/issues) 13 | [![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/jimeh/emacs-builds?style=flat&logo=github&logoColor=white)](https://github.com/jimeh/emacs-builds/pulls) 14 | [![Total downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjimeh%2Femacs-builds%2Fmeta%2Ftotal-downloads%2Fshield.json)](https://github.com/jimeh/emacs-builds/releases) 15 | 16 | **Self-contained Emacs.app builds for macOS, with native-compilation support.** 17 | 18 |
19 | 20 | ## Features 21 | 22 | - Self-contained Emacs.app application bundle, with no external dependencies. 23 | - Native compilation ([gccemacs][]). 24 | - Native JSON parsing. 25 | - SVG rendering via librsvg. 26 | - Various image formats are supported via macOS native image APIs. 27 | - Xwidget-webkit support, allowing access to a embedded WebKit-based browser 28 | with `M-x xwidget-webkit-browse-url`. 29 | - Native XML parsing via libxml2. 30 | - Dynamic module loading. 31 | - Includes the [fix-window-role][], [system-appearance][], and 32 | [round-undecorated-frame][] patches from the excellent [emacs-plus][] project. 33 | - Emacs source is fetched from the [emacs-mirror/emacs][] GitHub repository. 34 | - Build creation is transparent and public through the use of GitHub Actions, 35 | allowing anyone to inspect git commit SHAs, full source code, and exact 36 | commands used to produce a build. 37 | - Emacs.app is signed with a developer certificate and notarized by Apple. 38 | - Uses [build-emacs-for-macos][] to build the self-contained application bundle. 39 | 40 | [build-emacs-for-macos]: https://github.com/jimeh/build-emacs-for-macos 41 | [gccemacs]: https://www.emacswiki.org/emacs/GccEmacs 42 | [fix-window-role]: 43 | https://github.com/d12frosted/homebrew-emacs-plus/blob/master/patches/emacs-28/fix-window-role.patch 44 | [system-appearance]: 45 | https://github.com/d12frosted/homebrew-emacs-plus/blob/master/patches/emacs-28/system-appearance.patch 46 | [round-undecorated-frame]: 47 | https://github.com/d12frosted/homebrew-emacs-plus/blob/master/patches/emacs-29/round-undecorated-frame.patch 48 | [emacs-plus]: https://github.com/d12frosted/homebrew-emacs-plus 49 | [emacs-mirror/emacs]: https://github.com/emacs-mirror/emacs 50 | 51 | ## System Requirements 52 | 53 | - Builds produced after 2024-11-30: 54 | - macOS 11 or later. 55 | - Builds produced before 2024-11-30: 56 | - macOS 13 Ventura or later for Apple Silicon builds. 57 | - macOS 12 Monterey or later for Intel builds. 58 | - Xcode Command Line Tools to use native compilation in Emacs, available since 59 | Emacs 28.x builds. 60 | 61 | ## Installation 62 | 63 | ### Manual Download 64 | 65 | See the [Releases][] page to download latest builds, or [here][latest] for the 66 | latest stable release. 67 | 68 | Nightly builds of Emacs are for the most part just fine, but if you don't like 69 | living too close to the edge, see issue [#7 Known Good Nightly Builds][7] for a 70 | list of recent nightly builds which have been actively used by a living being 71 | for at least a day or two without any obvious issues. 72 | 73 | [releases]: https://github.com/jimeh/emacs-builds/releases 74 | [latest]: https://github.com/jimeh/emacs-builds/releases/latest 75 | [7]: https://github.com/jimeh/emacs-builds/issues/7 76 | 77 | ### Homebrew Cask 78 | 79 | The [`jimeh/emacs-builds`](https://github.com/jimeh/homebrew-emacs-builds) 80 | Homebrew Tap provides the following casks: 81 | 82 | - `jimeh/emacs-builds/emacs-app` — Latest stable release of Emacs. 83 | ```bash 84 | brew install --cask jimeh/emacs-builds/emacs-app 85 | ``` 86 | - `jimeh/emacs-builds/emacs-app-pretest` — Latest pretest build of Emacs. 87 | ```bash 88 | brew install --cask jimeh/emacs-builds/emacs-app-pretest 89 | ``` 90 | - `jimeh/emacs-builds/emacs-app-nightly` — Build of Emacs from the `master` 91 | branch, updated every night. 92 | ```bash 93 | brew install --cask jimeh/emacs-builds/emacs-app-nightly 94 | ``` 95 | - `jimeh/emacs-builds/emacs-app-monthly` — Build of Emacs from the `master` 96 | branch, updated on the 1st of each month. 97 | ```bash 98 | brew install --cask jimeh/emacs-builds/emacs-app-monthly 99 | ``` 100 | - `jimeh/emacs-builds/emacs-app-good` for the latest known good nightly build 101 | listed on [#7][7]: 102 | ```bash 103 | brew install --cask jimeh/emacs-builds/emacs-app-good 104 | ``` 105 | 106 | ## Apple Silicon 107 | 108 | As of 2024-11-30, all builds include both Apple Silicon (arm64) and Intel 109 | (x86_64) artifacts. 110 | 111 | ## Use Emacs.app as `emacs` CLI Tool 112 | 113 | ### Installed via Homebrew Cask 114 | 115 | The cask installation method sets up CLI usage automatically by exposing a 116 | `emacs` command. However it will launch Emacs into GUI mode. To instead have 117 | `emacs` in your terminal open a terminal instance of Emacs, add the following 118 | alias to your shell setup: 119 | 120 | ```bash 121 | alias emacs="emacs -nw" 122 | ``` 123 | 124 | ### Installed Manually 125 | 126 | Builds come with a custom `emacs` shell script launcher for use from the command 127 | line, located next to `emacsclient` in `Emacs.app/Contents/MacOS/bin`. 128 | 129 | The custom `emacs` script makes sure to use the main 130 | `Emacs.app/Contents/MacOS/Emacs` executable from the correct path, ensuring it 131 | finds all the relevant dependencies within the Emacs.app bundle, regardless of 132 | if it's exposed via `PATH` or symlinked from elsewhere. 133 | 134 | To use it, simply add `Emacs.app/Contents/MacOS/bin` to your `PATH`. For 135 | example, if you place Emacs.app in `/Applications`: 136 | 137 | ```bash 138 | if [ -d "/Applications/Emacs.app/Contents/MacOS/bin" ]; then 139 | export PATH="/Applications/Emacs.app/Contents/MacOS/bin:$PATH" 140 | alias emacs="emacs -nw" # Always launch "emacs" in terminal mode. 141 | fi 142 | ``` 143 | 144 | If you want `emacs` in your terminal to launch a GUI instance of Emacs, don't 145 | use the alias from the above example. 146 | 147 | ## Build Process 148 | 149 | Building Emacs is done using the [jimeh/build-emacs-for-macos][] build script, 150 | executed within a GitHub Actions [workflow][]. 151 | 152 | [jimeh/build-emacs-for-macos]: https://github.com/jimeh/build-emacs-for-macos 153 | [workflow]: 154 | https://github.com/jimeh/emacs-builds/blob/main/.github/workflows/nightly-master.yml 155 | 156 | Full history for all builds is available on GitHub Actions [here][actions]. 157 | Build logs are only retained by GitHub for 90 days though. 158 | 159 | [actions]: https://github.com/jimeh/emacs-builds/actions 160 | 161 | Nightly builds are scheduled for 23:00 UTC every night, based on the latest 162 | commit from the `master` branch of the [emacs-mirror/emacs][] repository. This 163 | means a nightly build will only be produced if there have been new commits since 164 | the last nightly build. 165 | 166 | ## Application Signing / Trust 167 | 168 | As of June 21st, 2021, all builds are fully signed and notarized. The signing 169 | certificate used is: `Developer ID Application: Jim Myhrberg (5HX66GF82Z)` 170 | 171 | To verify the application signature and notarization, you can use `spctl`: 172 | 173 | ```bash 174 | $ spctl -vvv --assess --type exec /Applications/Emacs.app 175 | /Applications/Emacs.app: accepted 176 | source=Notarized Developer ID 177 | origin=Developer ID Application: Jim Myhrberg (5HX66GF82Z) 178 | ``` 179 | 180 | All builds also come with a SHA256 checksum file, which itself can be double 181 | checked against the SHA256 checksum log output from the packaging step of the 182 | GitHub Actions workflow run which produced the build. 183 | 184 | ## Issues / To-Do 185 | 186 | Please see [Issues][] for details of things to come, or to report issues. 187 | 188 | [issues]: https://github.com/jimeh/emacs-builds/issues 189 | 190 | ## News / Recent Changes 191 | 192 | ### 2024-12-01 — Apple Silicon builds all the time, more stability via Nix 193 | 194 | GitHub's standard runner for macOS 14 and later runs on Apple Silicon, and are 195 | free to use for public repositories. As such we now use `runs-on: macos-13` for 196 | Intel builds, and `runs-on: macos-14` for Apple Silicon builds. And we do so on 197 | all builds, nightlies, pretests, and stable. 198 | 199 | Additionally, macOS 11 Big Sur is now the minimum required version again, for 200 | both Intel and Apple Silicon builds. This is due to switching from Homebrew to 201 | Nix for managing build-time dependencies. And it supports easily switching 202 | between different macOS SDK versions, meaning we can target an SDK that is older 203 | than the OS we are creating the builds on. 204 | 205 | ### 2023-11-22 — Apple Silicon builds, drop macOS 11 support 206 | 207 | Apple Silicon builds are now available, but limited to stable releases, and 208 | nightly builds on the 1st of each month due to the cost of using M1-based 209 | runners on GitHub Actions. Apple Silicon builds also require macOS 13 Ventura, 210 | as that is the oldest macOS version available on M1-based runners. 211 | 212 | Additionally, Intel builds minimum required macOS version has been increased 213 | from macOS 11 Big Sur, to macOS 12 Monterey. This was needed as Homebrew no 214 | longer supports Big Sur, leading to very lengthy and error prone builds as all 215 | Homebrew dependencies had to be installed from source. 216 | 217 | If dropping support for macOS 11 turns out to be a big issue, it may be possible 218 | to offer macOS 11 compatible builds on a less frequent schedule similar to what 219 | we're doing with Apple Silicon. 220 | --------------------------------------------------------------------------------