← Back to team overview

sts-sponsors team mailing list archive

[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