-
Notifications
You must be signed in to change notification settings - Fork 138
129 lines (112 loc) · 4.75 KB
/
autolabel-pr-issue.yml
File metadata and controls
129 lines (112 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
name: Sync Issue Metadata to PR
on:
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
pull-requests: write
issues: write
contents: read
repository-projects: write
jobs:
sync-pr-metadata:
runs-on: ubuntu-latest
steps:
# Checkout repository
- name: Checkout
uses: actions/checkout@v4
# Extract linked issues from PR
- name: Extract linked issue(s) from PR
id: extract-issues
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.pull_request.number;
const prTitle = context.payload.pull_request.title || '';
const prBody = context.payload.pull_request.body || '';
// Regex patterns to find linked issues
const patterns = [
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)/gi,
/#(\d+)/g
];
const issueNumbers = new Set();
const text = prTitle + ' ' + prBody;
for (const pattern of patterns) {
for (const match of text.matchAll(pattern)) {
issueNumbers.add(match[1]);
}
}
core.setOutput('issues', JSON.stringify(Array.from(issueNumbers)));
core.setOutput('pr', prNumber.toString());
# Sync issue metadata to PR safely
- name: Sync Issue Metadata to PR
if: steps.extract-issues.outputs.issues != '' && steps.extract-issues.outputs.issues != '[]'
uses: actions/github-script@v7
env:
ISSUES_JSON: ${{ steps.extract-issues.outputs.issues }}
PR_NUMBER: ${{ steps.extract-issues.outputs.pr }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// Read inputs from environment variables to avoid YAML quoting issues
const issuesOutput = process.env.ISSUES_JSON || '[]';
const prNumber = parseInt(process.env.PR_NUMBER, 10);
let issues = [];
try {
issues = JSON.parse(issuesOutput);
} catch (e) {
// Clean extra quotes/newlines
const cleaned = issuesOutput.replace(/^\s*['"]?/, '').replace(/['"]?\s*$/, '');
try {
issues = JSON.parse(cleaned);
} catch (err) {
console.error('Failed to parse issues output:', err.message);
console.error('Raw issues output:', JSON.stringify(issuesOutput));
return;
}
}
if (!Array.isArray(issues) || issues.length === 0) {
console.log('No linked issues found');
return;
}
for (const issueNumber of issues) {
try {
// Fetch issue details
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt(issueNumber, 10)
});
console.log(`Syncing metadata from Issue #${issueNumber} to PR #${prNumber}`);
// --- Sync Labels safely using addLabels ---
const issueLabels = Array.isArray(issue.labels) ? issue.labels.map(l => l.name) : [];
if (issueLabels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: issueLabels
});
console.log(`Labels added from issue: ${issueLabels.join(', ')}`);
}
// --- Sync Milestone ---
if (issue.milestone) {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
milestone: issue.milestone.number
});
console.log(`Milestone synced: ${issue.milestone.title}`);
}
// --- Add comment on PR ---
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `✅ Synchronized metadata from Issue #${issueNumber}:\n- Labels: ${issueLabels.length > 0 ? issueLabels.join(', ') : 'None'}\n- Milestone: ${issue.milestone ? issue.milestone.title : 'None'}`
});
} catch (error) {
console.error(`Error syncing issue #${issueNumber} to PR #${prNumber}:`, error);
}
}