You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Implement .terraform-version file discovery and version file resolution for the Go edition with identical precedence rules to the Bash edition.
Parent Epic
Part of #488 — Go Edition: Full Feature Parity Implementation
Motivation
Version file resolution is the core mechanism by which tfenv determines which Terraform version to use. It must walk up directories, handle multiple file formats, strip carriage returns, and respect environment variable overrides. Getting this wrong breaks every downstream command.
Clean-Room Constraint
This is a clean-room implementation. Contributors MUST NOT read, reference, copy, or adapt source code from tofuutils/tenv, hashicorp/hc-install, or any other third-party tfenv-like tool. The sole reference is tfenv's own Bash source code, documentation, and test suite.
This matches the Bash edition's behaviour in lib/tfenv-version-file.sh and lib/tfenv-version-name.sh.
File Content Parsing
The .terraform-version file may contain:
A literal version: 1.5.0
A v-prefixed version: v1.5.0 (strip the v prefix)
A keyword: latest, latest:^1.5, latest-allowed, min-required
Comments starting with # (strip everything from # to end of line)
Leading/trailing whitespace (strip)
Windows carriage returns \r (strip with strings.TrimRight)
Blank lines (skip)
The Bash edition's read_version_file() function in lib/helpers.sh (lines 113-116) applies these transformations:
sed -e 's/#.*$//' -e 's/[[:space:]]*$//' -e '/^[[:space:]]*$/d'"${file}"| tr -d '\r';
The Go equivalent should:
Read the file content
For each line: strip everything after # (comment removal)
Trim trailing whitespace
Skip blank lines
Strip \r (carriage return)
Return the first non-empty line
Important: Only the FIRST non-empty, non-comment line is used. The version file is not expected to contain multiple version specifiers.
Directory Walk
Starting from the current working directory (or TFENV_DIR if set), walk up parent directories looking for .terraform-version. The walk has TWO separate searches:
First search: Walk up from TFENV_DIR (or $PWD) toward the filesystem root
If not found: Walk up from $HOME toward the filesystem root
If still not found: Fall back to ${TFENV_CONFIG_DIR}/version
Reference: lib/tfenv-version-file.sh — find_local_version_file() is called twice: first with ${TFENV_DIR:-${PWD}}, then with ${HOME:-/}.
The walk stops at the filesystem root (detected when root becomes empty after stripping the last / component, or matches //[^/]*$ which is the UNC root pattern for network paths).
TFENV_DIR
TFENV_DIR overrides the starting directory for the .terraform-version walk. This is set by:
bin/tfenv sets it to $PWD at startup
lib/tfenv-exec.sh overrides it when -chdir=<dir> is detected in terraform arguments
Acceptance Criteria
TFENV_TERRAFORM_VERSION env var takes highest precedence
.terraform-version in current directory is found
.terraform-version walk discovers files in parent directories
Walk stops at filesystem root without error
${TFENV_CONFIG_DIR}/version is used as fallback default
Error is returned when no version source is found
Carriage returns (\r) are stripped from file content
Leading and trailing whitespace is stripped
Empty files produce a clear error
TFENV_DIR overrides the walk starting directory
Version file content is returned as-is (keyword resolution is a separate concern)
The source of the version (which file, or env var) is tracked for diagnostic purposes
Comprehensive unit tests with t.TempDir() fixtures cover all precedence combinations
Unit tests cover Windows-style line endings (\r\n)
Unit tests cover deeply nested directory structures
Summary
Implement
.terraform-versionfile discovery and version file resolution for the Go edition with identical precedence rules to the Bash edition.Parent Epic
Part of #488 — Go Edition: Full Feature Parity Implementation
Motivation
Version file resolution is the core mechanism by which tfenv determines which Terraform version to use. It must walk up directories, handle multiple file formats, strip carriage returns, and respect environment variable overrides. Getting this wrong breaks every downstream command.
Clean-Room Constraint
This is a clean-room implementation. Contributors MUST NOT read, reference, copy, or adapt source code from
tofuutils/tenv,hashicorp/hc-install, or any other third-party tfenv-like tool. The sole reference is tfenv's own Bash source code, documentation, and test suite.Proposed Design
Package Location
go/internal/resolve/(version file resolution component)Version Precedence (highest to lowest)
TFENV_TERRAFORM_VERSIONenvironment variable.terraform-versionfile in current directory.terraform-versionfile walking up parent directories to filesystem root${TFENV_CONFIG_DIR}/versionfile (default version)This matches the Bash edition's behaviour in
lib/tfenv-version-file.shandlib/tfenv-version-name.sh.File Content Parsing
The
.terraform-versionfile may contain:1.5.0v1.5.0(strip thevprefix)latest,latest:^1.5,latest-allowed,min-required#(strip everything from#to end of line)\r(strip withstrings.TrimRight)The Bash edition's
read_version_file()function inlib/helpers.sh(lines 113-116) applies these transformations:The Go equivalent should:
#(comment removal)\r(carriage return)Important: Only the FIRST non-empty, non-comment line is used. The version file is not expected to contain multiple version specifiers.
Directory Walk
Starting from the current working directory (or
TFENV_DIRif set), walk up parent directories looking for.terraform-version. The walk has TWO separate searches:TFENV_DIR(or$PWD) toward the filesystem root$HOMEtoward the filesystem root${TFENV_CONFIG_DIR}/versionReference:
lib/tfenv-version-file.sh—find_local_version_file()is called twice: first with${TFENV_DIR:-${PWD}}, then with${HOME:-/}.The walk stops at the filesystem root (detected when
rootbecomes empty after stripping the last/component, or matches//[^/]*$which is the UNC root pattern for network paths).TFENV_DIR
TFENV_DIRoverrides the starting directory for the.terraform-versionwalk. This is set by:bin/tfenvsets it to$PWDat startuplib/tfenv-exec.shoverrides it when-chdir=<dir>is detected in terraform argumentsAcceptance Criteria
TFENV_TERRAFORM_VERSIONenv var takes highest precedence.terraform-versionin current directory is found.terraform-versionwalk discovers files in parent directories${TFENV_CONFIG_DIR}/versionis used as fallback default\r) are stripped from file contentTFENV_DIRoverrides the walk starting directoryt.TempDir()fixtures cover all precedence combinations\r\n)Dependencies
TFENV_CONFIG_DIRfor default version file locationImplementation Notes
lib/tfenv-version-file.shfor the directory walk logiclib/tfenv-version-name.shfor the full precedence chain including env var overridelibexec/tfenv-version-filefor the user-facingtfenv version-filecommand (which prints which file was resolved)tfenv whycommand)filepath.Dir()andfilepath.Clean()for the directory walk — handle symlinks correctlyLabels
type:feature,priority:high,complexity:medium,category:version-resolution