Build #44
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# # | |
# ZETTLR MAIN BUILD GITHUB ACTIONS FILE # | |
# # | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# # | |
# This file contains the logic necessary to build a full release from source. # | |
# # | |
# WHEN IT RUNS: # | |
# # | |
# * Whenever someone successfully pushes develop --> master. # | |
# * Every Monday at noon (UTC) # | |
# * Manually # | |
# # | |
# The last two events are being used to create nightly releases. The first # | |
# event type indicates that the pipeline should build a regular release. # | |
# # | |
# HOW IT RUNS: # | |
# # | |
# 1. Three virtual machines are spun up in parallel: A Windows VM, a Ubuntu # | |
# VM, and a macOS VM. All three are tasked with building all releases that # | |
# we offer for the given platform. The Ubuntu VM builds the most since we # | |
# have many more Linux releases. Windows and macOS only build one x64 and # | |
# one ARM release. However, they also perform code signing (and # | |
# notarization in case of the macOS VM), which the Ubuntu VM doesn't do. # | |
# 2. Each VM uploads all resulting artifacts into their respective artifact # | |
# space, named "linux", "darwin", and "win32" respectively (analogous to # | |
# node.js's process.platform-variable). # | |
# 3. Iff (if and only if) all three runners have shut down successfully, # | |
# indicating successful builds, another Ubuntu VM will be started. That # | |
# one is tasked with downloading all releases from the three artifact # | |
# spaces, calculate the SHA-256 checksums for every file and afterwards # | |
# upload all files: In case of a nightly to the Zettlr server, where they # | |
# can be downloaded from nightly.zettlr.com, or, in case of a regular # | |
# release, to a newly created release draft here on GitHub. # | |
# # | |
# THINGS TO NOTE: # | |
# # | |
# * Every runner will retrieve the package.json's "version" field by running # | |
# a somewhat weird-looking command. This is necessary to make finding the # | |
# releases easier which are being produced by electron-forge and electron- # | |
# builder. # | |
# * Especially the macOS runner can often produce problems, because there # | |
# have been rumors that apparently even the macOS server operating systems # | |
# tend to open modal windows -- even though they're running headless. This # | |
# means that in case the macOS runners seem to hang it's likely we again # | |
# need to update the add-osx-cert.sh script. # | |
# * Everything is being run on Bash. Although PowerShell can do a lot, this # | |
# way all steps are within one language, making it easier to maintain. # | |
# # | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
on: | |
push: | |
branches: | |
- master | |
workflow_dispatch: {} # Used to manually trigger a nightly build. | |
schedule: # Every Monday at noon (UTC) we run a scheduled nightly build | |
- cron: '0 12 * * 1' | |
# Defaults for every job and step in this workflow | |
defaults: | |
run: | |
shell: bash # Run everything using bash | |
# Global environment variables | |
env: | |
NODE_VERSION: '18' | |
# Ensure only a single build workflow runs at any one time | |
concurrency: | |
group: ${{ github.workflow }} | |
cancel-in-progress: true | |
# This workflow file contains four jobs, three to build the corresponding | |
# releases on all three supported platforms, and a last one, which will | |
# create the release draft. | |
jobs: | |
# Trigger a refresh of the translations before every *proper* build. | |
i18n: | |
if: github.ref_name == 'master' | |
name: 'Preflight: Update translations' | |
uses: ./.github/workflows/i18n.yaml | |
# First, ensure that nothing breaks before attempting to build | |
preflight: | |
name: 'Preflight: Lint/Unit tests' | |
uses: ./.github/workflows/check.yml | |
# If we're building a full release, we have to make sure that nobody (that is: | |
# Hendrik) forgot to increment the tag version. If we already have a tag with | |
# this version, we should not proceed, because that will then lead to an | |
# overwriting of the files in the previous release. That doesn't wreak any | |
# havoc because we don't push unstable code to master, BUT it looks bad. | |
verify_version: | |
name: 'Preflight: Verify version tag' | |
runs-on: ubuntu-20.04 | |
steps: | |
- name: Clone repository (master branch) | |
uses: actions/checkout@v3 | |
with: | |
ref: 'master' | |
fetch-depth: 0 # Required for the tag verification step. | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
- name: Verify the corresponding tag does not yet exist | |
if: github.ref_name == 'master' | |
# NOTE: the ! will return 0 if the command fails, and 1 otherwise | |
run: '! git rev-parse "v${{env.version}}"' | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# # | |
# WINDOWS BUILDS # | |
# # | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
build_win_x64: | |
name: Windows (x86_64) | |
env: | |
npm_config_arch: x64 | |
needs: [preflight, verify_version, i18n] | |
runs-on: windows-latest | |
steps: | |
- name: Checkout branch ${{ github.ref_name }} | |
uses: actions/checkout@v3 | |
with: | |
ref: ${{ github.ref_name }} | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Set up build environment | |
run: yarn install --immutable | |
- name: Set tag version to nightly | |
if: github.ref_name == 'develop' | |
run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
- name: Package & Release | |
run: yarn package:win-x64 && yarn release:win-x64 | |
env: | |
CSC_LINK: ${{ secrets.WIN_CERT_2025_03_15 }} | |
CSC_KEY_PASSWORD: ${{ secrets.WIN_CERT_PASS_2025_03_15 }} | |
- name: Cache installer | |
uses: actions/upload-artifact@v3 | |
with: | |
name: win32_x64 | |
path: | | |
./release/Zettlr-${{env.version}}-x64.exe | |
# build_win_arm64: | |
# name: Windows (arm64) | |
# env: | |
# npm_config_arch: arm64 | |
# TARGET_ARCH: arm64 # Seen at https://github.com/hydraulic-software/github-desktop/blob/conveyorize/.github/workflows/ci.yml | |
# needs: [preflight, verify_version, i18n] | |
# runs-on: windows-latest | |
# steps: | |
# - name: Checkout branch ${{ github.ref_name }} | |
# uses: actions/checkout@v3 | |
# with: | |
# ref: ${{ github.ref_name }} | |
# - name: Setup NodeJS ${{ env.NODE_VERSION }} | |
# uses: actions/setup-node@v3 | |
# with: | |
# node-version: ${{ env.NODE_VERSION }} | |
# cache: 'yarn' | |
# # NOTE: While the GitHub Actions hosters have already all required | |
# # software installed for building native ARM64 modules, we have to do one | |
# # step more of preparation, unfortunately. Specifically, we have to | |
# # manually download the correct ARM64 headers as Node.js does not (yet) | |
# # ship those officially. This involves two steps. | |
# # (see https://www.electronjs.org/docs/latest/tutorial/windows-arm/, but | |
# # the tutorial is not completely correct. Shoutout to | |
# # https://github.com/hydraulic-software/github-desktop for the hopefully | |
# # last piece of info we need.) | |
# - name: Retrieve path to AppData/Local | |
# run: | | |
# "appdata=$($env:LOCALAPPDATA)" >> $env:GITHUB_ENV | |
# shell: pwsh # NOTE: Runs explicitly on PowerShell | |
# # Now, we can download the correct headers. NOTE that unlike described in | |
# # the docs, we need to version the cache with the used NODE version, not | |
# # Electron version! Also NOTE that we have to specify node.exe, just node | |
# # WILL NOT WORK, because Windows. | |
# - name: Download Windows arm64 headers | |
# run: | | |
# NODEVER=$(node.exe --version) | |
# mkdir -p "${{ env.appdata }}\\node-gyp\\Cache\\${NODEVER#v}\\arm64" | |
# curl -sL \ | |
# "https://unofficial-builds.nodejs.org/download/release/$NODEVER/win-arm64/node.lib" \ | |
# -o "${{ env.appdata }}\\node-gyp\\Cache\\${NODEVER#v}\\arm64\\node.lib" | |
# # At this point, the Windows ARM64 build should succeed. | |
# - name: Set up build environment | |
# run: yarn install --immutable | |
# env: | |
# npm_config_ensure: "true" | |
# npm_config_dist_url: https://unofficial-builds.nodejs.org/download/release | |
# - name: Set tag version to nightly | |
# if: github.ref_name == 'develop' | |
# run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
# - name: Retrieve tag version | |
# id: ref | |
# run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
# - name: Package & Release | |
# run: yarn package:win-arm && yarn release:win-arm | |
# env: | |
# CSC_LINK: ${{ secrets.WIN_CERT_2025_03_15 }} | |
# CSC_KEY_PASSWORD: ${{ secrets.WIN_CERT_PASS_2025_03_15 }} | |
# # The ARM64 artifact is being output simply as .exe w/o arch, since we | |
# # have to include --ia32 in the build flags for ARM builds (thus, | |
# # strictly speaking it has two architectures). | |
# - name: Rename artifact | |
# run: mv ./release/Zettlr-${{env.version}}.exe ./release/Zettlr-${{env.version}}-arm64.exe | |
# - name: Cache installer | |
# uses: actions/upload-artifact@v3 | |
# with: | |
# name: win32_arm64 | |
# path: | | |
# ./release/Zettlr-${{env.version}}-arm64.exe | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# # | |
# MACOS BUILDS # | |
# # | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
build_macos_x64: | |
name: macOS (x86_64) | |
env: | |
npm_config_arch: x64 | |
needs: [preflight, verify_version, i18n] | |
runs-on: macos-latest | |
steps: | |
# Check out master for a regular release, or develop branch for a nightly | |
- name: Checkout branch ${{ github.ref_name }} | |
uses: actions/checkout@v3 | |
with: | |
ref: ${{ github.ref_name }} | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Set up build environment | |
run: yarn install --immutable | |
- name: Set tag version to nightly | |
if: github.ref_name == 'develop' | |
run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
# Save the macOS certificate on this runner for forge to access it in the | |
# next step below. | |
- name: Retrieve code signing certificate | |
run: ./scripts/add-osx-cert.sh | |
env: | |
MACOS_CERT: ${{ secrets.MACOS_CERT }} | |
MACOS_CERT_PASS: ${{ secrets.MACOS_CERT_PASS }} | |
- name: Package | |
run: yarn package:mac-x64 | |
env: | |
APPLE_ID: ${{ secrets.APPLE_ID }} | |
APPLE_ID_PASS: ${{ secrets.APPLE_ID_PASS }} | |
- name: Release | |
run: yarn release:mac-x64 | |
- name: Cache image file | |
uses: actions/upload-artifact@v3 | |
with: | |
name: darwin_x64 | |
path: | | |
./release/Zettlr-${{env.version}}-x64.dmg | |
build_macos_arm64: | |
name: macOS (arm64) | |
env: | |
npm_config_arch: arm64 | |
needs: [preflight, verify_version, i18n] | |
runs-on: macos-latest | |
steps: | |
- name: Checkout branch ${{ github.ref_name }} | |
uses: actions/checkout@v3 | |
with: | |
ref: ${{ github.ref_name }} | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Set up build environment | |
run: yarn install --immutable | |
- name: Set tag version to nightly | |
if: github.ref_name == 'develop' | |
run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
# Save the macOS certificate on this runner for forge to access it in the | |
# next step below. | |
- name: Retrieve code signing certificate | |
run: ./scripts/add-osx-cert.sh | |
env: | |
MACOS_CERT: ${{ secrets.MACOS_CERT }} | |
MACOS_CERT_PASS: ${{ secrets.MACOS_CERT_PASS }} | |
- name: Package | |
run: yarn package:mac-arm | |
env: | |
APPLE_ID: ${{ secrets.APPLE_ID }} | |
APPLE_ID_PASS: ${{ secrets.APPLE_ID_PASS }} | |
- name: Release | |
run: yarn release:mac-arm | |
- name: Cache image file | |
uses: actions/upload-artifact@v3 | |
with: | |
name: darwin_arm64 | |
path: | | |
./release/Zettlr-${{env.version}}-arm64.dmg | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# # | |
# LINUX BUILDS # | |
# # | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
build_linux_x64: | |
name: Linux (x86_64) | |
env: | |
npm_config_arch: x64 | |
needs: [preflight, verify_version, i18n] | |
runs-on: ubuntu-20.04 | |
steps: | |
# Check out master for a regular release, or develop branch for a nightly | |
- name: Checkout branch ${{ github.ref_name }} | |
uses: actions/checkout@v3 | |
with: | |
ref: ${{ github.ref_name }} | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Set up build environment | |
run: yarn install --immutable | |
- name: Set tag version to nightly | |
# If this a scheduled workflow, we know that we should build a nightly | |
if: github.ref_name == 'develop' | |
run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
- name: Package & Release | |
run: | | |
yarn package:linux-x64 | |
yarn release:linux-x64 | |
- name: Cache installers | |
uses: actions/upload-artifact@v3 | |
with: | |
name: linux_x64 | |
path: | | |
./release/Zettlr-${{env.version}}-amd64.deb | |
./release/Zettlr-${{env.version}}-x86_64.rpm | |
./release/Zettlr-${{env.version}}-x86_64.AppImage | |
build_linux_arm64: | |
name: Linux (arm64) | |
env: | |
npm_config_arch: arm64 | |
needs: [preflight, verify_version, i18n] | |
runs-on: ubuntu-20.04 | |
steps: | |
- name: Checkout branch ${{ github.ref_name }} | |
uses: actions/checkout@v3 | |
with: | |
ref: ${{ github.ref_name }} | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Set up build environment | |
run: yarn install --immutable | |
- name: Set tag version to nightly | |
if: github.ref_name == 'develop' | |
run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
- name: Package & Release | |
run: | | |
yarn package:linux-arm | |
yarn release:linux-arm | |
- name: Cache installers | |
uses: actions/upload-artifact@v3 | |
with: | |
name: linux_arm64 | |
path: | | |
./release/Zettlr-${{env.version}}-arm64.deb | |
./release/Zettlr-${{env.version}}-aarch64.rpm | |
./release/Zettlr-${{env.version}}-arm64.AppImage | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# # | |
# PREPARE RELEASE DRAFT # | |
# # | |
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
# After the three builds, this job downloads all assets, creates and verifies | |
# SHA256 checksums, and finally creates a release draft and uploads all | |
# assets to it. NOTE: If the workflow detects a nightly is being built, this | |
# step rather uploads the binaries to the Zettlr server instead of creating | |
# a release draft. | |
prepare_release: | |
name: Prepare release draft | |
# Make sure (and wait until) the builds have succeeded | |
needs: | |
- build_win_x64 | |
# - build_win_arm64 # DEBUG: Disable win arm for now | |
- build_macos_x64 | |
- build_macos_arm64 | |
- build_linux_x64 | |
- build_linux_arm64 | |
runs-on: ubuntu-20.04 | |
steps: | |
- name: Checkout branch ${{ github.ref_name }} | |
uses: actions/checkout@v3 | |
- name: Setup NodeJS ${{ env.NODE_VERSION }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ env.NODE_VERSION }} | |
cache: 'yarn' | |
- name: Set up build environment | |
run: yarn install --immutable | |
- name: Set tag version to nightly | |
if: github.ref_name == 'develop' | |
run: echo "$(cat package.json | jq '.version = .version + "-nightly"')" > package.json | |
- name: Retrieve tag version | |
id: ref | |
run: echo "version=$(cat package.json | jq -r '.version')" >> $GITHUB_ENV | |
- name: Make release directory | |
run: mkdir ./release | |
# Download all resulting assets from the previous steps. | |
- name: Retrieve installers (Windows x86_64) | |
uses: actions/download-artifact@v3 | |
with: | |
name: win32_x64 | |
path: ./release | |
# - name: Retrieve installers (Windows arm64) | |
# uses: actions/download-artifact@v3 | |
# with: | |
# name: win32_arm64 | |
# path: ./release # DEBUG: Disable win arm for now | |
- name: Retrieve installers (macOS x86_64) | |
uses: actions/download-artifact@v3 | |
with: | |
name: darwin_x64 | |
path: ./release | |
- name: Retrieve installers (macOS arm64) | |
uses: actions/download-artifact@v3 | |
with: | |
name: darwin_arm64 | |
path: ./release | |
- name: Retrieve installers (Linux x86_64) | |
uses: actions/download-artifact@v3 | |
with: | |
name: linux_x64 | |
path: ./release | |
- name: Retrieve installers (Linux arm64) | |
uses: actions/download-artifact@v3 | |
with: | |
name: linux_arm64 | |
path: ./release | |
# Generate the checksums | |
- name: Generate SHA256 checksums | |
# sha256sum "Zettlr-${{env.version}}-arm64.exe" >> "SHA256SUMS.txt" # DEBUG: Disable win arm for now | |
run: | | |
cd ./release | |
sha256sum "Zettlr-${{env.version}}-x64.exe" > "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-x64.dmg" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-arm64.dmg" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-x86_64.AppImage" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-arm64.AppImage" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-amd64.deb" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-arm64.deb" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-x86_64.rpm" >> "SHA256SUMS.txt" | |
sha256sum "Zettlr-${{env.version}}-aarch64.rpm" >> "SHA256SUMS.txt" | |
cd .. | |
- name: Verify checksums | |
run: | | |
cd ./release | |
sha256sum -c SHA256SUMS.txt | |
cd .. | |
# IF WE BUILD A NIGHTLY, AT THIS POINT JUST UPLOAD TO THE SERVER. | |
# We must make sure to copy the three additional files | |
# to the release folder because of the --delete flag in rsync below. | |
- name: Copy Nightly Static Files | |
if: github.ref_name == 'develop' | |
run: | | |
cp ./scripts/assets/nightly-index.php ./release/index.php | |
cp ./scripts/assets/nightly-sm_preview.png ./release/sm_preview.png | |
cp ./resources/icons/png/512x512.png ./release/logo.png | |
- name: Upload nightlies to the server | |
if: github.ref_name == 'develop' | |
uses: easingthemes/ssh-deploy@v3.0.1 | |
env: | |
SSH_PRIVATE_KEY: ${{ secrets.NIGHTLY_SSH_PRIVATE_KEY }} | |
# --delete so that no old releases remain on the server. Each iteration is approx. 1GB in size. | |
ARGS: "-vzhr --delete" # verbose, compress, human-readble, recursive, delete | |
SOURCE: "release/" | |
REMOTE_HOST: ${{ secrets.NIGHTLY_REMOTE_HOST }} | |
REMOTE_USER: ${{ secrets.NIGHTLY_REMOTE_USER }} | |
TARGET: ${{ secrets.NIGHTLY_TARGET }} | |
# OTHERWISE: Create a new release draft | |
- name: Create release draft | |
if: github.ref_name == 'master' | |
uses: softprops/action-gh-release@v1 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
# Populate the inputs of the release we already know | |
tag_name: v${{env.version}} | |
name: Release v${{env.version}} | |
body: If you can read this, we have forgotten to fill in the changelog. Sorry! | |
draft: true # Always create as draft, so that we can populate the remaining values easily | |
# Gosh, is that convenient as opposed to earlier! | |
files: | | |
./release/Zettlr-${{env.version}}-x64.exe | |
./release/Zettlr-${{env.version}}-arm64.exe | |
./release/Zettlr-${{env.version}}-x64.dmg | |
./release/Zettlr-${{env.version}}-arm64.dmg | |
./release/Zettlr-${{env.version}}-amd64.deb | |
./release/Zettlr-${{env.version}}-arm64.deb | |
./release/Zettlr-${{env.version}}-x86_64.rpm | |
./release/Zettlr-${{env.version}}-aarch64.rpm | |
./release/Zettlr-${{env.version}}-x86_64.AppImage | |
./release/Zettlr-${{env.version}}-arm64.AppImage | |
./release/SHA256SUMS.txt |