Package Exports
- flughafen
Readme
Flughafen ๐ซ
Type-Safe GitHub Actions Workflow Builder for TypeScript
Build GitHub Actions workflows with full type safety, IntelliSense support, and compile-time validation. Flughafen eliminates the pain points of YAML-based workflows by providing a fluent, programmatic API with function-based scoping that prevents context switching errors.
๐ Table of Contents
- Why Flughafen?
- Key Features
- Installation
- Quick Start
- Documentation
- Examples
- CLI Tool
- Type Generation
- Local Custom Actions
- Development
- Contributing
- License
๐ฏ Why Flughafen?
YAML workflows are hard to maintain. You lose type safety, get no autocomplete, and errors only appear at runtime. Flughafen solves this:
| Problem | Flughafen Solution |
|---|---|
| โ No type safety in YAML | โ Full TypeScript type checking |
| โ No autocomplete/IntelliSense | โ Complete IDE support with autocomplete |
| โ Runtime errors only | โ Compile-time validation |
| โ Easy to mix up contexts (job vs step) | โ Function-based scoping prevents errors |
| โ Manual action input validation | โ Type-safe action configuration |
| โ Copy-paste for reusable logic | โ Local custom actions with type safety |
โจ Key Features
๐ฏ Function-Based API
Clean, scoped configuration with fluent interface that prevents context switching errors
createWorkflow()
.job('test', job =>
job.runsOn('ubuntu-latest') // โ
Only job methods available
.step(step =>
step.uses('actions/checkout@v4') // โ
Only step methods available
)
)๐ Type-Safe Configuration
Full TypeScript support with comprehensive type definitions for GitHub Actions
๐ก๏ธ Context-Safe
Prevents inappropriate method calls through proper function scoping - no more calling step methods at job level!
๐ฆ Comprehensive
Supports all GitHub Actions workflow features: triggers, jobs, steps, matrix builds, environments, permissions, and more
โ Validated
Built-in validation ensures valid workflow generation with helpful error messages
๐งช Well-Tested
Comprehensive test suite with 366+ tests across 26 test suites ensuring reliability
๐๏ธ Type-Safe Actions
Generate and use type-safe builders for any GitHub Action with full autocomplete
๐จ Local Custom Actions
Create and manage custom local actions with automatic file generation and type safety
๐ Reverse Engineering
Convert existing YAML workflows to type-safe TypeScript with automatic expression handling
โก Modern Tooling
Uses latest TypeScript features, Vitest for testing, and tsup for fast builds
๐ฆ Installation
npm install flughafen
# or
pnpm add flughafen
# or
yarn add flughafenRequirements:
- Node.js >= 18.0.0
- TypeScript >= 5.0.0
๐ Quick Start
Create Your First Workflow
import { createWorkflow } from 'flughafen';
const workflow = createWorkflow()
.name('CI Pipeline')
.on('push', { branches: ['main'] })
.on('pull_request')
.job('test', job =>
job
.runsOn('ubuntu-latest')
.step(step =>
step.name('Checkout code')
.uses('actions/checkout@v4')
)
.step(step =>
step.name('Setup Node.js')
.uses('actions/setup-node@v4', action =>
action.with({
'node-version': '20',
'cache': 'npm'
})
)
)
.step(step =>
step.name('Install dependencies')
.run('npm ci')
)
.step(step =>
step.name('Run tests')
.run('npm test')
)
);
// Generate YAML
console.log(workflow.toYAML());Use the CLI
# Create a workflow file
echo "export default createWorkflow()..." > my-workflow.ts
# Generate YAML files
flughafen build my-workflow.ts
# Outputs:
# โ .github/workflows/my-workflow.yml๐ Documentation
Core Documentation
- Tutorial - Step-by-step guide to building your first workflows
- API Reference - Complete API documentation with all methods and options
- Examples - Real-world examples and patterns
Quick Links
- Workflow Triggers
- Job Configuration
- Step Configuration
- Local Custom Actions
- Type Generation
- Validation
๐ก Examples
Matrix Build
createWorkflow()
.name('Matrix Build')
.on('push')
.job('test', job =>
job
.runsOn('${{ matrix.os }}')
.strategy({
matrix: {
os: ['ubuntu-latest', 'windows-latest', 'macos-latest'],
'node-version': ['18', '20', '22']
},
'fail-fast': false
})
.step(step =>
step.name('Checkout')
.uses('actions/checkout@v4')
)
.step(step =>
step.name('Setup Node.js ${{ matrix.node-version }}')
.uses('actions/setup-node@v4', action =>
action.with({ 'node-version': '${{ matrix.node-version }}' })
)
)
.step(step =>
step.name('Run tests')
.run('npm test')
)
);Workflow with Deployment
createWorkflow()
.name('Deploy to Production')
.on('release', { types: ['published'] })
.permissions({ contents: 'read', deployments: 'write' })
.job('build', job =>
job
.runsOn('ubuntu-latest')
.step(step => step.name('Build').run('npm run build'))
)
.job('deploy', job =>
job
.runsOn('ubuntu-latest')
.needs('build')
.environment({ name: 'production', url: 'https://example.com' })
.step(step =>
step.name('Deploy to production')
.run('npm run deploy')
.env({ DEPLOYMENT_ENV: 'production' })
)
);More Examples
Check out the examples/ directory for comprehensive examples:
basic-usage.ts- Complete workflow with multiple jobs and local actionssimple-local-action.ts- Creating and using local custom actionsadvanced-triggers.ts- Complex trigger configurationsvery-basic.ts- Minimal workflow example
๐ ๏ธ CLI Tool
Flughafen includes a powerful CLI for workflow building and type generation.
Installation
The CLI is included when you install the package:
npm install -g flughafen
# or use npx
npx flughafen --helpCommands
build <file> - Build Workflows
Generate YAML workflows and action files from TypeScript:
# Synthesize a single workflow
flughafen build my-workflow.ts
# Custom output directory
flughafen build my-workflow.ts -d ./ci
# Dry run (preview without writing)
flughafen build my-workflow.ts --dry-run
# Verbose output
flughafen build my-workflow.ts --verbosevalidate <files...> - Validate Workflows
Comprehensive validation with TypeScript compilation, structure checks, and security analysis:
# Validate workflow files
flughafen validate workflows/*.ts
# Strict mode (fail on warnings)
flughafen validate workflows/ci.ts --strict
# Verbose validation output
flughafen validate workflows/*.ts --verbosebuild <files...> - Complete Build Pipeline
Run validation, type generation, and synthesis in one command:
# Complete build
flughafen build workflows/ci.ts
# Build multiple workflows
flughafen build workflows/*.ts
# Build with verbose output
flughafen build workflows/ci.ts --verbosegenerate-types [files...] - Generate Action Types
Generate TypeScript types for GitHub Actions:
# Auto-detect and generate types
flughafen generate-types
# Generate from specific workflows
flughafen generate-types workflows/ci.ts workflows/deploy.ts
# Custom output location
flughafen generate-types -o ./types/actions.d.tsWorkflow File Pattern
Create workflow files that export a WorkflowBuilder as the default export:
// workflows/ci.ts
import { createWorkflow } from 'flughafen';
export default createWorkflow()
.name('Continuous Integration')
.on('push', { branches: ['main'] })
.job('test', job =>
job.runsOn('ubuntu-latest')
.step(step => step.run('npm test'))
);๐ง Type Generation
Generate TypeScript types from GitHub Action schemas for full type safety:
# Generate types from action schemas
pnpm run generate-types
# Fetch latest schemas and generate types
pnpm run fetch-schemas
pnpm run generate-types
# Or use the CLI
flughafen generate-typesThis creates type definitions in generated/types/ enabling:
- Full autocomplete for action inputs
- Compile-time validation of action configurations
- IntelliSense support in your IDE
Example with generated types:
// Types automatically generated for actions/checkout@v4
.step(step =>
step.uses('actions/checkout@v4', action =>
action.with({
repository: 'owner/repo', // โ
Autocomplete available
ref: 'main', // โ
Type-checked
'fetch-depth': 1 // โ
Validated
// invalidProp: 'test' // โ TypeScript error!
})
)
)๐จ Local Custom Actions
Create reusable local actions with automatic file generation and type safety:
import { createWorkflow, createLocalAction } from 'flughafen';
// Define a reusable local action
const setupAction = createLocalAction()
.name('setup-environment')
.description('Setup development environment')
.input('node-version', {
description: 'Node.js version to install',
required: true,
default: '20'
})
.input('package-manager', {
description: 'Package manager to use',
type: 'choice',
options: ['npm', 'yarn', 'pnpm'],
default: 'npm'
})
.output('cache-hit', {
description: 'Whether cache was restored',
value: '${{ steps.cache.outputs.cache-hit }}'
})
.using('composite')
.step(step =>
step.name('Setup Node.js')
.uses('actions/setup-node@v4', action =>
action.with({
'node-version': '${{ inputs.node-version }}'
})
)
)
.step(step =>
step.name('Install dependencies')
.run('${{ inputs.package-manager }} install')
);
// Use in workflow with type safety
const workflow = createWorkflow()
.name('CI with Local Action')
.on('push')
.job('build', job =>
job
.runsOn('ubuntu-latest')
.step(step =>
step.uses(setupAction, action =>
action.with({
'node-version': '20', // โ
Type-safe inputs
'package-manager': 'pnpm' // โ
Validated choices
})
)
)
);
// Generates:
// .github/workflows/ci.yml (references ./actions/setup-environment)
// .github/actions/setup-environment/action.ymlLocal Action Features
- โ Composite, Node.js, and Docker actions - Full support for all action types
- โ Type-safe inputs and outputs - Compile-time validation
- โ Automatic file generation - Action files created during synthesis
- โ Reusable across workflows - Share logic across your repository
- โ
Custom paths - Override default
.github/actions/location
Workflow Triggers
Flughafen supports all GitHub Events with full type safety:
createWorkflow()
.name('Comprehensive Triggers')
// Push events
.on('push', {
branches: ['main', 'develop'],
paths: ['src/**', '!docs/**']
})
// Pull request events
.on('pull_request', {
types: ['opened', 'synchronize', 'reopened'],
branches: ['main']
})
// Scheduled workflows (cron)
.on('schedule', [
{ cron: '0 2 * * 1' }, // Weekly on Monday 2 AM
{ cron: '0 0 1 * *' } // Monthly on 1st
])
// Manual workflow dispatch
.on('workflow_dispatch', {
inputs: {
environment: {
description: 'Target environment',
required: true,
type: 'choice',
options: ['dev', 'staging', 'prod']
},
debug: {
description: 'Enable debug mode',
type: 'boolean',
default: false
}
}
})
// Reusable workflow
.on('workflow_call', {
inputs: {
environment: {
description: 'Environment',
required: true,
type: 'string'
}
},
secrets: {
deploy_token: {
description: 'Deployment token',
required: true
}
}
})
// Other events
.on('release', { types: ['published'] })
.on('issues', { types: ['opened', 'labeled'] })
.on('deployment');Job Configuration
Configure jobs with matrix builds, containers, services, and more:
.job('my-job', job =>
job
// Basic configuration
.runsOn('ubuntu-latest')
.needs(['build', 'lint'])
.if("github.ref == 'refs/heads/main'")
// Environment
.environment({
name: 'production',
url: 'https://example.com'
})
.env({ NODE_ENV: 'production' })
.permissions({ contents: 'read', deployments: 'write' })
// Matrix strategy
.strategy({
matrix: {
os: ['ubuntu-latest', 'windows-latest'],
'node-version': ['18', '20', '22']
},
'fail-fast': false,
'max-parallel': 3
})
// Container and services
.container({
image: 'node:20',
env: { NODE_ENV: 'test' },
options: '--cpus 2'
})
.services({
postgres: {
image: 'postgres:15',
env: { POSTGRES_PASSWORD: 'postgres' },
ports: ['5432:5432']
}
})
// Configuration
.timeoutMinutes(30)
.continueOnError(false)
.concurrency({
group: '${{ github.workflow }}-${{ github.ref }}',
'cancel-in-progress': true
})
// Steps
.step(step => step.run('echo "Hello"'))
)Step Configuration
Configure steps with actions, commands, and conditions:
.step(step =>
step
// Basic configuration
.name('My Step')
.id('my-step')
.if("success()")
// Using actions - Callback form (recommended)
.uses('actions/checkout@v4', action =>
action
.with({
repository: 'owner/repo',
ref: 'main',
'fetch-depth': 1
})
.env({ GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' })
)
// Using actions - Shorthand form
.uses('actions/checkout@v4', {
repository: 'owner/repo',
ref: 'main'
})
// Or run shell commands
.run('npm ci && npm test')
.shell('bash')
.workingDirectory('./packages/app')
// Environment and error handling
.env({ CI: 'true', NODE_ENV: 'test' })
.continueOnError(true)
.timeoutMinutes(10)
)Validation
Built-in comprehensive validation with TypeScript compilation, security checks, and best practices:
import { validate } from 'flughafen';
// Programmatic validation
const result = await validate({
files: ['workflows/ci.ts'],
strict: true,
verbose: true
});
if (!result.valid) {
console.error('Validation errors:', result.errors);
}
// Or use CLI
// flughafen validate workflows/*.ts --strictValidation includes:
- โ TypeScript compilation and type checking
- โ Workflow structure validation
- โ Security best practices (secrets, permissions)
- โ GitHub Actions expression validation
- โ Job dependencies and circular reference detection
- โ Action version and input validation
๐จ Development
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Run tests in watch mode
pnpm test:watch
# Build the project
pnpm build
# Development mode with hot reload
pnpm dev
# Type checking
pnpm typecheck
# Linting
pnpm lint
pnpm lint:fix
# Generate types from schemas
pnpm run generate-types
# Fetch latest GitHub Action schemas
pnpm run fetch-schemas๐ค Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Before submitting:
- Run tests:
pnpm test - Run linter:
pnpm lint - Ensure types are valid:
pnpm typecheck
๐ License
MIT ยฉ [Your Name]
๐ Acknowledgments
- Inspired by the need for type-safe GitHub Actions workflows
- Built with modern TypeScript tooling: Vitest, tsup, Turborepo
- Schema types generated from SchemaStore
๐ Support
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
Made with โค๏ธ for the TypeScript community