Jump to content
Toggle menu
  • 22 articles
  • 1 files
  • 1 users
  • 216 edits
terraform-github-tacos
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Runs

From terraform-github-tacos
More actions

Your workflow calls the action once in each job, with step set to the job it runs in. The apply job's environment has the same name as the workspace.

By default it applies after the merge, in HCP Terraform's order: a pull request only plans, and once it merges, the push to the default branch plans again and applies when the environment approves, or at once for a workspace in auto-apply. With apply-before-merge set to "true" on the pending, apply and merge steps, a pull request is applied first and merges once the apply succeeds.

Steps

step Job What it does
plan plan, before planning Sets the plan output to "false" when a pull request changes nothing in the workspace's directory, the calling workflow or shared-paths, so the later steps can be skipped with if: steps.<id>.outputs.plan == 'true'. With require-up-to-date, refuses a pull request that is behind its base. Restores the providers dflook downloads, cached by the workspace's .terraform.lock.hcl, and saves them when the job ends.
changes plan, after planning Marks the workspace as having changes to apply.
pending one job after the plans Lists the workspaces to apply, and refuses an environment that is missing, or has no required reviewers unless its workspace is in auto-apply. Cancels older runs of the same branch that still wait for approval, unless one of their jobs is running. On a pull request it lists nothing, unless apply-before-merge, and then fails a pull request high in a stack that changes more than one workspace.
apply apply, first step Restores the providers the plan job cached, so the apply does not download them again. Records who approved, or that nobody had to. On a push, refuses unless the commit is still the head of the branch. On a pull request, refuses unless apply-before-merge, and then refuses when the pull request moved or merged, targets another branch outside a native stack, or with require-up-to-date fell behind.
result apply, last step, with if: always() Writes what the apply changed and whether it succeeded.
gate the required check Fails unless every job it needs succeeded. The apply job may be skipped.
merge after the gate, with apply-before-merge Merges the pull request through the async merge API, which also merges every pull request below it in a stack. When this run has nothing to apply, merges only if an earlier run of it was approved or applied an auto-apply workspace. Fails when the pull request has not merged 2 minutes after the apply, since production is then ahead of the default branch. Does nothing without apply-before-merge.
collapse plan, last step, with if: always() Hides, as outdated, every plan comment of dflook/tofu-plan or dflook/terraform-plan but the newest of each workspace. Comments starting with **<workspace> apply: are hidden the same way.

Plan comments

The plan job's dflook/tofu-plan comments each workspace's plan on the pull request. Pushing again plans again, and the collapse step hides the older plan comments as outdated, so only the newest of each workspace stays open.

The apply job should make a fresh plan and apply it only when it matches the approved one, as dflook/tofu-apply does without plan_path or auto_approve. On a push, dflook's plan updates the merged pull request's plan comment with the plan of the default branch, and the apply compares against that comment.

Which commit applies

Only the newest commit of the default branch applies, since its plan carries the changes of every commit before it that has not been applied. So the push run has to plan every workspace that has changes, and the plan step's plan output is always "true" outside a pull request. A change made since the plan, such as a workflow_dispatch apply, makes the fresh plan differ and stops the apply; "Re-run all jobs" plans again. A commit pushed to the default branch without a pull request has no plan comment, so apply it with workflow_dispatch.

Job summaries

Each step writes a summary on the run page, so a reviewer can see what they are approving without opening the logs.

step Summary
changes How many resources the plan adds, changes, destroys, moves and imports, the plan itself folded, and whether it waits for an approval.
pending Each environment to apply and who can approve it.
apply Who approved, or who started a run that needed no approval, and the commit it applies.
result Whether the apply succeeded, with the same counts and plan as changes.
gate Each job it needs and how it ended.
merge Whether the pull request merged, and if not, why.

Full workflow

