Skip to content
Latchkey

Go workflow (mxschmitt/playwright-go)

The Go workflow from mxschmitt/playwright-go, explained and optimized by Latchkey.

B

CI health: B - good

Point runs-on at Latchkey and get 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: mxschmitt/playwright-go.github/workflows/build.ymlLicense MITView source

What it does

This is the Go workflow from the mxschmitt/playwright-go 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: Go
on:
  push:
    branches: [ main, roll/* ]
  pull_request:
    branches: [ main, roll/* ]
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v7
    - name: Set up Go 1.x
      uses: actions/setup-go@v6
      with:
        go-version: oldstable
      id: go
    - name: golangci-lint
      uses: golangci/golangci-lint-action@v9
      with:
        version: latest
  test:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        browser: [chromium, firefox, webkit]
        go: ['stable', 'oldstable']
    runs-on: ${{ matrix.os }}
    name:  ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }}
    permissions:
      # Needed for flakiness.io upload via GitHub OIDC (no access token required).
      id-token: write
      contents: read
    steps:
    - uses: actions/checkout@v7
      with:
        submodules: true
    - name: Set up Go
      uses: actions/setup-go@v6
      with:
        go-version: ${{ matrix.go }}
      id: go
    - name: Cache drivers
      uses: actions/cache@v6
      with:
        # In order:
        # * Driver for linux
        # * Driver for macOS
        # * Driver for windows
        path: |
          ~/.cache/ms-playwright-go
          ~/.cache/ms-playwright
          ~/Library/Caches/ms-playwright-go
          ~/Library/Caches/ms-playwright
          ~\AppData\Local\ms-playwright-go
          ~\AppData\Local\ms-playwright
        key: ${{ runner.os }}-go${{ matrix.go }}-${{ matrix.browser }}-${{ hashFiles('**/run.go') }}
    - run: |
        go install ./...
        go install github.com/mxschmitt/flakiness-go/cmd/flakiness-go@latest
        go install gotest.tools/gotestsum@latest
        playwright install --with-deps ${{ matrix.browser }}
    # We run the suite through gotestsum so that flaky tests (browser-side
    # timing races that upstream microsoft/playwright absorbs with `retries: 3`)
    # are re-run instead of failing the whole job. gotestsum re-runs ONLY the
    # failed tests, exits 0 if each passes within the attempt budget, and
    # writes every attempt to --jsonfile. We then pipe that json into
    # `flakiness-go --stdin`, which records each attempt as a distinct
    # RunAttempt - so a fail-then-pass is uploaded to flakiness.io as *flaky*
    # (visible), not hidden. A test that fails every attempt still fails the
    # job (gotestsum exits non-zero), and --rerun-fails-max-failures aborts the
    # rerun if a broad breakage produces too many failures to be "flaky".
    #
    # Exit handling: `flakiness-go --stdin` always exits 0 (it is a reporter),
    # so the pass/fail gate is gotestsum's exit code, captured below. We always
    # run the reporter - even on a hard failure - so the failure is uploaded.
    #
    # Coverage caveat: when a rerun happens, `go test` overwrites covprofile
    # with only the re-run test's coverage. Reruns are rare (only on a flake)
    # and coverage upload is best-effort (continue-on-error, stable only), so we
    # accept the occasional degraded number rather than running the suite twice.
    - name: Test
      shell: bash
      env:
        BROWSER: ${{ matrix.browser }}
        FLAKINESS_PROJECT: playwright-community/playwright-go
        FLAKINESS_NAME: ${{ matrix.browser }}
      if: matrix.os == 'ubuntu-latest'
      run: |
        ec=0
        xvfb-run gotestsum \
          --format standard-verbose \
          --rerun-fails=2 \
          --rerun-fails-max-failures=15 \
          --packages=./... \
          --jsonfile=gotest-report.json \
          -- -timeout=15m -coverprofile=covprofile -coverpkg="github.com/mxschmitt/playwright-go" --race || ec=$?
        flakiness-go --stdin < gotest-report.json || true
        exit $ec
    - name: Test
      shell: bash
      env:
        BROWSER: ${{ matrix.browser }}
        FLAKINESS_PROJECT: playwright-community/playwright-go
        FLAKINESS_NAME: ${{ matrix.browser }}
      if: matrix.os != 'ubuntu-latest'
      run: |
        ec=0
        gotestsum \
          --format standard-verbose \
          --rerun-fails=2 \
          --rerun-fails-max-failures=15 \
          --packages=./... \
          --jsonfile=gotest-report.json \
          -- -timeout=15m -coverprofile=covprofile -coverpkg="github.com/mxschmitt/playwright-go" --race || ec=$?
        flakiness-go --stdin < gotest-report.json || true
        exit $ec
    - name: Send coverage
      uses: shogo82148/actions-goveralls@v1
      if: matrix.go == 'stable'
      with:
          path-to-profile: covprofile
          flag-name: ${{ matrix.os }}-${{ matrix.browser }}
          parallel: true
      continue-on-error: true
  finish:
    if: ${{ always() }}
    needs: test
    runs-on: ubuntu-latest
    steps:
    - uses: shogo82148/actions-goveralls@v1
      with:
        parallel-finished: true
  test-examples:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v7
    - name: Set up Go 1.x
      uses: actions/setup-go@v6
      with:
        go-version: oldstable
      id: go
    - run: |
        go install ./...
        playwright install --with-deps
    - name: Run examples
      run: |
        for dir in examples/*; do
          echo "::group::go run $dir/main.go"
          xvfb-run -a go run $dir/main.go
          echo "::endgroup::"
        done

The same workflow, on Latchkey

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

name: Go
on:
  push:
    branches: [ main, roll/* ]
  pull_request:
    branches: [ main, roll/* ]
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
  lint:
    timeout-minutes: 30
    name: Lint
    runs-on: latchkey-small
    steps:
    - uses: actions/checkout@v7
    - name: Set up Go 1.x
      uses: actions/setup-go@v6
      with:
        go-version: oldstable
      id: go
    - name: golangci-lint
      uses: golangci/golangci-lint-action@v9
      with:
        version: latest
  test:
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        browser: [chromium, firefox, webkit]
        go: ['stable', 'oldstable']
    runs-on: ${{ matrix.os }}
    name:  ${{ matrix.browser }} on ${{ matrix.os }}, go ${{ matrix.go }}
    permissions:
      # Needed for flakiness.io upload via GitHub OIDC (no access token required).
      id-token: write
      contents: read
    steps:
    - uses: actions/checkout@v7
      with:
        submodules: true
    - name: Set up Go
      uses: actions/setup-go@v6
      with:
        go-version: ${{ matrix.go }}
      id: go
    - name: Cache drivers
      uses: actions/cache@v6
      with:
        # In order:
        # * Driver for linux
        # * Driver for macOS
        # * Driver for windows
        path: |
          ~/.cache/ms-playwright-go
          ~/.cache/ms-playwright
          ~/Library/Caches/ms-playwright-go
          ~/Library/Caches/ms-playwright
          ~\AppData\Local\ms-playwright-go
          ~\AppData\Local\ms-playwright
        key: ${{ runner.os }}-go${{ matrix.go }}-${{ matrix.browser }}-${{ hashFiles('**/run.go') }}
    - run: |
        go install ./...
        go install github.com/mxschmitt/flakiness-go/cmd/flakiness-go@latest
        go install gotest.tools/gotestsum@latest
        playwright install --with-deps ${{ matrix.browser }}
    # We run the suite through gotestsum so that flaky tests (browser-side
    # timing races that upstream microsoft/playwright absorbs with `retries: 3`)
    # are re-run instead of failing the whole job. gotestsum re-runs ONLY the
    # failed tests, exits 0 if each passes within the attempt budget, and
    # writes every attempt to --jsonfile. We then pipe that json into
    # `flakiness-go --stdin`, which records each attempt as a distinct
    # RunAttempt - so a fail-then-pass is uploaded to flakiness.io as *flaky*
    # (visible), not hidden. A test that fails every attempt still fails the
    # job (gotestsum exits non-zero), and --rerun-fails-max-failures aborts the
    # rerun if a broad breakage produces too many failures to be "flaky".
    #
    # Exit handling: `flakiness-go --stdin` always exits 0 (it is a reporter),
    # so the pass/fail gate is gotestsum's exit code, captured below. We always
    # run the reporter - even on a hard failure - so the failure is uploaded.
    #
    # Coverage caveat: when a rerun happens, `go test` overwrites covprofile
    # with only the re-run test's coverage. Reruns are rare (only on a flake)
    # and coverage upload is best-effort (continue-on-error, stable only), so we
    # accept the occasional degraded number rather than running the suite twice.
    - name: Test
      shell: bash
      env:
        BROWSER: ${{ matrix.browser }}
        FLAKINESS_PROJECT: playwright-community/playwright-go
        FLAKINESS_NAME: ${{ matrix.browser }}
      if: matrix.os == 'ubuntu-latest'
      run: |
        ec=0
        xvfb-run gotestsum \
          --format standard-verbose \
          --rerun-fails=2 \
          --rerun-fails-max-failures=15 \
          --packages=./... \
          --jsonfile=gotest-report.json \
          -- -timeout=15m -coverprofile=covprofile -coverpkg="github.com/mxschmitt/playwright-go" --race || ec=$?
        flakiness-go --stdin < gotest-report.json || true
        exit $ec
    - name: Test
      shell: bash
      env:
        BROWSER: ${{ matrix.browser }}
        FLAKINESS_PROJECT: playwright-community/playwright-go
        FLAKINESS_NAME: ${{ matrix.browser }}
      if: matrix.os != 'ubuntu-latest'
      run: |
        ec=0
        gotestsum \
          --format standard-verbose \
          --rerun-fails=2 \
          --rerun-fails-max-failures=15 \
          --packages=./... \
          --jsonfile=gotest-report.json \
          -- -timeout=15m -coverprofile=covprofile -coverpkg="github.com/mxschmitt/playwright-go" --race || ec=$?
        flakiness-go --stdin < gotest-report.json || true
        exit $ec
    - name: Send coverage
      uses: shogo82148/actions-goveralls@v1
      if: matrix.go == 'stable'
      with:
          path-to-profile: covprofile
          flag-name: ${{ matrix.os }}-${{ matrix.browser }}
          parallel: true
      continue-on-error: true
  finish:
    timeout-minutes: 30
    if: ${{ always() }}
    needs: test
    runs-on: latchkey-small
    steps:
    - uses: shogo82148/actions-goveralls@v1
      with:
        parallel-finished: true
  test-examples:
    timeout-minutes: 30
    runs-on: latchkey-small
    steps:
    - uses: actions/checkout@v7
    - name: Set up Go 1.x
      uses: actions/setup-go@v6
      with:
        go-version: oldstable
      id: go
    - run: |
        go install ./...
        playwright install --with-deps
    - name: Run examples
      run: |
        for dir in examples/*; do
          echo "::group::go run $dir/main.go"
          xvfb-run -a go run $dir/main.go
          echo "::endgroup::"
        done
 

What changed

2 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 (21 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