forked from babalae/bettergi-scripts-list
-
Notifications
You must be signed in to change notification settings - Fork 0
544 lines (483 loc) · 22.6 KB
/
jsonDataValidation.yml
File metadata and controls
544 lines (483 loc) · 22.6 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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
name: JSON Data Validation
on:
pull_request_target:
types: [opened, synchronize, reopened, edited]
branches:
- main
paths:
- 'repo/pathing/**/*.json'
workflow_dispatch:
inputs:
path:
description: '要验证的路径'
required: true
default: 'repo/pathing'
type: string
auto_fix:
description: '是否自动修复问题'
required: false
default: true
type: boolean
pr_number:
description: '关联的 PR 号'
required: false
type: string
jobs:
validate-json:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Set environment variables based on trigger type
id: set_env
run: |
# 根据触发类型设置环境变量
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
echo "触发类型: PR触发"
echo "trigger_type=pr" >> $GITHUB_OUTPUT
echo "validate_path=pr_files" >> $GITHUB_OUTPUT
echo "auto_fix=true" >> $GITHUB_OUTPUT
echo "pr_number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
echo "head_ref=${{ github.event.pull_request.head.ref }}" >> $GITHUB_OUTPUT
echo "head_repo=${{ github.event.pull_request.head.repo.full_name }}" >> $GITHUB_OUTPUT
echo "base_ref=${{ github.event.pull_request.base.ref }}" >> $GITHUB_OUTPUT
echo "base_sha=${{ github.event.pull_request.base.sha }}" >> $GITHUB_OUTPUT
else
echo "触发类型: 手动触发"
echo "trigger_type=manual" >> $GITHUB_OUTPUT
echo "validate_path=${{ github.event.inputs.path }}" >> $GITHUB_OUTPUT
echo "auto_fix=${{ github.event.inputs.auto_fix }}" >> $GITHUB_OUTPUT
echo "pr_number=${{ github.event.inputs.pr_number }}" >> $GITHUB_OUTPUT
echo "head_ref=" >> $GITHUB_OUTPUT
echo "head_repo=" >> $GITHUB_OUTPUT
echo "base_ref=main" >> $GITHUB_OUTPUT
echo "base_sha=" >> $GITHUB_OUTPUT
fi
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || github.sha }}
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install packaging semver
pip install chardet
- name: Debug file structure
run: |
echo "触发类型: ${{ steps.set_env.outputs.trigger_type }}"
echo "验证路径: ${{ steps.set_env.outputs.validate_path }}"
echo "自动修复: ${{ steps.set_env.outputs.auto_fix }}"
echo "PR号: ${{ steps.set_env.outputs.pr_number }}"
echo "Current directory: $(pwd)"
echo "List files in root:"
ls -la
echo "List files in build directory (if exists):"
if [ -d "build" ]; then
ls -la build/
else
echo "build directory does not exist"
mkdir -p build
fi
- name: Setup Git and repositories
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"
# 设置Git处理中文等特殊字符
git config --global core.quotepath false
# 确保远程仓库设置正确
echo "当前远程仓库配置:"
git remote -v
# 设置变量
MAIN_REPO="${{ github.repository }}"
PR_REPO="${{ github.event.pull_request.head.repo.full_name || github.repository }}"
# 设置上游仓库(upstream)指向主仓库
UPSTREAM_REPO="https://github.com/${MAIN_REPO}.git"
echo "设置upstream指向主仓库: $UPSTREAM_REPO"
git remote remove upstream 2>/dev/null || true
git remote add upstream $UPSTREAM_REPO
# 确保origin指向PR的fork仓库
if [ "$PR_REPO" != "$MAIN_REPO" ] && [ "${{ steps.set_env.outputs.trigger_type }}" = "pr" ]; then
ORIGIN_REPO="https://github.com/${PR_REPO}.git"
echo "PR来自fork仓库,设置origin指向: $ORIGIN_REPO"
else
ORIGIN_REPO=$UPSTREAM_REPO
echo "PR来自同一仓库或非PR触发,origin与upstream相同: $ORIGIN_REPO"
fi
git remote set-url origin $ORIGIN_REPO 2>/dev/null || git remote add origin $ORIGIN_REPO
# 获取最新的主仓库和分支
echo "获取远程分支信息"
git fetch upstream
git fetch origin
# 显示远程仓库配置
echo "更新后的远程仓库配置:"
git remote -v
# 检查是否处于PR环境并切换到正确的分支
if [ "${{ steps.set_env.outputs.trigger_type }}" = "pr" ] && [ -n "${{ steps.set_env.outputs.head_ref }}" ]; then
echo "检测到PR,切换到PR分支: ${{ steps.set_env.outputs.head_ref }}"
if [ "$PR_REPO" != "$MAIN_REPO" ]; then
# fork仓库的PR,需要先创建本地分支追踪fork的远程分支
git checkout -b "${{ steps.set_env.outputs.head_ref }}" --track "origin/${{ steps.set_env.outputs.head_ref }}" || \
git checkout -b "${{ steps.set_env.outputs.head_ref }}" --no-track && \
git push --set-upstream origin "${{ steps.set_env.outputs.head_ref }}"
else
# 同一仓库的PR
git checkout "${{ steps.set_env.outputs.head_ref }}" || git checkout -b "${{ steps.set_env.outputs.head_ref }}"
fi
elif [ -n "${{ github.ref_name }}" ]; then
echo "切换到分支: ${{ github.ref_name }}"
if [[ "${{ github.ref_name }}" == "main" ]]; then
# main分支需要明确指定
git checkout upstream/main -b main
else
git checkout "${{ github.ref_name }}" || git checkout -b "${{ github.ref_name }}"
fi
else
echo "创建临时分支"
git checkout -b temp-validation-branch
fi
- name: Prepare validation script
run: |
# 检查build目录和validate.py文件是否存在
mkdir -p build
if [ ! -f "build/validate.py" ]; then
echo "build/validate.py不存在,跳过获取步骤"
else
echo "build/validate.py已存在,检查文件头部"
head -n 5 build/validate.py
fi
- name: Get PR information for workflow_dispatch
if: ${{ steps.set_env.outputs.trigger_type == 'manual' && steps.set_env.outputs.pr_number != '' }}
id: pr_info
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
try {
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: parseInt(${{ steps.set_env.outputs.pr_number }})
});
core.setOutput('head_sha', pr.data.head.sha);
core.setOutput('head_ref', pr.data.head.ref);
core.setOutput('head_repo', pr.data.head.repo.full_name);
core.setOutput('found', 'true');
console.log(`找到 PR #${{ steps.set_env.outputs.pr_number }}`);
console.log(`Head SHA: ${pr.data.head.sha}`);
console.log(`Head Ref: ${pr.data.head.ref}`);
console.log(`Head Repo: ${pr.data.head.repo.full_name}`);
// 如果找到PR,切换到PR分支
const exec = require('child_process').execSync;
if (pr.data.head.ref) {
console.log(`切换到PR分支: ${pr.data.head.ref}`);
exec(`git checkout ${pr.data.head.ref} || git checkout -b ${pr.data.head.ref}`);
}
} catch (error) {
console.log(`获取 PR #${{ steps.set_env.outputs.pr_number }} 信息失败: ${error.message}`);
core.setOutput('found', 'false');
}
- name: Get changed files for PR trigger
id: changed_files
if: ${{ steps.set_env.outputs.trigger_type == 'pr' }}
run: |
# 输出分支信息便于调试
echo "当前分支: $(git branch --show-current)"
echo "HEAD指向: $(git rev-parse HEAD)"
echo "PR基础分支: ${{ steps.set_env.outputs.base_ref }}"
# 确保有upstream/main分支
git fetch upstream main
echo "Upstream/main SHA: $(git rev-parse upstream/main)"
# 创建临时变量来存储修改的文件列表
CHANGED_FILES=""
# 方法1:尝试使用git diff检测变化
echo "检测方法1: 使用git diff检测"
FILES_METHOD_1=$(git diff --name-only upstream/main HEAD | grep -E '^repo/pathing/.*\.json$' || true)
if [ -n "$FILES_METHOD_1" ]; then
echo "方法1找到的JSON文件:"
echo "$FILES_METHOD_1"
CHANGED_FILES="$FILES_METHOD_1"
else
echo "方法1未找到修改的JSON文件"
fi
# 方法2:如果方法1失败,尝试直接查询PR API获取修改的文件
if [ -z "$CHANGED_FILES" ] && [ -n "${{ steps.set_env.outputs.pr_number }}" ]; then
echo "检测方法2: 使用GitHub API检测"
PR_FILES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.set_env.outputs.pr_number }}/files" | \
jq -r '.[] | select(.filename | test("^repo/pathing/.*\\.json$")) | .filename')
if [ -n "$PR_FILES" ]; then
echo "方法2找到的JSON文件:"
echo "$PR_FILES"
CHANGED_FILES="$PR_FILES"
else
echo "方法2未找到修改的JSON文件"
fi
fi
# 方法3:如果前两种方法都失败,列出所有repo/pathing中的JSON文件,但限制在最近修改的
if [ -z "$CHANGED_FILES" ]; then
echo "检测方法3: 列出最近修改的JSON文件"
# 列出过去5次提交中修改的JSON文件
RECENT_FILES=$(git log -n 5 --name-only --pretty=format: | grep -E '^repo/pathing/.*\.json$' | sort -u || true)
if [ -n "$RECENT_FILES" ]; then
echo "最近修改的JSON文件:"
echo "$RECENT_FILES"
CHANGED_FILES="$RECENT_FILES"
echo "⚠️ 警告: 使用最近修改的文件作为回退方案"
else
echo "方法3未找到最近修改的JSON文件"
fi
fi
# 最后回退方案:直接指定验证目录
if [ -z "$CHANGED_FILES" ]; then
echo "⚠️ 警告: 所有方法均未检测到修改的JSON文件,将验证整个repo/pathing目录"
CHANGED_FILES="repo/pathing"
fi
# 输出结果
echo "最终找到的修改文件:"
echo "$CHANGED_FILES"
# 使用base64编码保存文件列表,避免特殊字符问题
echo "changed_files=$(echo "$CHANGED_FILES" | base64 -w 0)" >> $GITHUB_OUTPUT
- name: Run validation for PR trigger
if: ${{ steps.set_env.outputs.trigger_type == 'pr' }}
env:
GITHUB_ACTOR: ${{ github.actor }}
PR_NUMBER: ${{ steps.set_env.outputs.pr_number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_REF: ${{ steps.set_env.outputs.head_ref }}
PR_REPO: ${{ steps.set_env.outputs.head_repo || github.repository }}
CHANGED_FILES_B64: ${{ steps.changed_files.outputs.changed_files }}
run: |
set -e
# 使用base64解码文件列表
CHANGED_FILES=$(echo "$CHANGED_FILES_B64" | base64 --decode)
echo "进行地图追踪目录结构校验"
# 地图追踪目录结构校验
echo "🔍 开始地图追踪目录结构校验..."
: > validation_output.log
set +e
python build/validate.py "repo/pathing" --structure 2>&1 | tee -a validation_output.log
PY_EXIT=$?
set -e
# 检查目录结构校验结果
if [ $PY_EXIT -ne 0 ]; then
echo "❌ pathing目录结构校验失败"
VALIDATION_FAILED=true
elif grep -E "❌.*目录结构错误" -q validation_output.log; then
echo "❌ 检测到地图追踪目录结构错误"
VALIDATION_FAILED=true
else
echo "✅ 地图追踪目录结构校验通过"
VALIDATION_FAILED=false
fi
# 如果目录结构校验失败,直接退出
if [ "$VALIDATION_FAILED" = true ]; then
echo "检测到地图追踪目录结构错误,生成校验说明并标记失败"
{
echo "### ❌ 地图追踪目录结构校验失败"
echo "请前往 Actions 查看报错详情(运行日志)。"
} > validation_notes.md
exit 1
fi
# 目录结构校验通过后,继续验证修改的JSON文件
echo "PR 触发模式,验证修改的 JSON 文件"
if [ -z "$CHANGED_FILES" ]; then
echo "没有找到修改的 JSON 文件,跳过JSON内容验证"
exit 0
fi
# 检查Python解释器编码设置
echo "Python编码设置:"
python -c "import sys; print(sys.getdefaultencoding())"
# 重新初始化日志文件用于JSON内容校验
: > validation_output.log
VALIDATION_FAILED=false
# 验证修改的文件格式
echo "$CHANGED_FILES" > temp_file_list.txt
# 单独验证每个修改的文件,使用while读取避免文件名中的空格和特殊字符问题
while IFS= read -r file; do
echo "验证文件: $file"
if [ -f "$file" ]; then
set +e
python build/validate.py "$file" --fix 2>&1 | tee -a validation_output.log
PY_EXIT=$?
set -e
if [ $PY_EXIT -ne 0 ]; then
VALIDATION_FAILED=true
fi
else
echo "警告: 文件不存在 - $file"
fi
done < temp_file_list.txt
rm temp_file_list.txt
# 检查是否有文件被修改
if [ -n "$(git status --porcelain)" ]; then
echo "发现修改,提交更改"
git add .
git commit -m "自动修复 JSON 格式和版本号 [ci skip]"
# 确定当前分支
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "当前分支: ${CURRENT_BRANCH}"
if [ "$CURRENT_BRANCH" = "HEAD" ]; then
# 如果在detached HEAD状态,使用正确的方式推送
if [ -n "${HEAD_REF}" ]; then
echo "在detached HEAD状态,使用HEAD_REF推送: ${HEAD_REF}"
git push origin HEAD:${HEAD_REF}
else
echo "无法确定目标分支,跳过推送"
fi
else
# 常规推送
echo "推送到分支: ${CURRENT_BRANCH}"
git push origin ${CURRENT_BRANCH}
fi
else
echo "没有文件被修改,无需提交"
fi
# 基于日志内容二次判定失败(validate.py 若未正确返回非零时)
if grep -E "❌|JSON 格式错误|JSON格式错误|Expecting property name enclosed in double quotes|Traceback|Error:" -q validation_output.log; then
VALIDATION_FAILED=true
fi
if [ "$VALIDATION_FAILED" = true ]; then
echo "检测到校验错误,生成校验说明并标记失败"
{
echo "### ❌ 校验失败"
echo "请前往 Actions 查看报错详情(运行日志)。"
} > validation_notes.md
exit 1
fi
- name: Run validation for manual trigger
if: ${{ steps.set_env.outputs.trigger_type == 'manual' }}
env:
GITHUB_ACTOR: ${{ github.actor }}
PR_NUMBER: ${{ steps.set_env.outputs.pr_number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_REF: ${{ steps.pr_info.outputs.head_ref || '' }}
PR_REPO: ${{ steps.pr_info.outputs.head_repo || github.repository }}
VALIDATE_PATH: ${{ steps.set_env.outputs.validate_path }}
AUTO_FIX: ${{ steps.set_env.outputs.auto_fix }}
run: |
set -e
echo "手动触发模式,验证路径: ${VALIDATE_PATH}"
# 使用引号包裹路径,处理特殊字符
: > validation_output.log
set +e
python build/validate.py "${VALIDATE_PATH}" $([[ "${AUTO_FIX}" == "true" ]] && echo "--fix") 2>&1 | tee -a validation_output.log
PY_EXIT=$?
set -e
VALIDATION_FAILED=false
if [ $PY_EXIT -ne 0 ]; then
VALIDATION_FAILED=true
fi
if grep -E "❌|JSON 格式错误|JSON格式错误|Expecting property name enclosed in double quotes|Traceback|Error:" -q validation_output.log; then
VALIDATION_FAILED=true
fi
if [ "$VALIDATION_FAILED" = true ]; then
{
echo "### ❌ 校验失败"
echo "请前往 Actions 查看报错详情(运行日志)。"
} > validation_notes.md
fi
# 检查是否有文件被修改
if [ -n "$(git status --porcelain)" ]; then
echo "发现修改,提交更改"
git add .
git commit -m "自动修复 JSON 格式和版本号 [ci skip]"
# 如果关联了PR,尝试提交更改到PR
if [ -n "$PR_NUMBER" ] && [ -n "$HEAD_REF" ]; then
echo "提交更改到PR: #$PR_NUMBER"
# 确定当前分支
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
echo "当前分支: ${CURRENT_BRANCH}"
if [ "$CURRENT_BRANCH" = "HEAD" ]; then
# 如果在detached HEAD状态,使用正确的方式推送
echo "在detached HEAD状态,使用HEAD_REF推送: ${HEAD_REF}"
git push origin HEAD:${HEAD_REF}
else
# 常规推送
echo "推送到分支: ${CURRENT_BRANCH}"
git push origin ${CURRENT_BRANCH}
fi
else
# 未关联PR或无法确定分支,直接提交到main分支
echo "未关联PR或无法确定分支,直接提交到main分支"
# 保存修改的文件列表
MODIFIED_FILES=$(git status --porcelain | grep -E "^ M|^M" | awk '{print $2}')
echo "已修改的文件:"
echo "$MODIFIED_FILES"
# 将修改的文件保存到临时目录
TEMP_DIR=$(mktemp -d)
echo "创建临时目录: $TEMP_DIR"
for file in $MODIFIED_FILES; do
# 确保目标目录存在
mkdir -p "$TEMP_DIR/$(dirname "$file")"
# 复制修改后的文件到临时目录
cp "$file" "$TEMP_DIR/$file"
echo "已复制文件: $file"
done
# 切换到main分支
git fetch upstream main
git checkout -b temp-main upstream/main
# 从临时目录复制修改后的文件到main分支
for file in $MODIFIED_FILES; do
# 确保目标目录存在
mkdir -p "$(dirname "$file")"
# 复制文件
cp "$TEMP_DIR/$file" "$file"
echo "已应用修改到main分支: $file"
done
# 提交并推送
git add .
git commit -m "自动修复 JSON 格式和版本号 [ci skip]"
git push upstream temp-main:main
fi
else
echo "没有文件被修改,无需提交"
fi
if [ "$VALIDATION_FAILED" = true ]; then
exit 1
fi
- name: Add PR comment
if: ${{ always() && ((steps.set_env.outputs.trigger_type == 'pr') || (steps.set_env.outputs.trigger_type == 'manual' && steps.set_env.outputs.pr_number != '' && steps.pr_info.outputs.found == 'true')) }}
continue-on-error: true
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const pr_number = ${{ steps.set_env.outputs.pr_number }};
if (fs.existsSync('validation_notes.md')) {
const message = fs.readFileSync('validation_notes.md', 'utf8');
await github.rest.issues.createComment({
issue_number: pr_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});
} else {
console.log("没有发现 validation_notes.md 文件");
// 检查是否有文件被修改并提交
const { execSync } = require('child_process');
let commitMessage = '';
try {
const lastCommit = execSync('git log -1 --pretty=%B').toString().trim();
if (lastCommit.includes('自动修复')) {
commitMessage = '✅ 校验完成并自动修复了一些问题。修改已提交到PR中。';
} else {
commitMessage = '✅ 校验完成,没有发现需要修复的问题';
}
} catch (error) {
commitMessage = '✅ 校验完成,没有发现需要修复的问题';
}
await github.rest.issues.createComment({
issue_number: pr_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: commitMessage
});
}