This is the workflow of Get started with every step that runs after the merge. A workflow_dispatch run applies the chosen workspace from its branch once the environment approves, the collapse step hides outdated plan comments, and the job summaries show each plan folded.

name: tofu
on:
  pull_request:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      workspace:
        description: The workspace to apply from this branch, once its environment approves.
        required: true
        type: choice
        options: &workspaces [network, dns]
permissions: {}
jobs:
  plan:
    name: ${{ matrix.workspace }} plan
    if: github.event_name != 'workflow_dispatch'
    strategy:
      fail-fast: false
      matrix:
        workspace: *workspaces
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: femiwiki/terraform-github-tacos@v0.7.0
        with:
          step: plan
          workspace: ${{ matrix.workspace }}

      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0  # v7.0.0
        with:
          persist-credentials: false

      - uses: dflook/tofu-plan@c7416238983bdd94c5486fb856bb7358f2bcc935  # v3.1.0
        id: plan
        env:
          GITHUB_TOKEN: ${{ github.token }}
        with:
          path: ${{ matrix.workspace }}

      - uses: femiwiki/terraform-github-tacos@v0.7.0
        with:
          step: changes
          workspace: ${{ matrix.workspace }}
          changes: ${{ steps.plan.outputs.changes }}
          plan-json: ${{ steps.plan.outputs.json_plan_path }}
          plan-text: ${{ steps.plan.outputs.text_plan_path }}

      - uses: femiwiki/terraform-github-tacos@v0.7.0
        if: always()
        with:
          step: collapse

  pending:
    needs: plan
    if: >-
      !cancelled() && (github.event_name == 'workflow_dispatch'
      || (github.event_name == 'push' && needs.plan.result == 'success'))
    runs-on: ubuntu-latest
    permissions:
      actions: write
      checks: read
    outputs:
      workspaces: ${{ steps.pending.outputs.workspaces }}
    steps:
      - uses: femiwiki/terraform-github-tacos@v0.7.0
        id: pending
        with:
          step: pending
          workspaces: ${{ inputs.workspace && format('["{0}"]', inputs.workspace) || '' }}

  apply:
    name: ${{ matrix.workspace }} apply
    needs: pending
    if: >-
      !cancelled() && needs.pending.result == 'success'
      && needs.pending.outputs.workspaces != '[]'
    strategy:
      fail-fast: false
      matrix:
        workspace: ${{ fromJSON(needs.pending.outputs.workspaces) }}
    runs-on: ubuntu-latest
    environment: ${{ matrix.workspace }}
    permissions:
      actions: read
      contents: read
      pull-requests: write
    steps:
      - uses: femiwiki/terraform-github-tacos@v0.7.0
        id: approver
        with:
          step: apply
          workspace: ${{ matrix.workspace }}

      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0  # v7.0.0
        with:
          persist-credentials: false

      - uses: dflook/tofu-apply@e3e5dfc8f935d4b152c767801046f63abf8a77d3  # v3.1.0
        id: apply
        env:
          GITHUB_TOKEN: ${{ github.token }}
        with:
          path: ${{ matrix.workspace }}
          auto_approve: ${{ github.event_name == 'workflow_dispatch' }}

      - uses: femiwiki/terraform-github-tacos@v0.7.0
        if: always()
        with:
          step: result
          workspace: ${{ matrix.workspace }}
          outcome: ${{ steps.apply.outcome }}
          plan-json: ${{ steps.apply.outputs.json_plan_path }}
          plan-text: ${{ steps.apply.outputs.text_plan_path }}
          approver: ${{ steps.approver.outputs.approver }}

  # Make this the one required check
  gate:
    name: ${{ github.event_name == 'pull_request' && 'tofu gate' || 'tofu gate (pull requests only)' }}
    needs: plan
    if: always() && github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    permissions: {}
    steps:
      - uses: femiwiki/terraform-github-tacos@v0.7.0
        with:
          step: gate
          needs: ${{ toJSON(needs) }}