From 3aafd7b811b34ba138f7f2a51f5b66f6ca4c8cd2 Mon Sep 17 00:00:00 2001 From: Allister MacLeod Date: Wed, 26 Aug 2026 16:10:24 -0400 Subject: [PATCH] Leave a shipped milestone open when it still holds open items The close-on-release step closed the milestone unconditionally. Closing does not close or detach open issues, but it does drop the milestone off the default milestones view and reads its progress bar as complete, so a straggler stops being somewhere anyone looks. Check open_issues before closing. When any remain, leave the milestone open and emit a warning naming each one, so the release log says what needs triage. Still warns rather than fails in every path, including a failed API call, so it cannot block or redden a release. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release-unity.yml | 33 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release-unity.yml b/.github/workflows/release-unity.yml index 71c06dac8b..ed9b9d7f87 100644 --- a/.github/workflows/release-unity.yml +++ b/.github/workflows/release-unity.yml @@ -396,23 +396,40 @@ jobs: } }' - # Close the matching "Unity X.Y.Z" milestone once a production release ships. - # Warns (does not fail) when no open milestone matches, so it never blocks a release. ~Claude + # Close the matching "Unity X.Y.Z" milestone once a production release ships, + # but only when nothing is still open in it. A milestone holding open issues has + # not shipped everything it claims, and closing it drops it off the default + # milestones view -- the issues stay open and stay attached, but they stop being + # somewhere anyone looks. So leave it open and name the stragglers instead. + # Warns, never fails: this step cannot block or redden a release. - name: Close shipped milestone if: ${{ inputs.dryRun == false && inputs.releaseType == 'production' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | title="Unity ${{ inputs.major }}.${{ inputs.minor }}.${{ inputs.patch }}" - num=$(gh api "repos/${{ github.repository }}/milestones?state=open&per_page=100" \ - --jq ".[] | select(.title==\"$title\") | .number") - if [ -n "$num" ]; then - gh api -X PATCH "repos/${{ github.repository }}/milestones/$num" -f state=closed - echo "Closed milestone $title (#$num)" - else + milestone=$(gh api "repos/${{ github.repository }}/milestones?state=open&per_page=100" \ + --jq ".[] | select(.title==\"$title\")" || true) + + if [ -z "$milestone" ]; then echo "::warning::No open milestone titled '$title' to close" + exit 0 fi + num=$(printf '%s' "$milestone" | jq -r '.number') + open_count=$(printf '%s' "$milestone" | jq -r '.open_issues') + + if [ "$open_count" -gt 0 ]; then + echo "::warning::Milestone '$title' still has $open_count open item(s), so it was left OPEN. Move them to the next milestone, then close '$title' by hand." + gh issue list --repo "${{ github.repository }}" --milestone "$title" \ + --state open --limit 100 --json number,title \ + --jq '.[] | "::warning::still open in milestone: #\(.number) \(.title)"' || true + exit 0 + fi + + gh api -X PATCH "repos/${{ github.repository }}/milestones/$num" -f state=closed + echo "Closed milestone $title (#$num)" + lightbeam: needs: package uses: ./.github/workflows/lightBeamRelease.yml