Release workflow (xo/dbtpl)
The Release workflow from xo/dbtpl, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Release workflow from the xo/dbtpl repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Release
on: push
env:
APP: xo
VER: ${{ github.ref_name }}
GO_VERSION: stable
jobs:
build_for_linux:
name: Build for Linux
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
arch: [amd64, arm, arm64]
steps:
- name: Install build dependencies
run: |
sudo apt-get -qq update
sudo apt-get install -y \
build-essential \
qemu-user \
gcc-arm-linux-gnueabihf \
g++-arm-linux-gnueabihf \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
libstdc++6-armhf-cross \
libstdc++6-arm64-cross \
libc6-dev-armhf-cross \
libc6-dev-arm64-cross \
file
- name: Checkout
uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Build ${{ matrix.arch }}
run: |
./build.sh -v $VER -a ${{ matrix.arch }}
- name: Build ${{ matrix.arch }} (static)
if: matrix.arch != 'arm'
run: |
./build.sh -v $VER -a ${{ matrix.arch }} -s
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: dist-linux-${{ matrix.arch }}
path: build/linux/**/*
if-no-files-found: error
build_for_macos:
name: Build for macOS
runs-on: macos-latest
strategy:
matrix:
arch: [amd64, arm64]
steps:
- name: Install build dependencies
run: |
brew install coreutils gnu-tar
- name: Checkout
uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Build ${{ matrix.arch }}
run: |
./build.sh -v $VER -a ${{ matrix.arch }}
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: dist-darwin-${{ matrix.arch }}
path: build/darwin/**/*
if-no-files-found: error
build_for_macos_universal:
name: Build for macOS (universal)
needs:
- build_for_macos
runs-on: macos-latest
steps:
- name: Install build dependencies
run: |
brew install coreutils gnu-tar
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Build universal
run: |
export WORKDIR=$PWD/build/darwin/universal/$VER
mkdir -p $WORKDIR
gtar -jxvf dist-darwin-amd64/*/*/*.tar.bz2 -C $WORKDIR $APP
gtar -jxvf dist-darwin-amd64/*/*/*.tar.bz2 -C $WORKDIR LICENSE
mv $WORKDIR/$APP $WORKDIR/$APP-amd64
gtar -jxvf dist-darwin-arm64/*/*/*.tar.bz2 -C $WORKDIR $APP
mv $WORKDIR/$APP $WORKDIR/$APP-arm64
file $WORKDIR/$APP-{amd64,arm64}
lipo -create -output $WORKDIR/$APP $WORKDIR/$APP-amd64 $WORKDIR/$APP-arm64
chmod +x $WORKDIR/$APP
file $WORKDIR/$APP
rm $WORKDIR/$APP-{amd64,arm64}
sudo /usr/sbin/purge
gtar -C $WORKDIR -cjf $WORKDIR/$APP-${VER#v}-darwin-universal.tar.bz2 $APP LICENSE
ls -alh $WORKDIR/*
sha256sum $WORKDIR/*
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: dist-darwin-universal
path: build/darwin/**/*
if-no-files-found: error
build_for_windows:
name: Build for Windows
runs-on: windows-latest
steps:
- name: Install build dependencies
run: choco install zip
- name: Checkout
uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Build amd64
shell: bash
run: |
./build.sh -v $VER
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: dist-windows
path: build/windows/**/*
if-no-files-found: error
release:
name: Draft Release
needs:
- build_for_linux
- build_for_macos
- build_for_macos_universal
- build_for_windows
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/v')
with:
name: ${{ env.APP }} ${{ env.VER }}
draft: true
generate_release_notes: true
files: |
dist-*/*/*/*.tar.bz2
dist-*/*/*/*.zip
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Release on: push env: APP: xo VER: ${{ github.ref_name }} GO_VERSION: stable concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build_for_linux: timeout-minutes: 30 name: Build for Linux runs-on: latchkey-small strategy: fail-fast: false matrix: arch: [amd64, arm, arm64] steps: - name: Install build dependencies run: | sudo apt-get -qq update sudo apt-get install -y \ build-essential \ qemu-user \ gcc-arm-linux-gnueabihf \ g++-arm-linux-gnueabihf \ gcc-aarch64-linux-gnu \ g++-aarch64-linux-gnu \ libstdc++6-armhf-cross \ libstdc++6-arm64-cross \ libc6-dev-armhf-cross \ libc6-dev-arm64-cross \ file - name: Checkout uses: actions/checkout@v3 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Build ${{ matrix.arch }} run: | ./build.sh -v $VER -a ${{ matrix.arch }} - name: Build ${{ matrix.arch }} (static) if: matrix.arch != 'arm' run: | ./build.sh -v $VER -a ${{ matrix.arch }} -s - name: Archive artifacts uses: actions/upload-artifact@v3 with: name: dist-linux-${{ matrix.arch }} path: build/linux/**/* if-no-files-found: error build_for_macos: timeout-minutes: 30 name: Build for macOS runs-on: macos-latest strategy: matrix: arch: [amd64, arm64] steps: - name: Install build dependencies run: | brew install coreutils gnu-tar - name: Checkout uses: actions/checkout@v3 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Build ${{ matrix.arch }} run: | ./build.sh -v $VER -a ${{ matrix.arch }} - name: Archive artifacts uses: actions/upload-artifact@v3 with: name: dist-darwin-${{ matrix.arch }} path: build/darwin/**/* if-no-files-found: error build_for_macos_universal: timeout-minutes: 30 name: Build for macOS (universal) needs: - build_for_macos runs-on: macos-latest steps: - name: Install build dependencies run: | brew install coreutils gnu-tar - name: Download artifacts uses: actions/download-artifact@v3 - name: Build universal run: | export WORKDIR=$PWD/build/darwin/universal/$VER mkdir -p $WORKDIR gtar -jxvf dist-darwin-amd64/*/*/*.tar.bz2 -C $WORKDIR $APP gtar -jxvf dist-darwin-amd64/*/*/*.tar.bz2 -C $WORKDIR LICENSE mv $WORKDIR/$APP $WORKDIR/$APP-amd64 gtar -jxvf dist-darwin-arm64/*/*/*.tar.bz2 -C $WORKDIR $APP mv $WORKDIR/$APP $WORKDIR/$APP-arm64 file $WORKDIR/$APP-{amd64,arm64} lipo -create -output $WORKDIR/$APP $WORKDIR/$APP-amd64 $WORKDIR/$APP-arm64 chmod +x $WORKDIR/$APP file $WORKDIR/$APP rm $WORKDIR/$APP-{amd64,arm64} sudo /usr/sbin/purge gtar -C $WORKDIR -cjf $WORKDIR/$APP-${VER#v}-darwin-universal.tar.bz2 $APP LICENSE ls -alh $WORKDIR/* sha256sum $WORKDIR/* - name: Archive artifacts uses: actions/upload-artifact@v3 with: name: dist-darwin-universal path: build/darwin/**/* if-no-files-found: error build_for_windows: timeout-minutes: 30 name: Build for Windows runs-on: windows-latest steps: - name: Install build dependencies run: choco install zip - name: Checkout uses: actions/checkout@v3 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Build amd64 shell: bash run: | ./build.sh -v $VER - name: Archive artifacts uses: actions/upload-artifact@v3 with: name: dist-windows path: build/windows/**/* if-no-files-found: error release: timeout-minutes: 30 name: Draft Release needs: - build_for_linux - build_for_macos - build_for_macos_universal - build_for_windows runs-on: latchkey-small steps: - name: Download artifacts uses: actions/download-artifact@v3 - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/v') with: name: ${{ env.APP }} ${{ env.VER }} draft: true generate_release_notes: true files: | dist-*/*/*/*.tar.bz2 dist-*/*/*/*.zip
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
1 third-party action is referenced by a movable tag. Pin it to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 5 jobs (8 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.