Check docs workflow (ddev/ddev)
The Check docs workflow from ddev/ddev, explained and optimized by Latchkey.
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.
What it does
This is the Check docs workflow from the ddev/ddev repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Check docs
defaults:
run:
shell: bash
on:
push:
branches: [ main ]
pull_request:
paths:
- "docs/**"
- ".spellcheckwordlist.txt"
- ".spellcheck.yml"
- ".markdownlint.jsonc"
- "mkdocs.yml"
- ".readthedocs.yaml"
- ".github/workflows/**"
- ".linkspector.yml"
workflow_dispatch:
inputs:
debug_enabled:
description: 'Run the build with tmate set "debug_enabled"'
type: boolean
required: false
default: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
actions: write
jobs:
build:
name: Docs check (spellcheck, links, markdownlint, textlint)
# linkspector seems to fail with "No usable sandbox"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Spellcheck
uses: rojopolis/spellcheck-github-actions@v0
- name: Install textlint
run: |
npm init -y
npm install textlint textlint-filter-rule-comments textlint-rule-no-todo textlint-rule-stop-words textlint-rule-terminology
- name: Run textlint
uses: tsuyoshicho/action-textlint@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-check
textlint_flags: "{README.md,version-history.md,docs/**}"
- name: Setup tmate session
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
- name: Run linkspector to check external links
uses: umbrelladocs/action-linkspector@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-check
fail_on_error: true
# Check links only in the added lines for PRs, but check everything otherwise
filter_mode: ${{ github.event_name == 'pull_request' && 'added' || 'nofilter' }}
config_file: '.linkspector.yml'
- name: Run markdownlint
run: |
npm install -g markdownlint-cli
make markdownlint
- name: Test zensical
run: |
pip install -r docs/requirements.txt
zensical build --clean --strict
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Check docs defaults: run: shell: bash on: push: branches: [ main ] pull_request: paths: - "docs/**" - ".spellcheckwordlist.txt" - ".spellcheck.yml" - ".markdownlint.jsonc" - "mkdocs.yml" - ".readthedocs.yaml" - ".github/workflows/**" - ".linkspector.yml" workflow_dispatch: inputs: debug_enabled: description: 'Run the build with tmate set "debug_enabled"' type: boolean required: false default: false concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: actions: write jobs: build: timeout-minutes: 30 name: Docs check (spellcheck, links, markdownlint, textlint) # linkspector seems to fail with "No usable sandbox" runs-on: latchkey-small steps: - uses: actions/checkout@v7 with: fetch-depth: 0 - name: Spellcheck uses: rojopolis/spellcheck-github-actions@v0 - name: Install textlint run: | npm init -y npm install textlint textlint-filter-rule-comments textlint-rule-no-todo textlint-rule-stop-words textlint-rule-terminology - name: Run textlint uses: tsuyoshicho/action-textlint@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-check textlint_flags: "{README.md,version-history.md,docs/**}" - name: Setup tmate session if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }} uses: mxschmitt/action-tmate@v3 with: limit-access-to-actor: true - name: Run linkspector to check external links uses: umbrelladocs/action-linkspector@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-check fail_on_error: true # Check links only in the added lines for PRs, but check everything otherwise filter_mode: ${{ github.event_name == 'pull_request' && 'added' || 'nofilter' }} config_file: '.linkspector.yml' - name: Run markdownlint run: | npm install -g markdownlint-cli make markdownlint - name: Test zensical run: | pip install -r docs/requirements.txt zensical build --clean --strict
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. - Add a job timeout so a hung step cannot burn hours of runner time.
4 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:
- Dependency installs
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.