上一个提交把 data/forum_posted.json 直接加进 git add, 但该文件只在真正发过帖时才生成。默认关闭发帖时文件不存在, git add 报 "pathspec did not match",导致提交步骤失败(exit 128)。 改为先判断文件是否存在再添加,两种情况都安全。 已在本地用隔离脚本验证: - 文件不存在:add_all 成功,正常提交其他产物 - 文件存在:正确暂存 forum_posted.json
161 lines
6.1 KiB
YAML
161 lines
6.1 KiB
YAML
name: Update deals
|
|
|
|
# 定时抓取 → 生成站点 → 提交回仓库 →(可选)推送到自有服务器
|
|
#
|
|
# 为什么用 GitHub Actions 抓取而不是自有服务器:
|
|
# Actions 每次运行都是**不同的云 IP**,可避开 Cloudflare 对固定 IP 的拦截;
|
|
# 而站点仍可发布到自己的域名与服务器。
|
|
|
|
on:
|
|
schedule:
|
|
# 每 6 小时一次(UTC)。GitHub 的 cron 在高负载时可能延后几分钟,属正常。
|
|
- cron: '17 */6 * * *'
|
|
workflow_dispatch:
|
|
inputs:
|
|
with_replies:
|
|
description: '抓取回帖(库存更准,耗时更长)'
|
|
type: boolean
|
|
default: true
|
|
recent_days:
|
|
description: '只保留最近 N 天(0=全部)'
|
|
type: string
|
|
default: '90'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
# 避免上一次未跑完时重复触发
|
|
concurrency:
|
|
group: update-deals
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
update:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Install test dependency
|
|
run: python -m pip install --upgrade pip pytest
|
|
|
|
- name: Run tests
|
|
run: python -m pytest tests -q
|
|
|
|
- name: Fetch, extract and build site
|
|
env:
|
|
# 站点与域名配置(在仓库 Settings → Variables 中设置)
|
|
LDR_SITE_TITLE: ${{ vars.LDR_SITE_TITLE }}
|
|
LDR_SITE_URL: ${{ vars.LDR_SITE_URL }}
|
|
LDR_SITE_DESC: ${{ vars.LDR_SITE_DESC }}
|
|
LDR_SITE_FOOTER: ${{ vars.LDR_SITE_FOOTER }}
|
|
# 抓取参数:手动触发时用输入值,定时触发时用默认值
|
|
WITH_REPLIES: ${{ github.event.inputs.with_replies || '1' }}
|
|
RECENT_DAYS: ${{ github.event.inputs.recent_days || '90' }}
|
|
PYTHON: python
|
|
run: bash deploy/run_pipeline.sh
|
|
|
|
- name: Verify output is non-empty
|
|
# 安全网:抓取失败或全部被过滤时,拒绝提交,保留上次线上数据
|
|
run: |
|
|
COUNT=$(python -c "import json;print(json.load(open('data/deals.json'))['count'])")
|
|
echo "记录数: $COUNT"
|
|
if [ "$COUNT" -lt 1 ]; then
|
|
echo "::error::记录数为 0,拒绝提交(保留上次数据)"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Upload site artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: site-${{ github.run_number }}
|
|
path: site/
|
|
retention-days: 7
|
|
if-no-files-found: error
|
|
|
|
- name: Post to forum
|
|
# 把优惠帖搬运到 LowSeek 论坛。
|
|
#
|
|
# 默认关闭:LDR_FORUM_ENABLED 未设置时该步骤只打印「已关闭」并退出,
|
|
# 不会发布任何内容。想开启时在仓库 Variables 里设:
|
|
# LDR_FORUM_ENABLED = true
|
|
# LDR_FORUM_DRY_RUN = false (先设 true 可只看演练日志)
|
|
# 并在 Secrets 里配置 LDR_FORUM_API_KEY。
|
|
env:
|
|
LDR_FORUM_ENABLED: ${{ vars.LDR_FORUM_ENABLED || 'false' }}
|
|
LDR_FORUM_DRY_RUN: ${{ vars.LDR_FORUM_DRY_RUN || 'true' }}
|
|
LDR_FORUM_API_KEY: ${{ secrets.LDR_FORUM_API_KEY }}
|
|
LDR_FORUM_URL: ${{ vars.LDR_FORUM_URL || 'https://lowseek.ai' }}
|
|
LDR_FORUM_TAG_ID: ${{ vars.LDR_FORUM_TAG_ID || '21' }}
|
|
LDR_FORUM_MAX_PER_RUN: ${{ vars.LDR_FORUM_MAX_PER_RUN || '3' }}
|
|
LDR_FORUM_MAX_AGE_DAYS: ${{ vars.LDR_FORUM_MAX_AGE_DAYS || '3' }}
|
|
LDR_FORUM_MIN_PERCENT: ${{ vars.LDR_FORUM_MIN_PERCENT || '30' }}
|
|
# 读上一步生成的 deals.json,不重复抓取
|
|
run: python -m letdeals --forum-only
|
|
|
|
- name: Commit refreshed data
|
|
run: |
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
# forum_posted.json 是幂等依据,必须提交;但它只在真正发过帖时
|
|
# 才存在。文件不存在时若直接 git add 会报
|
|
# "pathspec did not match",因此先判断再添加。
|
|
add_all() {
|
|
git add data/deals.json data/deals.md site/
|
|
if [ -f data/forum_posted.json ]; then
|
|
git add data/forum_posted.json
|
|
fi
|
|
}
|
|
|
|
add_all
|
|
if git diff --staged --quiet; then
|
|
echo "无变化,跳过提交"
|
|
exit 0
|
|
fi
|
|
git commit -m "chore: refresh deals [skip ci]"
|
|
|
|
# 远端可能已被另一次运行推进(手动重跑、cron 延迟等),
|
|
# 直接 push 会因非快进而被拒。做法:把 HEAD 移到远端最新提交,
|
|
# 保留我们刚生成的数据(这些是产物,永远以最新一次为准),
|
|
# 在其之上重新提交,从而始终是快进推送。
|
|
git fetch origin main
|
|
git reset --soft origin/main
|
|
add_all
|
|
if git diff --staged --quiet; then
|
|
echo "与远端一致,无需提交"
|
|
else
|
|
git commit -m "chore: refresh deals [skip ci]"
|
|
fi
|
|
git push
|
|
|
|
# 可选:推送到自有服务器(配置 LDR_DEPLOY_HOST 后自动启用)
|
|
- name: Deploy to own server
|
|
if: ${{ vars.LDR_DEPLOY_HOST != '' }}
|
|
env:
|
|
SSH_KEY: ${{ secrets.LDR_DEPLOY_SSH_KEY }}
|
|
HOST: ${{ vars.LDR_DEPLOY_HOST }}
|
|
USER: ${{ vars.LDR_DEPLOY_USER }}
|
|
TARGET: ${{ vars.LDR_DEPLOY_PATH }}
|
|
PORT: ${{ vars.LDR_DEPLOY_PORT || '22' }}
|
|
run: |
|
|
if [ -z "$SSH_KEY" ]; then
|
|
echo "::warning::未配置 LDR_DEPLOY_SSH_KEY,跳过部署"
|
|
exit 0
|
|
fi
|
|
mkdir -p ~/.ssh
|
|
printf '%s\n' "$SSH_KEY" > ~/.ssh/deploy_key
|
|
chmod 600 ~/.ssh/deploy_key
|
|
# 首次连接自动接受主机指纹;更高安全性可改为预置 known_hosts
|
|
ssh-keyscan -p "$PORT" -H "$HOST" >> ~/.ssh/known_hosts 2>/dev/null || true
|
|
rsync -avz --delete -e "ssh -i ~/.ssh/deploy_key -p $PORT" \
|
|
site/ "$USER@$HOST:$TARGET/"
|
|
echo "已推送到 $USER@$HOST:$TARGET"
|