-
Notifications
You must be signed in to change notification settings - Fork 33
147 lines (127 loc) · 5.47 KB
/
release-notification.yml
File metadata and controls
147 lines (127 loc) · 5.47 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
name: Release Notification
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g., v0.1.0)"
required: true
type: string
permissions:
contents: read
issues: write
pull-requests: write
jobs:
notify-release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Comment on PRs and Linked Issues
uses: actions/github-script@v7
with:
script: |
const tag = context.payload.inputs.tag;
const { owner, repo } = context.repo;
const releaseUrl = `https://github.com/${owner}/${repo}/releases/tag/${tag}`;
console.log(`🚀 Start processing version: ${tag}`);
// 1. Find the previous Tag
let prevTag = null;
try {
// Sort by version number descending
const { stdout } = await exec.getExecOutput('git', ['tag', '--list', 'v*', '--sort=-v:refname']);
const tags = stdout.trim().split('\n').filter(Boolean);
const currentIndex = tags.indexOf(tag);
if (currentIndex !== -1 && currentIndex < tags.length - 1) {
prevTag = tags[currentIndex + 1];
}
} catch (error) {
console.log('⚠️ Failed to get Tag list');
}
// If no previous Tag found, exit
if (!prevTag) {
console.log('🛑 Previous version Tag not found, skipping comment process.');
return;
}
const range = `${prevTag}..${tag}`;
console.log(`📍 Analyzing commit range: ${range}`);
// 2. Get Commits within range
let commitShas = [];
try {
const { stdout } = await exec.getExecOutput('git', ['log', '--format=%H', range]);
commitShas = stdout.trim().split('\n').filter(Boolean);
} catch (error) {
console.log('❌ Failed to get commits');
return;
}
if (commitShas.length === 0) return;
console.log(`🔍 Found ${commitShas.length} commits`);
// 3. Find associated PRs
const prNumbers = new Set();
for (const sha of commitShas) {
try {
const { data: pulls } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner,
repo,
commit_sha: sha,
});
pulls.forEach(p => prNumbers.add(p.number));
} catch (e) { }
}
console.log(`📋 Involves PRs: ${Array.from(prNumbers).join(', ')}`);
// 4. Comment on PRs and parse associated Issues
// Regex explanation:
// - /.../gi: g=global, i=case insensitive
// - (?:...): non-capturing group for keywords
// - :?: match optional colon, e.g. "Fixes: #123"
const issueRegex = /(?:close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved):?\s+(?:#(\d+)|https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/(\d+))/gi;
for (const prNumber of prNumbers) {
// A. Comment on PR
const prCommentBody = `🎉 此 PR 的修改已在版本 [${tag}](${releaseUrl}) 中发布。\n🎉 The changes in this PR have been released in version [${tag}](${releaseUrl}).`;
try {
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: prCommentBody
});
console.log(`✅ Commented on PR #${prNumber}`);
} catch (e) {
console.log(`❌ Failed to comment on PR #${prNumber}: ${e.message}`);
}
// B. Find and comment on associated Issue
try {
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: prNumber,
});
if (pr.body) {
const issuesToNotify = new Set();
let match;
// Reset regex index (good practice)
issueRegex.lastIndex = 0;
while ((match = issueRegex.exec(pr.body)) !== null) {
// match[1] is number from #123, match[2] is number from link
issuesToNotify.add(match[1] || match[2]);
}
const issueCommentBody = `✅ 此 Issue 已在版本 [${tag}](${releaseUrl}) 中修复 (通过 PR #${prNumber})。\n✅ This Issue has been fixed in version [${tag}](${releaseUrl}) (via PR #${prNumber}).`;
for (const issueId of issuesToNotify) {
try {
await github.rest.issues.createComment({
owner,
repo,
issue_number: parseInt(issueId, 10),
body: issueCommentBody
});
console.log(`✅ Commented on associated Issue #${issueId}`);
} catch (e) {
console.log(`❌ Failed to comment on Issue #${issueId}: ${e.message}`);
}
}
}
} catch (e) {
console.log(`⚠️ Error processing PR #${prNumber} associated Issues`);
}
}