sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #08252
[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