Link winget PRs to Package Request issues automatically

Scrape the PR URL from wingetcreate's output, open a Package Request issue on first submission, and rewrite the winget-pkgs PR body to fill the Description, tick the issue checkbox, and add Resolves #NNN. This replaces the manual post-release step of editing each PR by hand. Co-Authored-By: siGit Code v1.6.7-acp <noreply@sigit.si>

Seto Elkahfi committed Oct 11, 2026 at 20:34 UTC 1abc3cafe0515c645c1c528ed14cff5b3184f2bc
1 file changed +93 -2
.github/workflows/release-winget.yml
+93 -2
@@ -124,6 +124,7 @@ jobs:
124 run: Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
125
126 - name: Submit new package
127 + id: submit_new
128 if: steps.exists.outputs.found == 'false'
129 shell: pwsh
130 env:
@@ -138,16 +139,28 @@ jobs:
139
140 $version = "${{ steps.release.outputs.version }}"
141
142 + # Tee stdout so we can scrape the PR URL afterwards. wingetcreate
143 + # prints "Pull request can be found here: <url>" on success, and
144 + # that line is the only handle we get on the PR it just opened.
145 # --no-open because the runner has no browser to open the PR in.
146 .\wingetcreate.exe submit manifests `
147 --prtitle "New package: $env:PACKAGE_IDENTIFIER version $version" `
144 - --no-open
148 + --no-open 2>&1 | Tee-Object -Variable output
149
150 if ($LASTEXITCODE -ne 0) {
151 Write-Error "wingetcreate submit failed with exit code $LASTEXITCODE"
152 }
153
154 + $match = [regex]::Match(($output -join "`n"), 'https://github\.com/microsoft/winget-pkgs/pull/(\d+)')
155 + if ($match.Success) {
156 + "pr_url=$($match.Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
157 + "pr_number=$($match.Groups[1].Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
158 + } else {
159 + Write-Warning "Could not find the PR URL in wingetcreate output; skipping issue linking."
160 + }
161 +
162 - name: Submit manifest update
163 + id: submit_update
164 if: steps.exists.outputs.found == 'true'
165 shell: pwsh
166 env:
@@ -171,8 +184,86 @@ jobs:
184 --release-date "${{ steps.release.outputs.date }}" `
185 --prtitle "Update $env:PACKAGE_IDENTIFIER to version $version" `
186 --submit `
174 - --no-open
187 + --no-open 2>&1 | Tee-Object -Variable output
188
189 if ($LASTEXITCODE -ne 0) {
190 Write-Error "wingetcreate failed with exit code $LASTEXITCODE"
191 }
192 +
193 + $match = [regex]::Match(($output -join "`n"), 'https://github\.com/microsoft/winget-pkgs/pull/(\d+)')
194 + if ($match.Success) {
195 + "pr_url=$($match.Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
196 + "pr_number=$($match.Groups[1].Value)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
197 + } else {
198 + Write-Warning "Could not find the PR URL in wingetcreate output; skipping issue linking."
199 + }
200 +
201 + # wingetcreate has no --prbody flag, so it always opens the PR with the
202 + # winget-pkgs template: an empty Description and an unticked
203 + # "Linked to an issue" box next to a "Resolves #[Issue Number]"
204 + # placeholder. We used to tick that box and fill in the issue number by
205 + # hand after every release. This step does it instead.
206 + #
207 + # On a first submission it also files the Package Request issue the
208 + # linkable number comes from. Updates to an existing package don't need
209 + # one (the checkbox is "if applicable"), so there we just fill the
210 + # Description.
211 + - name: Link the winget PR to a Package Request issue
212 + id: link
213 + if: >-
214 + (steps.submit_new.outputs.pr_number != '') ||
215 + (steps.submit_update.outputs.pr_number != '')
216 + shell: bash
217 + env:
218 + # The PR and the issue both live in microsoft/winget-pkgs, which the
219 + # default GITHUB_TOKEN can't write to. Reuse the wingetcreate PAT,
220 + # which already has the scope to open PRs there.
221 + GH_TOKEN: ${{ secrets.WINGET_TOKEN }}
222 + run: |
223 + set -euo pipefail
224 +
225 + PR_URL="${{ steps.submit_new.outputs.pr_url || steps.submit_update.outputs.pr_url }}"
226 + NEW_PACKAGE="${{ steps.exists.outputs.found == 'false' }}"
227 + VERSION="${{ steps.release.outputs.version }}"
228 + TAG="${{ steps.release.outputs.tag }}"
229 +
230 + ISSUE_NUMBER=""
231 + if [ "$NEW_PACKAGE" = "true" ]; then
232 + ISSUE_URL=$(gh issue create \
233 + --repo microsoft/winget-pkgs \
234 + --title "Package Request: ${PACKAGE_IDENTIFIER} ${VERSION}" \
235 + --body "Request to add ${PACKAGE_IDENTIFIER} version ${VERSION} to the Windows Package Manager Community Repository. Installers come from ${TAG} of ${REPO}.")
236 + echo "Opened issue ${ISSUE_URL}"
237 + ISSUE_NUMBER="${ISSUE_URL##*/}"
238 + fi
239 +
240 + # Rewrite the template body: fill the Description, tick the issue
241 + # box when we have an issue, and drop in the real number (or remove
242 + # the placeholder line on updates that aren't linked to anything).
243 + if [ -n "$ISSUE_NUMBER" ]; then
244 + CHECKBOX="- [x] Linked to an issue (if applicable)"
245 + RESOLVES="- Resolves #${ISSUE_NUMBER}"
246 + DESC="Adds ${PACKAGE_IDENTIFIER} version ${VERSION} from ${TAG}."
247 + else
248 + CHECKBOX="- [ ] Linked to an issue (if applicable)"
249 + RESOLVES=""
250 + DESC="Updates ${PACKAGE_IDENTIFIER} to version ${VERSION} from ${TAG}."
251 + fi
252 +
253 + BODY=$(cat <<EOF
254 + ## 📖 Description
255 + ${DESC}
256 + ## ✅ Checklist
257 + - [x] Signed the [Contributor License Agreement](https://cla.opensource.microsoft.com)
258 + ${CHECKBOX}
259 + ${RESOLVES}
260 + ## 📦 Manifest Checklist
261 + - [x] Checked that there aren't other open [pull requests](https://github.com/microsoft/winget-pkgs/pulls) for the same manifest update/change
262 + - [x] This PR only modifies one (1) manifest
263 + - [x] Validated manifest locally with \`winget validate\`
264 + - [x] Tested manifest locally with \`winget install\`
265 + EOF
266 + )
267 +
268 + gh pr edit "$PR_URL" --body "$BODY"
269 + echo "Linked ${PR_URL} to issue #${ISSUE_NUMBER:-<none>}"