Skip to content

Commit c0a9c28

Browse files
committed
main release_notes routines
1 parent 76dcb4e commit c0a9c28

File tree

5 files changed

+179
-4
lines changed

5 files changed

+179
-4
lines changed

src/gardenlinux/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,5 @@
147147
OCI_IMAGE_INDEX_MEDIA_TYPE = "application/vnd.oci.image.index.v1+json"
148148

149149
RELEASE_ID_FILE = ".github_release_id"
150+
151+
REQUESTS_TIMEOUTS = (5, 30) # connect, read

src/gardenlinux/github/release/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44

55
import requests
66

7-
from gardenlinux.constants import RELEASE_ID_FILE
7+
from gardenlinux.constants import RELEASE_ID_FILE, REQUESTS_TIMEOUTS
88
from gardenlinux.logger import LoggerSetup
99

10-
LOGGER = LoggerSetup.get_logger("gardenlinux.github", "INFO")
11-
12-
REQUESTS_TIMEOUTS = (5, 30) # connect, read
10+
LOGGER = LoggerSetup.get_logger("gardenlinux.github.release", "INFO")
1311

1412

1513
def create_github_release(owner, repo, tag, commitish, latest, body):
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from .helpers import get_package_list
2+
from .sections import (
3+
release_notes_changes_section,
4+
release_notes_compare_package_versions_section,
5+
release_notes_software_components_section,
6+
)
7+
8+
9+
def create_github_release_notes(gardenlinux_version, commitish):
10+
package_list = get_package_list(gardenlinux_version)
11+
12+
output = ""
13+
14+
output += release_notes_changes_section(gardenlinux_version)
15+
16+
output += release_notes_software_components_section(package_list)
17+
18+
output += release_notes_compare_package_versions_section(
19+
gardenlinux_version, package_list
20+
)
21+
22+
output += "\n"
23+
output += "## Kernel Module Build Container (kmodbuild)"
24+
output += "\n"
25+
output += "```"
26+
output += "\n"
27+
output += f"ghcr.io/gardenlinux/gardenlinux/kmodbuild:{gardenlinux_version}"
28+
output += "\n"
29+
output += "```"
30+
output += "\n"
31+
return output
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import gzip
2+
import io
3+
4+
import requests
5+
6+
from gardenlinux.apt import DebsrcFile, GardenLinuxRepo
7+
from gardenlinux.apt.package_repo_info import compare_repo
8+
from gardenlinux.constants import REQUESTS_TIMEOUTS
9+
10+
11+
def get_package_list(gardenlinux_version):
12+
url = f"https://packages.gardenlinux.io/gardenlinux/dists/{gardenlinux_version}/main/binary-amd64/Packages.gz"
13+
response = requests.get(url, timeout=REQUESTS_TIMEOUTS)
14+
response.raise_for_status()
15+
16+
d = DebsrcFile()
17+
18+
with io.BytesIO(response.content) as buf:
19+
with gzip.open(buf, "rt") as f:
20+
d.read(f)
21+
22+
return d
23+
24+
25+
def compare_apt_repo_versions(previous_version, current_version):
26+
previous_repo = GardenLinuxRepo(previous_version)
27+
current_repo = GardenLinuxRepo(current_version)
28+
pkg_diffs = sorted(compare_repo(previous_repo, current_repo), key=lambda t: t[0])
29+
30+
output = f"| Package | {previous_version} | {current_version} |\n"
31+
output += "|---------|--------------------|-------------------|\n"
32+
33+
for pkg in pkg_diffs:
34+
output += f"|{pkg[0]} | {pkg[1] if pkg[1] is not None else '-'} | {pkg[2] if pkg[2] is not None else '-'} |\n"
35+
return output
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import re
2+
import textwrap
3+
4+
import requests
5+
6+
from gardenlinux.constants import REQUESTS_TIMEOUTS
7+
from gardenlinux.logger import LoggerSetup
8+
9+
from .helpers import compare_apt_repo_versions
10+
11+
LOGGER = LoggerSetup.get_logger("gardenlinux.github.release_notes", "INFO")
12+
13+
14+
def release_notes_changes_section(gardenlinux_version):
15+
"""
16+
Get list of fixed CVEs, grouped by upgraded package.
17+
Note: This result is not perfect, feel free to edit the generated release notes and
18+
file issues in glvd for improvement suggestions https://github.com/gardenlinux/glvd/issues
19+
"""
20+
try:
21+
url = f"https://glvd.ingress.glvd.gardnlinux.shoot.canary.k8s-hana.ondemand.com/v1/patchReleaseNotes/{gardenlinux_version}"
22+
response = requests.get(url, timeout=REQUESTS_TIMEOUTS)
23+
response.raise_for_status()
24+
data = response.json()
25+
26+
if len(data["packageList"]) == 0:
27+
return ""
28+
29+
output = [
30+
"## Changes",
31+
"The following packages have been upgraded, to address the mentioned CVEs:",
32+
]
33+
for package in data["packageList"]:
34+
upgrade_line = (
35+
f"- upgrade '{package['sourcePackageName']}' from `{package['oldVersion']}` "
36+
f"to `{package['newVersion']}`"
37+
)
38+
output.append(upgrade_line)
39+
40+
if package["fixedCves"]:
41+
for fixedCve in package["fixedCves"]:
42+
output.append(f" - {fixedCve}")
43+
44+
return "\n".join(output) + "\n\n"
45+
except Exception as exn:
46+
# There are expected error cases, for example with versions not supported by glvd (1443.x) or when the api is not available
47+
# Fail gracefully by adding the placeholder we previously used, so that the release note generation does not fail.
48+
LOGGER.error(f"Failed to process GLVD API output: {exn}")
49+
return textwrap.dedent(
50+
"""
51+
## Changes
52+
The following packages have been upgraded, to address the mentioned CVEs:
53+
**todo release facilitator: fill this in**
54+
"""
55+
)
56+
57+
58+
def release_notes_software_components_section(package_list):
59+
output = "## Software Component Versions\n"
60+
output += "```"
61+
output += "\n"
62+
packages_regex = re.compile(
63+
r"^linux-image-amd64$|^systemd$|^containerd$|^runc$|^curl$|^openssl$|^openssh-server$|^libc-bin$"
64+
)
65+
for entry in package_list.values():
66+
if packages_regex.match(entry.deb_source):
67+
output += f"{entry!r}\n"
68+
output += "```"
69+
output += "\n\n"
70+
return output
71+
72+
73+
def release_notes_compare_package_versions_section(gardenlinux_version, package_list):
74+
output = ""
75+
version_components = gardenlinux_version.split(".")
76+
# Assumes we always have version numbers like 1443.2
77+
if len(version_components) == 2:
78+
try:
79+
major = int(version_components[0])
80+
patch = int(version_components[1])
81+
82+
if patch > 0:
83+
previous_version = f"{major}.{patch - 1}"
84+
85+
output += (
86+
f"## Changes in Package Versions Compared to {previous_version}\n"
87+
)
88+
output += compare_apt_repo_versions(
89+
previous_version, gardenlinux_version
90+
)
91+
elif patch == 0:
92+
output += f"## Full List of Packages in Garden Linux version {major}\n"
93+
output += "<details><summary>Expand to see full list</summary>\n"
94+
output += "<pre>"
95+
output += "\n"
96+
for entry in package_list.values():
97+
output += f"{entry!r}\n"
98+
output += "</pre>"
99+
output += "\n</details>\n\n"
100+
101+
except ValueError:
102+
LOGGER.error(
103+
f"Could not parse {gardenlinux_version} as the Garden Linux version, skipping version compare section"
104+
)
105+
else:
106+
LOGGER.error(
107+
f"Unexpected version number format {gardenlinux_version}, expected format (major is int).(patch is int)"
108+
)
109+
return output

0 commit comments

Comments
 (0)