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

Proposed by Adam Collard
Status: Merged
Approved by: Adam Collard
Approved revision: 26aa090a5e6db2847f4f1107a1b47b0a86724acb
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~adam-collard/maas/+git/maas-release-tools:sync-milestones
Merge into: ~maas-committers/maas/+git/maas-release-tools:main
Diff against target: 108 lines (+57/-3)
3 files modified
maas_release_tools/actions.py (+4/-0)
maas_release_tools/launchpad.py (+42/-0)
maas_release_tools/scripts/release_manage.py (+11/-3)
Reviewer Review Type Date Requested Status
Thorsten Merten Approve
MAAS Lander Approve
Review via email: mp+442591@code.launchpad.net

Commit message

Add milestone syncing

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b sync-milestones lp:~adam-collard/maas/+git/maas-release-tools into -b main lp:~maas-committers/maas/+git/maas-release-tools

STATUS: SUCCESS
COMMIT: 26aa090a5e6db2847f4f1107a1b47b0a86724acb

review: Approve
Revision history for this message
Thorsten Merten (thorsten-merten) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/maas_release_tools/actions.py b/maas_release_tools/actions.py
2index a0b9e38..67f25cc 100644
3--- a/maas_release_tools/actions.py
4+++ b/maas_release_tools/actions.py
5@@ -36,3 +36,7 @@ class Actions:
6 def release_milestone(self):
7 """Release a milestone."""
8 self.lp_actions.release_milestone(self.args.milestone)
9+
10+ def sync_milestones_to(self) -> None:
11+ """Sync milestones between projects."""
12+ self.lp_actions.sync_milestones_to(self.args.target_project)
13diff --git a/maas_release_tools/launchpad.py b/maas_release_tools/launchpad.py
14index db115b9..484c1b7 100644
15--- a/maas_release_tools/launchpad.py
16+++ b/maas_release_tools/launchpad.py
17@@ -158,6 +158,48 @@ class LaunchpadActions:
18 else:
19 self.logger.info(f"milestone {milestone.name} already released")
20
21+ def sync_milestones_to(self, target_project_name: str) -> None:
22+ """Sync milestones to target project."""
23+ source_project = self._project
24+ target_project = self.lp.projects[target_project_name]
25+ if not target_project:
26+ raise UnknownLaunchpadEntry("project", target_project)
27+ for source_series in source_project.series:
28+ source_series_name = source_series.name
29+ target_series = target_project.getSeries(name=source_series_name)
30+ if target_series is None:
31+ self.logger.info(
32+ f"creating missing series {source_series_name} "
33+ f"for {target_project_name}"
34+ )
35+ if not self.dry_run:
36+ target_series = target_project.newSeries(
37+ name=source_series_name, summary=source_series.summary
38+ )
39+ for source_milestone in source_series.active_milestones:
40+ milestone_name = source_milestone.name
41+ if self.dry_run and target_series is None:
42+ self.logger.info(
43+ "dry run but target series is missing - can assume that "
44+ f"we'd need to create {milestone_name}"
45+ )
46+ continue
47+ target_milestone = target_project.getMilestone(
48+ name=milestone_name
49+ )
50+ if target_milestone is None:
51+ self.logger.info(
52+ f"creating missing milestone {milestone_name} in "
53+ f"{target_project_name}/{source_series_name}"
54+ )
55+ if not self.dry_run:
56+ target_series.newMilestone(
57+ name=milestone_name,
58+ summary=source_milestone.summary,
59+ code_name=source_milestone.code_name,
60+ date_targeted=source_milestone.date_targeted,
61+ )
62+
63 def _get_client(self, credentials_file: Path | None = None) -> Launchpad:
64 """Return a Launchpad API client."""
65 kwargs = {
66diff --git a/maas_release_tools/scripts/release_manage.py b/maas_release_tools/scripts/release_manage.py
67index aee1598..6a44636 100644
68--- a/maas_release_tools/scripts/release_manage.py
69+++ b/maas_release_tools/scripts/release_manage.py
70@@ -1,6 +1,6 @@
71 """Manage releases and milestones."""
72
73-from argparse import ArgumentParser, FileType
74+from argparse import ArgumentParser, FileType, Namespace
75 import logging
76 import sys
77
78@@ -9,7 +9,7 @@ from ..actions import Actions
79 from ..launchpad import LaunchpadActions
80
81
82-def parse_args():
83+def parse_args() -> Namespace:
84 """Return parsed arguments for the script."""
85
86 def add_move_across_milestones_args(parser):
87@@ -73,12 +73,20 @@ def parse_args():
88 )
89 release.add_argument("milestone", help="the milestone to release")
90
91+ sync_milestones_to = subparsers.add_parser(
92+ "sync-milestones-to", help="Sync milestones across projects' series"
93+ )
94+ sync_milestones_to.add_argument(
95+ "target_project",
96+ help="Target project to copy milestones to",
97+ metavar="PROJECT",
98+ )
99 ns = parser.parse_args()
100 convert_file_descriptors_to_path(ns)
101 return ns
102
103
104-def main():
105+def main() -> None:
106 args = parse_args()
107 logging.basicConfig(
108 level=logging.DEBUG if args.debug else logging.INFO,

Subscribers

People subscribed via source and target branches

to all changes: