Skip to content

chore: build releases on a single Linux runner (switch to rcodesign) #3890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 66 additions & 155 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
# GitHub release workflow.
#
# This workflow is a bit complicated because we have to build darwin binaries on
# a mac runner, but the mac runners are extremely slow. So instead of running
# the entire release on a mac (which will take an hour to run), we run only the
# mac build on a mac, and the rest on a linux runner. The final release is then
# published using a final linux runner.
name: release
on:
push:
Expand All @@ -31,7 +25,7 @@ env:
CODER_RELEASE: ${{ github.event.inputs.snapshot && 'false' || 'true' }}

jobs:
linux-windows:
release:
runs-on: ubuntu-latest
env:
# Necessary for Docker manifest
Expand Down Expand Up @@ -72,21 +66,58 @@ jobs:
js-${{ runner.os }}-

- name: Install nfpm
run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.16.0
run: |
set -euo pipefail
wget -O /tmp/nfpm.deb https://github.com/goreleaser/nfpm/releases/download/v2.18.1/nfpm_amd64.deb
sudo dpkg -i /tmp/nfpm.deb
- name: Install zstd
run: sudo apt-get install -y zstd

- name: Build Linux and Windows Binaries
- name: Install rcodesign
run: |
set -euo pipefail

# Install a prebuilt binary of rcodesign for linux amd64. Once the
# following PR is merged and released upstream, we can download
# directly from GitHub releases instead:
# https://github.com/indygreg/PyOxidizer/pull/635
wget -O /tmp/rcodesign https://cdn.discordapp.com/attachments/283356472258199552/1016767245717872700/rcodesign
sudo install --mode 755 /tmp/rcodesign /usr/local/bin/rcodesign

- name: Setup Apple Developer certificate and API key
run: |
set -euo pipefail
touch /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}
chmod 600 /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}
echo "$AC_CERTIFICATE_P12_BASE64" | base64 -d > /tmp/apple_cert.p12
echo "$AC_CERTIFICATE_PASSWORD" > /tmp/apple_cert_password.txt
echo "$AC_APIKEY_P8_BASE64" | base64 -d > /tmp/apple_apikey.p8
env:
AC_CERTIFICATE_P12_BASE64: ${{ secrets.AC_CERTIFICATE_P12_BASE64 }}
AC_CERTIFICATE_PASSWORD: ${{ secrets.AC_CERTIFICATE_PASSWORD }}
AC_APIKEY_P8_BASE64: ${{ secrets.AC_APIKEY_P8_BASE64 }}

- name: Build binaries
run: |
set -euo pipefail
go mod download

version="$(./scripts/version.sh)"
make gen/mark-fresh
make -j \
-W coderd/database/querier.go \
build/coder_"$version"_linux_{amd64,arm64,armv7}.{tar.gz,apk,deb,rpm} \
build/coder_"$version"_windows_{amd64,arm64}.zip \
build/coder_"$version"_linux_{amd64,armv7,arm64}.{tar.gz,apk,deb,rpm} \
build/coder_"$version"_{darwin,windows}_{amd64,arm64}.zip \
build/coder_helm_"$version".tgz
env:
CODER_SIGN_DARWIN: "1"
AC_CERTIFICATE_FILE: /tmp/apple_cert.p12
AC_CERTIFICATE_PASSWORD_FILE: /tmp/apple_cert_password.txt
AC_APIKEY_ISSUER_ID: ${{ secrets.AC_APIKEY_ISSUER_ID }}
AC_APIKEY_ID: ${{ secrets.AC_APIKEY_ID }}
AC_APIKEY_FILE: /tmp/apple_apikey.p8

- name: Delete Apple Developer certificate and API key
run: rm -f /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}

