Skip to content

Latest commit

 

History

History
194 lines (148 loc) · 7.12 KB

File metadata and controls

194 lines (148 loc) · 7.12 KB

GitHub Actions

Usage

cinzel github -h

Parse HCL to YAML

Convert HCL files containing workflow, job, step, and action blocks into GitHub Actions YAML files.

cinzel github parse --file ./cinzel/steps.hcl --output-directory .github/workflows

Unparse YAML to HCL

Convert GitHub Actions workflow YAML, composite action YAML, or step-only YAML back to HCL.

cinzel github unparse --file ./.github/workflows/steps.yaml --output-directory ./cinzel

Use --dry-run to print generated files to stdout.

HCL shape: workflows

step "checkout" {
  uses {
    action  = "actions/checkout"
    version = "v4"
  }
}

step "test" {
  run = "go test ./..."
}

job "build" {
  runs_on {
    runners = "ubuntu-latest"
  }

  steps = [
    step.checkout,
    step.test,
  ]
}

workflow "ci" {
  filename = "ci"

  on "push" {
    branches = ["main"]
  }

  jobs = [
    job.build,
  ]
}

HCL shape: composite actions

step "setup" {
  name = "Setup Node"

  uses {
    action  = "actions/setup-node"
    version = "v4"
  }

  with {
    name  = "node-version"
    value = "20"
  }
}

step "build" {
  name = "Build"
  run  = "npm run build"
}

action "my_action" {
  filename    = "my-action"
  name        = "My Composite Action"
  description = "Runs setup and build"

  input "node_version" {
    description = "Node.js version"
    required    = true
    default     = "20"
  }

  output "result" {
    description = "Build result"
    value       = "$${{ steps.build.outputs.result }}"
  }

  runs {
    using = "composite"
    steps = [step.setup, step.build]
  }
}

Actions are written to <output-directory>/<filename>/action.yml during parse.

Notes

  • workflow.jobs, job.steps, and action.runs.steps are explicit references (job.<id> and step.<id>).
  • YAML unparse generates stable HCL identifiers (sanitized when YAML keys contain -).
  • Document type is auto-detected during unparse: workflow (has on/jobs), action (has name/runs, no on/jobs), or step-only.
  • Parse schema is defined by typed HCL structs in provider/github/config.go; avoid schema key allowlist tables.
  • Unparse schema validation uses strict typed YAML decode (goccy/go-yaml strict mode), not manual key allowlists.

Terminology distinction

  • HCL attribute: depends_on
  • GitHub YAML key: needs
  • Mapping rule: depends_on <-> needs:
  • HCL needs is not supported.

Validation rules

The same rules are enforced in both directions (HCL → YAML and YAML → HCL):

  • A workflow must define at least one on trigger and at least one job reference.
  • A normal job (without uses) must define runs_on and at least one referenced step.
  • A reusable job (with uses) cannot define runs_on or steps.
  • with and secrets are only valid for reusable jobs (uses set).
  • permissions scopes and levels are validated against the known GitHub Actions set.
  • on.schedule cron expressions are validated (5-field format, value ranges).
  • ${{ }} expression syntax is checked for balanced delimiters and non-empty bodies.
  • Step uses references are validated for correct format (owner/repo@ref, ./path, or docker://image).
  • An action must define name and runs.using.

Testing

Test coverage includes golden fixtures, a fixture-driven compatibility matrix under provider/github/testdata/fixtures/matrix, strict validation checks, semantic roundtrip tests, and benchmarks under provider/github/*_test.go.

Fixture matrix workflow

  • Add new parse scenarios in provider/github/testdata/fixtures/matrix/parse.
  • Add new unparse scenarios in provider/github/testdata/fixtures/matrix/unparse.
  • For valid parse scenarios, add <name>.hcl and <name>.golden.yaml.
  • For invalid parse scenarios, add <name>.hcl and <name>.error.txt.
  • For valid unparse scenarios, add <name>.yaml and <name>.roundtrip.golden.yaml.
  • For invalid unparse scenarios, add <name>.yaml and <name>.error.txt.
  • Keep .error.txt messages focused on stable substrings, not full error text.

Coverage

  • HCL workflow, job, step, and action reference graph with explicit references (workflow.jobs, job.steps, job.depends_on, action.runs.steps).
  • Action support for all runs.using types: composite, node20, and docker, in both parse and unparse directions.
  • action blocks support input, output, runs, and branding sub-blocks, written to <filename>/action.yml.
  • Common workflow triggers and event maps, including empty event blocks for trigger-only events.
  • YAML workflow on shorthand forms (on: push and on: [push, pull_request]) are normalized during unparse.
  • YAML on.schedule list form is normalized to HCL cron list in on "schedule" blocks.
  • Standard jobs (runs-on, steps) and reusable jobs (uses, with, secrets) with strict validation.
  • Job-level common keys parse/unparse: if, timeout-minutes, continue-on-error, permissions, defaults, concurrency, container, services, environment, and strategy (matrix, include, exclude, fail-fast, max-parallel).
  • Step run and structured uses { action, version } parsing and unparsing.
  • GitHub expression strings (${{ ... }}) are preserved across workflow, job, and step fields in parse/unparse flows.
  • Expression syntax validation (balanced ${{ }} delimiters, non-empty bodies).
  • Permissions validation (known scopes and levels).
  • Cron expression validation (5-field format, value ranges).
  • Uses reference validation (owner/repo@ref, ./path, docker://image).
  • Strategy matrix normalization for supported shapes (matrix.variable in HCL and matrix axes in YAML).
  • Auto-detection of document type during unparse (workflow, action, or step-only).
  • Semantic roundtrip stability for covered fixtures (HCL → YAML → HCL → YAML).

Known limitations

  • Not every GitHub Actions schema edge case or uncommon field combination is covered. The most common workflow, job, step, and action fields are supported.
  • Roundtrip output is semantically stable but not byte-stable: key ordering and formatting may normalize even when the meaning is preserved.

Output guarantees

  • Parse output uses unquoted on (never "on").
  • Parse output uses 2-space YAML indentation.
  • Parse output top-level key order is deliberate (name, on, jobs, then remaining keys).
  • Parse output includes cinzel provider markers in generated YAML headers (generated-by and cinzel-provider).
  • Parse cleanup prunes stale workflow YAML only when marker ownership matches the current provider.
  • Unparse output formats HCL with clear section separators and trailing commas in reference lists.
  • Identifier normalization is stable: YAML names are sanitized to valid HCL identifiers when needed.
  • Expression escaping is stable in HCL output (${{ ... }} in YAML becomes $${{ ... }} in HCL string literals).

Troubleshooting stale files

  • If a stale YAML file is not removed, confirm it still has cinzel markers and matches the current provider (generated-by: cinzel and cinzel-provider: github).
  • If marker checks pass but deletion still fails, confirm output directory write/delete permissions for the current user/CI runner.