Bits

Validate YAML in GitHub Actions

A repository full of YAML config files needs a gate that rejects a broken or off-schema file on any branch, before a human reviews it. GitHub Actions can run that gate on every push and pull request, and the Python schema package can hold the rules in a few lines. The workflow lists the YAML files the push changed and hands the list to a script.

1. Write the schema and the checker

# .github/validate_yaml.py
import sys
import yaml
from schema import Optional, Regex, Schema, SchemaError

SERVICE = Schema({
    "name": Regex(r"^[a-z][a-z0-9-]*$"),
    "owner": str,
    Optional("environments"): [lambda e: e in ("dev", "qa", "prod")],
    Optional("public"): bool,
})

failed = 0
for path in open(sys.argv[1]).read().split():
    try:
        SERVICE.validate(yaml.safe_load(open(path)))
        print(f"ok    {path}")
    except (yaml.YAMLError, SchemaError) as e:
        failed += 1
        print(f"FAIL  {path}\n{e}")
sys.exit(1 if failed else 0)

yaml.safe_load fails on bad YAML. Schema.validate fails on a missing key, a wrong type, or a value outside the allowed set. The script checks every file before it exits, so one run reports all failures.

2. Run it on every push and pull request

# .github/workflows/validate-yaml.yml
name: validate-yaml
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - run: pip install pyyaml schema
      - name: Validate changed YAML files
        run: |
          if [[ "$" == "pull_request" ]]; then
            BASE="origin/$"
          else
            BASE="$"
          fi
          [[ "$BASE" =~ ^0+$ ]] && BASE="origin/main"
          LIST=$(mktemp)
          git diff --name-only --diff-filter=d "$BASE" HEAD | grep -E '\.ya?ml$' | grep -v '^\.github/' > "$LIST" || true
          if [[ -s "$LIST" ]]; then python3 .github/validate_yaml.py "$LIST"; else echo "No YAML files changed"; fi

To check every file in the repository instead, replace the git diff command with git ls-files.

3. Which commit the job sees

github.sha depends on the event:

actions/checkout checks out that commit by default. On a pull request the script therefore sees the merged result, not the branch tip alone.

All entries | Español