33import argparse
44import os
55import 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+
613import 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
60108def main (image_file : str ):
0 commit comments