| name | check-milestones |
| description | Check and fix milestones on PRs and their associated issues. Sets PR milestones based on the branch they merged into, and issue milestones based on the smallest version with a merged fix. Triggers on: check milestones, fix milestones, /check-milestones. |
| argument-hint | [github-username] [all|PR1,PR2,PR3] |
| allowed-tools | Bash, Read, Grep, Glob |
Check Milestones
Check and fix milestones on a contributor's merged PRs and their associated
GitHub issues.
Inputs
- Arguments:
$ARGUMENTS -- space-separated values:
- First argument: GitHub username (the author whose merged PRs to check)
- Second argument (optional): PR filter -- either:
all -- evaluate all closed/merged PRs from this author in the past 30
days.
- A comma-separated list of PR numbers with no spaces (e.g.,
100,105,110) -- only evaluate these specific PRs.
- If omitted, defaults to the recent 50 closed PRs.
Parse the arguments by splitting $ARGUMENTS on whitespace. Examples:
/check-milestones alice -> username=alice, filter=recent 50
/check-milestones alice all -> username=alice, filter=all PRs (past 30 days)
/check-milestones alice 100,105,110 -> username=alice, filter=only those PRs
Step 1: Gather Information
Auto-detect the repository:
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
Run these in parallel:
-
Fetch PRs (method depends on the second argument):
- Default (no second arg): Use
gh pr list --repo $REPO --author <username> --state closed --limit 50 --json number,title,mergedAt,mergeCommit,labels,body,url,baseRefName,milestone --jq 'sort_by(.mergedAt)'
all: Use
gh pr list --repo $REPO --author <username> --state closed --limit 200 --search "closed:>YYYY-MM-DD" --json number,title,mergedAt,mergeCommit,labels,body,url,baseRefName,milestone --jq 'sort_by(.mergedAt)'
where YYYY-MM-DD is 30 days ago from today.
- Comma-separated PR list: For each PR number, use
gh pr view <number> --repo $REPO --json number,title,mergedAt,mergeCommit,labels,body,url,baseRefName,milestone.
Collect results sorted by mergedAt.
Skip any PR where mergedAt is null (not merged).
-
Auto-detect milestone naming convention: Fetch existing milestones from
the repo to understand the naming pattern:
gh api "repos/$REPO/milestones" --paginate --jq '.[].title' | sort -V
From the existing milestones, detect the naming convention. Common patterns:
v1.2.3 (semver)
1.89.x - Nightly (channel-based)
Sprint 42 (sprint-based)
2024-Q1 (quarter-based)
Release 5.0 (release-based)
-
Detect the default branch and release branches:
DEFAULT_BRANCH=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')
gh api "repos/$REPO/branches" --paginate --jq '.[].name' | grep -E '(release|v?[0-9]+\.[0-9]+)' | sort -V
Step 2: Determine Correct PR Milestones
For each merged PR, determine the correct milestone based on its baseRefName
(the branch it was merged into):
- If
baseRefName is the default branch (main or master) -> the milestone
corresponding to the development/nightly channel
- If
baseRefName matches a release branch -> the milestone corresponding to
that release version
To map branches to milestones, use the auto-detected milestone naming convention
from Step 1. Match the version number in the branch name to the closest
milestone.
Compare the PR's current milestone (from the milestone field) against the
correct one. If they differ (or the milestone is not set), add the PR to the
list of PRs that need updating.
Step 3: Determine Correct Issue Milestones
For each merged PR, extract the associated issue number(s) from the PR body.
Look for patterns like:
Resolves #XXXXX or Resolves OWNER/REPO#XXXXX
Fixes #XXXXX or Fixes OWNER/REPO#XXXXX
Closes #XXXXX or Closes OWNER/REPO#XXXXX
Fixes https://github.com/OWNER/REPO/issues/XXXXX
Resolves https://github.com/OWNER/REPO/issues/XXXXX
For each associated issue:
-
Find all PRs that reference this issue -- check if the issue has
cherry-pick/uplift PRs by searching for other merged PRs that reference the
same issue across different branches:
gh api search/issues --method GET \
-f q="repo:$REPO is:pr is:merged $ISSUE_NUMBER" \
--jq '.items[] | {number, title, html_url}'
-
Determine which branches this fix has been merged into (considering
cherry-picks/uplifts):
- The original PR's base branch
- Any cherry-pick/uplift PRs merged into release branches
-
The correct issue milestone is the smallest version where the fix is
merged. Use the version ordering from the auto-detected milestones to
determine which is smallest.
-
Check the issue's current milestone and compare:
gh issue view <ISSUE_NUMBER> --repo $REPO --json milestone --jq '.milestone.title'
Step 4: Apply Milestone Updates
Update PR Milestones
For each PR that needs a milestone update:
gh pr edit <PR_NUMBER> --repo $REPO --milestone "<milestone-name>"
Update Issue Milestones
For each issue that needs a milestone update:
gh issue edit <ISSUE_NUMBER> --repo $REPO --milestone "<milestone-name>"
Important: Only update an issue's milestone to a smaller version number
than what is currently set. For example:
- Milestone is unset -> set it to the computed milestone
- Milestone is a development/nightly milestone but fix was cherry-picked to a
release branch -> update to the release milestone
- Do NOT update if the current milestone already has a smaller version number
than the computed one
Step 5: Summary
Output a clear summary of all actions taken:
PR Milestones Updated:
| PR | Title | Base Branch | Old Milestone | New Milestone |
|---|
| #XXXXX | PR title | main | (none) | v2.1.0 |
Issue Milestones Updated:
| Issue | Old Milestone | New Milestone | Reason |
|---|
| #XXXXX | (none) | v2.0.1 | Merged cherry-pick to release (#YY) |
Already Correct:
List PRs and issues that already had the correct milestone (brief count or
list).
Skipped:
List any PRs or issues that were skipped with the reason (e.g., "no associated
issue", "could not determine branch", "unmerged cherry-pick").