CI workflow (itchyny/gojq)
The CI workflow from itchyny/gojq, 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 CI workflow from the itchyny/gojq 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: CI
on:
push:
branches:
- main
tags:
- v*
pull_request:
permissions:
contents: read
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: 1.26.x
- name: Build
run: make build
- name: Check command examples
run: |
# shellcheck disable=SC2016
./gojq -Rsr 'scan("```sh\n( \\$ .*?)```"; "m")[] |
gsub(" +#.*"; "") | splits(" \\$ ") |
capture("(?<command>.+?)\n(?<output>.+)"; "m") |
"if diff <(printf %s \(.output | @sh)) \\
<(\(.command | gsub("gojq"; "./gojq")) 2>&1); then
echo ok: \(.command | @sh)
else
echo ng: \(.command | @sh); exit 1
fi"
' README.md | bash
shell: bash
- name: Cross build
run: make cross
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: goxz
path: goxz
- name: Clean
run: make clean
test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: [1.26.x, 1.25.x, 1.24.x]
fail-fast: false
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}
- name: Test
run: make test
- name: Test with GOARCH=386
run: env GOARCH=386 go test -v ./...
if: matrix.os != 'macos-latest'
- name: Lint
run: make lint
- name: Check tools
run: make check-tools
- name: Check go generate
run: go generate && ! git diff | grep ^
shell: bash
docker:
name: Docker
permissions:
packages: write
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Docker metadata
uses: docker/metadata-action@v6
id: metadata
with:
images: |
${{ github.repository }}
ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=sha,format=long,enable=${{ !startsWith(github.ref, 'refs/tags/v') }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
if: startsWith(github.ref, 'refs/tags/v')
uses: docker/login-action@v4
with:
username: ${{ vars.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
if: startsWith(github.ref, 'refs/tags/v')
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and release Docker image
uses: docker/build-push-action@v7
with:
context: .
push: ${{ startsWith(github.ref, 'refs/tags/v') }}
provenance: false
platforms: linux/amd64, linux/arm64
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
release:
name: Release
needs: [build, test, docker]
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Download artifacts
uses: actions/download-artifact@v8
with:
name: goxz
path: goxz
- name: Setup release body
run: sed -n '/\[${{ github.ref_name }}\]/,/^$/{//!p}' CHANGELOG.md >release-body.txt
- name: Create release
uses: ncipollo/release-action@v1
with:
name: Release ${{ github.ref_name }}
bodyFile: release-body.txt
artifacts: goxz/*
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: CI on: push: branches: - main tags: - v* pull_request: permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: timeout-minutes: 30 name: Build runs-on: latchkey-small steps: - name: Checkout code uses: actions/checkout@v7 - name: Setup Go uses: actions/setup-go@v6 with: go-version: 1.26.x - name: Build run: make build - name: Check command examples run: | # shellcheck disable=SC2016 ./gojq -Rsr 'scan("```sh\n( \\$ .*?)```"; "m")[] | gsub(" +#.*"; "") | splits(" \\$ ") | capture("(?<command>.+?)\n(?<output>.+)"; "m") | "if diff <(printf %s \(.output | @sh)) \\ <(\(.command | gsub("gojq"; "./gojq")) 2>&1); then echo ok: \(.command | @sh) else echo ng: \(.command | @sh); exit 1 fi" ' README.md | bash shell: bash - name: Cross build run: make cross - name: Upload artifact uses: actions/upload-artifact@v7 with: name: goxz path: goxz - name: Clean run: make clean test: timeout-minutes: 30 name: Test runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] go: [1.26.x, 1.25.x, 1.24.x] fail-fast: false steps: - name: Checkout code uses: actions/checkout@v7 - name: Setup Go uses: actions/setup-go@v6 with: go-version: ${{ matrix.go }} - name: Test run: make test - name: Test with GOARCH=386 run: env GOARCH=386 go test -v ./... if: matrix.os != 'macos-latest' - name: Lint run: make lint - name: Check tools run: make check-tools - name: Check go generate run: go generate && ! git diff | grep ^ shell: bash docker: timeout-minutes: 30 name: Docker permissions: packages: write runs-on: latchkey-small steps: - name: Checkout code uses: actions/checkout@v7 - name: Docker metadata uses: docker/metadata-action@v6 id: metadata with: images: | ${{ github.repository }} ghcr.io/${{ github.repository }} tags: | type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }} type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }} type=semver,pattern={{major}},enable=${{ startsWith(github.ref, 'refs/tags/v') }} type=sha,format=long,enable=${{ !startsWith(github.ref, 'refs/tags/v') }} - name: Set up QEMU uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Login to Docker Hub if: startsWith(github.ref, 'refs/tags/v') uses: docker/login-action@v4 with: username: ${{ vars.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Login to GitHub Container Registry if: startsWith(github.ref, 'refs/tags/v') uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and release Docker image uses: docker/build-push-action@v7 with: context: . push: ${{ startsWith(github.ref, 'refs/tags/v') }} provenance: false platforms: linux/amd64, linux/arm64 tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} release: timeout-minutes: 30 name: Release needs: [build, test, docker] if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write runs-on: latchkey-small steps: - name: Checkout code uses: actions/checkout@v7 - name: Download artifacts uses: actions/download-artifact@v8 with: name: goxz path: goxz - name: Setup release body run: sed -n '/\[${{ github.ref_name }}\]/,/^$/{//!p}' CHANGELOG.md >release-body.txt - name: Create release uses: ncipollo/release-action@v1 with: name: Release ${{ github.ref_name }} bodyFile: release-body.txt artifacts: goxz/*
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.
6 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:
- Container pulls and builds
This workflow runs 4 jobs (12 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.