Skip to content

Commit 0a3c2ca

Browse files
committed
Fix the problems introduced with minrequired changes
1 parent fc0a718 commit 0a3c2ca

11 files changed

Lines changed: 94 additions & 331 deletions

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 [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.
84+
If no parameter is passed, the version to use is resolved automatically via [TFENV\_TERRAFORM\_VERSION environment variable](#tfenv_terraform_version) or [.terraform-version files](#terraform-version-file), in that order of precedence, i.e. TFENV\_TERRAFORM\_VERSION, then .terraform-version. The default is 'latest' if none are found.
8585

8686
If a parameter is passed, available options:
8787

lib/helpers.sh

Lines changed: 5 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -63,91 +63,6 @@ else
6363
export -f log;
6464
fi;
6565

66-
resolve_version () {
67-
declare version_requested version regex min_required version_file;
68-
69-
declare arg="${1:-""}";
70-
71-
if [ -z "${arg}" -a -z "${TFENV_TERRAFORM_VERSION:-""}" ]; then
72-
version_file="$(tfenv-version-file)";
73-
log 'debug' "Version File: ${version_file}";
74-
75-
if [ "${version_file}" != "${TFENV_CONFIG_DIR}/version" ]; then
76-
log 'debug' "Version File (${version_file}) is not the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
77-
version_requested="$(cat "${version_file}")" \
78-
|| log 'error' "Failed to open ${version_file}";
79-
fi
80-
81-
if [ -z "${version_requested:-""}" ]; then
82-
log 'debug' 'Trying to set version from "required_version" under "terraform" section';
83-
versions="$( echo $(cat {*.tf,*.tf.json} 2>/dev/null | grep -h required_version) | grep -o '\([0-9]\+\.\?\)\{2,3\}\(-[a-z]\+[0-9]\+\)\?')";
84-
if [[ "${versions}" =~ ([~=!<>]{0,2}[[:blank:]]*[0-9]+[0-9.]+)[^0-9]*(-[a-z]+[0-9]+)? ]]; then
85-
found_min_required="${BASH_REMATCH[1]}${BASH_REMATCH[2]}";
86-
if [[ "${found_min_required}" =~ ^!=.+ ]]; then
87-
log 'debug' "required_version is a negation - we cannot guess the desired one, skipping.";
88-
else
89-
found_min_required="$(echo "$found_min_required")";
90-
91-
# Probably not an advisable way to choose a terraform version,
92-
# but this is the way this functionality works in terraform:
93-
# add .0 to versions without a minor and/or patch version (e.g. 12.0)
94-
while ! [[ "${found_min_required}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; do
95-
found_min_required="${found_min_required}.0";
96-
done;
97-
version_requested="${found_min_required}";
98-
fi;
99-
fi;
100-
fi;
101-
102-
if [ -z "${version_requested}" -a -f "${version_file}" ]; then
103-
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version)";
104-
version_requested="$(cat "${version_file}")" \
105-
|| log 'error' "Failed to open ${version_file}";
106-
107-
if [ -z "${version_requested}" ]; then
108-
log 'debug' 'Version file had no content. Falling back to "latest"';
109-
version_requested='latest';
110-
fi;
111-
112-
# Absolute fallback
113-
elif [ -z "${version_requested}" ]; then
114-
log 'debug' "Version File is the default \${TFENV_CONFIG_DIR}/version (${TFENV_CONFIG_DIR}/version) but it doesn't exist";
115-
log 'info' 'No version requested on the command line or in the version file search path. Installing "latest"';
116-
version_requested='latest';
117-
fi;
118-
elif [ -n "${TFENV_TERRAFORM_VERSION:-""}" ]; then
119-
version_requested="${TFENV_TERRAFORM_VERSION}";
120-
log 'debug' "TFENV_TERRAFORM_VERSION is set: ${TFENV_TERRAFORM_VERSION}";
121-
else
122-
version_requested="${arg}";
123-
fi;
124-
125-
log 'debug' "Version Requested: ${version_requested}";
126-
127-
if [[ "${version_requested}" =~ ^min-required$ ]]; then
128-
log 'info' 'Detecting minimum required version...';
129-
min_required="$(tfenv-min-required)" \
130-
|| log 'error' 'tfenv-min-required failed';
131-
132-
log 'info' "Minimum required version detected: ${min_required}";
133-
version_requested="${min_required}";
134-
fi;
135-
136-
if [[ "${version_requested}" =~ ^latest\:.*$ ]]; then
137-
version="${version_requested%%\:*}";
138-
regex="${version_requested##*\:}";
139-
log 'debug' "Version uses latest keyword with regex: ${regex}";
140-
elif [[ "${version_requested}" =~ ^latest$ ]]; then
141-
version="${version_requested}";
142-
regex="^[0-9]\+\.[0-9]\+\.[0-9]\+$";
143-
log 'debug' "Version uses latest keyword alone. Forcing regex to match stable versions only: ${regex}";
144-
else
145-
version="${version_requested}";
146-
regex="^${version_requested}$";
147-
log 'debug' "Version is explicit: ${version}. Regex enforces the version: ${regex}";
148-
fi;
149-
};
150-
15166
# Curl wrapper to switch TLS option for each OS
15267
function curlw () {
15368
local TLS_OPT="--tlsv1.2";
@@ -167,27 +82,27 @@ function curlw () {
16782
};
16883
export -f curlw;
16984

170-
check_active_version() {
85+
function check_active_version() {
17186
local v="${1}";
17287
[ -n "$(${TFENV_ROOT}/bin/terraform version | grep -E "^Terraform v${v}((-dev)|( \([a-f0-9]+\)))?$")" ];
17388
};
17489
export -f check_active_version;
17590

176-
check_installed_version() {
91+
function check_installed_version() {
17792
local v="${1}";
17893
local bin="${TFENV_CONFIG_DIR}/versions/${v}/terraform";
17994
[ -n "$(${bin} version | grep -E "^Terraform v${v}((-dev)|( \([a-f0-9]+\)))?$")" ];
18095
};
18196
export -f check_installed_version;
18297

183-
check_default_version() {
98+
function check_default_version() {
18499
local v="${1}";
185100
local def="$(cat "${TFENV_CONFIG_DIR}/version")";
186101
[ "${def}" == "${v}" ];
187102
};
188103
export -f check_default_version;
189104

190-
cleanup() {
105+
function cleanup() {
191106
log 'info' 'Performing cleanup';
192107
local pwd="$(pwd)";
193108
log 'debug' "Deleting ${pwd}/versions";
@@ -196,8 +111,6 @@ cleanup() {
196111
rm -rf ./.terraform-version;
197112
log 'debug' "Deleting ${pwd}/min_required.tf";
198113
rm -rf ./min_required.tf;
199-
log 'debug' "Deleting ${pwd}/required_version.tf";
200-
rm -rf ./required_version.tf;
201114
};
202115
export -f cleanup;
203116

@@ -220,6 +133,7 @@ function check_dependencies() {
220133
export -f check_dependencies;
221134

222135
source "$TFENV_ROOT/lib/tfenv-exec.sh";
136+
source "$TFENV_ROOT/lib/tfenv-min-required.sh";
223137
source "$TFENV_ROOT/lib/tfenv-version-file.sh";
224138
source "$TFENV_ROOT/lib/tfenv-version-name.sh";
225139

lib/tfenv-exec.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
#!/usr/bin/env bash
2+
3+
set -uo pipefail;
4+
15
function tfenv-exec() {
26
log 'debug' 'Getting version from tfenv-version-name';
37
TFENV_VERSION="$(tfenv-version-name)" \

lib/tfenv-min-required.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
3+
set -uo pipefail;
4+
5+
function tfenv-min-required() {
6+
local path="${1:-.}";
7+
8+
local versions="$( echo $(cat ${path}/{*.tf,*.tf.json} 2>/dev/null | grep -Eh '^\s*[^#]*\s*required_version') | grep -o '[~=!<>]\{0,2\}\s*\([0-9]\+\.\?\)\{2,3\}\(-[a-z]\+[0-9]\+\)\?')";
9+
10+
if [[ "${versions}" =~ ([~=!<>]{0,2}[[:blank:]]*)([0-9]+[0-9.]+)[^0-9]*(-[a-z]+[0-9]+)? ]]; then
11+
qualifier="${BASH_REMATCH[1]}";
12+
found_min_required="${BASH_REMATCH[2]}${BASH_REMATCH[3]}";
13+
if [[ "${qualifier}" =~ ^!= ]]; then
14+
log 'debug' "required_version is a negation - we cannot guess the desired one, skipping.";
15+
else
16+
local min_required_file="$(grep -Hn required_version ${path}/{*.tf,*.tf.json} 2>/dev/null | xargs)";
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+
25+
log 'debug' "Determined min-required to be '${found_min_required}' (${min_required_file})";
26+
echo -en "${found_min_required}";
27+
return;
28+
fi;
29+
fi;
30+
31+
log 'debug' 'Appropriate required_version not found, skipping min-required';
32+
};
33+
export -f tfenv-min-required;

lib/tfenv-version-file.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1-
find_local_version_file() {
1+
#!/usr/bin/env bash
2+
3+
set -uo pipefail;
4+
5+
function find_local_version_file() {
26
log 'debug' "Looking for a version file in ${1}";
7+
38
local root="${1}";
9+
410
while ! [[ "${root}" =~ ^//[^/]*$ ]]; do
11+
512
if [ -e "${root}/.terraform-version" ]; then
613
log 'debug' "Found at ${root}/.terraform-version";
714
echo "${root}/.terraform-version";
815
return 0;
916
else
1017
log 'debug' "Not found at ${root}/.terraform-version";
1118
fi;
19+
1220
[ -n "${root}" ] || break;
1321
root="${root%/*}";
22+
1423
done;
24+
1525
log 'debug' "No version file found in ${1}";
1626
return 1;
1727
};

lib/tfenv-version-name.sh

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,45 @@
1+
#!/usr/bin/env bash
2+
3+
set -uo pipefail;
4+
15
function tfenv-version-name() {
26
if [[ -z "${TFENV_TERRAFORM_VERSION:-""}" ]]; then
7+
log 'debug' 'We are not hardcoded by a TFENV_TERRAFORM_VERSION environment variable';
8+
39
TFENV_VERSION_FILE="$(tfenv-version-file)" \
410
&& log 'debug' "TFENV_VERSION_FILE retrieved from tfenv-version-file: ${TFENV_VERSION_FILE}" \
511
|| log 'error' 'Failed to retrieve TFENV_VERSION_FILE from tfenv-version-file';
612

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

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}";
16+
TFENV_VERSION_SOURCE="${TFENV_VERSION_FILE}";
3417

35-
TFENV_VERSION_SOURCE="${TFENV_VERSION_FILE}";
36-
fi;
3718
else
3819
TFENV_VERSION="${TFENV_TERRAFORM_VERSION}" \
39-
&& log 'debug' "TFENV_VERSION specified in TFENV_TERRAFORM_VERSION: ${TFENV_VERSION}";
20+
&& log 'debug' "TFENV_VERSION specified in TFENV_TERRAFORM_VERSION environment variable: ${TFENV_VERSION}";
4021

4122
TFENV_VERSION_SOURCE='TFENV_TERRAFORM_VERSION';
4223
fi;
4324

25+
local auto_install="${TFENV_AUTO_INSTALL:-true}";
26+
27+
if [[ "${TFENV_VERSION}" == "min-required" ]]; then
28+
log 'debug' 'TFENV_VERSION uses min-required keyword, looking for a required_version in the code';
29+
30+
local potential_min_required="$(tfenv-min-required)";
31+
if [[ -n "${potential_min_required}" ]]; then
32+
log 'debug' "'min-required' converted to '${potential_min_required}'";
33+
TFENV_VERSION="${potential_min_required}" \
34+
TFENV_VERSION_SOURCE='terraform{required_version}';
35+
else
36+
log 'error' 'Specifically asked for min-required via terraform{required_version}, but none found';
37+
fi;
38+
fi;
39+
4440
if [[ "${TFENV_VERSION}" =~ ^latest.*$ ]]; then
4541
log 'debug' "TFENV_VERSION uses 'latest' keyword: ${TFENV_VERSION}";
4642

47-
[ -d "${TFENV_CONFIG_DIR}/versions" ] \
48-
|| log 'error' 'No versions of terraform installed. Please install one with: tfenv install';
49-
5043
if [[ "${TFENV_VERSION}" =~ ^latest\:.*$ ]]; then
5144
regex="${TFENV_VERSION##*\:}";
5245
log 'debug' "'latest' keyword uses regex: ${regex}";
@@ -62,10 +55,14 @@ function tfenv-version-name() {
6255
| sort -t'.' -k 1nr,1 -k 2nr,2 -k 3nr,3 \
6356
| grep -e "${regex}" \
6457
| head -n 1)";
58+
59+
log 'debug' "Resolved ${TFENV_VERSION} to locally installed version: ${local_version}";
60+
elif [[ "${auto_install}" != "true" ]]; then
61+
log 'error' 'No versions of terraform installed and TFENV_AUTO_INSTALL is not true. Please install a version of terraform before it can be selected as latest';
6562
fi;
6663

67-
if [[ "${TFENV_AUTO_INSTALL:-true}" == "true" ]]; then
68-
log 'debug' "Trying to find the remote version using the regex: ${regex}";
64+
if [[ "${auto_install}" == "true" ]]; then
65+
log 'debug' "Using latest keyword and auto_install means the current version is whatever is latest in the remote. Trying to find the remote version using the regex: ${regex}";
6966
remote_version="$(tfenv-list-remote | grep -e "${regex}" | head -n 1)";
7067
if [[ -n "${remote_version}" ]]; then
7168
if [[ "${local_version}" != "${remote_version}" ]]; then

libexec/tfenv-init

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bash
22

3-
[ -n "${TFENV_DEBUG}" ] && set -x:
3+
[ -n "${TFENV_DEBUG}" ] && set -x;
44

55
export PATH="${TFENV_ROOT}/bin:${PATH}";

libexec/tfenv-min-required

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -71,34 +71,7 @@ terraform {
7171
see https://www.terraform.io/docs/configuration/terraform.html for details';
7272
};
7373

74-
find_min_required() {
75-
local root="${1}";
76-
77-
versions="$( echo $(grep -h required_version "${root}"/{*.tf,*.tf.json} 2>/dev/null ) | grep -o '\([0-9]\+\.\?\)\{2,3\}\(-[a-z]\+[0-9]\+\)\?')";
78-
79-
if [[ "${versions}" =~ ([~=!<>]{0,2}[[:blank:]]*[0-9]+[0-9.]+)[^0-9]*(-[a-z]+[0-9]+)? ]]; then
80-
found_min_required="${BASH_REMATCH[1]}${BASH_REMATCH[2]}";
81-
82-
if [[ "${found_min_required}" =~ ^!=.+ ]]; then
83-
log 'debug' "Error: Min required version is a negation ($found_min_required) - we cannot guess the desired one.";
84-
bailout;
85-
else
86-
found_min_required="$(echo "$found_min_required")";
87-
#echo "Min required version is detected as ${found_min_required}";
88-
89-
# Probably not an advisable way to choose a terraform version,
90-
# but this is the way this functionality works in terraform:
91-
# add .0 to versions without a minor and/or patch version (e.g. 12.0)
92-
while ! [[ "${found_min_required}" =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; do
93-
found_min_required="${found_min_required}.0";
94-
done;
95-
96-
echo "${found_min_required}";
97-
exit 0;
98-
fi;
99-
fi;
100-
101-
bailout;
102-
};
103-
104-
find_min_required "${TFENV_DIR:-$(pwd)}";
74+
declare min_required="$(tfenv-min-required "${TFENV_DIR:-$(pwd)}")";
75+
[[ -n "${min_required}" ]] \
76+
&& echo "${min_required}" \
77+
|| bailout;

0 commit comments

Comments
 (0)