name: upstream-sync # 上游 ui-ux-pro-max 一有更新,就自动重新封装并开 PR。 # --check 会比对:上游 commit、本地打包内容的逐文件 hash。无漂移时 --check 退出 0,本工作流安静结束。 on: schedule: - cron: '23 4 * * *' workflow_dispatch: push: branches: [main] permissions: contents: write pull-requests: write jobs: test: # 每次 push / PR 都跑一遍插件测试。没有这个 job 时,改动只有等到真正触发 resync # 才会被测到——也就是「上游恰好在这次改动之后更新」的那一刻,太晚。 # matrix 同时把 MIN_VERSION 的设计假设(Python 3.8+)变成实测。 runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: # ubuntu-latest 已是 26.04,它的 python-versions 清单里没有 3.8 的构建, # 所以 3.8 这条必须钉在 22.04 上跑——否则会「因为装不上解释器」而假失败。 include: - python: '3.8' os: ubuntu-22.04 - python: '3.10' os: ubuntu-latest - python: '3.12' os: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '22' - uses: actions/setup-python@v5 with: python-version: '${{ matrix.python }}' - name: 插件测试 run: node --test test/plugin.test.mjs check: runs-on: ubuntu-latest outputs: drift: ${{ steps.check.outcome == 'failure' }} steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '22' - name: 比对上游 id: check continue-on-error: true run: node scripts/vendor.mjs --check resync: needs: check if: needs.check.outputs.drift == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '22' - uses: actions/setup-python@v5 with: python-version: '3.12' - name: 记录上游旧 commit id: before run: echo "commit=$(node -p "require('./upstream.lock.json').sources[0].commit" 2>/dev/null || echo none)" >> "$GITHUB_OUTPUT" - name: 重新封装 run: node scripts/vendor.mjs - name: 递增 patch 版本 id: bump run: | node -e " const fs = require('node:fs'); const pkg = JSON.parse(fs.readFileSync('package.json','utf8')); const [major, minor, patch] = pkg.version.split('.').map(Number); pkg.version = major + '.' + minor + '.' + (patch + 1); fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); fs.appendFileSync(process.env.GITHUB_OUTPUT, 'version=' + pkg.version + '\n'); " - name: 重新打包清单里的版本号 run: | node -e " const fs = require('node:fs'); const pkg = JSON.parse(fs.readFileSync('package.json','utf8')); const m = JSON.parse(fs.readFileSync('skills/upm.manifest.json','utf8')); m.pluginVersion = pkg.version; m.generatedAt = new Date().toISOString(); fs.writeFileSync('skills/upm.manifest.json', JSON.stringify(m, null, 2) + '\n'); " - name: 跑测试 run: node --test test/plugin.test.mjs - name: 自检(打包后必须无漂移) run: node scripts/vendor.mjs --check - name: 推送分支并开 PR env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NEW_VERSION: ${{ steps.bump.outputs.version }} OLD_COMMIT: ${{ steps.before.outputs.commit }} run: | set -euo pipefail NEW_COMMIT=$(node -p "require('./upstream.lock.json').sources[0].commit") SHORT=$(echo "$NEW_COMMIT" | cut -c1-8) BRANCH="upstream-sync/$SHORT" git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git checkout -b "$BRANCH" git add -A if git diff --cached --quiet; then echo "重新封装后没有改动,结束。" exit 0 fi git commit -m "chore: re-vendor ui-ux-pro-max ${OLD_COMMIT:0:8} -> $SHORT (v${NEW_VERSION})" # 幂等:同一上游 commit 的分支可能已经存在(前一次运行推过), # 强制更新而不是让 push 因非快进而失败。 git push --force -u origin "$BRANCH" # 已经是开的 PR 就不再重复创建 EXISTING=$(gh pr list --head "$BRANCH" --state open --json number --jq 'length') if [ "$EXISTING" != "0" ]; then echo "已存在 PR,分支已更新,不重复创建。" exit 0 fi gh pr create \ --title "chore: 上游 ui-ux-pro-max 更新 ${OLD_COMMIT:0:8} → $SHORT" \ --body "自动重新封装。 - 上游:\`${OLD_COMMIT}\` → \`${NEW_COMMIT}\` - 插件版本:v${NEW_VERSION} - \`skills/\` 由 \`scripts/vendor.mjs\` 重建,测试与 \`--check\` 都已通过 合并后请发新版(打 tag 或 \`npm publish\`)。" \ --base main --head "$BRANCH"