1818 - name : Checkout
1919 uses : actions/checkout@v4
2020
21- # Step 1: Extract linked issues
22- - name : Extract linked issue(s)
21+ - name : Extract linked issue(s) from PR
2322 id : extract-issues
2423 uses : actions/github-script@v7
2524 with :
3130 const prTitle = context.payload.pull_request.title || '';
3231 const prBody = context.payload.pull_request.body || '';
3332
33+ // Regex patterns for issue references
3434 const patterns = [
3535 /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi,
3636 /#(\d+)/g
@@ -45,86 +45,74 @@ jobs:
4545 }
4646 }
4747
48- core.setOutput('result', JSON.stringify({ issues: Array.from(issueNumbers), pr: prNumber }));
48+ // Use core.setOutput instead of return
49+ core.setOutput('issues', JSON.stringify(Array.from(issueNumbers)));
50+ core.setOutput('pr', prNumber.toString());
4951
50- # Step 2: Sync metadata
5152 - name : Sync Issue Metadata to PR
53+ if : steps.extract-issues.outputs.issues != '[]'
5254 uses : actions/github-script@v7
53- env :
54- RESULT_JSON : ${{ steps.extract-issues.outputs.result }}
5555 with :
5656 github-token : ${{ secrets.GITHUB_TOKEN }}
5757 script : |
58- const core = require('@actions/core');
58+ const issueNumbers = JSON.parse('${{ steps.extract-issues.outputs.issues }}');
59+ const prNumber = parseInt('${{ steps.extract-issues.outputs.pr }}');
5960
60- // Parse JSON safely
61- let data;
62- try {
63- data = JSON.parse(process.env.RESULT_JSON);
64- if (typeof data === 'string') data = JSON.parse(data);
65- } catch (err) {
66- core.setFailed(`Failed to parse JSON: ${err.message}\nRaw: ${process.env.RESULT_JSON}`);
67- return;
68- }
69-
70- const prNumber = data.pr;
71- const issueNumbers = data.issues || [];
72-
73- if (!issueNumbers.length) {
74- console.log("No linked issues found.");
61+ if (issueNumbers.length === 0) {
62+ console.log("No linked issues found");
7563 return;
7664 }
7765
7866 for (const issueNumber of issueNumbers) {
79- let issue;
8067 try {
81- const res = await github.rest.issues.get({
68+ // Fetch issue
69+ const { data: issue } = await github.rest.issues.get({
8270 owner: context.repo.owner,
8371 repo: context.repo.repo,
8472 issue_number: parseInt(issueNumber)
8573 });
86- issue = res.data;
87- } catch (err) {
88- console.warn(`Cannot access Issue #${issueNumber}, skipping sync.`);
89- continue; // skip to next issue
90- }
91-
92- console.log(`Syncing metadata from Issue #${issueNumber} to PR #${prNumber}`);
93-
94- // --- Sync Labels ---
95- const issueLabels = issue.labels.map(l => l.name);
96- const { data: pr } = await github.rest.pulls.get({
97- owner: context.repo.owner,
98- repo: context.repo.repo,
99- pull_number: prNumber
100- });
101- const currentPRLabels = pr.labels.map(l => l.name);
102- const combinedLabels = Array.from(new Set([...currentPRLabels, ...issueLabels]));
103-
104- await github.rest.issues.addLabels({
105- owner: context.repo.owner,
106- repo: context.repo.repo,
107- issue_number: prNumber,
108- labels: combinedLabels
109- });
110- console.log(`Labels applied: ${combinedLabels.join(', ')}`);
111-
112- // --- Sync Milestone ---
113- if (issue.milestone) {
114- await github.rest.issues.update({
74+
75+ console.log(`Syncing metadata from Issue #${issueNumber} to PR #${prNumber}`);
76+
77+ // --- Sync Labels ---
78+ const issueLabels = issue.labels.map(l => l.name);
79+ const { data: pr } = await github.rest.pulls.get({
80+ owner: context.repo.owner,
81+ repo: context.repo.repo,
82+ pull_number: prNumber
83+ });
84+ const currentPRLabels = pr.labels.map(l => l.name);
85+ const combinedLabels = Array.from(new Set([...currentPRLabels, ...issueLabels]));
86+
87+ if (combinedLabels.length > 0) {
88+ await github.rest.issues.setLabels({
89+ owner: context.repo.owner,
90+ repo: context.repo.repo,
91+ issue_number: prNumber,
92+ labels: combinedLabels
93+ });
94+ console.log(`Labels applied: ${combinedLabels.join(', ')}`);
95+ }
96+
97+ // --- Sync Milestone ---
98+ if (issue.milestone) {
99+ await github.rest.issues.update({
100+ owner: context.repo.owner,
101+ repo: context.repo.repo,
102+ issue_number: prNumber,
103+ milestone: issue.milestone.number
104+ });
105+ console.log(`Milestone synced: ${issue.milestone.title}`);
106+ }
107+
108+ // --- Add a comment on PR ---
109+ await github.rest.issues.createComment({
115110 owner: context.repo.owner,
116111 repo: context.repo.repo,
117112 issue_number: prNumber,
118- milestone: issue.milestone.number
113+ body: `✅ Synchronized metadata from Issue #${issueNumber}:\n- Labels: ${issueLabels.length > 0 ? issueLabels.join(', ') : 'None'}\n- Milestone: ${ issue.milestone ? issue.milestone.title : 'None'}`
119114 });
120- console.log(`Milestone synced: ${issue.milestone.title}`);
115+ } catch (error) {
116+ console.error(`Error syncing issue #${issueNumber} to PR #${prNumber}:`, error.message);
121117 }
122-
123- // --- Add a comment on PR ---
124- await github.rest.issues.createComment({
125- owner: context.repo.owner,
126- repo: context.repo.repo,
127- issue_number: prNumber,
128- body: `✅ Synchronized metadata from Issue #${issueNumber}:\nLabels: ${issueLabels.join(', ')}\nMilestone: ${issue.milestone ? issue.milestone.title : 'None'}`
129- });
130118 }
0 commit comments