Skip to content

Commit 5c19a01

Browse files
committed
experimentation: use Test Observer
1 parent 47a424a commit 5c19a01

File tree

5 files changed

+161
-403
lines changed

5 files changed

+161
-403
lines changed

experimentations/fetch-serials.py

Lines changed: 0 additions & 124 deletions
This file was deleted.

experimentations/publish-image-set

Lines changed: 161 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,186 @@
11
#!/usr/bin/python3
22

3-
4-
from pathlib import Path
53
import argparse
6-
import yaml
7-
8-
9-
def parse_args():
10-
args = argparse.ArgumentParser()
11-
args.add_argument(
12-
"--data",
13-
"-d",
14-
type=Path,
15-
required=True,
16-
help="Path to the data.yaml file describing the release",
17-
)
18-
19-
return args.parse_args()
20-
4+
import requests
5+
6+
7+
def slugify(string):
8+
return string.lower().replace(" ", "-")
9+
10+
11+
def str_image(image):
12+
return f"{image['os']: <25} {image['arch']: <14} {image['name']: <50} {image['version']: <12}"
13+
14+
15+
def is_official(os):
16+
if os in ["ubuntu", "ubuntu-server", "ubuntu-wsl"]:
17+
return True
18+
return False
19+
20+
21+
def get_artifacts(series, pre_publish):
22+
"""
23+
Yields all 'Approved' artifacts for a given release using the
24+
Ubuntu Test Observer API.
25+
26+
:param release_name: The Ubuntu release codename (e.g., 'noble', 'jammy')
27+
"""
28+
base_url = "https://tests-api.ubuntu.com"
29+
params = {
30+
"family": "image",
31+
}
32+
33+
response = requests.get(base_url + "/v1/artefacts", params=params)
34+
response.raise_for_status()
35+
36+
artifacts = [a for a in response.json() if a["release"] == series]
37+
if pre_publish:
38+
artifacts = [a for a in artifacts if is_official(a["os"])]
39+
print(f"Found {len(artifacts)} artifacts")
40+
artifacts = [a for a in artifacts if a["status"] == "APPROVED"]
41+
print(f"Found {len(artifacts)} approved artifacts")
42+
for artifact in artifacts:
43+
response = requests.get(base_url + f"/v1/artefacts/{artifact['id']}/builds")
44+
response.raise_for_status()
45+
build = response.json()[0]
46+
image = {
47+
"name": artifact["name"],
48+
"os": artifact["os"],
49+
"version": artifact["version"],
50+
"arch": build["architecture"].split(".")[0], # fixup old cdimage bug
51+
}
52+
yield image
53+
54+
55+
def get_type(image):
56+
os = image["os"]
57+
dir = image["dir"]
58+
59+
if os == "ubuntu-base":
60+
return "base"
61+
if os == "ubuntu-mini-iso":
62+
return "mini-iso"
63+
if os == "ubuntu-wsl":
64+
return "wsl"
65+
if os == "ubuntu-server":
66+
if "daily-preinstalled" in dir:
67+
return "preinstalled-server"
68+
if "daily-live" in dir:
69+
return "live-server"
70+
if os in ["ubuntu", "edubuntu"]:
71+
if dir == "daily-preinstalled":
72+
return "preinstalled-desktop"
73+
if os == "xubuntu":
74+
if dir == "daily-minimal":
75+
return "minimal"
76+
77+
return "desktop"
78+
79+
80+
def get_dir(image):
81+
os = image["os"]
82+
name = image["name"]
83+
84+
dir = "daily-live"
85+
if os == "ubuntu-base":
86+
dir = "daily"
87+
if name.startswith("dangerous"):
88+
dir = "daily-dangerous"
89+
if "minimal" in name:
90+
dir = "daily-minimal"
91+
if "preinstalled" in name:
92+
dir = "daily-preinstalled"
93+
if os in ["ubuntu-server", "ubuntu-wsl"]:
94+
dir = f"{os}/{dir}"
95+
return dir
96+
97+
98+
def get_project(image):
99+
os = image["os"]
100+
if os in ["ubuntu-desktop", "ubuntu-server", "ubuntu-wsl"]:
101+
return "ubuntu"
102+
return os
103+
104+
105+
def get_official(image, milestone, pre_publish):
106+
os = image["os"]
107+
108+
if "snapshot" in milestone.lower():
109+
return "named"
110+
if is_official(os):
111+
if pre_publish:
112+
return "poolonly"
113+
else:
114+
return "yes"
115+
return "no"
21116

