Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0296e22
Update README.md
bonclay7 Oct 20, 2022
e87532a
Update CI badge in README
davidjb Dec 6, 2022
fb2086c
Update link to terraform docs
bobidle Mar 12, 2023
8d515e8
Check for github action updates monthly
jlosito Apr 2, 2023
0e7c19e
Do not check the release list if a Terraform is already installed (fi…
dluchini-ai May 30, 2023
594cd00
Added export PATH zprofile example in README.md
fALKENdk Aug 22, 2023
c6d00c2
Merge pull request #364 from bonclay7/patch-1
Zordrak Dec 19, 2023
bf5aa77
Merge pull request #370 from davidjb/patch-1
Zordrak Dec 19, 2023
84f8f4a
Merge pull request #385 from bobidle/terraform_docs
Zordrak Dec 19, 2023
0d8a2e9
Merge pull request #389 from jlosito/dbot
Zordrak Dec 19, 2023
e70ae89
Bump docker/build-push-action from 3 to 5
dependabot[bot] Dec 19, 2023
0d39389
Bump actions/checkout from 2 to 4
dependabot[bot] Dec 19, 2023
01e171f
Merge pull request #397 from don-code/master
Zordrak Dec 19, 2023
641a4ef
Merge pull request #408 from fALKENdk/feature/add-zprofile-to-readme
Zordrak Dec 19, 2023
b4dff21
Merge branch 'master' into dependabot/github_actions/actions/checkout-4
Zordrak Dec 19, 2023
093fcf6
Merge pull request #417 from tfutils/dependabot/github_actions/action…
Zordrak Dec 19, 2023
b476877
Merge pull request #416 from tfutils/dependabot/github_actions/docker…
Zordrak Dec 19, 2023
266c764
Bump docker/setup-buildx-action from 2 to 3
dependabot[bot] Dec 19, 2023
8c0f86b
Merge pull request #415 from tfutils/dependabot/github_actions/docker…
Zordrak Dec 19, 2023
c14ab32
Revert "Do not check the release list if a Terraform is already insta…
Zordrak Dec 19, 2023
a14e553
Merge pull request #419 from tfutils/revert-397-master
Zordrak Dec 19, 2023
6f3d636
Replace use of rev for Windows compatibility
Zordrak Dec 19, 2023
b9042b0
Just suppress darwin tests for unsupported darwin builds
Zordrak Dec 19, 2023
6bbd3ec
Merge pull request #421 from tfutils/darwin-fail
Zordrak Dec 19, 2023
c12a0ad
Fix bug in regex for darwin arm64->amd64 workaround
bryanhiestand Jun 24, 2023
9d2bd77
allow match for 0. versions that end with extra characters like 0.11.…
bryanhiestand Jun 24, 2023
3782903
Merge pull request #403 from bryanhiestand/fix_darwin_arm64_regex
Zordrak Dec 19, 2023
e00d30a
Update test.yml
Zordrak Dec 19, 2023
bcfaed2
fix: Underscores are needed for Cygwin-like tools
ElvenSpellmaker Feb 21, 2023
521e2c5
Update tfenv-install
Zordrak Dec 19, 2023
39d8c27
Merge pull request #382 from ElvenSpellmaker/fix/windows-os-selection
Zordrak Dec 19, 2023
28de4b0
Added fish way to add PATH to README.md
sato-s Nov 26, 2024
51cce09
Fix latest-allowed version matching
Zordrak Jul 2, 2025
8d1c241
Fix testing to be source path agnostic
Zordrak Jul 4, 2025
5354074
Reduce duplication, and add safety
Zordrak Jul 4, 2025
f6cc330
Merge pull request #444 from tfutils/improve-testing
Zordrak Jul 4, 2025
6e0116f
Merge branch 'master' into patch-1
Zordrak Jul 4, 2025
99b06bd
Merge pull request #438 from sato-s/patch-1
Zordrak Jul 4, 2025
08d328e
Cope with different line endings in .terraform-version
fractos Jul 11, 2024
66cea4c
Merge pull request #434 from fractos/fix/ignore-terraform-version-fil…
Zordrak Jul 4, 2025
01ef43c
GitHub Actions: fix `matrix.os` strategy
takano32 Feb 19, 2024
2bb36e0
Merge pull request #428 from takano32/fix-github-actions
Zordrak Jul 4, 2025
37bac16
fix README.md
Zordrak Jul 4, 2025
79a3b2f
docs: fix README to enable copy and use as is
kuredev Feb 15, 2024
106a75b
Merge pull request #427 from kuredev/fix-README-zsh-script
Zordrak Jul 4, 2025
461d5c7
Bump docker/build-push-action from 5 to 6
dependabot[bot] Jul 4, 2025
ca62417
Merge pull request #433 from tfutils/dependabot/github_actions/docker…
Zordrak Jul 4, 2025
b80e3ce
Add test to reproduce #354
OJFord Jul 27, 2022
12be2ac
Fix use of -chdir with an absolute path
OJFord Jul 27, 2022
9acfdf8
Fix realpath not available on macOS
OJFord Nov 4, 2022
fe8767d
Merge pull request #355 from OJFord/fix-354
Zordrak Jul 4, 2025
c8eb402
Update test os matrix
Zordrak Jul 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
27 changes: 14 additions & 13 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- 'macos-latest'
- 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v2'
- uses: 'actions/checkout@v4'
with:
fetch-depth: 1
- name: 'Install Dependencies'
Expand All @@ -30,21 +30,21 @@ jobs:
run: './test/run.sh'
shell: 'bash'

- uses: 'docker/setup-buildx-action@v2'
- uses: 'docker/setup-buildx-action@v3'
if: contains(matrix.os, 'ubuntu')
with:
install: true
- uses: 'docker/build-push-action@v3'
- uses: 'docker/build-push-action@v6'
if: contains(matrix.os, 'ubuntu')
with:
context: .
load: true
tags: "tfenv-terraform:${{ github.head_ref }}"
tags: "tfenv-terraform:${{ github.sha }}"
- name: 'Check Dockerfile'
if: contains(matrix.os, 'ubuntu')
run: |
expect=1.2.3;
got="$(docker run -e "TFENV_TERRAFORM_VERSION=${expect}" "tfenv-terraform:${{ github.head_ref }}" version)";
got="$(docker run -e "TFENV_TERRAFORM_VERSION=${expect}" "tfenv-terraform:${{ github.sha }}" version)";
echo "${got}" | tee /dev/stderr | grep -e 'Terraform v1.2.3'

# When we push to master, test everything in order to guarantee releases
Expand All @@ -54,13 +54,14 @@ jobs:
strategy:
matrix:
os:
- 'macos-11'
- 'macos-10.15'
- 'ubuntu-20.04'
- 'ubuntu-18.04'
- 'windows-2019'
- 'ubuntu-24.04'
- 'ubuntu-22.04'
- 'macos-14'
- 'macos-13'
- 'windows-2025'
- 'windows-2022'
steps:
- uses: 'actions/checkout@v2'
- uses: 'actions/checkout@v4'
with:
fetch-depth: 1
- name: 'Install Dependencies'
Expand All @@ -69,11 +70,11 @@ jobs:
run: './test/run.sh'
shell: 'bash'

- uses: 'docker/setup-buildx-action@v2'
- uses: 'docker/setup-buildx-action@v3'
if: contains(matrix.os, 'ubuntu')
with:
install: true
- uses: 'docker/build-push-action@v3'
- uses: 'docker/build-push-action@v6'
if: contains(matrix.os, 'ubuntu')
with:
context: .
Expand Down
73 changes: 42 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![CI](https://github.com/tfutils/tfenv/workflows/CI/badge.svg)
[![CI Test](https://github.com/tfutils/tfenv/actions/workflows/test.yml/badge.svg)](https://github.com/tfutils/tfenv/actions/workflows/test.yml)

# tfenv

Expand All @@ -23,13 +23,13 @@ Currently tfenv supports the following OSes
Install via Homebrew

```console
$ brew install tfenv
brew install tfenv
```

Install via Arch User Repository (AUR)

```console
$ yay --sync tfenv
yay --sync tfenv
```

Install via puppet
Expand All @@ -45,34 +45,45 @@ include ::tfenv
1. Check out tfenv into any path (here is `${HOME}/.tfenv`)

```console
$ git clone --depth=1 https://github.com/tfutils/tfenv.git ~/.tfenv
git clone --depth=1 https://github.com/tfutils/tfenv.git ~/.tfenv
```

2. Add `~/.tfenv/bin` to your `$PATH` any way you like

bash:
```console
$ echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bash_profile
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bash_profile
```

For WSL users
zsh:
```console
echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.zprofile
```

fish:
```console
echo 'set -x PATH $HOME/.tfenv/bin $PATH' >> ~/.config/fish/config.fish
```

For WSL users:
```bash
$ echo 'export PATH=$PATH:$HOME/.tfenv/bin' >> ~/.bashrc
echo 'export PATH=$PATH:$HOME/.tfenv/bin' >> ~/.bashrc
```

OR you can make symlinks for `tfenv/bin/*` scripts into a path that is already added to your `$PATH` (e.g. `/usr/local/bin`) `OSX/Linux Only!`

```console
$ ln -s ~/.tfenv/bin/* /usr/local/bin
ln -s ~/.tfenv/bin/* /usr/local/bin
```

On Ubuntu/Debian touching `/usr/local/bin` might require sudo access, but you can create `${HOME}/bin` or `${HOME}/.local/bin` and on next login it will get added to the session `$PATH`
or by running `. ${HOME}/.profile` it will get added to the current shell session's `$PATH`.

```console
$ mkdir -p ~/.local/bin/
$ . ~/.profile
$ ln -s ~/.tfenv/bin/* ~/.local/bin
$ which tfenv
mkdir -p ~/.local/bin/
. ~/.profile
ln -s ~/.tfenv/bin/* ~/.local/bin
which tfenv
```

## Usage
Expand All @@ -91,7 +102,7 @@ If a parameter is passed, available options:
- `latest-allowed` is a syntax to scan your Terraform files to detect which version is maximally allowed.
- `min-required` is a syntax to scan your Terraform files to detect which version is minimally required.

See [required_version](https://www.terraform.io/docs/configuration/terraform.html) docs. Also [see min-required & latest-allowed](#min-required) section below.
See [required_version](https://developer.hashicorp.com/terraform/language/settings) docs. Also [see min-required & latest-allowed](#min-required) section below.

```console
$ tfenv install
Expand All @@ -110,8 +121,8 @@ You can opt-in to using GnuPG tools for PGP signature verification if keybase is
Where `TFENV_INSTALL_DIR` is for example, `~/.tfenv` or `/usr/local/Cellar/tfenv/<version>`

```console
$ echo 'trust-tfenv: yes' > ${TFENV_INSTALL_DIR}/use-gpgv
$ tfenv install
echo 'trust-tfenv: yes' > ${TFENV_INSTALL_DIR}/use-gpgv
tfenv install
```

The `trust-tfenv` directive means that verification uses a copy of the
Expand Down Expand Up @@ -157,7 +168,7 @@ Specify architecture. Architecture other than the default amd64 can be specified
Note: Default changes to `arm64` for versions that have arm64 builds available when `$(uname -m)` matches `aarch64* | arm64*`

```console
$ TFENV_ARCH=arm64 tfenv install 0.7.9
TFENV_ARCH=arm64 tfenv install 0.7.9
```

##### `TFENV_AUTO_INSTALL`
Expand All @@ -167,11 +178,11 @@ String (Default: true)
Should tfenv automatically install terraform if the version specified by defaults or a .terraform-version file is not currently installed.

```console
$ TFENV_AUTO_INSTALL=false terraform plan
TFENV_AUTO_INSTALL=false terraform plan
```

```console
$ terraform use <version that is not yet installed>
terraform use <version that is not yet installed>
```

##### `TFENV_CURL_OUTPUT`
Expand Down Expand Up @@ -202,7 +213,7 @@ String (Default: https://releases.hashicorp.com)
To install from a remote other than the default

```console
$ TFENV_REMOTE=https://example.jfrog.io/artifactory/hashicorp
TFENV_REMOTE=https://example.jfrog.io/artifactory/hashicorp
```

##### `TFENV_REVERSE_REMOTE`
Expand All @@ -217,7 +228,7 @@ is instead providing a list that is oldes-first, set `TFENV_REVERSE_REMOTE=1` an
functionality will be restored.

```console
$ TFENV_REVERSE_REMOTE=1 tfenv list-remote
TFENV_REVERSE_REMOTE=1 tfenv list-remote
```

##### `TFENV_CONFIG_DIR`
Expand All @@ -241,7 +252,7 @@ If not empty string, this variable overrides Terraform version, specified in [.t
e.g.

```console
$ TFENV_TERRAFORM_VERSION=latest:^0.11. terraform --version
TFENV_TERRAFORM_VERSION=latest:^0.11. terraform --version
```

##### `TFENV_NETRC_PATH`
Expand All @@ -253,7 +264,7 @@ If not empty string, this variable specifies the credentials file used to access
e.g.

```console
$ TFENV_NETRC_PATH="$PWD/.netrc.tfenv"
TFENV_NETRC_PATH="$PWD/.netrc.tfenv"
```

#### Bashlog Logging Library
Expand Down Expand Up @@ -294,7 +305,7 @@ Each executable logs to its own file.
e.g.

```console
$ BASHLOG_FILE=1 tfenv use latest
BASHLOG_FILE=1 tfenv use latest
```

will log to `/tmp/tfenv-use.log`
Expand All @@ -316,7 +327,7 @@ This variable allows you to pass a string containing a command that will be exec
e.g.

```console
$ BASHLOG_I_PROMISE_TO_BE_CAREFUL_CUSTOM_EVAL_PREFIX='echo "${$$} "'
BASHLOG_I_PROMISE_TO_BE_CAREFUL_CUSTOM_EVAL_PREFIX='echo "${$$} "'
```
will prefix every log line with the calling process' PID.

Expand All @@ -332,7 +343,7 @@ Each executable logs to its own file.
e.g.

```console
$ BASHLOG_JSON=1 tfenv use latest
BASHLOG_JSON=1 tfenv use latest
```

will log in JSON format to `/tmp/tfenv-use.log.json`
Expand All @@ -356,10 +367,10 @@ To log to syslog using the `logger` binary, set this to 1.
The basic functionality is thus:

```console
$ local tag="${BASHLOG_SYSLOG_TAG:-$(basename "${0}")}";
$ local facility="${BASHLOG_SYSLOG_FACILITY:-local0}";
$ local pid="${$}";
$ logger --id="${pid}" -t "${tag}" -p "${facility}.${severity}" "${syslog_line}"
local tag="${BASHLOG_SYSLOG_TAG:-$(basename "${0}")}";
local facility="${BASHLOG_SYSLOG_FACILITY:-local0}";
local pid="${$}";
logger --id="${pid}" -t "${tag}" -p "${facility}.${severity}" "${syslog_line}"
```

##### `BASHLOG_SYSLOG_FACILITY`
Expand Down Expand Up @@ -489,13 +500,13 @@ Terraform v0.7.3
## Upgrading

```console
$ git --git-dir=~/.tfenv/.git pull
git --git-dir=~/.tfenv/.git pull
```

## Uninstalling

```console
$ rm -rf /some/path/to/tfenv
rm -rf /some/path/to/tfenv
```

## LICENSE
Expand Down
15 changes: 11 additions & 4 deletions lib/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,17 @@ export -f check_default_version;
function cleanup() {
log 'info' 'Performing cleanup';
local pwd="$(pwd)";
log 'debug' "Deleting ${pwd}/version";
rm -rf ./version;
log 'debug' "Deleting ${pwd}/versions";
rm -rf ./versions;

# Safety check to ensure TFENV_CONFIG_DIR is set and not empty
if [ -z "${TFENV_CONFIG_DIR:-""}" ]; then
log 'error' 'TFENV_CONFIG_DIR is not set, cannot perform cleanup safely';
return 1;
fi;

log 'debug' "Deleting ${TFENV_CONFIG_DIR}/version";
rm -rf "${TFENV_CONFIG_DIR}/version";
log 'debug' "Deleting ${TFENV_CONFIG_DIR}/versions";
rm -rf "${TFENV_CONFIG_DIR}/versions";
log 'debug' "Deleting ${pwd}/.terraform-version";
rm -rf ./.terraform-version;
log 'debug' "Deleting ${pwd}/latest_allowed.tf";
Expand Down
32 changes: 30 additions & 2 deletions lib/tfenv-exec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,39 @@

set -uo pipefail;

function realpath-relative-to() {
# A basic implementation of GNU `realpath --relative-to=$1 $2`
# that can also be used on macOS.

# http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
readlink_f() {
local target_file="${1}";
local file_name;

while [ "${target_file}" != "" ]; do
cd "$(dirname "$target_file")" || early_death "Failed to 'cd \$(${target_file%/*})'";
file_name="${target_file##*/}" || early_death "Failed to '\"${target_file##*/}\"'";
target_file="$(readlink "${file_name}")";
done;

echo "$(pwd -P)/${file_name}";
};

local relative_to="$(readlink_f "${1}")";
local path="$(readlink_f "${2}")";

echo "${path#"${relative_to}/"}";
return 0;
}
export -f realpath-relative-to;

function tfenv-exec() {
for _arg in ${@:1}; do
if [[ "${_arg}" == -chdir=* ]]; then
log 'debug' "Found -chdir arg. Setting TFENV_DIR to: ${_arg#-chdir=}";
export TFENV_DIR="${PWD}/${_arg#-chdir=}";
chdir="${_arg#-chdir=}";
log 'debug' "Found -chdir arg: ${chdir}";
export TFENV_DIR="${PWD}/$(realpath-relative-to "${PWD}" "${chdir}")";
log 'debug' "Setting TFENV_DIR to: ${TFENV_DIR}";
fi;
done;

Expand Down
2 changes: 1 addition & 1 deletion lib/tfenv-version-name.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function tfenv-version-name() {
&& log 'debug' "TFENV_VERSION_FILE retrieved from tfenv-version-file: ${TFENV_VERSION_FILE}" \
|| log 'error' 'Failed to retrieve TFENV_VERSION_FILE from tfenv-version-file';

TFENV_VERSION="$(cat "${TFENV_VERSION_FILE}" || true)" \
TFENV_VERSION="$(cat "${TFENV_VERSION_FILE}" || true | tr -d '\r')" \
&& log 'debug' "TFENV_VERSION specified in TFENV_VERSION_FILE: ${TFENV_VERSION}";

TFENV_VERSION_SOURCE="${TFENV_VERSION_FILE}";
Expand Down
6 changes: 3 additions & 3 deletions libexec/tfenv-install
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ case "$(uname -s)" in
MINGW64*)
kernel="windows";
;;
MSYSNT*)
MSYS*NT*)
kernel="windows";
;;
CYGWINNT*)
CYGWIN*NT*)
kernel="windows";
;;
FreeBSD*)
Expand Down Expand Up @@ -124,7 +124,7 @@ case "$(uname -m)" in
;;
"darwin")
# No Apple Silicon builds before 1.0.2
if [[ "${version}" =~ 0\..+$ || "${version}" =~ 1\.0\.0|1$
if [[ "${version}" =~ ^0\.[0-9]+\.[0-9]+ || "${version}" =~ ^1\.0\.[0-1]$
]]; then
TFENV_ARCH="${TFENV_ARCH:-amd64}";
else
Expand Down
2 changes: 1 addition & 1 deletion libexec/tfenv-min-required
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ terraform {
required_version = ">= 0.0.0"
}

see https://www.terraform.io/docs/configuration/terraform.html for details';
see https://developer.hashicorp.com/terraform/language/settings for details';
};

declare min_required="$(tfenv-min-required "${TFENV_DIR:-$(pwd)}")";
Expand Down
Loading