JSPM

  • Created
  • Published
  • Downloads 118
  • Score
    100M100P100Q69372F
  • License MIT

Type-safe, fluent GitHub Actions workflow builder for TypeScript

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.

npm version License: MIT TypeScript


๐Ÿ“‹ Table of Contents


๐ŸŽฏ 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 flughafen

Requirements:

  • 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

๐Ÿ’ก 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 actions
  • simple-local-action.ts - Creating and using local custom actions
  • advanced-triggers.ts - Complex trigger configurations
  • very-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 --help

Commands

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 --verbose

validate <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 --verbose

build <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 --verbose

generate-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.ts

Workflow 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-types

This 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.yml

Local 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 --strict

Validation 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:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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


Made with โค๏ธ for the TypeScript community