Skip to content

Commit b9e8e1f

Browse files
authored
Fix Garden Linux Bumper (#2103)
Garden Linux changed how it names its GCP images, so we cannot get that from the assets of a release directly. Instead, we need to parse the markdown text on the release itself and get it from there.
1 parent 0ad3ee5 commit b9e8e1f

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

utilities/gardenlinux-bumper/bumper.py

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,52 @@
33
import argparse
44
import os
55
import re
6+
from typing import NamedTuple
7+
8+
from bs4 import BeautifulSoup
9+
10+
# gfm stands for Github Flavoured Markdown
11+
from marko.ext.gfm import gfm
12+
613
import requests
714

815

9-
def get_latest_release() -> (int, int, str):
10-
gcp_vm_re = re.compile(r'^gcp-gardener_prod-amd64-([0-9]+)\.([0-9]+)-([0-9a-f]+)\.tar\.xz$')
11-
url = "https://api.github.com/repos/gardenlinux/gardenlinux/releases/latest"
16+
class GardenVersion(NamedTuple):
17+
"""
18+
Type alias for the garden version
19+
"""
20+
checksum: str
21+
major: int
22+
minor: int
23+
commit: str
24+
25+
26+
def get_latest_release() -> GardenVersion:
27+
"""
28+
Find the Garden Linux version in a GH release.
29+
30+
This method queries the GH API for the latest release of gardenlinux
31+
and attempts to extract the version for the gcp image from it.
32+
33+
The block that holds the image name looks something like this in
34+
markdown:
35+
### Google Cloud Platform (amd64)
36+
```
37+
gcp_image_name: gardenlinux-gcp-8bd7b82716e90c634df25013-1592-9-2eaf0fc6
38+
```
39+
40+
marko parses the markdown string and translates it to equivalent
41+
html that looks something like this:
42+
<h3>Google Cloud Platform (amd64)</h3>
43+
<pre><code>gcp_image_name: gardenlinux-gcp-8bd7b82716e90c634df25013-1592-9-2eaf0fc6</code></pre>
44+
45+
We can then use BeautifulSoup to parse the html and look for the
46+
data we want. A bit convoluted, but it does not look like we can do
47+
the same with marko directly.
48+
"""
49+
gcp_vm_re = re.compile(
50+
r'^gcp_image_name: gardenlinux-gcp-([0-9a-f]+)-([0-9]+)-([0-9]+)-([0-9a-f]+)$')
51+
url = 'https://api.github.com/repos/gardenlinux/gardenlinux/releases/latest'
1252
headers = {
1353
'Accept': 'application/vnd.github+json',
1454
'Authorization': f'Bearer {os.environ["GITHUB_TOKEN"]}',
@@ -18,43 +58,51 @@ def get_latest_release() -> (int, int, str):
1858
response.raise_for_status()
1959
latest_release = response.json()
2060

21-
for a in latest_release['assets']:
22-
match = gcp_vm_re.match(a['name'])
23-
if match:
24-
major = int(match[1])
25-
minor = int(match[2])
26-
checksum = match[3]
61+
body = gfm.convert(latest_release['body'])
62+
body = BeautifulSoup(body, features='html.parser')
63+
h = body.find(name='h3', string='Google Cloud Platform (amd64)')
64+
if h is None:
65+
raise RuntimeError('Failed to find the GCP VM image: Missed <h3>')
66+
67+
pre = h.find_next_sibling('pre')
68+
if pre is None:
69+
raise RuntimeError('Failed to find the GCP VM image: Missed <pre>')
70+
71+
match = gcp_vm_re.match(pre.code.string.strip())
72+
if match is None:
73+
raise RuntimeError(
74+
'Failed to find the GCP VM image: Version did not match')
2775

28-
return (major, minor, checksum)
29-
raise RuntimeError("Failed to find the GCP VM asset")
76+
checksum, major, minor, commit = match.groups()
77+
return GardenVersion(checksum, int(major), int(minor), commit)
3078

3179

32-
def get_current_version(image_file: str) -> (int, int, str):
33-
gcp_vm_re = re.compile(r'^gardenlinux-gcp-gardener-prod-amd64-([0-9]+)-([0-9]+)-([0-9a-f]+)$')
80+
def get_current_version(image_file: str) -> GardenVersion:
81+
gcp_vm_re = re.compile(
82+
r'^gardenlinux-gcp-([-0-9a-z]+)-([0-9]+)-([0-9]+)-([0-9a-f]+)$')
3483

3584
with open(image_file, 'r') as f:
3685
image = f.readline()
3786
match = gcp_vm_re.match(image)
3887
if match is None:
3988
raise RuntimeError('Configured image did not match')
4089

41-
major = int(match[1])
42-
minor = int(match[2])
43-
checksum = match[3]
90+
checksum = match[1]
91+
major = int(match[2])
92+
minor = int(match[3])
93+
commit = match[4]
4494

45-
return (major, minor, checksum)
95+
return GardenVersion(checksum, major, minor, commit)
4696

4797

48-
def get_gardenlinux_image(version_data: (int, int, str)) -> str:
49-
major = version_data[0]
50-
minor = version_data[1]
51-
checksum = version_data[2]
98+
def get_gardenlinux_image(version_data: GardenVersion) -> str:
99+
checksum, major, minor, commit = version_data
52100

53-
return f'gardenlinux-gcp-gardener-prod-amd64-{major}-{minor}-{checksum}'
101+
return f'gardenlinux-gcp-{checksum}-{major}-{minor}-{commit}'
54102

55103

56-
def image_is_outdated(latest: (int, int, str), current: (int, int, str)) -> bool:
57-
return latest[:2] > current[:2]
104+
def image_is_outdated(latest: GardenVersion, current: GardenVersion) -> bool:
105+
return latest[1:3] > current[1:3]
58106

59107

60108
def main(image_file: str):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
requests==2.31.0
2+
marko==2.1.3
3+
beautifulsoup4==4.13.4

0 commit comments

Comments
 (0)