@@ -108,37 +108,60 @@ def verify_milestone(version: Version, *, base: Version, head: BranchType = None
108108 head = str (version )
109109
110110 problems = []
111+ unresolved = []
111112 for proj in [EsphomeProject , EsphomeDocsProject ]:
112113 milestone = None
113114 for title in milestone_title_candidates (version ):
114115 milestone = proj .get_milestone_by_title (title )
115116 if milestone is not None :
116117 break
117118 if milestone is None :
119+ # No milestone resolved under either title model. Don't skip
120+ # silently — that would print a green "verified" having checked
121+ # nothing, the exact false-confidence this guard exists to prevent.
122+ unresolved .append (proj )
118123 continue
119124 milestone_prs = proj .get_milestone_pr_numbers (milestone )
120125 release_prs = proj .prs_between (f"{ base } " , head )
121126 for number in find_missing_milestone_prs (milestone_prs , release_prs ):
122127 problems .append ((proj , number ))
123128
124- if not problems :
129+ if not problems and not unresolved :
125130 gprint (
126131 f"Milestone { version } verified: all merged milestone PRs are in the release."
127132 )
128133 return
129134
130- gprint (click .style (
131- f"Warning: { len (problems )} merged milestone PR(s) missing from the { version } release:" ,
132- fg = "yellow" ,
133- ))
134- for proj , number in problems :
135- gprint (f" - [{ proj .shortname } ] #{ number } : { proj .repo .html_url } /pull/{ number } " )
136-
137- confirm (click .style (
138- "Milestone is incomplete. Cherry-pick the missing PRs (or confirm to "
139- "continue anyway)." ,
140- fg = "red" ,
141- ))
135+ if unresolved :
136+ gprint (click .style (
137+ f"Warning: could not resolve a { version } milestone for "
138+ f"{ len (unresolved )} project(s) — nothing was verified for them:" ,
139+ fg = "yellow" ,
140+ ))
141+ tried = ", " .join (milestone_title_candidates (version ))
142+ for proj in unresolved :
143+ gprint (f" - [{ proj .shortname } ] tried: { tried } " )
144+
145+ if problems :
146+ gprint (click .style (
147+ f"Warning: { len (problems )} merged milestone PR(s) missing from the { version } release:" ,
148+ fg = "yellow" ,
149+ ))
150+ for proj , number in problems :
151+ gprint (f" - [{ proj .shortname } ] #{ number } : { proj .repo .html_url } /pull/{ number } " )
152+
153+ # Mirror the open-PR check: offer an explicit abort so the operator can
154+ # stop, cherry-pick the missing PRs, and re-run — rather than being forced
155+ # to either continue or Ctrl-C. Default is to abort.
156+ if not click .confirm (
157+ click .style (
158+ "Milestone is incomplete. Cherry-pick the missing PRs and re-run, "
159+ "or continue anyway?" ,
160+ fg = "red" ,
161+ ),
162+ default = False ,
163+ ):
164+ raise EsphomeReleaseError ("Aborted: incomplete milestone" )
142165
143166
144167def _strategy_merge (project : Project , version : Version , * , base : Branch , head : Branch ):
0 commit comments