Skip to content

Commit a6cafb6

Browse files
committed
Merge branch 'auto_use_required_version' of github.com:people-ai/tfenv into auto_use_required_version
2 parents 371b76c + 43092a8 commit a6cafb6

8 files changed

Lines changed: 244 additions & 14 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ $ which tfenv
8181

8282
Install a specific version of Terraform.
8383

84-
If no parameter is passed, the version to use is resolved automatically via [.terraform-version files](#terraform-version-file) or [TFENV\_TERRAFORM\_VERSION environment variable](#tfenv_terraform_version) (TFENV\_TERRAFORM\_VERSION takes precedence), defaulting to 'latest' if none are found.
84+
If no parameter is passed, the version to use is resolved automatically via [TFENV\_TERRAFORM\_VERSION environment variable](#tfenv_terraform_version), [.terraform-version files](#terraform-version-file), or [required_version in "terraform" section of any .tf or .tf.json file](#min-required), in that order of precedence, i.e. TFENV\_TERRAFORM\_VERSION, then .terraform-version, and then required_version in .tf. The default is 'latest' if none are found.
8585

8686
If a parameter is passed, available options:
8787

lib/helpers.sh

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,41 @@ resolve_version () {
7575
log 'debug' "Version File (${version_file}) is not the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
7676
version_requested="$(cat "${version_file}")" \
7777
|| log 'error' "Failed to open ${version_file}";
78+
fi
79+
80+
if [ -z "${version_requested:-""}" ]; then
81+
log 'debug' 'Tryng to set version from "required_version" under "terraform" section'
82+
versions="$( echo $(cat {*.tf,*.tf.json} 2>/dev/null | grep -h required_version) | grep -o '\([0-9]\+\.\?\)\{2,3\}\(-[a-z]\+[0-9]\+\)\?')";
83+
if [[ "${versions}" =~ ([~=!<>]{0,2}[[:blank:]]*[0-9]+[0-9.]+)[^0-9]*(-[a-z]+[0-9]+)? ]]; then
84+
found_min_required="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
85+
if [[ "${found_min_required}" =~ ^!=.+ ]]; then
86+
log 'debug' "required_version is a negation - we cannot guess the desired one, skipping.";
87+
else
88+
found_min_required="$(echo "$found_min_required")";
89+
90+
# Probably not an advisable way to choose a terraform version,
91+
# but this is the way this functionality works in terraform:
92+
# add .0 to versions without a minor and/or patch version (e.g. 12.0)
93+
while ! [[ "${found_min_required}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; do
94+
found_min_required="${found_min_required}.0";
95+
done;
96+
version_requested="${found_min_required}";
97+
fi;
98+
fi;
99+
fi;
78100

79-
elif [ -f "${version_file}" ]; then
101+
if [ -z "${version_requested}" -a -f "${version_file}" ]; then
80102
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
81103
version_requested="$(cat "${version_file}")" \
82104
|| log 'error' "Failed to open ${version_file}";
83105

84-
# Absolute fallback
85106
if [ -z "${version_requested}" ]; then
86107
log 'debug' 'Version file had no content. Falling back to "latest"';
87108
version_requested='latest';
88109
fi;
89110

90-
else
111+
# Absolute fallback
112+
elif [ -z "${version_requested}" ]; then
91113
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version) but it doesn't exist";
92114
log 'info' 'No version requested on the command line or in the version file search path. Installing "latest"';
93115
version_requested='latest';
@@ -173,6 +195,8 @@ cleanup() {
173195
rm -rf ./.terraform-version;
174196
log 'debug' "Deleting ${pwd}/min_required.tf";
175197
rm -rf ./min_required.tf;
198+
log 'debug' "Deleting ${pwd}/required_version.tf";
199+
rm -rf ./required_version.tf;
176200
};
177201
export -f cleanup;
178202

lib/tfenv-version-name.sh

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,36 @@ function tfenv-version-name() {
44
&& log 'debug' "TFENV_VERSION_FILE retrieved from tfenv-version-file: ${TFENV_VERSION_FILE}" \
55
|| log 'error' 'Failed to retrieve TFENV_VERSION_FILE from tfenv-version-file';
66

7-
TFENV_VERSION="$(cat "${TFENV_VERSION_FILE}" || true)" \
8-
&& log 'debug' "TFENV_VERSION specified in TFENV_VERSION_FILE: ${TFENV_VERSION}";
7+
if [ "${TFENV_VERSION_FILE}" = "${TFENV_CONFIG_DIR}/version" ]; then
8+
log 'debug' 'Tryng to set version from "required_version" under "terraform" section'
99

10-
TFENV_VERSION_SOURCE="${TFENV_VERSION_FILE}";
10+
versions="$( echo $(cat {*.tf,*.tf.json} 2>/dev/null | grep -h required_version) | grep -o '\([0-9]\+\.\?\)\{2,3\}\(-[a-z]\+[0-9]\+\)\?')";
11+
if [[ "${versions}" =~ ([~=!<>]{0,2}[[:blank:]]*[0-9]+[0-9.]+)[^0-9]*(-[a-z]+[0-9]+)? ]]; then
12+
found_min_required="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
13+
if [[ "${found_min_required}" =~ ^!=.+ ]]; then
14+
log 'debug' "required_version is a negation - we cannot guess the desired one, skipping.";
15+
else
16+
found_min_required="$(echo "$found_min_required")";
17+
18+
# Probably not an advisable way to choose a terraform version,
19+
# but this is the way this functionality works in terraform:
20+
# add .0 to versions without a minor and/or patch version (e.g. 12.0)
21+
while ! [[ "${found_min_required}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; do
22+
found_min_required="${found_min_required}.0";
23+
done;
24+
TFENV_VERSION="${found_min_required}";
25+
fi;
26+
fi;
27+
28+
TFENV_VERSION_SOURCE='terraform{required_version}'
29+
fi;
30+
31+
if [[ -z "${TFENV_VERSION:-""}" ]]; then
32+
TFENV_VERSION="$(cat "${TFENV_VERSION_FILE}" || true)" \
33+
&& log 'debug' "TFENV_VERSION specified in TFENV_VERSION_FILE: ${TFENV_VERSION}";
34+
35+
TFENV_VERSION_SOURCE="${TFENV_VERSION_FILE}";
36+
fi;
1137
else
1238
TFENV_VERSION="${TFENV_TERRAFORM_VERSION}" \
1339
&& log 'debug' "TFENV_VERSION specified in TFENV_TERRAFORM_VERSION: ${TFENV_VERSION}";
@@ -79,3 +105,4 @@ function tfenv-version-name() {
79105
echo "${TFENV_VERSION}";
80106
}
81107
export -f tfenv-version-name;
108+

libexec/tfenv-install

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ declare regex="${resolved##*\:}";
7373

7474
log 'debug' "Processing install for version ${version}, using regex ${regex}";
7575

76-
version="$(tfenv-list-remote | grep -e "${regex}" | head -n 1)";
77-
[ -n "${version}" ] || log 'error' "No versions matching '${requested}' found in remote";
76+
remote_version="$(tfenv-list-remote | grep -e "${regex}" | head -n 1)";
77+
[ -n "${remote_version}" ] && version="${remote_version}" || log 'error' "No versions matching '${requested:-$version}' found in remote";
7878

7979
dst_path="${TFENV_CONFIG_DIR}/versions/${version}";
8080
if [ -f "${dst_path}/terraform" ]; then
@@ -188,11 +188,14 @@ download_signature() {
188188
};
189189

190190
# If on MacOS with Homebrew, use GNU grep
191-
# This allows keybase login detection to work on Mac
191+
# This allows keybase login detection to work on Mac,
192+
# and is required to be able to detect terraform version
193+
# from "required_version" setting in "*.tf" files
192194
if [[ $(uname) == 'Darwin' ]] && [ $(which brew) ]; then
193195
if ! [ $(which ggrep) ]; then
194196
brew install grep;
195197
fi
198+
shopt -s expand_aliases
196199
alias grep=ggrep;
197200
fi
198201

libexec/tfenv-resolve-version

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ for dir in libexec bin; do
5757
esac;
5858
done;
5959

60+
# If on MacOS with Homebrew, use GNU grep
61+
# This allows keybase login detection to work on Mac,
62+
# and is required to be able to detect terraform version
63+
# from "required_version" setting in "*.tf" files
64+
if [[ $(uname) == 'Darwin' ]] && [ $(which brew) ]; then
65+
if ! [ $(which ggrep) ]; then
66+
brew install grep;
67+
fi
68+
shopt -s expand_aliases
69+
alias grep=ggrep;
70+
fi
6071
#####################
6172
# Begin Script Body #
6273
#####################
@@ -73,19 +84,41 @@ if [ -z "${arg}" -a -z "${TFENV_TERRAFORM_VERSION:-""}" ]; then
7384
log 'debug' "Version File (${version_file}) is not the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
7485
version_requested="$(cat "${version_file}")" \
7586
|| log 'error' "Failed to open ${version_file}";
87+
fi;
7688

77-
elif [ -f "${version_file}" ]; then
89+
if [ -z "${version_requested:-""}" ]; then
90+
log 'debug' 'Tryng to set version from "required_version" under "terraform" section'
91+
versions="$( echo $(cat {*.tf,*.tf.json} 2>/dev/null | grep -h required_version) | grep -o '\([0-9]\+\.\?\)\{2,3\}\(-[a-z]\+[0-9]\+\)\?')";
92+
if [[ "${versions}" =~ ([~=!<>]{0,2}[[:blank:]]*[0-9]+[0-9.]+)[^0-9]*(-[a-z]+[0-9]+)? ]]; then
93+
found_min_required="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
94+
if [[ "${found_min_required}" =~ ^!=.+ ]]; then
95+
log 'debug' "required_version is a negation - we cannot guess the desired one, skipping.";
96+
else
97+
found_min_required="$(echo "$found_min_required")";
98+
99+
# Probably not an advisable way to choose a terraform version,
100+
# but this is the way this functionality works in terraform:
101+
# add .0 to versions without a minor and/or patch version (e.g. 12.0)
102+
while ! [[ "${found_min_required}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; do
103+
found_min_required="${found_min_required}.0";
104+
done;
105+
version_requested="${found_min_required}";
106+
fi;
107+
fi;
108+
fi;
109+
110+
if [ -z "${version_requested}" -a -f "${version_file}" ]; then
78111
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
79112
version_requested="$(cat "${version_file}")" \
80113
|| log 'error' "Failed to open ${version_file}";
81114

82-
# Absolute fallback
83115
if [ -z "${version_requested}" ]; then
84116
log 'debug' 'Version file had no content. Falling back to "latest"';
85117
version_requested='latest';
86118
fi;
87119

88-
else
120+
# Absolute fallback
121+
elif [ -z "${version_requested}" ]; then
89122
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version) but it doesn't exist";
90123
log 'info' 'No version requested on the command line or in the version file search path. Installing "latest"';
91124
version_requested='latest';

libexec/tfenv-use

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ log debug "Resolving version with: tfenv-resolve-version ${requested_arg}";
7979
declare resolved="$(tfenv-resolve-version ${requested_arg})";
8080
log debug "Resolved to: ${resolved}";
8181

82+
declare requested_version="${resolved%%\:*}";
8283
declare version="${resolved%%\:*}";
8384
declare regex="${resolved##*\:}";
8485

@@ -92,7 +93,7 @@ declare version="$(\find "${TFENV_CONFIG_DIR}/versions/" -type d -exec basename
9293

9394
[ -n "${version}" ] \
9495
&& log 'debug' "Found version: ${version}" \
95-
|| log 'error' "No installed versions of terraform matched '${requested}'${version_source_suffix}";
96+
|| log 'error' "No installed versions of terraform matched '${requested_version}'${version_source_suffix}";
9697

9798
target_path="${TFENV_CONFIG_DIR}/versions/${version}";
9899
[ -f "${target_path}/terraform" ] \

libexec/tfenv-version-name

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ for dir in libexec bin; do
5656
esac;
5757
done;
5858

59+
# If on MacOS with Homebrew, use GNU grep
60+
# This allows keybase login detection to work on Mac,
61+
# and is required to be able to detect terraform version
62+
# from "required_version" setting in "*.tf" files
63+
if [[ $(uname) == 'Darwin' ]] && [ $(which brew) ]; then
64+
if ! [ $(which ggrep) ]; then
65+
brew install grep;
66+
fi
67+
shopt -s expand_aliases
68+
alias grep=ggrep;
69+
fi
70+
5971
#####################
6072
# Begin Script Body #
6173
#####################
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env bash
2+
3+
set -uo pipefail;
4+
5+
####################################
6+
# Ensure we can execute standalone #
7+
####################################
8+
9+
function early_death() {
10+
echo "[FATAL] ${0}: ${1}" >&2;
11+
exit 1;
12+
};
13+
14+
if [ -z "${TFENV_ROOT:-""}" ]; then
15+
# http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
16+
readlink_f() {
17+
local target_file="${1}";
18+
local file_name;
19+
20+
while [ "${target_file}" != "" ]; do
21+
cd "$(dirname ${target_file})" || early_death "Failed to 'cd \$(dirname ${target_file})' while trying to determine TFENV_ROOT";
22+
file_name="$(basename "${target_file}")" || early_death "Failed to 'basename \"${target_file}\"' while trying to determine TFENV_ROOT";
23+
target_file="$(readlink "${file_name}")";
24+
done;
25+
26+
echo "$(pwd -P)/${file_name}";
27+
};
28+
29+
TFENV_ROOT="$(cd "$(dirname "$(readlink_f "${0}")")/.." && pwd)";
30+
[ -n ${TFENV_ROOT} ] || early_death "Failed to 'cd \"\$(dirname \"\$(readlink_f \"${0}\")\")/..\" && pwd' while trying to determine TFENV_ROOT";
31+
else
32+
TFENV_ROOT="${TFENV_ROOT%/}";
33+
fi;
34+
export TFENV_ROOT;
35+
36+
if [ -n "${TFENV_HELPERS:-""}" ]; then
37+
log 'debug' 'TFENV_HELPERS is set, not sourcing helpers again';
38+
else
39+
[ "${TFENV_DEBUG:-0}" -gt 0 ] && echo "[DEBUG] Sourcing helpers from ${TFENV_ROOT}/lib/helpers.sh";
40+
if source "${TFENV_ROOT}/lib/helpers.sh"; then
41+
log 'debug' 'Helpers sourced successfully';
42+
else
43+
early_death "Failed to source helpers from ${TFENV_ROOT}/lib/helpers.sh";
44+
fi;
45+
fi;
46+
47+
#####################
48+
# Begin Script Body #
49+
#####################
50+
51+
declare -a errors=();
52+
53+
cleanup || log 'error' 'Cleanup failed?!';
54+
55+
56+
log 'info' '### Install required_version normal version (#.#.#)';
57+
58+
reqv='0.14.11';
59+
60+
echo "terraform {
61+
required_version = \">=${reqv}\"
62+
}" > required_version.tf;
63+
64+
(
65+
tfenv install;
66+
tfenv use;
67+
check_active_version "${reqv}";
68+
) || error_and_proceed 'required_version does not match';
69+
70+
cleanup || log 'error' 'Cleanup failed?!';
71+
72+
73+
log 'info' '### Install required_version tagged version (#.#.#-tag#)'
74+
75+
reqv='0.14.0-rc1'
76+
77+
echo "terraform {
78+
required_version = \">=${reqv}\"
79+
}" > required_version.tf;
80+
81+
(
82+
tfenv install;
83+
tfenv use;
84+
check_active_version "${reqv}";
85+
) || error_and_proceed 'required_version tagged-version does not match';
86+
87+
cleanup || log 'error' 'Cleanup failed?!';
88+
89+
90+
log 'info' '### Install required_version incomplete version (#.#.<missing>)'
91+
92+
reqv='0.14';
93+
94+
echo "terraform {
95+
required_version = \">=${reqv}\"
96+
}" > required_version.tf;
97+
98+
(
99+
tfenv install;
100+
tfenv use;
101+
check_active_version "${reqv}.0";
102+
) || error_and_proceed 'required_version incomplete-version does not match';
103+
104+
cleanup || log 'error' 'Cleanup failed?!';
105+
106+
log 'info' '### Test auto-installing when running terraform';
107+
108+
reqv='0.14.11';
109+
110+
echo "terraform {
111+
required_version = \">=${reqv}\"
112+
}" > required_version.tf;
113+
114+
(
115+
check_active_version "${reqv}";
116+
) || error_and_proceed 'required_version does not match';
117+
118+
cleanup || log 'error' 'Cleanup failed?!';
119+
120+
if [ "${#errors[@]}" -gt 0 ]; then
121+
log 'warn' '===== The following required_version tests failed =====';
122+
for error in "${errors[@]}"; do
123+
log 'warn' "\t${error}";
124+
done;
125+
log 'error' 'required_version test failure(s)';
126+
else
127+
log 'info' 'All required_version tests passed.';
128+
fi;
129+
130+
exit 0;

0 commit comments

Comments
 (0)