From 1fbfc113782055959d84f7ba526bf15be7ed871c Mon Sep 17 00:00:00 2001 From: Tobias Svane Mikkelsen Date: Mon, 14 Sep 2026 15:37:49 +0200 Subject: [PATCH] feat(terraform): default every stack to one Terraform version [NOJIRA] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Monta runs three Terraform versions today: 1.5.7 (Cloudflare, Grafana), 1.9.8 (terraform-core) and 1.13.5 (ClickHouse, all of db-access). The workflow had no opinion and hard-failed when a repo carried no .terraform-version, so every repo had to state it. Default to 1.13.5 — already the majority — as the last fallback, after the input, the stack file and the root file. A stack that must differ keeps its own .terraform-version. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/terraform-stack.yml | 22 ++++++++++++++-------- docs/workflow-guide.md | 6 +++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.github/workflows/terraform-stack.yml b/.github/workflows/terraform-stack.yml index ef8c66f..75af3f8 100644 --- a/.github/workflows/terraform-stack.yml +++ b/.github/workflows/terraform-stack.yml @@ -29,7 +29,10 @@ on: type: string default: eu-west-1 terraform-version: - description: Overrides .terraform-version in the stack directory or repository root. + description: > + Overrides .terraform-version in the stack directory or repository root. + Resolution order: this input, the stack's .terraform-version, the repository + root's, then the org default below. type: string default: "" plan-retention-days: @@ -75,17 +78,20 @@ jobs: working-directory: . env: OVERRIDE: ${{ inputs.terraform-version }} + # The version every Monta Terraform stack runs unless it says otherwise. + # Bumping this moves a repo only when that repo re-pins this workflow, so + # stacks still upgrade one at a time — the first apply on a new version + # rewrites the state format and cannot be rolled back. + DEFAULT_VERSION: "1.13.5" run: | set -eu - if [ -n "$OVERRIDE" ]; then v="$OVERRIDE" - elif [ -f "$STACK/.terraform-version" ]; then v=$(cat "$STACK/.terraform-version") - elif [ -f ".terraform-version" ]; then v=$(cat .terraform-version) - else - echo "::error title=No Terraform version::Add .terraform-version to $STACK or the repository root." - exit 1 + if [ -n "$OVERRIDE" ]; then v="$OVERRIDE"; src="the caller's terraform-version input" + elif [ -f "$STACK/.terraform-version" ]; then v=$(cat "$STACK/.terraform-version"); src="$STACK/.terraform-version" + elif [ -f ".terraform-version" ]; then v=$(cat .terraform-version); src="the repository root .terraform-version" + else v="$DEFAULT_VERSION"; src="the org default" fi echo "version=$v" >> "$GITHUB_OUTPUT" - echo "Terraform $v" + echo "Terraform $v (from $src)" - uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # v4.0.0 with: diff --git a/docs/workflow-guide.md b/docs/workflow-guide.md index 09bb659..cb9f4aa 100644 --- a/docs/workflow-guide.md +++ b/docs/workflow-guide.md @@ -1358,7 +1358,11 @@ A **stack** is any directory containing `backend.tf`. That directory is simultan A change to a path owned by no stack (`modules/**`, `.github/**`) fans out to **every** stack for plan. Changes to `*.md` are ignored. -Each stack needs `.terraform-version` (its own, or one at the repository root) and a committed `.terraform.lock.hcl`. Generate the lock file for the runner architecture: +Every stack runs the org default Terraform version — **1.13.5**, set as `DEFAULT_VERSION` in `terraform-stack.yml` — unless it says otherwise. Resolution order is: the caller's `terraform-version` input, then `.terraform-version` in the stack directory, then one at the repository root, then that default. Pin a stack below or above the default with its own `.terraform-version`; `tfenv` and `asdf` read the same file, so a local plan matches CI. + +Bumping the default does not move anything on its own: a repo picks it up only when it re-pins this workflow. Upgrade stack by stack — the first apply on a new version rewrites the state format, and older Terraform cannot read it back. + +Each stack also needs a committed `.terraform.lock.hcl`. Generate the lock file for the runner architecture: ```bash terraform providers lock -platform=linux_arm64 -platform=darwin_arm64