Skip to main content

Generate GitHub Actions workflow YAML from Python code

Project description

ghagen

Generate GitHub Actions workflows from Python or TypeScript code.

CI PyPI Python License

Features

  • Dual language support - The tool comes in two flavors depending on your constraints/preferences: Python and Javascript/Typescript.
  • Typed models — type checking and IDE autocomplete which prevents typos or unsupported values.
  • YAML comments — Add comments to the generated yaml for additional documentation/clarity
  • Helpers — expression builder (expr) ensures you are using supported template variables
  • Escape hatches — Break out of the type system when you want to. You're not stuck with the schema if new features come out or you need to override something.
  • Linting — catch gotchas like invalid permissions and more. timeout-minutes, and duplicate step ids with source-line precision
  • Freshness checking — ensure your generated yaml files are in sync with your defined ghagen models
  • Version pinning — Prevent surprises and security risks by ensuring the same actions run every time.

[!NOTE] You might not need this if your GitHub Actions setup is relatively simple, ghagen might not be worth the added complexity — actionlint renovate/dependabot and ratchet can cover a lot of common issues. Reach for ghagen when keeping track of workflows by hand becomes painful, or when you want the extra assurances a real programming language provides (types, tests, refactoring tools).

Quickstart

Python

pip install ghagen        # or: uv tool install ghagen
from ghagen import App, Job, On, PushTrigger, Step, Workflow

ci = Workflow(
    name="CI",
    on=On(push=PushTrigger(branches=["main"])),
    jobs={
        "test": Job(
            runs_on="ubuntu-latest",
            steps=[Step(uses="actions/checkout@v4"), Step(run="pytest")],
        ),
    },
)

app = App()
app.add_workflow(ci, "ci.yml")
app.synth()
ghagen synth

TypeScript

npm install --save-dev @ghagen/ghagen
import { App, workflow, job, step, on, pushTrigger } from "@ghagen/ghagen";

const ci = workflow({
  name: "CI",
  on: on({ push: pushTrigger({ branches: ["main"] }) }),
  jobs: {
    test: job({
      runsOn: "ubuntu-latest",
      steps: [step({ uses: "actions/checkout@v4" }), step({ run: "pytest" })],
    }),
  },
});

const app = new App();
app.addWorkflow(ci, "ci.yml");
await app.synth();
npx ghagen synth

GitHub Action

Run ghagen check-synced in CI so a PR fails if the generated YAML drifts from the Python config:

jobs:
  check-workflows:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: nathanjordan/ghagen/check-synth@v0
        with:
          config: .github/ghagen_workflows.py  # optional; default shown
          python-version: "3.13"               # optional; default shown
          ghagen-version: ""                   # optional; empty = latest

v0 is a rolling major tag. The Action is a drift check for the Python path; TypeScript users can run npx ghagen check-synced instead.

Example output

Both snippets above generate:

name: CI
on:
  push:
    branches:
    - main
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - run: pytest

FAQ

Python or TypeScript — which should I pick? Pick whatever you're comfortable with or fits with your project. Both Python and Typescript/Javscript implementations have feature parity and are interchangeable.

Can I mix ghagen-generated workflows with hand-written YAML? Yes. ghagen only touches files you explicitly register. Any other file in .github/workflows/ is left alone — drop a hand-written weekly-report.yml next to a ghagen-generated ci.yml and nothing breaks.

What does the GitHub Action do? It runs ghagen check-synced against your Python config and fails the build if the generated YAML doesn't match what the current definitions would produce. It prevents changes made to the Python/JS code from not making it into the YAML spec.

How do I handle something ghagen's models don't cover? Use extras on any model for arbitrary keys, or Raw / raw() to drop an expression into a field that expects a literal. Both leave the rest of the model fully typed.

How do I pin actions to commit SHAs? Run ghagen deps pin to populate .github/ghagen.lock.toml; subsequent ghagen synth calls rewrite every uses: to its pinned SHA. Wire ghagen deps check-synced into CI to catch unpinned additions.

More questions? See the full FAQ.

Documentation

Full documentation: nathanjordan.github.io/ghagen

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ghagen-0.5.0.tar.gz (375.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ghagen-0.5.0-py3-none-any.whl (108.5 kB view details)

Uploaded Python 3

File details

Details for the file ghagen-0.5.0.tar.gz.

File metadata

  • Download URL: ghagen-0.5.0.tar.gz
  • Upload date:
  • Size: 375.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for ghagen-0.5.0.tar.gz
Algorithm Hash digest
SHA256 936e39158d7625aa28b68f86337bdd9a5e0fc3d8b788d4038384e076c4e67bab
MD5 28fe8ba5a771a529718e8e4233e280b5
BLAKE2b-256 4051edb92799972b4665b7844f14b4192c8a0498462793da44a1b7f8e675d2c8

See more details on using hashes here.

Provenance

The following attestation bundles were made for ghagen-0.5.0.tar.gz:

Publisher: release.yml on nathanjordan/ghagen

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ghagen-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: ghagen-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 108.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for ghagen-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0b1ad353da4533d5d9a19eecb37bdc5d4fdd2fa80fa84611a0b74573d2f371c3
MD5 f032610648d9298480ffa71fad3c7325
BLAKE2b-256 276c1bb2faa75ab327a92e755b92456a6a04b34c8c1d716f3106993a31e24d41

See more details on using hashes here.

Provenance

The following attestation bundles were made for ghagen-0.5.0-py3-none-any.whl:

Publisher: release.yml on nathanjordan/ghagen

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page