← Back to team overview

sts-sponsors team mailing list archive

[Merge] ~adam-collard/maas/+git/maas-release-tools:sync-milestones into ~maas-committers/maas/+git/maas-release-tools:main

 

Adam Collard has proposed merging ~adam-collard/maas/+git/maas-release-tools:sync-milestones into ~maas-committers/maas/+git/maas-release-tools:main.

Commit message:
Add milestone syncing



Requested reviews:
  MAAS Committers (maas-committers)

For more details, see:
https://code.launchpad.net/~adam-collard/maas/+git/maas-release-tools/+merge/442591
-- 
Your team MAAS Committers is requested to review the proposed merge of ~adam-collard/maas/+git/maas-release-tools:sync-milestones into ~maas-committers/maas/+git/maas-release-tools:main.
diff --git a/maas_release_tools/actions.py b/maas_release_tools/actions.py
index a0b9e38..67f25cc 100644
--- a/maas_release_tools/actions.py
+++ b/maas_release_tools/actions.py
@@ -36,3 +36,7 @@ class Actions:
     def release_milestone(self):
         """Release a milestone."""
         self.lp_actions.release_milestone(self.args.milestone)
+
+    def sync_milestones_to(self) -> None:
+        """Sync milestones between projects."""
+        self.lp_actions.sync_milestones_to(self.args.target_project)
diff --git a/maas_release_tools/launchpad.py b/maas_release_tools/launchpad.py
index db115b9..484c1b7 100644
--- a/maas_release_tools/launchpad.py
+++ b/maas_release_tools/launchpad.py
@@ -158,6 +158,48 @@ class LaunchpadActions:
         else:
             self.logger.info(f"milestone {milestone.name} already released")
 
+    def sync_milestones_to(self, target_project_name: str) -> None:
+        """Sync milestones to target project."""
+        source_project = self._project
+        target_project = self.lp.projects[target_project_name]
+        if not target_project:
+            raise UnknownLaunchpadEntry("project", target_project)
+        for source_series in source_project.series:
+            source_series_name = source_series.name
+            target_series = target_project.getSeries(name=source_series_name)
+            if target_series is None:
+                self.logger.info(
+                    f"creating missing series {source_series_name} "
+                    f"for {target_project_name}"
+                )
+                if not self.dry_run:
+                    target_series = target_project.newSeries(
+                        name=source_series_name, summary=source_series.summary
+                    )
+            for source_milestone in source_series.active_milestones:
+                milestone_name = source_milestone.name
+                if self.dry_run and target_series is None:
+                    self.logger.info(
+                        "dry run but target series is missing - can assume that "
+                        f"we'd need to create {milestone_name}"
+                    )
+                    continue
+                target_milestone = target_project.getMilestone(
+                    name=milestone_name
+                )
+                if target_milestone is None:
+                    self.logger.info(
+                        f"creating missing milestone {milestone_name} in "
+                        f"{target_project_name}/{source_series_name}"
+                    )
+                    if not self.dry_run:
+                        target_series.newMilestone(
+                            name=milestone_name,
+                            summary=source_milestone.summary,
+                            code_name=source_milestone.code_name,
+                            date_targeted=source_milestone.date_targeted,
+                        )
+
     def _get_client(self, credentials_file: Path | None = None) -> Launchpad:
         """Return a Launchpad API client."""
         kwargs = {
diff --git a/maas_release_tools/scripts/release_manage.py b/maas_release_tools/scripts/release_manage.py
index aee1598..6a44636 100644
--- a/maas_release_tools/scripts/release_manage.py
+++ b/maas_release_tools/scripts/release_manage.py
@@ -1,6 +1,6 @@
 """Manage releases and milestones."""
 
-from argparse import ArgumentParser, FileType
+from argparse import ArgumentParser, FileType, Namespace
 import logging
 import sys
 
@@ -9,7 +9,7 @@ from ..actions import Actions
 from ..launchpad import LaunchpadActions
 
 
-def parse_args():
+def parse_args() -> Namespace:
     """Return parsed arguments for the script."""
 
     def add_move_across_milestones_args(parser):
@@ -73,12 +73,20 @@ def parse_args():
     )
     release.add_argument("milestone", help="the milestone to release")
 
+    sync_milestones_to = subparsers.add_parser(
+        "sync-milestones-to", help="Sync milestones across projects' series"
+    )
+    sync_milestones_to.add_argument(
+        "target_project",
+        help="Target project to copy milestones to",
+        metavar="PROJECT",
+    )
     ns = parser.parse_args()
     convert_file_descriptors_to_path(ns)
     return ns
 
 
-def main():
+def main() -> None:
     args = parse_args()
     logging.basicConfig(
         level=logging.DEBUG if args.debug else logging.INFO,

Follow ups