Skip to content

Sync Official NestJS Docs #37

Sync Official NestJS Docs

Sync Official NestJS Docs #37

name: Sync Official NestJS Docs
on:
schedule:
# 每天 UTC 时间 02:00 运行(北京时间 10:00)
- cron: '0 2 * * *'
workflow_dispatch:
# 允许手动触发
push:
branches:
- main
paths:
- '.github/workflows/sync-official-docs.yml'
jobs:
sync-docs:
runs-on: ubuntu-latest
env:
# Cloudflare Workers AI 配置
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
steps:
- name: Checkout current repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Setup Git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Update sync time badge JSON (Gist)
if: steps.sync-content.outputs.content_changed == 'true' || steps.translate-content.outputs.translation_changed == 'true' || steps.sync-assets.outputs.assets_changed == 'true'
env:
GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
run: |
SYNC_TIME=$(date -u '+%Y-%m-%d')
cat > sync-summary.json <<EOF
{
"schemaVersion": 1,
"label": "sync-docs",
"message": "$SYNC_TIME",
"color": "brightgreen"
}
EOF
gist_id="b3a004684a48178741a9ab9e1a90ab3e"
file_name="nestjscn-sync-time.json"
curl -X PATCH "https://api.github.com/gists/$gist_id" \
-H "Authorization: token $GIST_TOKEN" \
-d "{\"files\": {\"$file_name\": {\"content\": $(jq -Rs . < sync-summary.json)}}}"
- name: Clone official NestJS docs repository
run: |
git clone --depth 1 https://github.com/nestjs/docs.nestjs.com.git official-docs
- name: Compare and sync content folder
id: sync-content
run: |
if [ ! -d "official-docs/content" ]; then
echo "❌ 官方仓库中未找到 content 文件夹"
exit 1
fi
echo "🔍 正在比较 content 文件夹..."
CONTENT_CHANGED=false
# 检查 content 文件夹是否存在差异
if [ -d "content" ]; then
# 使用 rsync 的 dry-run 模式检查差异
if ! rsync -avu --dry-run --delete official-docs/content/ content/ > /tmp/content-diff.log 2>&1; then
CONTENT_CHANGED=true
elif [ -s /tmp/content-diff.log ]; then
# 检查是否有实际的文件差异(过滤掉仅有的时间戳差异)
if grep -E "^(deleting|>|<|\*)" /tmp/content-diff.log > /dev/null; then
CONTENT_CHANGED=true
fi
fi
else
echo "📁 本地不存在 content 文件夹,将创建"
CONTENT_CHANGED=true
fi
if [ "$CONTENT_CHANGED" = true ]; then
echo "📋 检测到内容变更:"
cat /tmp/content-diff.log || echo "初始同步 - 无差异日志可用"
# 备份现有内容(如果存在)
if [ -d "content" ]; then
echo "💾 正在备份当前内容..."
mv content content-backup-$(date +%Y%m%d-%H%M%S)
fi
# 同步新内容
echo "🔄 正在同步 content 文件夹..."
cp -r official-docs/content ./
echo "✅ content 文件夹同步成功"
echo "content_changed=true" >> $GITHUB_OUTPUT
else
echo "✅ content 文件夹已是最新版本,无需更改"
echo "content_changed=false" >> $GITHUB_OUTPUT
fi
- name: Compare and sync assets folder
id: sync-assets
run: |
ASSETS_CHANGED=false
if [ -d "official-docs/src/assets" ]; then
echo "🔍 正在比较 assets 文件夹..."
# 创建 public 目录(如果不存在)
mkdir -p public
# 检查 assets 文件夹是否存在差异
if [ -d "public/assets" ]; then
# 使用 rsync 的 dry-run 模式检查差异
if ! rsync -avu --dry-run --delete official-docs/src/assets/ public/assets/ > /tmp/assets-diff.log 2>&1; then
ASSETS_CHANGED=true
elif [ -s /tmp/assets-diff.log ]; then
# 检查是否有实际的文件差异
if grep -E "^(deleting|>|<|\*)" /tmp/assets-diff.log > /dev/null; then
ASSETS_CHANGED=true
fi
fi
else
echo "📁 本地不存在 assets 文件夹,将创建"
ASSETS_CHANGED=true
fi
if [ "$ASSETS_CHANGED" = true ]; then
echo "📋 检测到资源变更:"
cat /tmp/assets-diff.log || echo "初始同步 - 无差异日志可用"
# 同步新资源
echo "🔄 正在同步 assets 文件夹..."
rsync -av --delete official-docs/src/assets/ public/assets/
echo "✅ assets 文件夹同步成功"
echo "assets_changed=true" >> $GITHUB_OUTPUT
else
echo "✅ assets 文件夹已是最新版本,无需更改"
echo "assets_changed=false" >> $GITHUB_OUTPUT
fi
else
echo "⚠️ 官方仓库中未找到 assets 文件夹,跳过..."
echo "assets_changed=false" >> $GITHUB_OUTPUT
fi
- name: Clean up
run: |
rm -rf official-docs
- name: Process and translate content changes
id: translate-content
if: steps.sync-content.outputs.content_changed == 'true'
run: |
echo "🔄 正在处理内容变更并进行翻译..."
# 检查是否有可用的 Cloudflare 配置
if [ -n "$CLOUDFLARE_API_TOKEN" ] && [ -n "$CLOUDFLARE_ACCOUNT_ID" ]; then
echo "✅ Cloudflare Workers AI 已配置,使用 AI 翻译"
if bun run translate-docs:verbose; then
echo "✅ 翻译完成,有内容更新"
echo "translation_changed=true" >> $GITHUB_OUTPUT
else
TRANSLATION_EXIT_CODE=$?
if [ $TRANSLATION_EXIT_CODE -eq 1 ]; then
echo "✅ 翻译完成,但无需更新"
echo "translation_changed=false" >> $GITHUB_OUTPUT
else
echo "❌ 翻译失败,退出代码 $TRANSLATION_EXIT_CODE"
echo "translation_changed=error" >> $GITHUB_OUTPUT
exit 1
fi
fi
else
echo "⚠️ 未配置 Cloudflare API 凭据,使用仅格式化模式"
if bun run translate-docs:no-ai; then
echo "✅ 格式处理完成,有内容更新"
echo "translation_changed=true" >> $GITHUB_OUTPUT
else
TRANSLATION_EXIT_CODE=$?
if [ $TRANSLATION_EXIT_CODE -eq 1 ]; then
echo "✅ 格式处理完成,但无需更新"
echo "translation_changed=false" >> $GITHUB_OUTPUT
else
echo "❌ 格式处理失败,退出代码 $TRANSLATION_EXIT_CODE"
echo "translation_changed=error" >> $GITHUB_OUTPUT
exit 1
fi
fi
fi
- name: Fix code blocks and template syntax
if: steps.translate-content.outputs.translation_changed == 'true'
run: |
echo "🔧 正在运行代码块和模板语法修复..."
bun run fix-all
echo "✅ 代码格式化完成"
- name: Update README sync time and check for changes
id: changes
run: |
# 如果有内容同步或翻译更新,更新 README 中的同步时间
if [ "${{ steps.sync-content.outputs.content_changed }}" == "true" ] || [ "${{ steps.translate-content.outputs.translation_changed }}" == "true" ] || [ "${{ steps.sync-assets.outputs.assets_changed }}" == "true" ]; then
echo "📅 正在更新 README.md 中的同步时间..."
# 获取当前时间(北京时间)- 格式: 2025年07月01日 17:48
SYNC_TIME=$(TZ='Asia/Shanghai' date '+%Y年%m月%d日 %H:%M')
# 更新 README.md 中的同步时间标记
sed -i "s|<!-- LAST_SYNC_TIME -->.*<!-- /LAST_SYNC_TIME -->|<!-- LAST_SYNC_TIME --> $SYNC_TIME <!-- /LAST_SYNC_TIME -->|g" README.md
echo "✅ 同步时间已更新为: $SYNC_TIME"
fi
# 检查是否有变更需要提交
git add .
if git diff --cached --quiet; then
echo "未检测到变更"
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "检测到变更"
echo "has_changes=true" >> $GITHUB_OUTPUT
# 输出变更的文件列表
echo "📋 变更的文件:"
git diff --cached --name-status
fi
- name: Commit and push changes
if: steps.changes.outputs.has_changes == 'true'
run: |
# 生成详细的提交信息
COMMIT_MSG="🔄 Sync official NestJS docs content and assets"
if [ "${{ steps.sync-content.outputs.content_changed }}" == "true" ]; then
COMMIT_MSG="${COMMIT_MSG}
📝 Content changes detected and synced"
fi
if [ "${{ steps.translate-content.outputs.translation_changed }}" == "true" ]; then
COMMIT_MSG="${COMMIT_MSG}
🌐 Translations updated with Cloudflare Workers AI"
fi
if [ "${{ steps.sync-assets.outputs.assets_changed }}" == "true" ]; then
COMMIT_MSG="${COMMIT_MSG}
🎨 Assets changes detected and synced"
fi
# 添加同步信息
COMMIT_MSG="${COMMIT_MSG}
🕒 Sync date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
📦 Source: https://github.com/nestjs/docs.nestjs.com"
git commit -m "$COMMIT_MSG"
git push
- name: Create summary
run: |
echo "## 📋 同步摘要" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **同步日期**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "- **源仓库**: https://github.com/nestjs/docs.nestjs.com" >> $GITHUB_STEP_SUMMARY
# Content 同步状态
if [ "${{ steps.sync-content.outputs.content_changed }}" == "true" ]; then
echo "- **内容同步**: ✅ 是(检测到变更并应用)" >> $GITHUB_STEP_SUMMARY
else
echo "- **内容同步**: ✅ 已是最新(无需更改)" >> $GITHUB_STEP_SUMMARY
fi
# 翻译状态
if [ "${{ steps.translate-content.outputs.translation_changed }}" == "true" ]; then
echo "- **翻译更新**: ✅ 是(使用 Cloudflare Workers AI 更新了 docs 文件夹)" >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.translate-content.outputs.translation_changed }}" == "false" ]; then
echo "- **翻译更新**: ✅ 已是最新(无需翻译更改)" >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.sync-content.outputs.content_changed }}" == "true" ]; then
echo "- **翻译更新**: ⚠️ 内容已变更但跳过了翻译" >> $GITHUB_STEP_SUMMARY
else
echo "- **翻译更新**: ➖ 无内容变更需要翻译" >> $GITHUB_STEP_SUMMARY
fi
# Assets 同步状态
if [ "${{ steps.sync-assets.outputs.assets_changed }}" == "true" ]; then
echo "- **资源同步**: ✅ 是(检测到变更并应用)" >> $GITHUB_STEP_SUMMARY
elif [ -d "public/assets" ]; then
echo "- **资源同步**: ✅ 已是最新(无需更改)" >> $GITHUB_STEP_SUMMARY
else
echo "- **资源同步**: ⚠️ 源中未找到" >> $GITHUB_STEP_SUMMARY
fi
# Git 提交状态
if [ "${{ steps.changes.outputs.has_changes }}" == "true" ]; then
echo "- **变更提交**: ✅ 是,变更已提交并推送" >> $GITHUB_STEP_SUMMARY
else
echo "- **变更提交**: ❌ 无变更需要提交" >> $GITHUB_STEP_SUMMARY
fi
- name: Notify on failure
if: failure()
run: |
echo "## ❌ 同步失败" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "同步操作失败。请检查日志了解详细信息。" >> $GITHUB_STEP_SUMMARY
echo "您可以手动重新触发此工作流或调查问题。" >> $GITHUB_STEP_SUMMARY