Skip to content

同步招聘信息 #358

同步招聘信息

同步招聘信息 #358

Workflow file for this run

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