1515 runs-on : ubuntu-latest
1616
1717 steps :
18+ # Step 1: Checkout repository
1819 - name : Checkout
1920 uses : actions/checkout@v4
2021
22+ # Step 2: Extract linked issues from PR
2123 - name : Extract linked issue(s) from PR
2224 id : extract-issues
2325 uses : actions/github-script@v7
2729 const prNumber = context.payload.pull_request.number;
2830 const prTitle = context.payload.pull_request.title || '';
2931 const prBody = context.payload.pull_request.body || '';
30-
31- // Regex patterns for issue references
32+
33+ // Regex patterns to find linked issues
3234 const patterns = [
3335 /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi,
3436 /#(\d+)/g
@@ -42,56 +44,67 @@ jobs:
4244 issueNumbers.add(match[1]);
4345 }
4446 }
45-
46- // Use core.setOutput instead of return
47+
4748 core.setOutput('issues', JSON.stringify(Array.from(issueNumbers)));
4849 core.setOutput('pr', prNumber.toString());
4950
51+ # Step 3: Sync issue metadata to PR safely
5052 - name : Sync Issue Metadata to PR
51- if : steps.extract-issues.outputs.issues != '[]'
53+ if : steps.extract-issues.outputs.issues != '' && steps.extract-issues.outputs.issues != ' []'
5254 uses : actions/github-script@v7
55+ env :
56+ ISSUES_JSON : ${{ steps.extract-issues.outputs.issues }}
57+ PR_NUMBER : ${{ steps.extract-issues.outputs.pr }}
5358 with :
5459 github-token : ${{ secrets.GITHUB_TOKEN }}
5560 script : |
56- const issueNumbers = JSON.parse('${{ steps.extract-issues.outputs.issues }}');
57- const prNumber = parseInt('${{ steps.extract-issues.outputs.pr }}');
58-
59- if (issueNumbers.length === 0) {
60- console.log("No linked issues found");
61+ // Read inputs from environment variables to avoid YAML quoting issues
62+ const issuesOutput = process.env.ISSUES_JSON || '[]';
63+ const prNumber = parseInt(process.env.PR_NUMBER, 10);
64+
65+ let issues = [];
66+ try {
67+ issues = JSON.parse(issuesOutput);
68+ } catch (e) {
69+ // Clean extra quotes/newlines
70+ const cleaned = issuesOutput.replace(/^\s*['"]?/, '').replace(/['"]?\s*$/, '');
71+ try {
72+ issues = JSON.parse(cleaned);
73+ } catch (err) {
74+ console.error('Failed to parse issues output:', err.message);
75+ console.error('Raw issues output:', JSON.stringify(issuesOutput));
76+ return;
77+ }
78+ }
79+
80+ if (!Array.isArray(issues) || issues.length === 0) {
81+ console.log('No linked issues found');
6182 return;
6283 }
63-
64- for (const issueNumber of issueNumbers ) {
84+
85+ for (const issueNumber of issues ) {
6586 try {
66- // Fetch issue
87+ // Fetch issue details
6788 const { data: issue } = await github.rest.issues.get({
6889 owner: context.repo.owner,
6990 repo: context.repo.repo,
70- issue_number: parseInt(issueNumber)
91+ issue_number: parseInt(issueNumber, 10 )
7192 });
7293
7394 console.log(`Syncing metadata from Issue #${issueNumber} to PR #${prNumber}`);
74-
75- // --- Sync Labels ---
76- const issueLabels = issue.labels.map(l => l.name);
77- const { data: pr } = await github.rest.pulls.get({
78- owner: context.repo.owner,
79- repo: context.repo.repo,
80- pull_number: prNumber
81- });
82- const currentPRLabels = pr.labels.map(l => l.name);
83- const combinedLabels = Array.from(new Set([...currentPRLabels, ...issueLabels]));
84-
85- if (combinedLabels.length > 0) {
86- await github.rest.issues.setLabels({
95+
96+ // --- Sync Labels safely using addLabels ---
97+ const issueLabels = Array.isArray(issue.labels) ? issue.labels.map(l => l.name) : [];
98+ if (issueLabels.length > 0) {
99+ await github.rest.issues.addLabels({
87100 owner: context.repo.owner,
88101 repo: context.repo.repo,
89102 issue_number: prNumber,
90- labels: combinedLabels
103+ labels: issueLabels
91104 });
92- console.log(`Labels applied : ${combinedLabels .join(', ')}`);
105+ console.log(`Labels added from issue : ${issueLabels .join(', ')}`);
93106 }
94-
107+
95108 // --- Sync Milestone ---
96109 if (issue.milestone) {
97110 await github.rest.issues.update({
@@ -102,15 +115,15 @@ jobs:
102115 });
103116 console.log(`Milestone synced: ${issue.milestone.title}`);
104117 }
105-
106- // --- Add a comment on PR ---
118+
119+ // --- Add comment on PR ---
107120 await github.rest.issues.createComment({
108121 owner: context.repo.owner,
109122 repo: context.repo.repo,
110123 issue_number: prNumber,
111124 body: `✅ Synchronized metadata from Issue #${issueNumber}:\n- Labels: ${issueLabels.length > 0 ? issueLabels.join(', ') : 'None'}\n- Milestone: ${issue.milestone ? issue.milestone.title : 'None'}`
112125 });
113126 } catch (error) {
114- console.error(`Error syncing issue #${issueNumber} to PR #${prNumber}:`, error.message );
127+ console.error(`Error syncing issue #${issueNumber} to PR #${prNumber}:`, error);
115128 }
116129 }
0 commit comments