22-
def parse_milestone(milestone: Path):
23-
return yaml.safe_load(milestone.read_text())
24117

118+
def render_publishing_script(milestone, images):
119+
milestone_slug = slugify(milestone)
25120

26-
def render_publishing_script(
27-
milestone: dict[str, str],
28-
images: dict[str, dict[str, str]],
29-
):
30121
print("""
31122
## make backup:
32123
cd ~/cdimage/; rm -rf www.prev; cp -al www www.prev; cd www
33124
""")
34125

35-
for image_name, image_data in images.items():
36-
print(f"\n# {image_name}")
37-
if image_data["serial"]:
38-
print(
39-
image_data["publishing_command"]
40-
.replace("SERIAL", image_data["serial"])
41-
.replace("MILESTONE_SLUG", milestone["slug"])
42-
)
43-
else:
44-
print("# No serial set for publication, skipping")
126+
for image in images:
127+
print(f"\n# {str_image(image)}")
128+
print(
129+
f"ARCHES='{image['arch']}' for-project {image['project']} "
130+
f"publish-release {image['dir']} {image['version']} {image['type']} {image['official']} {milestone_slug}"
131+
)
45132

46133
print(f"""
47134
## fix name in headers:
48-
find full -path '*/{milestone["slug"]}*HEADER.html' | xargs sed -i 's/Daily Build/{milestone["name"]}/'
135+
find full -path '*/{milestone_slug}*HEADER.html' | xargs sed -i 's/Daily Build/{milestone}/'
49136
50137
## check changes against www.prev:
51138
diff -u <(cd ../www.prev/full && find | sort) <(cd full && find | sort) | less
52139
""")
53140

54141

142+
def parse_args():
143+
args = argparse.ArgumentParser()
144+
args.add_argument(
145+
"--series",
146+
"-s",
147+
type=str,
148+
required=True,
149+
help="The series to release (e.g. 'noble', 'resolute'...)",
150+
)
151+
args.add_argument(
152+
"--milestone",
153+
"-m",
154+
type=str,
155+
required=True,
156+
help="The milestone to release (e.g. 'Final', 'Snapshot 1'...)",
157+
)
158+
args.add_argument(
159+
"--pre-publish",
160+
action="store_true",
161+
help="Whether to pre-publish or do a full release",
162+
)
163+
164+
return args.parse_args()
165+
166+
55167
def main():
56168
args = parse_args()
57-
input_data = parse_milestone(args.data)
58-
render_publishing_script(input_data["milestone"], input_data["images"])
169+
print(f"Fetching approved artifacts for {args.series}...")
170+
171+
images = list(get_artifacts(args.series, args.pre_publish))
172+
images.sort(key=lambda a: a["os"])
173+
print(" Summary of images to be released ".center(120, "="))
174+
for image in images:
175+
image["dir"] = get_dir(image)
176+
image["type"] = get_type(image)
177+
image["project"] = get_project(image)
178+
image["official"] = get_official(image, args.milestone, args.pre_publish)
179+
print(str_image(image))
180+
print("=" * 120)
181+
print(" Publishing script ".center(120, "="))
182+
render_publishing_script(args.milestone, images)
183+
print(" End of script ".center(120, "="))
59184

60185

61186
if __name__ == "__main__":

0 commit comments

Comments
 (0)