Skip to content

Commit 46dfa11

Browse files
Github cli - Adds retry logic for find git tags (#310)
* Github cli - Adds retry logic for find git tags * re-add set -e * address comment
1 parent 64f0e10 commit 46dfa11

4 files changed

Lines changed: 148 additions & 4 deletions

File tree

src/github-cli/devcontainer-feature.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "github-cli",
3-
"version": "1.0.7",
3+
"version": "1.0.8",
44
"name": "GitHub CLI",
55
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/github-cli",
66
"description": "Installs the GitHub CLI. Auto-detects latest version and installs needed dependencies.",

src/github-cli/install.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,46 @@ find_version_from_git_tags() {
158158
echo "${variable_name}=${!variable_name}"
159159
}
160160

161+
# Use semver logic to decrement a version number then look for the closest match
162+
find_prev_version_from_git_tags() {
163+
local variable_name=$1
164+
local current_version=${!variable_name}
165+
local repository=$2
166+
# Normally a "v" is used before the version number, but support alternate cases
167+
local prefix=${3:-"tags/v"}
168+
# Some repositories use "_" instead of "." for version number part separation, support that
169+
local separator=${4:-"."}
170+
# Some tools release versions that omit the last digit (e.g. go)
171+
local last_part_optional=${5:-"false"}
172+
# Some repositories may have tags that include a suffix (e.g. actions/node-versions)
173+
local version_suffix_regex=$6
174+
# Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios.
175+
set +e
176+
major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')"
177+
minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')"
178+
breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')"
179+
180+
if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then
181+
((major=major-1))
182+
declare -g ${variable_name}="${major}"
183+
# Look for latest version from previous major release
184+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
185+
# Handle situations like Go's odd version pattern where "0" releases omit the last part
186+
elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
187+
((minor=minor-1))
188+
declare -g ${variable_name}="${major}.${minor}"
189+
# Look for latest version from previous minor release
190+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
191+
else
192+
((breakfix=breakfix-1))
193+
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
194+
declare -g ${variable_name}="${major}.${minor}"
195+
else
196+
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
197+
fi
198+
fi
199+
set -e
200+
}
161201

162202
# Fall back on direct download if no apt package exists
163203
# Fetches .deb file to be installed with dpkg
@@ -171,6 +211,15 @@ install_deb_using_github() {
171211
mkdir -p /tmp/ghcli
172212
pushd /tmp/ghcli
173213
wget https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename}
214+
exit_code=$?
215+
set -e
216+
if [ "$exit_code" != "0" ]; then
217+
# Handle situation where git tags are ahead of what was is available to actually download
218+
echo "(!) github-cli version ${CLI_VERSION} failed to download. Attempting to fall back one version to retry..."
219+
find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli
220+
wget https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename}
221+
fi
222+
174223
dpkg -i /tmp/ghcli/${cli_filename}
175224
popd
176225
rm -rf /tmp/ghcli

src/nix/utils.sh

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,19 +282,26 @@ find_prev_version_from_git_tags() {
282282
major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')"
283283
minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')"
284284
breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')"
285-
set -e
285+
286+
if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then
287+
((major=major-1))
288+
declare -g ${variable_name}="${major}"
289+
# Look for latest version from previous major release
290+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
286291
# Handle situations like Go's odd version pattern where "0" releases omit the last part
287-
if [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
292+
elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
288293
((minor=minor-1))
289294
declare -g ${variable_name}="${major}.${minor}"
290295
# Look for latest version from previous minor release
291296
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
292-
else
297+
else
293298
((breakfix=breakfix-1))
294299
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
295300
declare -g ${variable_name}="${major}.${minor}"
296301
else
297302
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
298303
fi
299304
fi
305+
306+
set -e
300307
}

test/github-cli/test.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,93 @@ source dev-container-features-test-lib
88
# Definition specific tests
99
check "version" gh --version
1010

11+
find_version_from_git_tags() {
12+
local variable_name=$1
13+
local requested_version=${!variable_name}
14+
if [ "${requested_version}" = "none" ]; then return; fi
15+
local repository=$2
16+
local prefix=${3:-"tags/v"}
17+
local separator=${4:-"."}
18+
local last_part_optional=${5:-"false"}
19+
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
20+
local escaped_separator=${separator//./\\.}
21+
local last_part
22+
if [ "${last_part_optional}" = "true" ]; then
23+
last_part="(${escaped_separator}[0-9]+)?"
24+
else
25+
last_part="${escaped_separator}[0-9]+"
26+
fi
27+
local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
28+
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
29+
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
30+
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
31+
else
32+
set +e
33+
declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
34+
set -e
35+
fi
36+
fi
37+
if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then
38+
echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
39+
exit 1
40+
fi
41+
echo "${variable_name}=${!variable_name}"
42+
}
43+
44+
find_prev_version_from_git_tags() {
45+
local variable_name=$1
46+
local current_version=${!variable_name}
47+
local repository=$2
48+
# Normally a "v" is used before the version number, but support alternate cases
49+
local prefix=${3:-"tags/v"}
50+
# Some repositories use "_" instead of "." for version number part separation, support that
51+
local separator=${4:-"."}
52+
# Some tools release versions that omit the last digit (e.g. go)
53+
local last_part_optional=${5:-"false"}
54+
# Some repositories may have tags that include a suffix (e.g. actions/node-versions)
55+
local version_suffix_regex=$6
56+
# Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios.
57+
set +e
58+
major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')"
59+
minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')"
60+
breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')"
61+
62+
if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then
63+
((major=major-1))
64+
declare -g ${variable_name}="${major}"
65+
# Look for latest version from previous major release
66+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
67+
# Handle situations like Go's odd version pattern where "0" releases omit the last part
68+
elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
69+
((minor=minor-1))
70+
declare -g ${variable_name}="${major}.${minor}"
71+
# Look for latest version from previous minor release
72+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
73+
else
74+
((breakfix=breakfix-1))
75+
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
76+
declare -g ${variable_name}="${major}.${minor}"
77+
else
78+
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
79+
fi
80+
fi
81+
}
82+
83+
CLI_VERSION="2.20.0"
84+
find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli
85+
check "pre-version-to-2.20.0" bash -c "echo ${CLI_VERSION} | grep '2.19.0'"
86+
87+
CLI_VERSION="2.18.1"
88+
find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli
89+
check "pre-version-to-2.18.1" bash -c "echo ${CLI_VERSION} | grep '2.18.0'"
90+
91+
CLI_VERSION="2.15.0"
92+
find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli
93+
check "pre-version-to-2.15.0" bash -c "echo ${CLI_VERSION} | grep '2.14.7'"
94+
95+
CLI_VERSION="2.0.0"
96+
find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli
97+
check "pre-version-to-2.0.0" bash -c "echo ${CLI_VERSION} | grep '1.14.0'"
98+
1199
# Report result
12100
reportResults

0 commit comments

Comments
 (0)