Repository navigation
236 lines (214 loc) · 8.68 KB
/
Copy pathqq-jobs-sync.yml
File metadata and controls
236 lines (214 loc) · 8.68 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
name: 同步招聘信息
on:
schedule:
- cron: "17 * * * *"
workflow_dispatch:
inputs:
probe_only:
description: 只验证腾讯文档完整性,不修改内容
required: false
default: false
type: boolean
accept_source_deletions:
description: 确认将本次缺失记录标记为源表已移除
required: false
default: false
type: boolean
permissions:
actions: write
contents: write
issues: write
concurrency:
group: ${{ github.repository }}-qq-jobs-sync
cancel-in-progress: false
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
HUGO_VERSION: 0.159.0
PLAYWRIGHT_VERSION: 1.55.0
PYTHONDONTWRITEBYTECODE: "1"
jobs:
sync:
name: 校验、同步并发布
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: 检出最新默认分支
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.repository.default_branch }}
submodules: false
- name: 安装 Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: 还原滚动专用账号会话
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
QQ_STORAGE_STATE_B64: ${{ secrets.QQ_DOCS_STORAGE_STATE_B64 }}
run: |
if [[ -z "$QQ_STORAGE_STATE_B64" ]]; then
echo "缺少 QQ_DOCS_STORAGE_STATE_B64。" >&2
exit 1
fi
STORAGE_STATE="$RUNNER_TEMP/qq-docs-storage-state.json"
SESSION_ARTIFACT_DIR="$RUNNER_TEMP/qq-docs-session-artifacts"
mkdir -p "$SESSION_ARTIFACT_DIR"
session_key="$(printf '%s' "$QQ_STORAGE_STATE_B64" | sha256sum | cut -d ' ' -f 1)"
restored=false
while IFS= read -r run_id; do
candidate_dir="$SESSION_ARTIFACT_DIR/$run_id"
if gh run download "$run_id" \
--name qq-docs-storage-state \
--dir "$candidate_dir" >/dev/null 2>&1; then
encrypted_state="$candidate_dir/qq-docs-storage-state.json.enc"
if [[ ! -f "$encrypted_state" ]]; then
continue
fi
if SESSION_KEY="$session_key" openssl enc -d -aes-256-cbc -pbkdf2 \
-in "$encrypted_state" \
-out "$STORAGE_STATE" \
-pass env:SESSION_KEY; then
restored=true
echo "已恢复最近一次成功运行刷新后的专用账号会话。"
break
fi
echo "::warning::滚动会话无法用当前 Secret 解密,继续查找或回退到初始会话。"
fi
done < <(
gh run list \
--workflow qq-jobs-sync.yml \
--branch "$DEFAULT_BRANCH" \
--status success \
--limit 20 \
--json databaseId \
--jq '.[].databaseId'
)
if [[ "$restored" != "true" ]]; then
printf '%s' "$QQ_STORAGE_STATE_B64" | base64 --decode > "$STORAGE_STATE"
echo "未找到滚动会话,已使用初始专用账号会话。"
fi
chmod 600 "$STORAGE_STATE"
STORAGE_STATE="$STORAGE_STATE" \
python3 -c 'import json, os; state = json.load(open(os.environ["STORAGE_STATE"], encoding="utf-8")); assert isinstance(state.get("cookies"), list) and isinstance(state.get("origins"), list)'
echo "STORAGE_STATE=$STORAGE_STATE" >> "$GITHUB_ENV"
- name: 安装 Playwright Chromium
run: |
python3 -m pip install --disable-pip-version-check "playwright==$PLAYWRIGHT_VERSION"
python3 -m playwright install --with-deps chromium
- name: 运行同步测试
run: python3 -m unittest tests.test_sync_qq_jobs
- name: 双遍读取并校验腾讯文档
shell: bash
run: |
args=(
--storage-state "$STORAGE_STATE"
--timeout-seconds 120
)
if [[ "${{ inputs.probe_only || false }}" == "true" ]]; then
args+=(--probe-only)
else
args+=(--check-links)
fi
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.accept_source_deletions || false }}" == "true" ]]; then
args+=(--accept-source-deletions)
fi
python3 scripts/sync_qq_jobs.py "${args[@]}"
- name: 加密刷新后的专用账号会话
shell: bash
env:
QQ_STORAGE_STATE_B64: ${{ secrets.QQ_DOCS_STORAGE_STATE_B64 }}
run: |
session_key="$(printf '%s' "$QQ_STORAGE_STATE_B64" | sha256sum | cut -d ' ' -f 1)"
SESSION_KEY="$session_key" openssl enc -aes-256-cbc -pbkdf2 -salt \
-in "$STORAGE_STATE" \
-out "$RUNNER_TEMP/qq-docs-storage-state.json.enc" \
-pass env:SESSION_KEY
chmod 600 "$RUNNER_TEMP/qq-docs-storage-state.json.enc"
- name: 保存滚动专用账号会话
uses: actions/upload-artifact@v4
with:
name: qq-docs-storage-state
path: ${{ runner.temp }}/qq-docs-storage-state.json.enc
if-no-files-found: error
retention-days: 30
- name: 检查生成文件范围
id: changes
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.probe_only) }}
shell: bash
run: |
allowed='^(data/jobs/(daily-updates|early-recruitment)\.json|content/docs/jobs/(每日更新|秋招提前批)\.md)$'
changed_files="$(git -c core.quotepath=false diff --name-only)"
unexpected="$(printf '%s\n' "$changed_files" | sed '/^$/d' | grep -Ev "$allowed" || true)"
if [[ -n "$unexpected" ]]; then
echo "同步产生了白名单外改动:" >&2
echo "$unexpected" >&2
exit 1
fi
if [[ -z "$changed_files" ]]; then
echo "updated=false" >> "$GITHUB_OUTPUT"
else
echo "updated=true" >> "$GITHUB_OUTPUT"
git diff --check -- \
data/jobs/daily-updates.json \
data/jobs/early-recruitment.json \
content/docs/jobs/每日更新.md \
content/docs/jobs/秋招提前批.md
fi
- name: 初始化主题子模块
if: steps.changes.outputs.updated == 'true'
run: git submodule update --init --recursive
- name: 安装 Hugo
if: steps.changes.outputs.updated == 'true'
uses: peaceiris/actions-hugo@v3
with:
hugo-version: ${{ env.HUGO_VERSION }}
extended: true
- name: 构建整站
if: steps.changes.outputs.updated == 'true'
run: hugo --minify
- name: 校验搜索索引收录
if: steps.changes.outputs.updated == 'true'
run: python3 scripts/check_search_index.py --site public
- name: 提交并推送招聘信息
if: steps.changes.outputs.updated == 'true'
shell: bash
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -- \
data/jobs/daily-updates.json \
data/jobs/early-recruitment.json \
content/docs/jobs/每日更新.md \
content/docs/jobs/秋招提前批.md
git commit -m "更新招聘信息"
git push origin "HEAD:$DEFAULT_BRANCH"
- name: 触发现有 Pages 发布工作流
if: steps.changes.outputs.updated == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: gh workflow run static.yml --ref "$DEFAULT_BRANCH"
report_failure:
name: 报告同步失败
needs: sync
if: ${{ always() && needs.sync.result == 'failure' }}
runs-on: ubuntu-latest
steps:
- name: 创建或更新故障 Issue
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
shell: bash
run: |
title='招聘信息同步失败'
printf -v body '招聘信息同步未通过完整性门槛,现有站点内容保持不变。\n\n运行:%s\n触发方式:%s\n提交:%s' \
"$RUN_URL" "${{ github.event_name }}" "${{ github.sha }}"
issue_number="$(gh issue list --state open --search "$title in:title" --json number,title --jq '.[] | select(.title == "招聘信息同步失败") | .number' | head -n 1)"
if [[ -n "$issue_number" ]]; then
gh issue edit "$issue_number" --body "$body"
else
gh issue create --title "$title" --body "$body"
fi