main workflow (doitintl/kube-no-trouble)
The main workflow from doitintl/kube-no-trouble, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get caching, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the main workflow from the doitintl/kube-no-trouble 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: main
on:
push:
branches:
- master
tags:
- "*"
pull_request:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- uses: pre-commit/action@v3.0.0
test:
name: test
runs-on: ubuntu-latest
container: golang:1.23-alpine3.20
steps:
- name: Install git
run: apk add --update --no-cache git
- name: Checkout code
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Test
run: |
scripts/alpine-setup.sh
make test
build:
name: build
runs-on: ubuntu-latest
container: golang:1.23-alpine3.20
strategy:
matrix:
os: [linux, darwin, windows]
arch: [arm64, amd64]
exclude:
- os: windows
arch: arm64
steps:
- name: Install git
run: apk add --update --no-cache git
- name: Checkout
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Build
run: |
git config --global --add safe.directory /__w/kube-no-trouble/kube-no-trouble
scripts/alpine-setup.sh
GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} make all
shell: sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Archive release artifacts
uses: actions/upload-artifact@v4
with:
name: release-artifacts-${{ matrix.os }}-${{ matrix.arch }}
path: release-artifacts
build-docker:
name: Build Docker Image
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: false
platforms: |
linux/arm64
linux/amd64
build-args: |
GITHUB_REF
GITHUB_SHA
cache-from: type=gha
cache-to: type=gha
integration-test:
name: integration test
needs:
[pre-commit, build, build-docker, test]
runs-on: ubuntu-latest
strategy:
matrix:
k8s_version: [
"kindest/node:v1.19.16",
"kindest/node:v1.20.15",
"kindest/node:v1.21.14",
"kindest/node:v1.22.17",
"kindest/node:v1.23.17",
"kindest/node:v1.24.17",
"kindest/node:v1.25.16",
"kindest/node:v1.26.14",
"kindest/node:v1.27.11",
"kindest/node:v1.28.7",
"kindest/node:v1.29.2"
]
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
with:
name: release-artifacts-linux-amd64
path: release-artifacts
- name: Create k8s Kind Cluster
uses: helm/kind-action@v1.12.0
with:
node_image: ${{ matrix.k8s_version }}
cluster_name: kubent-test-cluster
- name: run integration test
run: |
tar xvzf release-artifacts/kubent-*-linux-amd64.tar.gz
kubectl version
kubectl cluster-info --context kind-kubent-test-cluster
./kubent
create-release:
name: Create Release
needs:
[integration-test]
runs-on: ubuntu-latest
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
tag_name: ${{ steps.get_tag.outputs.git_tag }}
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
with:
fetch-depth: 0
- name: Generate a changelog
uses: orhun/git-cliff-action@v4
id: git-cliff
with:
config: cliff.toml
args: --verbose --latest
env:
OUTPUT: changelog.md
- uses: actions/download-artifact@v4
with:
name: release-artifacts-linux-amd64
path: release-artifacts
- name: Get the tag
id: get_tag
run: echo "git_tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get_tag.outputs.git_tag }}
release_name: ${{ steps.get_tag.outputs.git_tag }}
body_path: ${{ steps.git-cliff.outputs.changelog }}
draft: ${{ startsWith(steps.get_tag.outputs.git_tag, 'nightly') != true }}
prerelease: ${{ startsWith(steps.get_tag.outputs.git_tag, 'nightly') }}
push-image:
name: Push Image
needs:
[create-release]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout repository
uses: actions/checkout@v4.2.2
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: |
linux/arm64
linux/amd64
tags: |
${{ format('{0}/{1}:{2}', env.REGISTRY, env.IMAGE_NAME, needs.create-release.outputs.tag_name) }}
${{ ( !startsWith(github.ref, 'refs/tags/nightly') && format('{0}/{1}:{2}', env.REGISTRY, env.IMAGE_NAME, 'latest') ) || '' }}
build-args: |
GITHUB_REF
GITHUB_SHA
cache-from: type=gha
cache-to: type=gha
release-artifacts:
name: Release Artifacts
needs:
[create-release]
runs-on: ubuntu-latest
strategy:
matrix:
os: [linux, darwin, windows]
arch: [arm64, amd64]
exclude:
- os: windows
arch: arm64
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/download-artifact@v4
with:
name: release-artifacts-${{ matrix.os }}-${{ matrix.arch }}
path: release-artifacts
- name: Upload Release Asset - ${{ matrix.os }}-${{ matrix.arch }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./release-artifacts/kubent-${{ needs.create-release.outputs.tag_name }}-${{ matrix.os }}-${{ matrix.arch }}.tar.gz
asset_name: kubent-${{ needs.create-release.outputs.tag_name }}-${{ matrix.os }}-${{ matrix.arch }}.tar.gz
asset_content_type: application/tar+gzip
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: main on: push: branches: - master tags: - "*" pull_request: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} concurrency: group: ${{ github.ref }}-${{ github.workflow }} cancel-in-progress: true jobs: pre-commit: timeout-minutes: 30 runs-on: latchkey-small steps: - uses: actions/checkout@v4.2.2 - uses: actions/setup-python@v5 with: cache: 'pip' python-version: '3.x' - uses: pre-commit/action@v3.0.0 test: timeout-minutes: 30 name: test runs-on: latchkey-small container: golang:1.23-alpine3.20 steps: - name: Install git run: apk add --update --no-cache git - name: Checkout code uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - name: Test run: | scripts/alpine-setup.sh make test build: timeout-minutes: 30 name: build runs-on: latchkey-small container: golang:1.23-alpine3.20 strategy: matrix: os: [linux, darwin, windows] arch: [arm64, amd64] exclude: - os: windows arch: arm64 steps: - name: Install git run: apk add --update --no-cache git - name: Checkout uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - name: Build run: | git config --global --add safe.directory /__w/kube-no-trouble/kube-no-trouble scripts/alpine-setup.sh GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} make all shell: sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Archive release artifacts uses: actions/upload-artifact@v4 with: name: release-artifacts-${{ matrix.os }}-${{ matrix.arch }} path: release-artifacts build-docker: timeout-minutes: 30 name: Build Docker Image runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build and push Docker image uses: docker/build-push-action@v6 with: context: . push: false platforms: | linux/arm64 linux/amd64 build-args: | GITHUB_REF GITHUB_SHA cache-from: type=gha cache-to: type=gha integration-test: timeout-minutes: 30 name: integration test needs: [pre-commit, build, build-docker, test] runs-on: latchkey-small strategy: matrix: k8s_version: [ "kindest/node:v1.19.16", "kindest/node:v1.20.15", "kindest/node:v1.21.14", "kindest/node:v1.22.17", "kindest/node:v1.23.17", "kindest/node:v1.24.17", "kindest/node:v1.25.16", "kindest/node:v1.26.14", "kindest/node:v1.27.11", "kindest/node:v1.28.7", "kindest/node:v1.29.2" ] steps: - name: Checkout uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - uses: actions/download-artifact@v4 with: name: release-artifacts-linux-amd64 path: release-artifacts - name: Create k8s Kind Cluster uses: helm/kind-action@v1.12.0 with: node_image: ${{ matrix.k8s_version }} cluster_name: kubent-test-cluster - name: run integration test run: | tar xvzf release-artifacts/kubent-*-linux-amd64.tar.gz kubectl version kubectl cluster-info --context kind-kubent-test-cluster ./kubent create-release: timeout-minutes: 30 name: Create Release needs: [integration-test] runs-on: latchkey-small if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') outputs: upload_url: ${{ steps.create_release.outputs.upload_url }} tag_name: ${{ steps.get_tag.outputs.git_tag }} steps: - name: Checkout uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - name: Generate a changelog uses: orhun/git-cliff-action@v4 id: git-cliff with: config: cliff.toml args: --verbose --latest env: OUTPUT: changelog.md - uses: actions/download-artifact@v4 with: name: release-artifacts-linux-amd64 path: release-artifacts - name: Get the tag id: get_tag run: echo "git_tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT - name: Create Release id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ steps.get_tag.outputs.git_tag }} release_name: ${{ steps.get_tag.outputs.git_tag }} body_path: ${{ steps.git-cliff.outputs.changelog }} draft: ${{ startsWith(steps.get_tag.outputs.git_tag, 'nightly') != true }} prerelease: ${{ startsWith(steps.get_tag.outputs.git_tag, 'nightly') }} push-image: timeout-minutes: 30 name: Push Image needs: [create-release] runs-on: latchkey-small permissions: contents: read packages: write if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') steps: - name: Checkout repository uses: actions/checkout@v4.2.2 - name: Log in to the Container registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build and push Docker image uses: docker/build-push-action@v6 with: context: . push: true platforms: | linux/arm64 linux/amd64 tags: | ${{ format('{0}/{1}:{2}', env.REGISTRY, env.IMAGE_NAME, needs.create-release.outputs.tag_name) }} ${{ ( !startsWith(github.ref, 'refs/tags/nightly') && format('{0}/{1}:{2}', env.REGISTRY, env.IMAGE_NAME, 'latest') ) || '' }} build-args: | GITHUB_REF GITHUB_SHA cache-from: type=gha cache-to: type=gha release-artifacts: timeout-minutes: 30 name: Release Artifacts needs: [create-release] runs-on: latchkey-small strategy: matrix: os: [linux, darwin, windows] arch: [arm64, amd64] exclude: - os: windows arch: arm64 if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') steps: - uses: actions/download-artifact@v4 with: name: release-artifacts-${{ matrix.os }}-${{ matrix.arch }} path: release-artifacts - name: Upload Release Asset - ${{ matrix.os }}-${{ matrix.arch }} uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.create-release.outputs.upload_url }} asset_path: ./release-artifacts/kubent-${{ needs.create-release.outputs.tag_name }}-${{ matrix.os }}-${{ matrix.arch }}.tar.gz asset_name: kubent-${{ needs.create-release.outputs.tag_name }}-${{ matrix.os }}-${{ matrix.arch }}.tar.gz asset_content_type: application/tar+gzip
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. - Cache dependency installs on the setup step so they are served from cache.
- 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 8 jobs (28 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.