Skip to content

Commit 2e1f8e2

Browse files
authoredMar 7, 2025··
Merge pull request #480 from claranet/fix/github_releases_search
fix: GitHub releases page no longer support `after` parameter, use tags page
2 parents 899427b + 6600018 commit 2e1f8e2

File tree

3 files changed

+59
-45
lines changed

3 files changed

+59
-45
lines changed
 

‎src/claranet_tfwrapper/__init__.py

+32-20
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def get_architecture():
6565
RC_KO = 1
6666
RC_UNK = 2
6767

68-
GITHUB_RELEASES = "https://github.com/{}/releases"
68+
LIMIT_GITHUB_RELEASES = 42
69+
GITHUB_RELEASES = "https://github.com/{}/tags"
6970

7071
TERRAFORM_RELEASES_URL = "https://releases.hashicorp.com/terraform/index.json"
7172
TERRAFORM_MINOR_VERSION_REGEX = r"[0-9]+\.[0-9]+"
@@ -569,21 +570,32 @@ def bootstrap(wrapper_config):
569570
# FIXME: use https://pygithub.readthedocs.io/en/stable/github_objects/Repository.html#github.Repository.Repository.get_releases
570571
def search_on_github(repo, minor_version, patch_regex, patch):
571572
"""Search release on github."""
572-
# FIXME: the github UI seems to use a cache that does not return recent versions
573-
result = CachedRequestsSession.get("{}?q={}".format(GITHUB_RELEASES.format(repo), minor_version))
574-
releases = re.findall(r"<a href=\"/{}/releases/tag/.*\">(.*)</a>".format(repo), result.text)
575-
576-
for release in releases:
577-
logger.debug(
578-
'Release found: "{}", checking with "^v{}.{}$"'.format(release, minor_version, patch if patch else patch_regex)
579-
)
580-
if re.match(
581-
r"^v{}\.{}$".format(minor_version, patch if patch else patch_regex),
582-
release,
583-
):
584-
patch = patch or release.split(".")[-1]
585-
return patch
573+
# Start search from the next incremented minor version
574+
# Note: the github UI serves the first page if the requested version does not exist
575+
release = "v{}{}.0".format(minor_version[:-1], int(minor_version[-1]) + 1)
576+
releases_count = 0
577+
while True:
578+
result = CachedRequestsSession.get("{}?after={}".format(GITHUB_RELEASES.format(repo), release))
579+
releases = re.findall(r"<a href=\"/{}/releases/tag/.*\">(.*)</a>".format(repo), result.text)
580+
releases_count += len(releases)
581+
for release in releases:
582+
logger.debug(
583+
'Release found: "{}", checking with "^v{}.{}$"'.format(release, minor_version, patch if patch else patch_regex)
584+
)
585+
if re.match(
586+
r"^v{}\.{}$".format(minor_version, patch if patch else patch_regex),
587+
release,
588+
):
589+
patch = patch or release.split(".")[-1]
590+
return patch
591+
# hard limit or it will take too long
592+
if releases_count > LIMIT_GITHUB_RELEASES:
593+
return None
594+
if len(releases) < 1:
595+
# no more version available
596+
break
586597

598+
release = releases[-1:][0]
587599
return None
588600

589601

@@ -1190,7 +1202,7 @@ def parse_args(args):
11901202
"--pipe-plan",
11911203
action="store_true",
11921204
default=False,
1193-
help=("Pipe plan output to the command set in config" " or passed in --pipe-plan-command argument (cat by default)."),
1205+
help=("Pipe plan output to the command set in config or passed in --pipe-plan-command argument (cat by default)."),
11941206
)
11951207
parser_apply.add_argument(
11961208
"--pipe-plan-command",
@@ -1249,7 +1261,7 @@ def parse_args(args):
12491261
"--pipe-plan",
12501262
action="store_true",
12511263
default=False,
1252-
help=("Pipe plan output to the command set in config" " or passed in --pipe-plan-command argument (cat by default)."),
1264+
help=("Pipe plan output to the command set in config or passed in --pipe-plan-command argument (cat by default)."),
12531265
)
12541266
parser_plan.add_argument(
12551267
"--pipe-plan-command",
@@ -1364,6 +1376,9 @@ def main(argv=None):
13641376
)
13651377
stack_config = load_stack_config_from_file(stack_config_file)
13661378

