Skip to content
Latchkey

release workflow (bojand/ghz)

The release workflow from bojand/ghz, 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: bojand/ghz.github/workflows/release.yamlLicense Apache-2.0View source

What it does

This is the release workflow from the bojand/ghz repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: release

on:
  push:
    tags:
      - v*

jobs:
  github_build:
    name: Deploy Release
    strategy:
      matrix:
        target:
          - linux-x86_64
          - linux-arm64
          - darwin-x86_64
          - darwin-arm64
          - windows-x86_64
        include:
          - target: linux-x86_64
            os: ubuntu-latest
            name: ghz-linux-x86_64.tar.gz
            goos: linux
            goarch: amd64
          - target: linux-arm64
            os: ubuntu-latest
            name: ghz-linux-arm64.tar.gz
            goos: linux
            goarch: arm64
          - target: darwin-x86_64
            os: macOS-latest
            name: ghz-darwin-x86_64.tar.gz
            goos: darwin
            goarch: amd64
          - target: darwin-arm64
            os: macOS-latest
            name: ghz-darwin-arm64.tar.gz
            goos: darwin
            goarch: arm64
          - target: windows-x86_64
            os: windows-latest
            name: ghz-windows-x86_64.zip
            goos: windows
            goarch: amd64
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23.0

      - name: Get current time
        uses: josStorer/get-current-time@v2.0.2
        id: current-time

      - name: Get the version
        id: get_tag_version
        run: echo ::set-output name=TAG_VERSION::${GITHUB_REF/refs\/tags\//}
        shell: bash

      - name: Build ghz
        env:
          CGO_ENABLED: 0
          GOOS: ${{ matrix.goos }}
          GOARCH: ${{ matrix.goarch }}
        run: |
          mkdir ./dist/
          mkdir ./dist/${{ matrix.target }}/
          go build -ldflags="-s -w -X 'main.version=${{ steps.get_tag_version.outputs.TAG_VERSION  }}' -X 'main.commit=${{ github.sha }}' -X 'main.date=${{ steps.current-time.outputs.time }}'" -o ./dist/${{ matrix.target }}/ ./cmd/ghz/...
          # file ./dist/${{ matrix.target }}/ghz | grep -F ', statically linked,'

      - name: Build ghz-web
        env:
          CGO_ENABLED: 1
          # various issues with GitHub actions, ARM and CGO
          # disable for now
          # GOOS: ${{ matrix.goos }}
          # GOARCH: ${{ matrix.goarch }}
        run: |
          go build -ldflags="-s -w -X 'main.version=${{ github.ref }}' -X 'main.commit=${{ github.sha }}' -X 'main.date=${{ steps.current-time.outputs.time }}'" -o ./dist/${{ matrix.target }}/ ./cmd/ghz-web/...

      - name: Prepare build artifacts [Windows]
        if: matrix.os == 'windows-latest'
        run: |
          cp ./LICENSE ./dist/${{ matrix.target }}/LICENSE
          cd ./dist/${{ matrix.target }}
          7z a ../../${{ matrix.name }} ghz.exe ghz-web.exe ./LICENSE

      - name: Prepare build artifacts [-nix]
        if: matrix.os != 'windows-latest'
        run: |
          cp ./LICENSE ./dist/${{ matrix.target }}/LICENSE
          cd ./dist/${{ matrix.target }}
          tar czvf ../../${{ matrix.name }} ghz ghz-web LICENSE
          cd -

      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.name }}
          path: ${{ matrix.name }}

  github_release:
    name: Create GitHub Release
    needs: github_build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Prune & Unshallow
        run: git fetch --prune --unshallow

      - name: Set version
        run: |
          echo 'RELEASE_VERSION<<EOF' >> $GITHUB_ENV
          echo ${GITHUB_REF/refs\/tags\//} >> $GITHUB_ENV
          echo 'EOF' >> $GITHUB_ENV

      # These can be squashed when https://github.com/actions/download-artifact/issues/6 is closed
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-linux-x86_64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-linux-arm64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-darwin-x86_64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-darwin-arm64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-windows-x86_64.zip
          path: .

      - name: Generate checksums
        run: for file in ghz-*; do openssl dgst -sha256 -r "$file" | awk '{print $1}' > "${file}.sha256"; done

      - name: Generate release notes
        run: |
          export PATH=$PATH:$(go env GOPATH)/bin
          go install github.com/git-chglog/git-chglog/cmd/git-chglog@latest
          # git-chglog -c .chglog/config.yml $(git describe --tags $(git rev-list --tags --max-count=1))
          git-chglog -c .chglog/config.yml ${{ env.RELEASE_VERSION }} > RELEASE-${{ env.RELEASE_VERSION }}.md
      - name: Create GitHub release ${{ matrix.target }}
        uses: softprops/action-gh-release@v1
        with:
          files: |
            ghz-linux-x86_64.tar.gz
            ghz-linux-x86_64.tar.gz.sha256
            ghz-linux-arm64.tar.gz
            ghz-linux-arm64.tar.gz.sha256
            ghz-darwin-x86_64.tar.gz
            ghz-darwin-x86_64.tar.gz.sha256
            ghz-darwin-arm64.tar.gz
            ghz-darwin-arm64.tar.gz.sha256
            ghz-windows-x86_64.zip
            ghz-windows-x86_64.zip.sha256
          body_path: RELEASE-${{ env.RELEASE_VERSION }}.md
        env:
          GITHUB_TOKEN: ${{ secrets.GH_PAGES_ACTION_TOKEN }}

  update_brew_formula:
    name: Update Brew Formula
    needs: github_release
    runs-on: macos-latest
    strategy:
      matrix:
        formula: [ghz, ghz-web]
    steps:
      - uses: dawidd6/action-homebrew-bump-formula@v3
        with:
          formula: ${{ matrix.formula }}
          token: ${{ secrets.GH_PAGES_ACTION_TOKEN }}

  push_docker_image:
    name: Push Docker image
    needs: github_release
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Set Versions
      uses: actions/github-script@v6
      id: set_version
      with:
        script: |
          const tag = context.ref.substring(10)
          const no_v = tag.replace('v', '')
          core.setOutput('tag', tag)
          core.setOutput('nov', no_v)

    - name: Log in to GitHub Container Registry
      uses: docker/login-action@v2
      with:
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Build and Push Docker Image
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: |
            ghcr.io/${{ github.repository }}:${{steps.set_version.outputs.nov}}
            ghcr.io/${{ github.repository }}:latest

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: release
 
on:
  push:
    tags:
      - v*
 
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  github_build:
    timeout-minutes: 30
    name: Deploy Release
    strategy:
      matrix:
        target:
          - linux-x86_64
          - linux-arm64
          - darwin-x86_64
          - darwin-arm64
          - windows-x86_64
        include:
          - target: linux-x86_64
            os: ubuntu-latest
            name: ghz-linux-x86_64.tar.gz
            goos: linux
            goarch: amd64
          - target: linux-arm64
            os: ubuntu-latest
            name: ghz-linux-arm64.tar.gz
            goos: linux
            goarch: arm64
          - target: darwin-x86_64
            os: macOS-latest
            name: ghz-darwin-x86_64.tar.gz
            goos: darwin
            goarch: amd64
          - target: darwin-arm64
            os: macOS-latest
            name: ghz-darwin-arm64.tar.gz
            goos: darwin
            goarch: arm64
          - target: windows-x86_64
            os: windows-latest
            name: ghz-windows-x86_64.zip
            goos: windows
            goarch: amd64
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
 
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.23.0
 
      - name: Get current time
        uses: josStorer/get-current-time@v2.0.2
        id: current-time
 
      - name: Get the version
        id: get_tag_version
        run: echo ::set-output name=TAG_VERSION::${GITHUB_REF/refs\/tags\//}
        shell: bash
 
      - name: Build ghz
        env:
          CGO_ENABLED: 0
          GOOS: ${{ matrix.goos }}
          GOARCH: ${{ matrix.goarch }}
        run: |
          mkdir ./dist/
          mkdir ./dist/${{ matrix.target }}/
          go build -ldflags="-s -w -X 'main.version=${{ steps.get_tag_version.outputs.TAG_VERSION  }}' -X 'main.commit=${{ github.sha }}' -X 'main.date=${{ steps.current-time.outputs.time }}'" -o ./dist/${{ matrix.target }}/ ./cmd/ghz/...
          # file ./dist/${{ matrix.target }}/ghz | grep -F ', statically linked,'
 
      - name: Build ghz-web
        env:
          CGO_ENABLED: 1
          # various issues with GitHub actions, ARM and CGO
          # disable for now
          # GOOS: ${{ matrix.goos }}
          # GOARCH: ${{ matrix.goarch }}
        run: |
          go build -ldflags="-s -w -X 'main.version=${{ github.ref }}' -X 'main.commit=${{ github.sha }}' -X 'main.date=${{ steps.current-time.outputs.time }}'" -o ./dist/${{ matrix.target }}/ ./cmd/ghz-web/...
 
      - name: Prepare build artifacts [Windows]
        if: matrix.os == 'windows-latest'
        run: |
          cp ./LICENSE ./dist/${{ matrix.target }}/LICENSE
          cd ./dist/${{ matrix.target }}
          7z a ../../${{ matrix.name }} ghz.exe ghz-web.exe ./LICENSE
 
      - name: Prepare build artifacts [-nix]
        if: matrix.os != 'windows-latest'
        run: |
          cp ./LICENSE ./dist/${{ matrix.target }}/LICENSE
          cd ./dist/${{ matrix.target }}
          tar czvf ../../${{ matrix.name }} ghz ghz-web LICENSE
          cd -
 
      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.name }}
          path: ${{ matrix.name }}
 
  github_release:
    timeout-minutes: 30
    name: Create GitHub Release
    needs: github_build
    runs-on: latchkey-small
    steps:
      - name: Checkout
        uses: actions/checkout@v3
 
      - name: Prune & Unshallow
        run: git fetch --prune --unshallow
 
      - name: Set version
        run: |
          echo 'RELEASE_VERSION<<EOF' >> $GITHUB_ENV
          echo ${GITHUB_REF/refs\/tags\//} >> $GITHUB_ENV
          echo 'EOF' >> $GITHUB_ENV
 
      # These can be squashed when https://github.com/actions/download-artifact/issues/6 is closed
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-linux-x86_64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-linux-arm64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-darwin-x86_64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-darwin-arm64.tar.gz
          path: .
      - name: Download releases from github_build
        uses: actions/download-artifact@v4
        with:
          name: ghz-windows-x86_64.zip
          path: .
 
      - name: Generate checksums
        run: for file in ghz-*; do openssl dgst -sha256 -r "$file" | awk '{print $1}' > "${file}.sha256"; done
 
      - name: Generate release notes
        run: |
          export PATH=$PATH:$(go env GOPATH)/bin
          go install github.com/git-chglog/git-chglog/cmd/git-chglog@latest
          # git-chglog -c .chglog/config.yml $(git describe --tags $(git rev-list --tags --max-count=1))
          git-chglog -c .chglog/config.yml ${{ env.RELEASE_VERSION }} > RELEASE-${{ env.RELEASE_VERSION }}.md
      - name: Create GitHub release ${{ matrix.target }}
        uses: softprops/action-gh-release@v1
        with:
          files: |
            ghz-linux-x86_64.tar.gz
            ghz-linux-x86_64.tar.gz.sha256
            ghz-linux-arm64.tar.gz
            ghz-linux-arm64.tar.gz.sha256
            ghz-darwin-x86_64.tar.gz
            ghz-darwin-x86_64.tar.gz.sha256
            ghz-darwin-arm64.tar.gz
            ghz-darwin-arm64.tar.gz.sha256
            ghz-windows-x86_64.zip
            ghz-windows-x86_64.zip.sha256
          body_path: RELEASE-${{ env.RELEASE_VERSION }}.md
        env:
          GITHUB_TOKEN: ${{ secrets.GH_PAGES_ACTION_TOKEN }}
 
  update_brew_formula:
    timeout-minutes: 30
    name: Update Brew Formula
    needs: github_release
    runs-on: macos-latest
    strategy:
      matrix:
        formula: [ghz, ghz-web]
    steps:
      - uses: dawidd6/action-homebrew-bump-formula@v3
        with:
          formula: ${{ matrix.formula }}
          token: ${{ secrets.GH_PAGES_ACTION_TOKEN }}
 
  push_docker_image:
    timeout-minutes: 30
    name: Push Docker image
    needs: github_release
    runs-on: latchkey-small
    steps:
    - name: Checkout
      uses: actions/checkout@v4
 
    - name: Set Versions
      uses: actions/github-script@v6
      id: set_version
      with:
        script: |
          const tag = context.ref.substring(10)
          const no_v = tag.replace('v', '')
          core.setOutput('tag', tag)
          core.setOutput('nov', no_v)
 
    - name: Log in to GitHub Container Registry
      uses: docker/login-action@v2
      with:
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
 
    - name: Build and Push Docker Image
      uses: docker/build-push-action@v2
      with:
        push: true
        tags: |
            ghcr.io/${{ github.repository }}:${{steps.set_version.outputs.nov}}
            ghcr.io/${{ github.repository }}:latest

What changed

5 third-party actions are referenced by a movable tag. Pin them 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 4 jobs (9 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