forked from Ikalus1988/MisakaNet
-
Notifications
You must be signed in to change notification settings - Fork 0
90 lines (77 loc) 路 3.21 KB
/
Copy pathpr-quality-gate.yml
File metadata and controls
90 lines (77 loc) 路 3.21 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
name: PR Quality Gate
# Runs after CI checks complete to apply quality labels
on:
check_run:
types: [completed]
pull_request:
types: [synchronize]
permissions:
pull-requests: write
issues: write
jobs:
quality-labels:
runs-on: ubuntu-latest
if: github.event_name == 'check_run' || github.event_name == 'pull_request'
steps:
- name: Apply quality gate labels
uses: actions/github-script@v9
with:
script: |
// Get the PR number from context
let prNumber;
if (context.eventName === 'check_run') {
const prs = context.payload.check_run.pull_requests;
if (!prs || prs.length === 0) return;
prNumber = prs[0].number;
} else {
prNumber = context.payload.pull_request.number;
}
const owner = context.repo.owner;
const repo = context.repo.repo;
// Get PR details
const pr = await github.rest.pulls.get({
owner, repo, pull_number: prNumber,
});
// Get all check runs for the PR head
const checkRuns = await github.paginate(
github.rest.checks.listForRef,
{ owner, repo, ref: pr.data.head.sha, per_page: 100 }
);
const allPassed = checkRuns.every(cr =>
cr.conclusion === 'success' || cr.conclusion === 'skipped' || cr.conclusion === 'neutral'
);
const anyFailed = checkRuns.some(cr => cr.conclusion === 'failure');
const allComplete = checkRuns.every(cr => cr.status === 'completed');
const existing = pr.data.labels.map(l => l.name);
const toAdd = [];
const toRemove = [];
// needs-rebase: has merge conflicts
if (pr.data.mergeable === false) {
toAdd.push('needs-rebase');
} else {
toRemove.push('needs-rebase');
}
// ready-to-merge: ALL gates must pass
const gateBlocked =
!allComplete || anyFailed || !allPassed || // checks
pr.data.mergeable === false || // conflicts
existing.includes('shape-risk') || // shape
existing.includes('destructive-rewrite') || // destructive
existing.includes('generated-file') || // needs confirm
existing.includes('needs-dco'); // missing signoff
if (!gateBlocked && pr.data.mergeable === true) {
toAdd.push('ready-to-merge');
} else {
toRemove.push('ready-to-merge');
}
// Apply
const uniqueAdd = toAdd.filter(l => !existing.includes(l));
const uniqueRemove = toRemove.filter(l => existing.includes(l));
if (uniqueAdd.length > 0) {
await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: uniqueAdd });
}
for (const label of uniqueRemove) {
try {
await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: label });
} catch (e) {}
}