codegen-gha
v0.3.4
Published
Define GitHub Actions workflows in TypeScript and generate them into plain YAML
Maintainers
Readme
codegen-gha
codegen-gha is a TypeScript toolkit for defining GitHub Actions workflows as code and generating them into plain YAML. Instead of hand-writing and copy-pasting YAML across repos, you compose workflows, jobs, and steps using typed building blocks.
This is especially valuable in large CI setups: it keeps jobs and workflows consistent across many repos, and lets you make CI-wide changes (bumping a runner type, adding a permission, tweaking a shared step) in one place instead of editing dozens of YAML files by hand.
Install
pnpm add -D codegen-gha
# or
npm install --save-dev codegen-gha
# or
yarn add -D codegen-ghaRequires Node.js 22.18 or later. The package is ESM-only, so import it with import, not require().
[!NOTE]
codegen-ghais pre-1.0. Breaking changes can land in any minor release, so consider pinning the version.
TypeScript workflow files
cgha generate runs .ts workflow files with Node's built-in type stripping, so no extra loader is installed. Node only deletes types, so workflow files need to:
- include the extension on relative imports (
'../lib/index.ts', not'../lib/index') - import types with
import type - avoid
enum,namespaceand constructor parameter properties
To have TypeScript flag these for you, enable these options in your tsconfig.json:
{
"compilerOptions": {
"allowImportingTsExtensions": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true
}
}Example
import { Workflow } from 'codegen-gha/components/workflow';
import { NormalJob, RUNS_ON } from 'codegen-gha/components/job';
import { BashStep } from 'codegen-gha/components/step';
import { bash } from 'codegen-gha/components/bash-string';
export const ci = new Workflow({
name: 'CI',
trigger: { pull_request: null },
permissions: { 'id-token': 'none', contents: 'read', 'pull-requests': 'read', actions: 'read', checks: 'read' },
jobs: {
test: new NormalJob({
name: 'test',
runsOn: RUNS_ON.GITHUB_LATEST,
timeoutMinutes: 10,
steps: [new BashStep({ name: 'Run tests', run: bash`pnpm test` })],
}),
},
});Which serializes to:
name: CI
on:
pull_request:
permissions:
id-token: none
contents: read
pull-requests: read
actions: read
checks: read
jobs:
test:
name: test
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Run tests
shell: bash
run: |-
pnpm testGenerating workflow files
codegen-gha ships a cgha CLI.
Quick start: cgha init
pnpm exec cgha init # or: npx cgha initThis scaffolds a working setup in the current directory:
codegen-gha.yaml: the generator config (see below)workflows/example.ts: an example workflow to edit or replaceworkflows/verify-generation.ts: a CI workflow that fails if the generated YAML is out of date with its TypeScript sourcelib/index.ts: a place for shared steps and jobs (seelib/)
Then run pnpm exec cgha generate to write the YAML into .github/workflows/.
Config reference
Add a codegen-gha.yaml to the root of your repo:
# glob of files to scan for exported Workflow instances
include:
- "workflows/*.ts"
# where to write generated files
outDir: .github/workflows
# filename suffix, marks the file as generated
suffix: .gen.yaml
# {file} is replaced with the source path
commentHeader: "this file is generated using cgha generate {file}"Then run:
pnpm exec cgha generate # or: npx cgha generateThis scans every file matching include, picks up any exported Workflow instance, and writes one file per workflow into outDir as <slugified-name><suffix> — e.g. the ci.ts example above becomes .github/workflows/ci.gen.yaml. Commit the generated files: GitHub only runs the YAML, not the TypeScript.
lib/
This is how best to organize repeated YAML. Things like standard actions can be defined here and imported into the workflows.
Contributing
PR titles are checked for a semantic type prefix (e.g. feat: ..., fix: ..., chore: ..., docs: ...); pick whichever matches the change.
Releases
Releases are automated. Every merge to main runs release.yml, which bumps the version from the conventional commit history, tags it, and creates a GitHub Release with the changelog. Release only stages on npm.
A staged version isn't installable until a maintainer approves it. Please reach out if a release needs to be available.
