@@ -7,6 +7,7 @@ function isBotLogin(login = "") {
77function extractLinkedIssueNumbers ( prBody = "" ) {
88 const closingReferenceRegex =
99 / \b (?: f i x (?: e s | e d ) ? | c l o s e (?: s | d ) ? | r e s o l v e (?: s | d ) ? ) \s * : ? \s * ( (?: # \d + ) (?: \s * (?: , | a n d ) \s * # \d + ) * ) / gi;
10+
1011 const numbers = new Set ( ) ;
1112 let referenceMatch ;
1213
@@ -94,8 +95,7 @@ async function collectLabelsFromLinkedIssues({ github, owner, repo, linkedIssueN
9495
9596 const issueLabelNames = normalizeLabelNames ( issueResponse ?. data ?. labels || [ ] ) ;
9697 console . log (
97- `[sync-issue-labels] Issue #${ issueNumber } labels: ${
98- issueLabelNames . length ? issueLabelNames . join ( ", " ) : "(none)"
98+ `[sync-issue-labels] Issue #${ issueNumber } labels: ${ issueLabelNames . length ? issueLabelNames . join ( ", " ) : "(none)"
9999 } `
100100 ) ;
101101
@@ -133,6 +133,57 @@ async function addLabelsToPullRequest({ github, owner, repo, prNumber, labelsToA
133133 console . log ( `[sync-issue-labels] Added labels to PR #${ prNumber } : ${ labelsToAdd . join ( ", " ) } ` ) ;
134134}
135135
136+ // Logs context that helps diagnose permission / fork / event issues.
137+ function logExecutionDiagnostics ( context , prNumber , owner , repo , isDryRun ) {
138+ const pr = context ?. payload ?. pull_request ;
139+
140+ const baseRepo = pr ?. base ?. repo ?. full_name ;
141+ const headRepo = pr ?. head ?. repo ?. full_name ;
142+ const isFork = Boolean ( pr ?. head ?. repo ?. fork ) || ( baseRepo && headRepo && baseRepo !== headRepo ) ;
143+
144+ console . log ( "[sync-issue-labels] Diagnostics:" ) ;
145+ console . log ( ` eventName=${ context ?. eventName || "(unknown)" } ` ) ;
146+ console . log ( ` action=${ context ?. payload ?. action || "(none)" } ` ) ;
147+ console . log ( ` actor=${ context ?. actor || context ?. payload ?. sender ?. login || "(unknown)" } ` ) ;
148+ console . log ( ` repo=${ owner } /${ repo } ` ) ;
149+ console . log ( ` prNumber=${ prNumber } ` ) ;
150+ console . log ( ` dry_run=${ isDryRun } ` ) ;
151+ if ( pr ) {
152+ console . log ( ` prAuthor=${ pr ?. user ?. login || "(unknown)" } ` ) ;
153+ console . log ( ` baseRepo=${ baseRepo || "(unknown)" } ` ) ;
154+ console . log ( ` headRepo=${ headRepo || "(unknown)" } ` ) ;
155+ console . log ( ` isFork=${ isFork } ` ) ;
156+ console . log ( ` headRef=${ pr ?. head ?. ref || "(unknown)" } ` ) ;
157+ console . log ( ` baseRef=${ pr ?. base ?. ref || "(unknown)" } ` ) ;
158+ } else {
159+ console . log ( " pull_request payload not present (likely workflow_dispatch or API fetch path)." ) ;
160+ }
161+ }
162+
163+ // Formats Octokit/GitHub API errors with useful details.
164+ function logOctokitError ( prefix , error ) {
165+ console . log ( prefix ) ;
166+ console . log ( ` status: ${ error ?. status ?? "(unknown)" } ` ) ;
167+ console . log ( ` message: ${ error ?. message ?? "(none)" } ` ) ;
168+
169+ // Octokit typically provides response.data / response.headers on API errors
170+ if ( error ?. response ?. data ) {
171+ try {
172+ console . log ( ` response.data: ${ JSON . stringify ( error . response . data , null , 2 ) } ` ) ;
173+ } catch {
174+ console . log ( " response.data: (unserializable)" ) ;
175+ }
176+ }
177+
178+ const headers = error ?. response ?. headers ;
179+ if ( headers ) {
180+ // These are the most useful for “Resource not accessible by integration” cases.
181+ console . log ( ` x-accepted-github-permissions: ${ headers [ "x-accepted-github-permissions" ] || "(missing)" } ` ) ;
182+ console . log ( ` x-github-request-id: ${ headers [ "x-github-request-id" ] || "(missing)" } ` ) ;
183+ console . log ( ` github-authentication-token-expiration: ${ headers [ "github-authentication-token-expiration" ] || "(missing)" } ` ) ;
184+ }
185+ }
186+
136187// Main entry point: syncs labels from linked issues to the PR.
137188module . exports = async ( { github, context } ) => {
138189 const { prNumber, isDryRun, owner, repo } = resolveExecutionContext ( context ) ;
@@ -145,10 +196,14 @@ module.exports = async ({ github, context }) => {
145196 `[sync-issue-labels] Processing PR #${ prNumber } in ${ owner } /${ repo } (dry_run=${ isDryRun } ).`
146197 ) ;
147198
199+ // Added diagnostics early, before any API writes.
200+ logExecutionDiagnostics ( context , prNumber , owner , repo , isDryRun ) ;
201+
148202 let prData ;
149203 try {
150204 prData = await getPullRequestData ( { github, context, prNumber } ) ;
151205 } catch ( error ) {
206+ logOctokitError ( `[sync-issue-labels] Failed to fetch PR #${ prNumber } :` , error ) ;
152207 throw new Error ( `[sync-issue-labels] Failed to fetch PR #${ prNumber } : ${ error ?. message || error } ` ) ;
153208 }
154209
@@ -180,8 +235,7 @@ module.exports = async ({ github, context }) => {
180235 const prLabelNames = new Set ( normalizeLabelNames ( prData ?. labels || [ ] ) ) ;
181236
182237 console . log (
183- `[sync-issue-labels] Existing PR labels: ${
184- prLabelNames . size ? [ ...prLabelNames ] . join ( ", " ) : "(none)"
238+ `[sync-issue-labels] Existing PR labels: ${ prLabelNames . size ? [ ...prLabelNames ] . join ( ", " ) : "(none)"
185239 } `
186240 ) ;
187241 console . log (
@@ -201,8 +255,11 @@ module.exports = async ({ github, context }) => {
201255 try {
202256 await addLabelsToPullRequest ( { github, owner, repo, prNumber, labelsToAdd } ) ;
203257 } catch ( error ) {
258+ // Added rich error logging for permission debugging.
259+ logOctokitError ( `[sync-issue-labels] Failed to add labels to PR #${ prNumber } :` , error ) ;
260+
204261 throw new Error (
205262 `[sync-issue-labels] Failed to add labels to PR #${ prNumber } : ${ error ?. message || error } `
206263 ) ;
207264 }
208- } ;
265+ } ;
0 commit comments