Skip to content

Build, sign and publish release #4

Build, sign and publish release

Build, sign and publish release #4

name: Build, sign and publish release
# this workflow needs the following secrets set up:
#
# ARTIFACTORY_PASSWORD mongoDB artifactory password
# ARTIFACTORY_USER matching username
# GRS_PASSWORD Password for the Windows/Linux signer
# GRS_USERNAME Username for the Windows/Linux signer
# NOTARY_KEY_ID Key id for the macOS notary
# NOTARY_SECRET Secret for the macOS notary
# AWS_S3_ACCESS_KEY_ID Access key with write access to the release bucket
# AWS_S3_SECRET_ACCESS_KEY The matching secret key
# WG_CONFIG A complete wireguard configuration file for notary access
on:
workflow_dispatch:
inputs:
dry_run:
type: boolean
default: false
description: "Skip creating and merging PRs, posting messages and uploading artifacts to a test bucket"
env:
GRS_CONFIG_USER1_USERNAME: ${{ secrets.grs_username }}
GRS_CONFIG_USER1_PASSWORD: ${{ secrets.grs_password }}
S3_BUCKET: ${{ vars.AWS_S3_BUCKET }}
jobs:
build_sign_lw:
name: Build/sign Windows/Linux
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install wine
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt install -y wine wine32
- name: Install dependencies
run: npm ci
- name: Build the bundle
run: npm run build
- name: Store package version in environment
run: |
PACKAGE_VERSION=`jq -r '.version' package.json`
echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_ENV
# Both the Windows executable as well as the installer need to be signed.
# Electron builder will not rebuild existing files, even if they are
# different from the build results - that behaviour could be used to have
# it stop before packing everything into installers to sign the relevant
# binaries in place. Additionally there's also the option to pack up a
# prepared directory - as that's documented we're going with that one.
#
# Building for additional architectures works without conflicts - so to
# enable arm64 builds for Windows and Linux just add --arm64 here
- name: Prepare installer contents
run: |
npx electron-builder -lw --publish never --dir --x64
# Copying over the app-update.yml from Linux as it is skipped when using --dir
# https://github.com/electron-userland/electron-builder/blob/79df54238621fbe48ba20444129950ba2dc49983/packages/app-builder-lib/src/publish/PublishManager.ts#L113-L115
cat dist/linux-unpacked/resources/app-update.yml
cp dist/linux-unpacked/resources/app-update.yml dist/win-unpacked/resources/app-update.yml
# Docker actions don't seem to support supplying credentials, so log in
# manually
- name: Log in to mongodb registry
uses: docker/login-action@v3
with:
registry: artifactory.corp.mongodb.com
username: ${{ secrets.artifactory_user }}
password: ${{ secrets.artifactory_password }}
# Without having the image available locally the docker action referencing
# an image behind a registry requiring authentication may throw an error
# trying to pull the image - so we manually pull the image.
#
# A docker action has two ways of specifying the container to run:
# - container image, in which case this pull is required
# - Dockerfile, where it builds the image before launching in. In that
# case the pull is not required
# Dockerfile is most sensible when specifying ENTRYPOINT, and a separate
# entrypoint script - which in our simple case would just add two files
# for no added benefit.
- name: pull docker image
run: docker pull artifactory.corp.mongodb.com/release-tools-container-registry-local/garasign-jsign:latest
- name: Sign Windows executable
uses: ./actions/sign-windows
with:
binary: dist/win-unpacked/Realm Studio.exe
# Binary signing for Windows/arm64 just works, if arm64 is enabled above
#- name: Sign Windows executable (arm64)
# uses: ./actions/sign-windows
# with:
# binary: dist/win-arm64-unpacked/Realm Studio.exe
#
# This now just finishes the build step, packing up the installers using
# the binaries with the signatures attached
# Packing up would also work by just repeating above command without the
# --dir in a single command - but to avoid relying on undocumented
# behaviour splitting this up into multiple calls using the --pd switch
# is more sensible
#
# The Linux arm64 installer can easily be enabled, the windows one would
# overwrite the x86_64 one - that'd need changes in electron builder
# config to write that with a different name
- name: Build installers
run: |
npx electron-builder -l --publish never --pd dist/linux-unpacked
npx electron-builder -w --publish never --pd dist/win-unpacked
#npx electron-builder -l --arm64 --publish never --pd dist/linux-arm64-unpacked
#npx electron-builder -w --arm64 --publish never --pd dist/win-arm64-unpacked
#- name: Locate Windows installer
# run: |
# echo "WIN_SETUP=`find dist -name 'Realm Studio Setup *.exe'`" >> $GITHUB_ENV
- name: Rename yaml files
run: |
mv dist/major-*-linux.yml dist/latest-linux.yml
mv dist/major-*-linux-arm64.yml dist/latest-linux-arm64.yml || true
mv dist/major-*.yml dist/latest.yml
- name: Sign Windows installer
uses: ./actions/sign-windows
with:
binary: dist/Realm Studio Setup ${{ env.PACKAGE_VERSION }}.exe
#- name: Sign Windows installer (arm64)
# uses: ./actions/sign-windows
# with:
# binary: dist/Realm Studio Setup ${{ env.PACKAGE_VERSION }}.exe
- name: Archive Linux installers
uses: actions/upload-artifact@v3
with:
name: Linux
path: |
dist/realm-studio-*.tar.gz
dist/Realm Studio-*.AppImage
dist/latest-linux*.yml
- name: Archive Windows installers
uses: actions/upload-artifact@v3
with:
name: Windows
path: |
dist/Realm Studio *.exe
dist/Realm Studio-*-win.zip
dist/*.blockmap
dist/latest.yml
# most of that could be done on a Linux worker to speed things up, but
# - universal binary building is currently only supported on macOS
# - dmg building via electron builder only works on macOS; theoretically
# a dmg can be manually built on Linux, but it's a hacky mess
build_sign_m:
name: Build MacOS
runs-on: macOS-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Store package version in environment
run: |
PACKAGE_VERSION=`jq -r '.version' package.json`
echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_ENV
# the signing endpoint requires whitelisting IPs - we use wireguard to
# make sure we exit with a known IP. To make things easier the secret
# should contain the full client config, including the client secret
# key
- name: Configure wireguard
run: |
brew install wireguard-go wireguard-tools
echo "${{ secrets.WG_CONFIG }}" | base64 -d | sudo tee $(brew --prefix)/etc/wireguard/wg0.conf >/dev/null
sudo wg-quick up wg0
sudo wg
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Build the bundle
run: npm run build
# Producing universal binaries currently fails due to the native realm.node
# binary, and embedding multi-arch binaries there currently seems to be
# mostly unsupported. Once that has been solved the next few build steps
# can be switched to universal. Doing universal builds changes the name
# of the installers - but still creates an autoupdate file with the same
# name, but new installers referenced - so it should be possible to use
# that to pull existing installations to the universal binary via the
# update mechanism
- name: Prepare installer contents
run: |
npx electron-builder -m --publish never --c.mac.target=zip --c.mac.identity=null
#npx electron-builder -m --publish never --c.mac.target=zip --c.mac.identity=null --universal
# Renaming the .zip to make it easier to distinguish
mv dist/*.zip dist/unsigned-app.zip
- name: Download signer
run: |
wget https://macos-notary-1628249594.s3.amazonaws.com/releases/client/v3.8.1/darwin_amd64.zip
unzip darwin_amd64.zip
- name: Run signer
run: |
./darwin_amd64/macnotary -f dist/unsigned-app.zip -m notarizeAndSign -u https://dev.macos-notary.build.10gen.cc/api -s "${{ secrets.NOTARY_SECRET }}" -k "${{ secrets.NOTARY_KEY_ID }}" -b com.mongodb.realm-studio -o "output.zip" -t app -e resources/entitlements.mac.plist
- name: Extract notarized app in electron builder tree
run: |
unzip -d dist/mac -o output.zip
#unzip -d dist/mac-universal -o output.zip
- name: Build installers
run: |
npx electron-builder -m --publish never --pd "dist/mac/Realm Studio.app"
#npx electron-builder -m --publish never --universal --pd "dist/mac-universal/Realm Studio.app"
- name: Rename yaml files
run: |
ls dist/*.yml
mv dist/major-*-mac.yml dist/latest-mac.yml
- name: Archive macOS artifacts
uses: actions/upload-artifact@v3
with:
name: Mac
path: |
dist/latest-mac.yml
dist/*.dmg
dist/Realm Studio-${{ env.PACKAGE_VERSION }}-mac.zip
#dist/Realm Studio-${{ env.PACKAGE_VERSION }}-universal-mac.zip
upload_release:
name: Upload release artifacts to S3
needs: [ build_sign_m, build_sign_lw ]
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Store package version and release channel in environment
run: |
PACKAGE_VERSION=`jq -r '.version' package.json`
echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> $GITHUB_ENV
RELEASE_CHANNEL=`jq -r '.build.publish[0].channel' package.json`
echo "RELEASE_CHANNEL=$RELEASE_CHANNEL" >> $GITHUB_ENV
- run: |
env | sort
- name: Pull macOS artifacts
uses: actions/download-artifact@v3
with:
name: Mac
path: dist
- name: Pull Windows artifacts
uses: actions/download-artifact@v3
with:
name: Windows
path: dist
- name: Pull Linux artifacts
uses: actions/download-artifact@v3
with:
name: Linux
path: dist
- run: |
cargo install better-blockmap
# As the Windows installer gets signed after electron builder is done with
# with it the auto updater files will contain the wrong checksums - this
# just fixes the checksums in an existing yaml file
- name: Update Windows auto-update yaml file
run: |
WIN_INSTALLER="dist/Realm Studio Setup ${{env.PACKAGE_VERSION}}.exe"
OLD_WIN_SHA=`awk '/^sha512/ {print $2}' dist/latest.yml`
NEW_WIN_SHA=`openssl dgst -binary -sha512 "$WIN_INSTALLER" | openssl base64 -A`
if [ "$OLD_WIN_SHA" = "$NEW_WIN_SHA" ]; then
echo "Windows installer sha512 matches file"
echo "This should not happen - probably signing failed"
else
echo "Old windows sha512: $OLD_WIN_SHA"
echo "New windows sha512: $NEW_WIN_SHA"
sed -i "s,sha512:.*,sha512: $NEW_WIN_SHA,g" dist/latest.yml
WIN_SIZE=`stat -c %s "$WIN_INSTALLER"`
sed -i "s,size:.*,size: $WIN_SIZE,g" dist/latest.yml
fi
# The blockmap also is obviously wrong, and needs to be regenerated. For
# some reason Windows doesn't have the zip in the autoupdate file, and
# therefore no blockmap for that.
- name: build Windows blockmaps
run: |
better-blockmap --input "dist/Realm Studio Setup ${{env.PACKAGE_VERSION}}.exe" --output "dist/Realm Studio Setup ${{env.PACKAGE_VERSION}}.exe.blockmap"
# Creating the auto-update files from scratch is required when building
# disk images or installer files outside of electron builder. This
# would generate correct yaml files for macOS. The sed operates on
# a template like the following, default in resources/latest-mac.yml:
#
# version: VERSION
# files:
# - url: Realm Studio-VERSION-mac.zip
# sha512: ZIP_SHA
# size: ZIP_SIZE
# blockMapSize: ZIP_BLOCKMAP_SIZE
# - url: Realm Studio-VERSION.dmg
# sha512: DMG_SHA
# size: DMG_SIZE
# path: Realm Studio-VERSION.zip
# sha512: ZIP_SHA
# RELEASE_DATE
#
#- name: create mac auto-update yaml file
# run: |
# RELEASE_DATE=`grep ^releaseDate: dist/latest.yml`
# ZIP_SHA=`openssl dgst -binary -sha512 "dist/Realm Studio-${{env.PACKAGE_VERSION}}-mac.zip" | openssl base64 -A`
# DMG_SHA=`openssl dgst -binary -sha512 "dist/Realm Studio-${{env.PACKAGE_VERSION}}.dmg" | openssl base64 -A`
# ZIP_SIZE=`stat -c %s "dist/Realm Studio-${{env.PACKAGE_VERSION}}-mac.zip"`
# ZIP_BLOCKMAP_SIZE=`stat -c %s "dist/Realm Studio-${{env.PACKAGE_VERSION}}-mac.zip.blockmap"`
# DMG_SIZE=`stat -c %s "dist/Realm Studio-${{env.PACKAGE_VERSION}}.dmg"`
#
# sed -e "s/RELEASE_DATE/$RELEASE_DATE/" \
# -e "s/VERSION/${{env.PACKAGE_VERSION}}/g" \
# -e "s,ZIP_SHA,$ZIP_SHA,g" \
# -e "s/ZIP_SIZE/$ZIP_SIZE/g" \
# -e "s/ZIP_BLOCKMAP_SIZE/$ZIP_BLOCKMAP_SIZE/g" \
# -e "s,DMG_SHA,$DMG_SHA,g" \
# -e "s/DMG_SIZE/$DMG_SIZE/g" \
# resources/latest-mac.yml > dist/latest-mac.yml
#- name: build macOS blockmaps
# run: |
# better-blockmap --input "dist/Realm Studio-${{env.PACKAGE_VERSION}}.dmg" --output "dist/Realm Studio-${{env.PACKAGE_VERSION}}.dmg.blockmap"
# better-blockmap --input "dist/Realm Studio-${{env.PACKAGE_VERSION}}-mac.zip" --output "dist/Realm Studio-${{env.PACKAGE_VERSION}}-mac.zip.blockmap"
- name: Rename and dump auto-update yaml files for control
run: |
echo "** windows"
cat dist/latest.yml
mv dist/latest.yml dist/${{ env.RELEASE_CHANNEL }}.yml
echo "** linux"
cat dist/latest-linux.yml
mv dist/latest-linux.yml dist/${{ env.RELEASE_CHANNEL }}-linux.yml
echo "** mac"
cat dist/latest-mac.yml
mv dist/latest-mac.yml dist/${{ env.RELEASE_CHANNEL }}-mac.yml
- name: Extract latest release notes
run: |
node ./scripts/extract-changelog.mjs > ./RELEASENOTES.md
cat ./RELEASENOTES.md
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_S3_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_SECRET_ACCESS_KEY }}
aws-region: us-east-1
# This needs to be adjusted to the actual s3 bucket (which probably also
# could just come via repository secret). Initially this should go to the
# old location, and moved to a new one when we're sure we can move
# existing installations over via the auto update system
- name: Override the S3 bucket when dry running
if: ${{ inputs.dry_run }}
run: |
echo "S3_BUCKET=s3://static.realm.io/ci/test/$PACKAGE_VERSION" >> $GITHUB_ENV
- name: Upload release
run: |
aws s3 sync --acl public-read dist ${{ env.S3_BUCKET }}
- name: Find Release PR
uses: juliangruber/find-pull-request-action@v1.7.0
id: find-pull-request
with:
branch: ${{ github.ref }}
- name: Merge Pull Request
uses: juliangruber/merge-pull-request-action@8a13f2645ad8b6ada32f829b2fae9c0955a5265d
if: ${{ inputs.dry_run == false }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ steps.find-pull-request.outputs.number }}
method: squash
- name: Publish Github Release
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5
if: ${{ inputs.dry_run == false }}
with:
artifacts: "dist/*.exe,dist/*.dmg,dist/*.zip,dist/*.AppImage"
bodyFile: ./RELEASENOTES.md
commit: ${{ steps.find-pull-request.outputs.base-ref }}
tag: v${{ env.PACKAGE_VERSION }}
token: ${{ secrets.GITHUB_TOKEN }}
draft: false
- name: 'Post to Slack'
uses: realm/ci-actions/release-to-slack@fa20eb972b9f018654fdb4e2c7afb52b0532f907
if: ${{ inputs.dry_run == false }}
with:
changelog: ./RELEASENOTES.md
sdk: realm-studio
webhook-url: ${{ secrets.SLACK_RELEASE_WEBHOOK }}
version: ${{ env.PACKAGE_VERSION }}
# This job might fail due to failed markdown-to-slack conversion.
continue-on-error: true
- name: Checkout base branch (after merge)
uses: actions/checkout@v3
if: ${{ inputs.dry_run == false }}
with:
submodules: recursive
ref: ${{ steps.find-pull-request.outputs.base-ref }}
- name: Update Changelog
run: |
echo "## vNext (TBD)
### Enhancements
* None
### Fixed
* None
### Internals
* None
" | cat - CHANGELOG.md >> temp
mv temp CHANGELOG.md
shell: bash
- name: Create vNext PR
if: ${{ inputs.dry_run == false }}
id: vnext-pr
uses: peter-evans/create-pull-request@6c704eb7a8ba1daa13da0dcea9bb93a4fe530275
with:
branch: prepare-vnext
title: Prepare for vNext
body: Update Changelog for vNext
delete-branch: true
base: main
commit-message: Prepare for vNext
assignees: ${{ github.event.sender.login }}
labels: no-jira-ticket
- name: Merge Pull Request
uses: juliangruber/merge-pull-request-action@333730196b34b74936aad75a4e31c23a57582d14
if: ${{ inputs.dry_run == false }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ steps.vnext-pr.outputs.pull-request-number }}
method: squash