forked from siyuan-note/bazaar
-
Notifications
You must be signed in to change notification settings - Fork 0
216 lines (202 loc) · 9.29 KB
/
Copy pathpr-check.yml
File metadata and controls
216 lines (202 loc) · 9.29 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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
name: PR Check
# REF https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
#
# 触发:
# - pull_request_target:PR 打开 / 同步 / 重开 / 打 Check 标签时检查
# - schedule / workflow_dispatch:复检开放中的 ci-failed PR(作者常只改包仓库 Release)
# schedule 按评论 meta 指纹变更 / 退避到期筛选;workflow_dispatch 强制全选(仍受 SELECT_LIMIT)
#
# 标签:
# - Check:维护者打标以立即重跑本检查(打标后会自动去掉)
# - ci-skip:维护者打标则跳过检查(与 Check 同时存在时以 ci-skip 为准)
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
- labeled
branches:
- main
paths:
- plugins.txt
- themes.txt
- icons.txt
- templates.txt
- widgets.txt
# 黑名单路径:用于触发检查(命中后由 Go 以 FlowError 失败,不跑包检查)
- config/themes-theme-js-allowlist.txt
- stage/**
schedule:
# 每 20 分钟:select 按指纹 / 退避筛选后再全检
- cron: '7,27,47 * * * *'
workflow_dispatch:
# pull_request_target:同一 PR 重复触发时取消整次旧 run(含 prepare),减轻双开竞态
# schedule / workflow_dispatch:用 run_id 互不取消;同 PR 仍靠下方 check job 的 concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
# 产出待检 PR 矩阵:事件 PR 一条,或定时/手动筛选开放 ci-failed
prepare:
if: |
github.repository_owner == 'siyuan-note' &&
(
(
github.event_name == 'pull_request_target' &&
!contains(toJSON(github.event.pull_request.labels.*.name), '"ci-skip"') &&
(github.event.action != 'labeled' || github.event.label.name == 'Check')
) ||
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch'
)
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
pull-requests: read
contents: read
outputs:
matrix: ${{ steps.build.outputs.matrix || steps.build-select.outputs.matrix }}
any: ${{ steps.build.outputs.any || steps.build-select.outputs.any }}
steps:
- name: Build PR matrix (event)
id: build
if: github.event_name == 'pull_request_target'
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
run: |
set -euo pipefail
include=$(jq -nc \
--argjson number "$PR_NUMBER" \
--arg head_sha "$PR_HEAD_SHA" \
--arg base_sha "$PR_BASE_SHA" \
--arg head_repo "$PR_HEAD_REPO" \
'[{number: $number, head_sha: $head_sha, base_sha: $base_sha, head_repo: $head_repo}]')
matrix=$(jq -nc --argjson include "$include" '{include: $include}')
any=$(jq -nc --argjson include "$include" '$include | length > 0')
echo "PRs to check (any=$any): $include"
echo "matrix=$matrix" >> "$GITHUB_OUTPUT"
echo "any=$any" >> "$GITHUB_OUTPUT"
- name: Check out bazaar (select)
if: github.event_name != 'pull_request_target'
uses: actions/checkout@v7
- name: Setup Golang (select)
if: github.event_name != 'pull_request_target'
uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- name: Build PR matrix (schedule / dispatch)
id: build-select
if: github.event_name != 'pull_request_target'
env:
PAT: ${{ secrets.PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# workflow_dispatch:强制纳入全部开放 ci-failed(仍受 SELECT_LIMIT)
SELECT_FORCE_ALL: ${{ github.event_name == 'workflow_dispatch' }}
run: go run ./actions/check -select
check:
needs: prepare
if: needs.prepare.outputs.any == 'true'
# 覆盖默认矩阵名(会把 sha 拼进去);显示 PR 号与 fork owner/repo
name: "#${{ matrix.number }} ${{ matrix.head_repo }}"
runs-on: ubuntu-latest
# 正常单 PR 检查约 1 分钟;用于尽快杀掉卡在 Starting job 的幽灵占用,避免 concurrency 互等
timeout-minutes: 5
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
# 同一 PR 只保留最新一次检查,避免 synchronize / 定时复检重叠写评论
# (与 workflow 级 concurrency 互补:覆盖 schedule 与 PR 事件撞同一 PR 的情况)
concurrency:
group: pr-check-${{ matrix.number }}
cancel-in-progress: true
# 改 PR 标题 / 同步标签 / 请求审查 / 发评论 / 去掉 Check 标签;Release 与签出 fork 仍用 PAT
permissions:
contents: read
issues: write
pull-requests: write
env:
PAT: ${{ secrets.PAT }}
# 须显式传入;仅写 permissions 不会自动注入到进程环境,否则 Go 会回退 PAT
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# 检查通过后请求审查;名单在仓库 Actions Variables(勿写死在代码里)
BAZAAR_REVIEWERS: ${{ vars.BAZAAR_REVIEWERS }}
BAZAAR_HEAD_PATH: .
PR_HEAD_PATH: ./pr-head
PR_BASE_PATH: ./pr-base
CHECK_RESULT_OUTPUT: ./check-result.md
PR_NUMBER: ${{ matrix.number }}
steps:
# 签出 bazaar main 分支最新提交,用于过滤与 name 唯一性检查;fetch-depth: 0 以便后续计算 merge base
- name: Check out bazaar head
uses: actions/checkout@v7
with:
ref: main
fetch-depth: 0
# 获取 PR 的 merge base(与 GitHub "Files changed" 一致),避免 PR 分支未同步最新 main 时 diff 错位
# REF https://docs.github.com/zh/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-comparing-branches-in-pull-requests
- name: Get PR merge base
id: merge-base
run: |
set -e
git fetch origin "pull/${{ matrix.number }}/head:pr-head-ref"
merge_base_sha=$(git merge-base "${{ matrix.base_sha }}" pr-head-ref) || {
echo "::error::Failed to find merge base (e.g. PR branch has no common history with base)."
exit 1
}
if [ -z "$merge_base_sha" ] || [ ${#merge_base_sha} -ne 40 ]; then
echo "::error::Invalid merge base SHA: $merge_base_sha"
exit 1
fi
echo "sha=$merge_base_sha" >> $GITHUB_OUTPUT
# 签出 PR 的 head 提交(PR 分支当前提交)
# checkout@v7 默认拒绝在 pull_request_target 中签出 fork PR 代码;此处仅将列表文件当数据读取,不执行 PR 代码
# REF https://github.com/marketplace/actions/checkout#checkout-multiple-repos-nested
# REF https://github.com/marketplace/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit
# REF https://gh.io/securely-using-pull_request_target
- name: Check out PR head
uses: actions/checkout@v7
with:
path: ${{ env.PR_HEAD_PATH }}
ref: ${{ matrix.head_sha }}
repository: ${{ matrix.head_repo }}
token: ${{ env.PAT }}
allow-unsafe-pr-checkout: true
# 签出 PR 的 merge base 提交(与 GitHub "Files changed" 的基准一致,确保检查的 diff 即本 PR 实际改动)
- name: Check out PR base (merge base)
uses: actions/checkout@v7
with:
path: ${{ env.PR_BASE_PATH }}
ref: ${{ steps.merge-base.outputs.sha }}
- name: Setup Golang
uses: actions/setup-go@v7
with:
go-version-file: 'go.mod'
- name: Go Check
id: go-check
run: go run ./actions/check
# REF https://github.com/marketplace/actions/comment-pull-request
# 无实际变更且 PR 已合并/关闭时 Go 会设 skip_side_effects,避免竞态误评
# result_hash 变化时 Go 输出 comment_mode=recreate,重建评论以便 @ 作者再次收到通知;未变则 upsert
- name: Comment PR with check-result
if: steps.go-check.outputs.skip_side_effects != 'true'
uses: thollander/actions-comment-pull-request@v3
with:
file-path: ${{ env.CHECK_RESULT_OUTPUT }}
comment-tag: check-result
pr-number: ${{ matrix.number }}
mode: ${{ steps.go-check.outputs.comment_mode || 'upsert' }}
# REF https://docs.github.com/zh/rest/issues/labels?apiVersion=2022-11-28#remove-all-labels-from-an-issue
# REF https://docs.github.com/zh/actions/tutorials/authenticate-with-github_token#example-2-calling-the-rest-api
- name: Remove "Check" label
if: always() && github.event_name == 'pull_request_target' && github.event.action == 'labeled' && github.event.label.name == 'Check'
run: |
curl -L \
-X DELETE \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ matrix.number }}/labels/Check"