1379+
# parse all args
1380+
args = parse_args(argv or sys.argv[1:])
1381+
13671382
# select tool version for the stack if selected, with a fallback on v1.0
13681383
tool_version = (tf_config := stack_config.get(TOOL_TERRAFORM, {})).get(
13691384
"version", tf_config.get("vars", {}).get("version", "1.0")
@@ -1382,9 +1397,6 @@ def main(argv=None):
13821397
else:
13831398
select_terraform_version(tool_version)
13841399

1385-
# parse all args
1386-
args = parse_args(argv or sys.argv[1:])
1387-
13881400
# convert args to dict
13891401
wrapper_config.update(vars(args))
13901402

‎tests/test_cache_requests.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
@pytest.fixture
15-
def terraform_releases_html_q_0_12():
15+
def terraform_releases_html_after_v0_13_0():
1616
return """
1717
<!DOCTYPE html>
1818
<html lang="en">
@@ -43,7 +43,7 @@ def terraform_releases_html_q_0_12():
4343
# CacheControl at the same time as it also works at the Adapter level.
4444
# - pook intercepts requests at a lower level by replacing urllib3.urlopen() by its
4545
# own handler. This allows to actually verify what network requests would happen.
46-
# See See https://github.com/h2non/pook/blob/v1.0.2/pook/interceptors/urllib3.py#L24-L27
46+
# See https://github.com/h2non/pook/blob/v1.0.2/pook/interceptors/urllib3.py#L24-L27
4747

4848

4949
class AutoclosingBytesIO(io.BytesIO):
@@ -74,19 +74,19 @@ def read(self, size=-1):
7474

7575
def test_search_on_github_cache_terraform_releases_200(
7676
tmp_working_dir,
77-
terraform_releases_html_q_0_12,
77+
terraform_releases_html_after_v0_13_0,
7878
):
7979
with mock.patch("io.BytesIO", AutoclosingBytesIO):
8080
with pook.use():
8181
repo = "hashicorp/terraform"
82-
releases_url = "https://github.com/{}/releases?q=0.12".format(repo)
82+
releases_url = "https://github.com/{}/tags?after=v0.13.0".format(repo)
8383

8484
# A volatile mock that can only be invoked once
8585
pook.get(
8686
releases_url,
8787
reply=200,
8888
response_type="text/plain",
89-
response_body=terraform_releases_html_q_0_12,
89+
response_body=terraform_releases_html_after_v0_13_0,
9090
response_headers={
9191
"Status": "200 OK",
9292
"ETag": 'W/"df0474ebd25f223a95926ba58e11e77b"',
@@ -110,11 +110,13 @@ def test_search_on_github_cache_terraform_releases_200(
110110
assert not pook.isactive()
111111

112112

113-
def test_search_on_github_cache_terraform_releases_does_not_cache_error_429(tmp_working_dir, terraform_releases_html_q_0_12):
113+
def test_search_on_github_cache_terraform_releases_does_not_cache_error_429(
114+
tmp_working_dir, terraform_releases_html_after_v0_13_0
115+
):
114116
with mock.patch("io.BytesIO", AutoclosingBytesIO):
115117
with pook.use():
116118
repo = "hashicorp/terraform"
117-
releases_url = "https://github.com/{}/releases?q=0.12".format(repo)
119+
releases_url = "https://github.com/{}/tags?after=v0.13.0".format(repo)
118120

119121
# volatile mocks that can only be invoked once each
120122
pook.get(
@@ -127,7 +129,7 @@ def test_search_on_github_cache_terraform_releases_does_not_cache_error_429(tmp_
127129
releases_url,
128130
reply=200,
129131
response_type="text/plain",
130-
response_body=terraform_releases_html_q_0_12,
132+
response_body=terraform_releases_html_after_v0_13_0,
131133
response_headers={
132134
"Status": "200 OK",
133135
"ETag": 'W/"df0474ebd25f223a95926ba58e11e77b"',
@@ -157,12 +159,12 @@ def test_search_on_github_cache_terraform_releases_does_not_cache_error_429(tmp_
157159

158160
def test_search_on_github_cache_terraform_releases_does_not_cache_error_403(
159161
tmp_working_dir,
160-
terraform_releases_html_q_0_12,
162+
terraform_releases_html_after_v0_13_0,
161163
):
162164
with mock.patch("io.BytesIO", AutoclosingBytesIO):
163165
with pook.use():
164166
repo = "hashicorp/terraform"
165-
releases_url = "https://github.com/{}/releases?q=0.12".format(repo)
167+
releases_url = "https://github.com/{}/tags?after=v0.13.0".format(repo)
166168

167169
# volatile mocks that can only be invoked once each
168170
pook.get(
@@ -175,7 +177,7 @@ def test_search_on_github_cache_terraform_releases_does_not_cache_error_403(
175177
releases_url,
176178
reply=200,
177179
response_type="text/plain",
178-
response_body=terraform_releases_html_q_0_12,
180+
response_body=terraform_releases_html_after_v0_13_0,
179181
response_headers={
180182
"Status": "200 OK",
181183
"ETag": 'W/"df0474ebd25f223a95926ba58e11e77b"',
@@ -205,12 +207,12 @@ def test_search_on_github_cache_terraform_releases_does_not_cache_error_403(
205207

206208
def test_search_on_github_cache_terraform_releases_does_not_cache_error_404(
207209
tmp_working_dir,
208-
terraform_releases_html_q_0_12,
210+
terraform_releases_html_after_v0_13_0,
209211
):
210212
with mock.patch("io.BytesIO", AutoclosingBytesIO):
211213
with pook.use():
212214
repo = "hashicorp/terraform"
213-
releases_url = "https://github.com/{}/releases?q=0.12".format(repo)
215+
releases_url = "https://github.com/{}/tags?after=v0.13.0".format(repo)
214216

215217
# volatile mocks that can only be invoked once each
216218
pook.get(
@@ -223,7 +225,7 @@ def test_search_on_github_cache_terraform_releases_does_not_cache_error_404(
223225
releases_url,
224226
reply=200,
225227
response_type="text/plain",
226-
response_body=terraform_releases_html_q_0_12,
228+
response_body=terraform_releases_html_after_v0_13_0,
227229
response_headers={
228230
"Status": "200 OK",
229231
"ETag": 'W/"df0474ebd25f223a95926ba58e11e77b"',

‎tests/test_search_on_github.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
@pytest.fixture
10-
def provider_releases_html_q_2_5():
10+
def provider_releases_html_after_v2_6_0():
1111
return """
1212
<!DOCTYPE html>
1313
<html lang="en">
@@ -34,7 +34,7 @@ def provider_releases_html_q_2_5():
3434

3535

3636
@pytest.fixture
37-
def provider_releases_html_q_1_2():
37+
def provider_releases_html_after_v1_3_0():
3838
return """
3939
<!DOCTYPE html>
4040
<html lang="en">
@@ -62,28 +62,28 @@ def provider_releases_html_q_1_2():
6262

6363
def test_search_on_github_provider_releases(
6464
requests_mock,
65-
provider_releases_html_q_2_5,
66-
provider_releases_html_q_1_2,
65+
provider_releases_html_after_v2_6_0,
66+
provider_releases_html_after_v1_3_0,
6767
):
6868
from claranet_tfwrapper import GITHUB_RELEASES
6969

7070
repo = "claranet/terraform-provider-gitlab"
7171
releases_url = GITHUB_RELEASES.format(repo)
72-
releases_url_q_2_5 = releases_url + "?q=2.5"
73-
releases_url_q_1_2 = releases_url + "?q=1.2"
72+
releases_url_after_v2_6_0 = releases_url + "?after=v2.6.0"
73+
releases_url_after_v1_3_0 = releases_url + "?after=v1.3.0"
7474

7575
requests_mock.get(
76-
releases_url_q_2_5,
76+
releases_url_after_v2_6_0,
7777
complete_qs=True,
78-
text=provider_releases_html_q_2_5,
78+
text=provider_releases_html_after_v2_6_0,
7979
)
8080
requests_mock.get(
81-
releases_url_q_1_2,
81+
releases_url_after_v1_3_0,
8282
complete_qs=True,
83-
text=provider_releases_html_q_1_2,
83+
text=provider_releases_html_after_v1_3_0,
8484
)
8585

86-
assert provider_releases_html_q_2_5 == requests.get(releases_url_q_2_5).text
86+
assert provider_releases_html_after_v2_6_0 == requests.get(releases_url_after_v2_6_0).text
8787

8888
patch_regex = r"[0-9]+(((-alpha|-beta|-rc)[0-9]+)|(?P<dev>-dev))?"
8989
patch = tfwrapper.search_on_github(repo, "2.5", patch_regex, "")

0 commit comments

Comments
 (0)
Please sign in to comment.