Skip to content

Commit 9151b3e

Browse files
authored
Merge pull request tfutils#309 from OJFord/impl-307
Add `latest-allowed` option from required_version
2 parents 34c744b + 699f998 commit 9151b3e

File tree

6 files changed

+186
-5
lines changed

6 files changed

+186
-5
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,17 @@ If a parameter is passed, available options:
8888
- `x.y.z` [Semver 2.0.0](https://semver.org/) string specifying the exact version to install
8989
- `latest` is a syntax to install latest version
9090
- `latest:<regex>` is a syntax to install latest version matching regex (used by grep -e)
91-
- `min-required` is a syntax to recursively 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](#min-required) section below.
91+
- `latest-allowed` is a syntax to scan your Terraform files to detect which version is maximally allowed.
92+
- `min-required` is a syntax to scan your Terraform files to detect which version is minimally required.
93+
94+
See [required_version](https://www.terraform.io/docs/configuration/terraform.html) docs. Also [see min-required & latest-allowed](#min-required) section below.
9295

9396
```console
9497
$ tfenv install
9598
$ tfenv install 0.7.0
9699
$ tfenv install latest
97100
$ tfenv install latest:^0.8
101+
$ tfenv install latest-allowed
98102
$ tfenv install min-required
99103
```
100104

@@ -121,7 +125,8 @@ validation failure.
121125

122126
If you use a [.terraform-version](#terraform-version-file) file, `tfenv install` (no argument) will install the version written in it.
123127

124-
#### min-required
128+
<a name="min-required"></a>
129+
#### min-required & latest-allowed
125130

126131
Please note that we don't do semantic version range parsing but use first ever found version as the candidate for minimally required one. It is up to the user to keep the definition reasonable. I.e.
127132

@@ -133,9 +138,9 @@ terraform {
133138
```
134139

135140
```terraform
136-
// this will detect 0.10.0
141+
// this will detect 0.10.8 (the latest 0.10.x release)
137142
terraform {
138-
required_version = ">= 0.10.0, <0.12.3"
143+
required_version = "~> 0.10.0, <0.12.3"
139144
}
140145
```
141146

lib/helpers.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ function check_active_version() {
9191

9292
local active_version="$(${TFENV_ROOT}/bin/terraform ${maybe_chdir} version | grep '^Terraform')";
9393

94-
if ! grep -E "^Terraform v${v}((-dev)|( \([a-f0-9]+\)))?\$" <(echo "${active_version}"); then
94+
if ! grep -E "^Terraform v${v}((-dev)|( \([a-f0-9]+\)))?( is already installed)?\$" <(echo "${active_version}"); then
9595
log 'debug' "Expected version ${v} but found ${active_version}";
9696
return 1;
9797
fi;
@@ -124,6 +124,8 @@ function cleanup() {
124124
rm -rf ./versions;
125125
log 'debug' "Deleting ${pwd}/.terraform-version";
126126
rm -rf ./.terraform-version;
127+
log 'debug' "Deleting ${pwd}/latest_allowed.tf";
128+
rm -rf ./latest_allowed.tf;
127129
log 'debug' "Deleting ${pwd}/min_required.tf";
128130
rm -rf ./min_required.tf;
129131
log 'debug' "Deleting ${pwd}/chdir-dir";

lib/tfenv-version-name.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ function tfenv-version-name() {
4040
if [[ "${TFENV_VERSION}" =~ ^latest.*$ ]]; then
4141
log 'debug' "TFENV_VERSION uses 'latest' keyword: ${TFENV_VERSION}";
4242

43+
if [[ "${TFENV_VERSION}" == latest-allowed ]]; then
44+
TFENV_VERSION="$(tfenv-resolve-version)";
45+
log 'debug' "Resolved latest-allowed to: ${TFENV_VERSION}";
46+
fi;
47+
4348
if [[ "${TFENV_VERSION}" =~ ^latest\:.*$ ]]; then
4449
regex="${TFENV_VERSION##*\:}";
4550
log 'debug' "'latest' keyword uses regex: ${regex}";

libexec/tfenv-resolve-version

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,30 @@ if [[ "${version_requested}" =~ ^min-required$ ]]; then
127127
version_requested="${min_required}";
128128
fi;
129129

130+
if [[ "${version_requested}" =~ ^latest-allowed$ ]]; then
131+
log 'debug' 'Detecting latest allowable version...';
132+
version_spec="$(grep -h required_version "${TFENV_DIR:-$(pwd)}"/{*.tf,*.tf.json} 2>/dev/null | rev | cut -d'"' -f2 | rev | cut -d, -f1)";
133+
version_num="$(echo "${version_spec}" | sed -E 's/[^0-9.]+//')";
134+
log 'debug' "Using ${version_num} from version spec: ${version_spec}";
135+
136+
case "${version_spec}" in
137+
'>'*)
138+
version_requested=latest;
139+
;;
140+
'<='*)
141+
version_requested="${version_num}";
142+
;;
143+
'~>'*)
144+
version_without_rightmost="$(echo "${version_num}" | rev | cut -d. -f2- | rev)";
145+
version_requested="latest:^${version_without_rightmost}";
146+
;;
147+
*)
148+
log 'error' "Unsupported version spec: '${version_spec}', only >, >=, <=, and ~> are supported.";
149+
;;
150+
esac;
151+
log 'debug' "Determined the requested version to be: ${version_requested}";
152+
fi;
153+
130154
if [[ "${version_requested}" =~ ^latest\:.*$ ]]; then
131155
version="${version_requested%%\:*}";
132156
regex="${version_requested##*\:}";

libexec/tfenv-uninstall

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ if [[ "${version_requested}" =~ ^min-required$ ]]; then
9393
log 'error' 'min-required is an unsupported option for uninstall';
9494
fi;
9595

96+
if [[ "${version_requested}" == latest-allowed ]]; then
97+
log 'error' 'latest-allowed is an unsupported option for uninstall';
98+
fi;
99+
96100
if [[ "${version_requested}" =~ ^latest\:.*$ ]]; then
97101
version="${version_requested%%\:*}";
98102
regex="${version_requested##*\:}";

test/test_use_latestallowed.sh

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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 latest-allowed normal version (#.#.#)';
57+
58+
echo "terraform {
59+
required_version = \"~> 1.1.0\"
60+
}" > latest_allowed.tf;
61+
62+
(
63+
tfenv install latest-allowed;
64+
tfenv use latest-allowed;
65+
check_active_version 1.1.9;
66+
) || error_and_proceed 'Latest allowed version does not match';
67+
68+
cleanup || log 'error' 'Cleanup failed?!';
69+
70+
71+
log 'info' '### Install latest-allowed tagged version (#.#.#-tag#)'
72+
73+
echo "terraform {
74+
required_version = \"<=0.13.0-rc1\"
75+
}" > latest_allowed.tf;
76+
77+
(
78+
tfenv install latest-allowed;
79+
tfenv use latest-allowed;
80+
check_active_version 0.13.0-rc1;
81+
) || error_and_proceed 'Latest allowed tagged-version does not match';
82+
83+
cleanup || log 'error' 'Cleanup failed?!';
84+
85+
86+
log 'info' '### Install latest-allowed incomplete version (#.#.<missing>)'
87+
88+
echo "terraform {
89+
required_version = \"~> 0.12\"
90+
}" >> latest_allowed.tf;
91+
92+
(
93+
tfenv install latest-allowed;
94+
tfenv use latest-allowed;
95+
check_active_version 0.15.5;
96+
) || error_and_proceed 'Latest allowed incomplete-version does not match';
97+
98+
cleanup || log 'error' 'Cleanup failed?!';
99+
100+
101+
log 'info' '### Install latest-allowed with TFENV_AUTO_INSTALL';
102+
103+
echo "terraform {
104+
required_version = \"~> 1.0.0\"
105+
}" >> latest_allowed.tf;
106+
echo 'latest-allowed' > .terraform-version;
107+
108+
(
109+
TFENV_AUTO_INSTALL=true terraform version;
110+
check_active_version 1.0.11;
111+
) || error_and_proceed 'Latest allowed auto-installed version does not match';
112+
113+
cleanup || log 'error' 'Cleanup failed?!';
114+
115+
116+
log 'info' '### Install latest-allowed with TFENV_AUTO_INSTALL & -chdir';
117+
118+
mkdir -p chdir-dir
119+
echo "terraform {
120+
required_version = \"~> 0.14.3\"
121+
}" >> chdir-dir/latest_allowed.tf;
122+
echo 'latest-allowed' > chdir-dir/.terraform-version
123+
124+
(
125+
TFENV_AUTO_INSTALL=true terraform -chdir=chdir-dir version;
126+
check_active_version 0.14.11 chdir-dir;
127+
) || error_and_proceed 'Latest allowed version from -chdir does not match';
128+
129+
cleanup || log 'error' 'Cleanup failed?!';
130+
131+
if [ "${#errors[@]}" -gt 0 ]; then
132+
log 'warn' '===== The following use_latestallowed tests failed =====';
133+
for error in "${errors[@]}"; do
134+
log 'warn' "\t${error}";
135+
done;
136+
log 'error' 'use_latestallowed test failure(s)';
137+
else
138+
log 'info' 'All use_latestallowed tests passed.';
139+
fi;
140+
141+
exit 0;

0 commit comments

Comments
 (0)