sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #05462
[Merge] ~alexsander-souza/maas/+git/maas-release-tools:final_version_checks into ~maas-committers/maas/+git/maas-release-tools:main
Alexsander de Souza has proposed merging ~alexsander-souza/maas/+git/maas-release-tools:final_version_checks into ~maas-committers/maas/+git/maas-release-tools:main.
Requested reviews:
MAAS Committers (maas-committers)
For more details, see:
https://code.launchpad.net/~alexsander-souza/maas/+git/maas-release-tools/+merge/437920
--
Your team MAAS Committers is requested to review the proposed merge of ~alexsander-souza/maas/+git/maas-release-tools:final_version_checks into ~maas-committers/maas/+git/maas-release-tools:main.
diff --git a/maas_release_tools/git.py b/maas_release_tools/git.py
index 12b9dfc..07bbe03 100644
--- a/maas_release_tools/git.py
+++ b/maas_release_tools/git.py
@@ -65,6 +65,10 @@ class Git:
result = self._run("diff-index", "--quiet", "HEAD")
return not result.succeeded
+ def is_behind(self, remote: str, branch: str) -> bool:
+ result = self._run("rev-list", "--count", f"HEAD..{remote}/{branch}")
+ return result.succeeded and result.output != "0"
+
def list_from_remote(
self, repo: str, heads: bool = True, tags: bool = True
):
diff --git a/maas_release_tools/launchpad.py b/maas_release_tools/launchpad.py
index 2da3b68..ae17631 100644
--- a/maas_release_tools/launchpad.py
+++ b/maas_release_tools/launchpad.py
@@ -11,6 +11,7 @@ from launchpadlib.launchpad import Launchpad
from lazr.restfulclient.errors import NotFound
DONE_BUGS = ("Invalid", "Won't Fix", "Fix Committed", "Fix Released")
+SOLVED_BUGS = ("Invalid", "Won't Fix", "Fix Committed")
UNFINISHED_BUGS = ("New", "Confirmed", "Triaged", "In Progress", "Incomplete")
MAAS_USER = "maas-committers"
@@ -66,13 +67,22 @@ class LaunchpadActions:
"""Return a list this ppa dependecies"""
return [d.dependency.name for d in ppa.dependencies]
- def snap_builder_exist(self, builder_name: str) -> bool:
+ def get_snap_builder(self, builder_name: str):
try:
- _ = self.lp.snaps.getByName(name=builder_name, owner=self.maas)
+ return self.lp.snaps.getByName(name=builder_name, owner=self.maas)
except NotFound:
- return False
- else:
- return True
+ return None
+
+ def snap_builder_exist(self, builder_name: str) -> bool:
+ return self.get_snap_builder(builder_name) is not None
+
+ def get_series_status(self) -> list[tuple[str, str]]:
+ series = []
+ for s in self._project.series:
+ if s.active:
+ series.append((s.name, s.status))
+ series.sort(reverse=True)
+ return series
def move_done_bugs(
self,
diff --git a/maas_release_tools/scripts/release_status.py b/maas_release_tools/scripts/release_status.py
index b1835ce..1d580c8 100644
--- a/maas_release_tools/scripts/release_status.py
+++ b/maas_release_tools/scripts/release_status.py
@@ -31,9 +31,9 @@ import requests
from . import convert_file_descriptors_to_path
from ..git import Git
from ..launchpad import (
- DONE_BUGS,
LaunchpadActions,
MAAS_USER,
+ SOLVED_BUGS,
UnknownLaunchpadEntry,
)
from ..maasci import (
@@ -279,16 +279,26 @@ class SubmoduleInRemoteBranch(CommitInRemoteBranch):
@property
def title(self):
- return f"Submodule {self.mod_name} release commit in remote branch"
+ return (
+ f"Submodule {self.mod_name} release commit at tip of remote branch"
+ )
@property
def official_remote(self):
return self.git.get_official_remote(f"/{self.mod_name}")
+ def check(self) -> tuple[bool, str]:
+ if not self.official_remote:
+ return False, "Official remote not found"
+ if self.git.is_behind(self.official_remote, self.release_branch_name):
+ return False, "Local branch is not at remote tip"
+ return True, None
+
def fix(self, doit: bool = False) -> tuple[bool, list[str]]:
steps = [
f"cd {self.git.cwd}",
f"git checkout {self.release_branch_name}",
+ "git pull",
]
return False, steps
@@ -443,7 +453,8 @@ class MAASPPA(ReleaseStep):
if ppa_type == "candidate":
self.ppa_name += "-next"
elif ppa_type == "release-preparation":
- self.deps = [self.ppa_name + "-next"]
+ if not self.preparer.version.new_series:
+ self.deps = [self.ppa_name + "-next"]
self.ppa_name = "maas-" + self.ppa_name + "-next"
self.ppa_owner = self.launchpad.me
self.ppa_path = f"{self.ppa_owner.name}/{self.ppa_name}"
@@ -504,7 +515,7 @@ class MAASPPA(ReleaseStep):
steps.extend(
[
f"Go to {self.ppa.web_link}/+edit-dependencies",
- f"Add {', '.join(self.deps)} to Dependencies list",
+ f"Add {', '.join(map(lambda x: '~maas/ubuntu/'+x, self.deps))} to Dependencies list",
]
)
return False, steps
@@ -657,7 +668,10 @@ class PackagesCopiedToReleasePPA(MAASPPA, PPACopyMixin):
)
def check(self):
- if not self.preparer.version.new_series:
+ if (
+ self.ppa_type == "candidate"
+ and not self.preparer.version.new_series
+ ):
self.selected = ["maas"]
try:
self.source_ppa = self.source.ppa_owner.getPPAByName(
@@ -740,6 +754,58 @@ class PackageBuilt(ReleaseStep):
]
+class SnapDefaultTrack(ReleaseStep):
+ def __init__(
+ self,
+ preparer: ReleasePreparer,
+ snap_name: str = "maas",
+ cwd: str | None = None,
+ ):
+ super().__init__(preparer, cwd)
+ self.snap_name = snap_name
+
+ @property
+ def title(self):
+ return f"Snap `{self.snap_name}` default track"
+
+ def skip(self):
+ return not (
+ self.preparer.version.grade == "final"
+ and self.preparer.version.new_series
+ )
+
+ def _get_snap_info(self):
+ res = requests.get(
+ f"https://dashboard.snapcraft.io/api/v2/snaps/{self.snap_name}/channel-map",
+ headers={
+ "Authorization": self.preparer.snapstore_auth,
+ "Accept": "application/json",
+ },
+ )
+ auth_error = get_macaroon_auth_error(res, self.snap_name)
+ if auth_error:
+ return None, auth_error
+ return res.json()["snap"], None
+
+ def check(self):
+ snap_info, error_message = self._get_snap_info()
+ if snap_info is None:
+ return False, error_message
+ if snap_info["default-track"] != self.preparer.version.major:
+ return (
+ False,
+ f"Default track set to {snap_info['default-track']}, expected {self.preparer.version.major}",
+ )
+ return True, None
+
+ def fix(self, doit: bool = False) -> tuple[bool, list[str]]:
+ return False, [
+ f"go to https://snapcraft.io/{self.snap_name}/releases",
+ f"Select the {self.preparer.version.major} track",
+ "Click on 'Set as default track'",
+ ]
+
+
class SnapsUploaded(ReleaseStep):
def __init__(
self,
@@ -816,7 +882,7 @@ class SnapsUploaded(ReleaseStep):
steps = []
if self.launchpad.snap_builder_exist(builder):
steps.append(
- f"check the snap package status at https://launchpad.net/~{MAAS_USER}/+snap/{builder}"
+ f"check the snap package status at https://launchpad.net/~{MAAS_USER}/{self.snap_name}/+snap/{builder}"
)
else:
steps.extend(
@@ -1023,7 +1089,7 @@ class BugMovedToMilestone(ReleaseStep):
try:
ms = self.launchpad.get_milestone(tag_name)
self._ms_found = True
- bug_tasks = ms.searchTasks(status=DONE_BUGS)
+ bug_tasks = ms.searchTasks(status=SOLVED_BUGS)
if len(bug_tasks) > 0:
return (
False,
@@ -1120,6 +1186,114 @@ class SystemIntegrationTests(ReleaseStep):
return True, [f"check {self._url}"]
+class UsnBuilderUpdated(ReleaseStep):
+ def __init__(self, preparer: ReleasePreparer, cwd: str | None = None):
+ super().__init__(preparer, cwd)
+ self.builder_name = f"maas-{self.preparer.version.major}-candidate"
+ self.ref_path = f"refs/tags/{self.preparer.version.version}"
+ self.builder = None
+
+ @property
+ def title(self) -> str:
+ return "Check if SNAP USN builder is updated"
+
+ def check(self) -> tuple[bool, str]:
+ self.builder = self.launchpad.get_snap_builder(self.builder_name)
+ if self.builder is None:
+ return False, f"SNAP USN {self.builder_name} builder not found"
+ if self.builder.git_path != self.ref_path:
+ return (
+ False,
+ f"Builder source is {self.builder.git_path}, expected {self.ref_path}",
+ )
+ return True, None
+
+ def fix(self, doit: bool = False) -> tuple[bool, list[str]]:
+ if self.builder is None:
+ return False, [
+ f" go to https://code.launchpad.net/~{MAAS_USER}/maas/+git/maas/+ref/{self.preparer.version.major}/+new-snap",
+ f" * snap recipe name: maas-{self.preparer.version.major}-candidate",
+ f" * owner: {MAAS_USER}",
+ f" * processors: {', '.join(BUILD_ARCHS)}",
+ " * Source:",
+ f" * Repository: '~{MAAS_USER}/maas/+git/maas' Branch: {self.ref_path}",
+ " * Automatically build when branch changes",
+ f" * Source archive for automatic builds: ~maas/ubuntu/{self.preparer.version.major}",
+ " * Automatically upload to store",
+ f" * Track: {self.preparer.version.major} Risk: Candidate",
+ ]
+ return False, [
+ f" go to https://launchpad.net/~{MAAS_USER}/maas/+snap/{self.builder_name}/+edit",
+ " update source definition:",
+ f" * Repository: '~{MAAS_USER}/maas/+git/maas' Branch: {self.ref_path}",
+ ]
+
+
+class LaunchpadSeriesUpdated(ReleaseStep):
+ def __init__(self, preparer: ReleasePreparer, cwd: str | None = None):
+ super().__init__(preparer, cwd)
+ self._series = None
+
+ @property
+ def title(self) -> str:
+ return "Lauchpad series status updated"
+
+ def skip(self) -> bool:
+ return self.preparer.version.grade != "final"
+
+ def check(self) -> tuple[bool, str | None]:
+ self._series = self.launchpad.get_series_status()
+ for n, (name, status) in enumerate(self._series):
+ match n:
+ case 0:
+ if status != "Active Development":
+ self._series = name
+ return False, "Missing 'Active Development' series"
+ if (
+ self.preparer.version.new_series
+ and self.preparer.version.major == name
+ ):
+ self._series = name
+ return (
+ False,
+ f"{self.preparer.version.major} should be promoted to 'Current Stable Release'",
+ )
+ case 1:
+ if status != "Current Stable Release":
+ self._series = name
+ return False, "Missing 'Current Stable Release' series"
+ if (
+ self.preparer.version.new_series
+ and self.preparer.version.major != name
+ ):
+ self._series = name
+ return (
+ False,
+ f"{self.preparer.version.major} should be promoted to 'Current Stable Release'",
+ )
+ case 2:
+ if status != "Supported":
+ self._series = name
+ return (
+ False,
+ f"{name} series should have 'Supported' status, has '{status}'",
+ )
+ case _:
+ if status != "Obsolete":
+ self._series = name
+ return (
+ False,
+ f"{name} series should have 'Obsolete' status, has '{status}'",
+ )
+ return True, None
+
+ def fix(self, doit: bool = False) -> tuple[bool, list[str]]:
+ return False, [
+ f"go to https://launchpad.net/maas/{self._series}/+edit",
+ "set correct 'Status'",
+ ]
+
+
def parse_args():
parser = ArgumentParser(description=__doc__)
parser.add_argument("version", help="The version of MAAS to be released")
@@ -1233,8 +1407,12 @@ def main():
],
PackagesCopiedToReleasePPA(preparer, "stable"),
ReleaseTagged(preparer),
+ UsnBuilderUpdated(preparer),
MilestoneExist(preparer),
BugMovedToMilestone(preparer),
MilestoneReleased(preparer),
+ SnapDefaultTrack(preparer),
+ SnapDefaultTrack(preparer, snap_name="maas-test-db"),
+ LaunchpadSeriesUpdated(preparer),
]
return preparer.run(args)
Follow ups