- name: Build Linux Docker images
run: |
Expand All @@ -112,157 +143,37 @@ jobs:
# push it
if [[ "$(git tag | grep '^v' | grep -vE '(rc|dev|-|\+|\/)' | sort -r --version-sort | head -n1)" == "v$(./scripts/version.sh)" ]]; then
./scripts/build_docker_multiarch.sh \
--target "$(./scripts/image_tag.sh --version latest)" \
--push \
--target "$(./scripts/image_tag.sh --version latest)" \
$(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
fi

- name: Upload binary artifacts
uses: actions/upload-artifact@v3
- name: ls build
run: ls -lh build

- name: Publish release
run: |
./scripts/publish_release.sh \
${{ (github.event.inputs.dry_run || github.event.inputs.snapshot) && '--dry-run' }} \
./build/*.zip \
./build/*.tar.gz \
./build/*.tgz \
./build/*.apk \
./build/*.deb \
./build/*.rpm
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload artifacts to actions (if dry-run or snapshot)
if: ${{ github.event.inputs.dry_run || github.event.inputs.snapshot }}
uses: actions/upload-artifact@v2
with:
name: linux
name: release-artifacts
path: |
./build/*.zip
./build/*.tar.gz
./build/*.tgz
./build/*.apk
./build/*.deb
./build/*.rpm

# The mac binaries get built on mac runners because they need to be signed,
# and the signing tool only runs on mac. This darwin job only builds the Mac
# binaries and uploads them as job artifacts used by the publish step.
darwin:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

# If the event that triggered the build was an annotated tag (which our
# tags are supposed to be), actions/checkout has a bug where the tag in
# question is only a lightweight tag and not a full annotated tag. This
# command seems to fix it.
# https://github.com/actions/checkout/issues/290
- name: Fetch git tags
run: git fetch --tags --force

- uses: actions/setup-go@v3
with:
go-version: "~1.19"

- name: Import Signing Certificates
uses: Apple-Actions/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.AC_CERTIFICATE_P12_BASE64 }}
p12-password: ${{ secrets.AC_CERTIFICATE_PASSWORD }}

- name: Cache Node
id: cache-node
uses: actions/cache@v3
with:
path: |
**/node_modules
.eslintcache
key: js-${{ runner.os }}-test-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
js-${{ runner.os }}-

- name: Install dependencies
run: |
set -euo pipefail
# The version of bash that macOS ships with is too old
brew install bash

# The version of make that macOS ships with is too old
brew install make
echo "$(brew --prefix)/opt/make/libexec/gnubin" >> $GITHUB_PATH

# BSD getopt is incompatible with the build scripts
brew install gnu-getopt
echo "$(brew --prefix)/opt/gnu-getopt/bin" >> $GITHUB_PATH

# Used for notarizing the binaries
brew tap mitchellh/gon
brew install mitchellh/gon/gon

# Used for compressing embedded slim binaries
brew install zstd

- name: Build darwin Binaries (with signatures)
run: |
set -euo pipefail
go mod download

version="$(./scripts/version.sh)"
make gen/mark-fresh
make -j \
build/coder_"$version"_darwin_{amd64,arm64}.zip
env:
CODER_SIGN_DARWIN: "1"
AC_USERNAME: ${{ secrets.AC_USERNAME }}
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
AC_APPLICATION_IDENTITY: BDB050EB749EDD6A80C6F119BF1382ECA119CCCC

- name: Upload Binary Artifacts
uses: actions/upload-artifact@v3
with:
name: darwin
path: ./build/*.zip

publish:
runs-on: ubuntu-latest
needs:
- linux-windows
- darwin
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

# If the event that triggered the build was an annotated tag (which our
# tags are supposed to be), actions/checkout has a bug where the tag in
# question is only a lightweight tag and not a full annotated tag. This
# command seems to fix it.
# https://github.com/actions/checkout/issues/290
- name: Fetch git tags
run: git fetch --tags --force

- name: mkdir artifacts
run: mkdir artifacts

- name: Download darwin Artifacts
uses: actions/download-artifact@v3
with:
name: darwin
path: artifacts

- name: Download Linux and Windows Artifacts
uses: actions/download-artifact@v3
with:
name: linux
path: artifacts

- name: ls artifacts
run: ls artifacts

- name: Publish Helm
run: |
set -euxo pipefail

version="$(./scripts/version.sh)"
make -j \
build/coder_helm_"$version".tgz
mv ./build/*.tgz ./artifacts/

- name: Publish Release
run: |
./scripts/publish_release.sh \
${{ (github.event.inputs.dry_run || github.event.inputs.snapshot) && '--dry-run' }} \
./artifacts/*.zip \
./artifacts/*.tar.gz \
./artifacts/*.tgz \
./artifacts/*.apk \
./artifacts/*.deb \
./artifacts/*.rpm
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
retention-days: 7
20 changes: 8 additions & 12 deletions scripts/archive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
# If the --output parameter is not set, the default output path is the binary
# path (minus any .exe suffix) plus the format extension ".zip" or ".tar.gz".
#
# If --sign-darwin is specified, the zip file is signed with the `codesign`
# utility and then notarized using the `gon` utility, which may take a while.
# $AC_APPLICATION_IDENTITY must be set and the signing certificate must be
# imported for this to work. Also, the input binary must already be signed with
# the `codesign` tool.
# If --sign-darwin is specified, the zip file will be notarized using
# ./notarize_darwin.sh, which may take a while. Read that file for more details
# on the requirements.
#
# If the --agpl parameter is specified, only the AGPL license is included in the
# outputted archive.
Expand Down Expand Up @@ -82,20 +80,18 @@ if [[ ! -f "$1" ]]; then
fi
input_file="$(realpath "$1")"

sign_darwin="$([[ "$sign_darwin" == 1 ]] && [[ "$os" == "darwin" ]] && echo 1 || echo 0)"
if [[ "$sign_darwin" == 1 ]] && [[ "${AC_APPLICATION_IDENTITY:-}" == "" ]]; then
error "AC_APPLICATION_IDENTITY must be set when --sign-darwin or CODER_SIGN_DARWIN=1 is supplied"
fi

# Check dependencies
if [[ "$format" == "zip" ]]; then
dependencies zip
fi
if [[ "$format" == "tar.gz" ]]; then
dependencies tar
fi

sign_darwin="$([[ "$sign_darwin" == 1 ]] && [[ "$os" == "darwin" ]] && echo 1 || echo 0)"
if [[ "$sign_darwin" == 1 ]]; then
dependencies jq codesign gon
dependencies rcodesign
requiredenvs AC_APIKEY_ISSUER_ID AC_APIKEY_ID AC_APIKEY_FILE
fi

# Determine default output path.
Expand Down Expand Up @@ -139,7 +135,7 @@ rm -rf "$temp_dir"

if [[ "$sign_darwin" == 1 ]]; then
log "Notarizing archive..."
execrelative ./sign_darwin.sh "$output_path"
execrelative ./notarize_darwin.sh "$output_path"
fi

echo "$output_path"
20 changes: 6 additions & 14 deletions scripts/build_go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
# builds) and the absolute path to the binary will be printed to stdout on
# completion.
#
# If the --sign-darwin parameter is specified and the OS is darwin, binaries
# will be signed using the `codesign` utility. $AC_APPLICATION_IDENTITY must be
# set and the signing certificate must be imported for this to work.
# If the --sign-darwin parameter is specified and the OS is darwin, the output
# binary will be signed using ./sign_darwin.sh. Read that file for more details
# on the requirements.
#
# If the --agpl parameter is specified, builds only the AGPL-licensed code (no
# Coder enterprise features).
Expand Down Expand Up @@ -65,9 +65,6 @@ while true; do
shift
;;
--sign-darwin)
if [[ "${AC_APPLICATION_IDENTITY:-}" == "" ]]; then
error "AC_APPLICATION_IDENTITY must be set when --sign-darwin is supplied"
fi
sign_darwin=1
shift
;;
Expand All @@ -92,7 +89,8 @@ fi
# Check dependencies
dependencies go
if [[ "$sign_darwin" == 1 ]]; then
dependencies codesign
dependencies rcodesign
requiredenvs AC_CERTIFICATE_FILE AC_CERTIFICATE_PASSWORD_FILE
fi

build_args=(
Expand Down Expand Up @@ -133,13 +131,7 @@ CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" GOARM="$arm_version" go build \
"$cmd_path" 1>&2

if [[ "$sign_darwin" == 1 ]] && [[ "$os" == "darwin" ]]; then
codesign \
-f -v \
-s "$AC_APPLICATION_IDENTITY" \
--timestamp \
--options runtime \
"$output_path" \
1>&2
execrelative ./sign_darwin.sh "$output_path" 1>&2
fi

echo "$output_path"
15 changes: 15 additions & 0 deletions scripts/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ dependencies() {
fi
}

requiredenvs() {
local fail=0
for env in "$@"; do
if [[ "${!env:-}" == "" ]]; then
log "ERROR: The '$env' environment variable is required, but is not set."
fail=1
fi
done

if [[ "$fail" == 1 ]]; then
log
error "One or more required environment variables are not set, check above log output for more details."
fi
}

# maybedryrun prints the given program and flags, and then, if the first
# argument is 0, executes it. The reason the first argument should be 0 is that
# it is expected that you have a dry_run variable in your script that is set to
Expand Down
Loading