Test workflow (rubenv/sql-migrate)
The Test workflow from rubenv/sql-migrate, 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 Test workflow from the rubenv/sql-migrate 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: Test
on:
push:
branches:
- master
pull_request:
jobs:
test:
strategy:
fail-fast: true
matrix:
go-version: ["1.23", "1.24"]
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true
cache-dependency-path: go.sum
- name: go build
run: go build -o ./bin/sql-migrate ./sql-migrate && ./bin/sql-migrate --help
- name: go test
run: go test ./...
lint:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache: true
cache-dependency-path: go.sum
- name: golangci-lint
uses: golangci/golangci-lint-action@v7
with:
version: v2.1
- name: go mod tidy
run: go mod tidy
- name: check for any changes
run: |
[[ $(git status --porcelain) == "" ]] || (echo "changes detected" && exit 1)
integration:
needs:
- test
- lint
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
go-version: ["1.23", "1.24"]
services:
mysql:
image: mysql:8.0
env:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
MYSQL_ROOT_PASSWORD: ""
MYSQL_DATABASE: "test"
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: "password"
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
MYSQL_HOST: "127.0.0.1"
PGHOST: "127.0.0.1"
PGUSER: "postgres"
PGPASSWORD: "password"
steps:
- name: checkout
uses: actions/checkout@v4
- name: setup-go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true
cache-dependency-path: go.sum
- name: setup databases
run: |
mysql --user=root -e 'CREATE DATABASE IF NOT EXISTS test;'
mysql --user=root -e 'CREATE DATABASE IF NOT EXISTS test_env;'
psql -U postgres -c 'CREATE DATABASE test;'
- name: install sql-migrate
run: go install ./...
- name: postgres
run: bash ./test-integration/postgres.sh
- name: mysql
run: bash ./test-integration/mysql.sh
- name: mysql-flag
run: bash ./test-integration/mysql-flag.sh
- name: mysql-env
run: bash ./test-integration/mysql-env.sh
- name: sqlite
run: bash ./test-integration/sqlite.sh
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Test on: push: branches: - master pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: test: timeout-minutes: 30 strategy: fail-fast: true matrix: go-version: ["1.23", "1.24"] runs-on: latchkey-small steps: - name: checkout uses: actions/checkout@v4 - name: setup-go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} cache: true cache-dependency-path: go.sum - name: go build run: go build -o ./bin/sql-migrate ./sql-migrate && ./bin/sql-migrate --help - name: go test run: go test ./... lint: timeout-minutes: 30 runs-on: latchkey-small steps: - name: checkout uses: actions/checkout@v4 - name: setup-go uses: actions/setup-go@v5 with: go-version: "1.24" cache: true cache-dependency-path: go.sum - name: golangci-lint uses: golangci/golangci-lint-action@v7 with: version: v2.1 - name: go mod tidy run: go mod tidy - name: check for any changes run: | [[ $(git status --porcelain) == "" ]] || (echo "changes detected" && exit 1) integration: timeout-minutes: 30 needs: - test - lint runs-on: latchkey-small strategy: fail-fast: true matrix: go-version: ["1.23", "1.24"] services: mysql: image: mysql:8.0 env: MYSQL_ALLOW_EMPTY_PASSWORD: "1" MYSQL_ROOT_PASSWORD: "" MYSQL_DATABASE: "test" ports: - 3306:3306 options: >- --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 postgres: image: postgres:15 env: POSTGRES_PASSWORD: "password" ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 env: MYSQL_HOST: "127.0.0.1" PGHOST: "127.0.0.1" PGUSER: "postgres" PGPASSWORD: "password" steps: - name: checkout uses: actions/checkout@v4 - name: setup-go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} cache: true cache-dependency-path: go.sum - name: setup databases run: | mysql --user=root -e 'CREATE DATABASE IF NOT EXISTS test;' mysql --user=root -e 'CREATE DATABASE IF NOT EXISTS test_env;' psql -U postgres -c 'CREATE DATABASE test;' - name: install sql-migrate run: go install ./... - name: postgres run: bash ./test-integration/postgres.sh - name: mysql run: bash ./test-integration/mysql.sh - name: mysql-flag run: bash ./test-integration/mysql-flag.sh - name: mysql-env run: bash ./test-integration/mysql-env.sh - name: sqlite run: bash ./test-integration/sqlite.sh
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.
This workflow runs 3 jobs (5 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.