Skip to content
Latchkey

Release workflow (xo/dbtpl)

The Release workflow from xo/dbtpl, explained and optimized by Latchkey.

C

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.

Grade your own workflow free or run it on Latchkey →
Source: xo/dbtpl.github/workflows/release.ymlLicense MITView source

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

workflow (.yml)
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

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:

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.

Actions used in this workflow