Verify workflow (ueberdosis/tiptap)
The Verify workflow from ueberdosis/tiptap, explained and optimized by Latchkey.
CI health: B - good
Point runs-on at Latchkey and get caching, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Verify workflow from the ueberdosis/tiptap 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: Verify
env:
NODE_VERSION: 24
PNPM_VERSION: 11.2.2
PNPM_STORE_DIR: .pnpm-store
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
- next
- release/*
pull_request:
branches:
- main
- next
- release/*
jobs:
install-node-dependencies:
name: Install node dependencies
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure pnpm store
run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }}
- name: Install dependencies
run: pnpm install --frozen-lockfile --strict-peer-dependencies
- name: Pack dependency artifacts
run: |
tar -czf /tmp/pnpm-store.tar.gz ${{ env.PNPM_STORE_DIR }}
- name: Upload dependency artifacts
uses: actions/upload-artifact@v7
with:
name: node-dependencies
path: |
/tmp/pnpm-store.tar.gz
retention-days: 1
check-linting-formatting:
name: Check linting & formatting
runs-on: ubuntu-latest
needs: build-packages
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure pnpm store
run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }}
- name: Download dependency artifacts
uses: actions/download-artifact@v8
with:
name: node-dependencies
path: /tmp/node-dependencies
- name: Restore pnpm store
run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz
- name: Restore dependencies
run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies
- name: Run linting and formatting checks
run: pnpm run lint
build-packages:
name: Build packages
runs-on: ubuntu-latest
needs: install-node-dependencies
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure pnpm store
run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }}
- name: Download dependency artifacts
uses: actions/download-artifact@v8
with:
name: node-dependencies
path: /tmp/node-dependencies
- name: Restore pnpm store
run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz
- name: Restore dependencies
run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies
- name: Build packages
run: pnpm run build && pnpm run build:demos
- name: Pack build artifacts
run: tar -czf /tmp/build-output.tar.gz packages/*/dist packages-deprecated/*/dist demos/dist
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: build-output
path: /tmp/build-output.tar.gz
retention-days: 1
run-unit-tests:
name: Run unit tests
runs-on: ubuntu-latest
needs: build-packages
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure pnpm store
run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }}
- name: Download dependency artifacts
uses: actions/download-artifact@v8
with:
name: node-dependencies
path: /tmp/node-dependencies
- name: Restore pnpm store
run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz
- name: Restore dependencies
run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: /tmp/build-output
- name: Restore build output
run: tar -xzf /tmp/build-output/build-output.tar.gz
- name: Run unit tests
run: pnpm run test:unit
run-e2e-tests:
name: Run e2e tests (shard ${{ matrix.shard }}/${{ matrix.total }})
runs-on: ubuntu-latest
needs: build-packages
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
total: [4]
steps:
- uses: actions/checkout@v7
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure pnpm store
run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }}
- name: Download dependency artifacts
uses: actions/download-artifact@v8
with:
name: node-dependencies
path: /tmp/node-dependencies
- name: Restore pnpm store
run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz
- name: Restore dependencies
run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: /tmp/build-output
- name: Restore build output
run: tar -xzf /tmp/build-output/build-output.tar.gz
- name: Get Playwright version
id: playwright-version
run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }}
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm exec playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: pnpm exec playwright install-deps chromium
- name: Run Playwright tests
run: pnpm exec playwright test --project=chromium --shard=${{ matrix.shard }}/${{ matrix.total }}
- name: Upload blob report
if: always()
uses: actions/upload-artifact@v7
with:
name: e2e-blob-report-${{ matrix.shard }}
path: blob-report
retention-days: 7
merge-e2e-reports:
name: Merge e2e reports
runs-on: ubuntu-latest
needs: run-e2e-tests
if: always()
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- name: Install pnpm
uses: pnpm/action-setup@v5
with:
version: ${{ env.PNPM_VERSION }}
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Configure pnpm store
run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }}
- name: Download dependency artifacts
uses: actions/download-artifact@v8
with:
name: node-dependencies
path: /tmp/node-dependencies
- name: Restore pnpm store
run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz
- name: Restore dependencies
run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies
- name: Download blob reports
uses: actions/download-artifact@v8
with:
path: all-blob-reports
pattern: e2e-blob-report-*
merge-multiple: true
- name: Merge into HTML report
if: ${{ hashFiles('all-blob-reports/**') != '' }}
run: pnpm exec playwright merge-reports --reporter html ./all-blob-reports
- name: Upload merged HTML report
uses: actions/upload-artifact@v7
with:
name: playwright-html-report
path: playwright-report
retention-days: 14
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: Verify env: NODE_VERSION: 24 PNPM_VERSION: 11.2.2 PNPM_STORE_DIR: .pnpm-store concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: push: branches: - main - next - release/* pull_request: branches: - main - next - release/* jobs: install-node-dependencies: name: Install node dependencies runs-on: latchkey-small timeout-minutes: 15 steps: - uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v5 with: version: ${{ env.PNPM_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: cache: 'npm' node-version: ${{ env.NODE_VERSION }} - name: Configure pnpm store run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }} - name: Install dependencies run: pnpm install --frozen-lockfile --strict-peer-dependencies - name: Pack dependency artifacts run: | tar -czf /tmp/pnpm-store.tar.gz ${{ env.PNPM_STORE_DIR }} - name: Upload dependency artifacts uses: actions/upload-artifact@v7 with: name: node-dependencies path: | /tmp/pnpm-store.tar.gz retention-days: 1 check-linting-formatting: name: Check linting & formatting runs-on: latchkey-small needs: build-packages timeout-minutes: 15 steps: - uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v5 with: version: ${{ env.PNPM_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: cache: 'npm' node-version: ${{ env.NODE_VERSION }} - name: Configure pnpm store run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }} - name: Download dependency artifacts uses: actions/download-artifact@v8 with: name: node-dependencies path: /tmp/node-dependencies - name: Restore pnpm store run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz - name: Restore dependencies run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies - name: Run linting and formatting checks run: pnpm run lint build-packages: name: Build packages runs-on: latchkey-small needs: install-node-dependencies timeout-minutes: 20 steps: - uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v5 with: version: ${{ env.PNPM_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: cache: 'npm' node-version: ${{ env.NODE_VERSION }} - name: Configure pnpm store run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }} - name: Download dependency artifacts uses: actions/download-artifact@v8 with: name: node-dependencies path: /tmp/node-dependencies - name: Restore pnpm store run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz - name: Restore dependencies run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies - name: Build packages run: pnpm run build && pnpm run build:demos - name: Pack build artifacts run: tar -czf /tmp/build-output.tar.gz packages/*/dist packages-deprecated/*/dist demos/dist - name: Upload build artifacts uses: actions/upload-artifact@v7 with: name: build-output path: /tmp/build-output.tar.gz retention-days: 1 run-unit-tests: name: Run unit tests runs-on: latchkey-small needs: build-packages timeout-minutes: 20 steps: - uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v5 with: version: ${{ env.PNPM_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: cache: 'npm' node-version: ${{ env.NODE_VERSION }} - name: Configure pnpm store run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }} - name: Download dependency artifacts uses: actions/download-artifact@v8 with: name: node-dependencies path: /tmp/node-dependencies - name: Restore pnpm store run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz - name: Restore dependencies run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies - name: Download build artifacts uses: actions/download-artifact@v8 with: name: build-output path: /tmp/build-output - name: Restore build output run: tar -xzf /tmp/build-output/build-output.tar.gz - name: Run unit tests run: pnpm run test:unit run-e2e-tests: name: Run e2e tests (shard ${{ matrix.shard }}/${{ matrix.total }}) runs-on: latchkey-small needs: build-packages timeout-minutes: 30 strategy: fail-fast: false matrix: shard: [1, 2, 3, 4] total: [4] steps: - uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v5 with: version: ${{ env.PNPM_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: cache: 'npm' node-version: ${{ env.NODE_VERSION }} - name: Configure pnpm store run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }} - name: Download dependency artifacts uses: actions/download-artifact@v8 with: name: node-dependencies path: /tmp/node-dependencies - name: Restore pnpm store run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz - name: Restore dependencies run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies - name: Download build artifacts uses: actions/download-artifact@v8 with: name: build-output path: /tmp/build-output - name: Restore build output run: tar -xzf /tmp/build-output/build-output.tar.gz - name: Get Playwright version id: playwright-version run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT - name: Cache Playwright browsers id: playwright-cache uses: actions/cache@v6 with: path: ~/.cache/ms-playwright key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }} - name: Install Playwright browsers if: steps.playwright-cache.outputs.cache-hit != 'true' run: pnpm exec playwright install --with-deps chromium - name: Install Playwright system deps if: steps.playwright-cache.outputs.cache-hit == 'true' run: pnpm exec playwright install-deps chromium - name: Run Playwright tests run: pnpm exec playwright test --project=chromium --shard=${{ matrix.shard }}/${{ matrix.total }} - name: Upload blob report if: always() uses: actions/upload-artifact@v7 with: name: e2e-blob-report-${{ matrix.shard }} path: blob-report retention-days: 7 merge-e2e-reports: name: Merge e2e reports runs-on: latchkey-small needs: run-e2e-tests if: always() timeout-minutes: 10 steps: - uses: actions/checkout@v7 - name: Install pnpm uses: pnpm/action-setup@v5 with: version: ${{ env.PNPM_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: cache: 'npm' node-version: ${{ env.NODE_VERSION }} - name: Configure pnpm store run: pnpm config set store-dir ${{ github.workspace }}/${{ env.PNPM_STORE_DIR }} - name: Download dependency artifacts uses: actions/download-artifact@v8 with: name: node-dependencies path: /tmp/node-dependencies - name: Restore pnpm store run: tar -xzf /tmp/node-dependencies/pnpm-store.tar.gz - name: Restore dependencies run: pnpm install --offline --frozen-lockfile --strict-peer-dependencies - name: Download blob reports uses: actions/download-artifact@v8 with: path: all-blob-reports pattern: e2e-blob-report-* merge-multiple: true - name: Merge into HTML report if: ${{ hashFiles('all-blob-reports/**') != '' }} run: pnpm exec playwright merge-reports --reporter html ./all-blob-reports - name: Upload merged HTML report uses: actions/upload-artifact@v7 with: name: playwright-html-report path: playwright-report retention-days: 14
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.
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.
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:
- Dependency installs
- End-to-end and browser tests
This workflow runs 6 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.