Skip to content

jonathanrainer/ghafmt

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

ghafmt

A formatter for GitHub Actions workflow and action metadata files.

CI License: MIT OR Apache-2.0

ghafmt enforces a consistent style across your GitHub Actions YAML files — both workflow files and action metadata files (action.yml / action.yaml). It reorders keys, sorts blocks alphabetically, inserts blank lines between steps and jobs, and converts IDs to snake_case — so code review diffs show only meaningful changes, not formatting noise.

Workflow formatting rules:

  • Step keys reordered to: nameuses/runidwith/env
  • Top-level workflow keys sorted (nameonenvjobs)
  • Trigger events, needs arrays, runs-on arrays, and filter arrays sorted alphabetically
  • Blank lines inserted between top-level keys, jobs, and steps
  • Job IDs and step IDs converted to snake_case
  • Keys within with, env, permissions, and similar maps sorted alphabetically

Action metadata formatting rules (action.yml / action.yaml):

  • Top-level keys sorted to canonical order: namedescriptionauthorinputsoutputsrunsbranding
  • inputs and outputs sorted alphabetically; per-entry keys sorted idiomatically
  • runs keys sorted by action type: composite (usingsteps), JavaScript (usingprepre-ifmainpostpost-if), Docker (usingimageargsenvpre-entrypointentrypointpost-entrypoint)
  • Step keys and with maps inside composite action steps sorted alphabetically
  • Step IDs converted to snake_case
  • branding keys sorted (iconcolor)

Before / After

Before:

on:
  workflow_dispatch:
  push:
    branches: [main]
  pull_request:
name: CI Pipeline
jobs:
  RunTests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        name: Checkout
      - with:
          node-version: '20'
          cache: npm
        uses: actions/setup-node@v4
        name: Setup Node
      - run: npm install
        name: Install deps
        id: install
      - env:
          NODE_ENV: test
          CI: true
        run: npm test
        name: Run tests
        id: testStep
  BuildAndDeploy:
    needs: [RunTests]
    runs-on: ubuntu-latest
    steps:
      - name: Build
        run: npm run build
      - env:
          AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_KEY }}
          AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
          AWS_REGION: us-east-1
        run: aws s3 sync dist/ s3://my-bucket
        name: Deploy
        id: deployStep

After:

name: CI Pipeline

on:
  pull_request:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  run_tests:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          cache: npm
          node-version: '20'

      - name: Install deps
        id: install
        run: npm install

      - name: Run tests
        id: test_step
        run: npm test
        env:
          CI: true
          NODE_ENV: test

  build_and_deploy:
    needs: [run_tests]
    runs-on: ubuntu-latest
    steps:
      - name: Build
        run: npm run build

      - name: Deploy
        id: deploy_step
        run: aws s3 sync dist/ s3://my-bucket
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.ACCESS_KEY }}
          AWS_REGION: us-east-1
          AWS_SECRET_ACCESS_KEY: ${{ secrets.SECRET_KEY }}

Installation

Pre-built binary

Download the latest release from GitHub Releases:

# Replace <VERSION> and <TARGET> with values from the releases page:
#   x86_64-unknown-linux-musl  (Linux x86_64)
#   aarch64-unknown-linux-musl (Linux ARM64)
#   aarch64-apple-darwin       (macOS Apple Silicon)
#   x86_64-apple-darwin        (macOS Intel)
curl -fsSL https://github.com/jonathanrainer/ghafmt/releases/download/v<VERSION>/ghafmt-<VERSION>-<TARGET>.tar.gz | tar -xz
sudo mv ghafmt /usr/local/bin/

Docker

docker pull ghcr.io/jonathanrainer/ghafmt:latest

Usage

# Format to stdout
ghafmt workflow.yml

# Read from stdin
cat workflow.yml | ghafmt -

# Check formatting without writing (exits non-zero if any file is dirty)
ghafmt --mode=check .github/workflows/

# Write changes in place
ghafmt --mode=write .github/workflows/

# List files that would be changed
ghafmt --mode=list .github/workflows/

Docker

docker run --rm -v "$PWD":/work ghcr.io/jonathanrainer/ghafmt:latest --mode=check /work/.github/workflows/

CI Integration

GitHub Actions

Use the bundled action — it downloads the correct pre-built binary for the runner platform and automatically discovers both workflow files and any action.yml/action.yaml files in the repository:

- uses: jonathanrainer/ghafmt@83f66d258e2777ecb69a6445132f557c0e86d686 # v0.1.4
  with:
    mode: check          # check (default) | write | list
    path: .github/workflows/

Or use the Docker image directly:

- name: Check workflow formatting
  run: |
    docker run --rm -v "$GITHUB_WORKSPACE":/work \
      ghcr.io/jonathanrainer/ghafmt:latest --mode=check /work/.github/workflows/

CircleCI

- run:
    name: Check workflow formatting
    command: |
      VERSION=$(curl -fsSL https://api.github.com/repos/jonathanrainer/ghafmt/releases/latest | grep tag_name | cut -d'"' -f4 | sed 's/^v//')
      curl -fsSL "https://github.com/jonathanrainer/ghafmt/releases/download/v${VERSION}/ghafmt-${VERSION}-x86_64-unknown-linux-musl.tar.gz" | tar -xz -C /tmp
      /tmp/ghafmt --mode=check .github/workflows/

Pre-commit

Add to your .pre-commit-config.yaml (requires ghafmt on PATH):

repos:
  - repo: local
    hooks:
      - id: ghafmt
        name: ghafmt
        language: system
        entry: ghafmt --mode=check
        pass_filenames: true
        files: ^(\.github/workflows/.*\.ya?ml|(.*\/)?action\.ya?ml)$

Acknowledgements

ghafmt is built on top of two foundational projects:

  • libfyaml by @pantoniou — the YAML parser and emitter at the core of this tool. @pantoniou has been exceptionally generous in reviewing and merging patches to support ghafmt's use case.
  • fyaml by @0k — the Rust bindings to libfyaml that make it possible to use from this codebase.

Contributing

See CONTRIBUTING.md.

License

Licensed under either of MIT or Apache-2.0 at your option.

About

A formatter for GitHub Actions workflow and action metadata files

Topics

Resources

License

MIT, Unknown licenses found

Licenses found

MIT
LICENSE
Unknown
LICENSE-APACHE

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors