Browse Source

feat: enhance GitHub workflows for branch synchronization

- Added a new manual trigger for the `claude-ci-autofix` workflow to support branch synchronization tasks.
- Implemented a job to sync the `dev` branch with the `main` branch, ensuring only valid branches are used and preserving commits from the `dev` branch.
- Included detailed instructions for conflict resolution during the sync process.
- Updated the `release` workflow to trigger the autofix workflow in case of sync conflicts, providing a summary of the sync status.
ding113 3 months ago
parent
commit
14e3344745
2 changed files with 271 additions and 2 deletions
  1. 134 2
      .github/workflows/claude-ci-autofix.yml
  2. 137 0
      .github/workflows/release.yml

+ 134 - 2
.github/workflows/claude-ci-autofix.yml

@@ -5,12 +5,144 @@ on:
     workflows: ["PR Build Check", "Non-Main Branch CI/CD"]
     types: [completed]
 
+  # 支持手动触发或被其他 workflow 调用
+  workflow_dispatch:
+    inputs:
+      task_type:
+        description: 'Task type (ci-fix or sync-dev)'
+        required: true
+        default: 'ci-fix'
+        type: choice
+        options:
+          - ci-fix
+          - sync-dev
+      target_branch:
+        description: 'Target branch for sync-dev task'
+        required: false
+        default: 'dev'
+        type: string
+      source_branch:
+        description: 'Source branch for sync-dev task'
+        required: false
+        default: 'main'
+        type: string
+      release_tag:
+        description: 'Release tag that triggered sync'
+        required: false
+        type: string
+
 jobs:
+  # Job for dev branch sync (triggered by workflow_dispatch)
+  sync-dev:
+    if: github.event_name == 'workflow_dispatch' && github.event.inputs.task_type == 'sync-dev'
+    runs-on: ubuntu-latest
+    timeout-minutes: 15
+    permissions:
+      contents: write
+      pull-requests: write
+
+    steps:
+      # 安全验证:只允许 dev 分支作为目标,main 分支作为源
+      - name: Validate branch parameters
+        run: |
+          TARGET="${{ github.event.inputs.target_branch }}"
+          SOURCE="${{ github.event.inputs.source_branch }}"
+
+          if [[ "$TARGET" != "dev" ]]; then
+            echo "::error::Security: Only 'dev' branch is allowed as target. Got: $TARGET"
+            exit 1
+          fi
+
+          if [[ "$SOURCE" != "main" ]]; then
+            echo "::error::Security: Only 'main' branch is allowed as source. Got: $SOURCE"
+            exit 1
+          fi
+
+          echo "Branch validation passed: syncing $SOURCE -> $TARGET"
+
+      - name: Checkout code
+        uses: actions/checkout@v5
+        with:
+          ref: ${{ github.event.inputs.target_branch }}
+          fetch-depth: 0
+          token: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
+
+      - name: Run Claude Code for Dev Sync
+        uses: anthropics/claude-code-action@v1
+        env:
+          ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
+        with:
+          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
+          github_token: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
+
+          prompt: |
+            You are a Git branch synchronization assistant for the repository ${{ github.repository }}.
+
+            Context:
+            - Source branch: ${{ github.event.inputs.source_branch }} (contains new release)
+            - Target branch: ${{ github.event.inputs.target_branch }} (needs to be synced)
+            - Release tag: ${{ github.event.inputs.release_tag }}
+
+            Task: Sync the target branch with source branch while preserving target branch's ahead commits.
+
+            ## Instructions:
+
+            1. **Analyze the situation**:
+               ```bash
+               git fetch origin
+               git checkout ${{ github.event.inputs.target_branch }}
+               git log --oneline -10
+               git rev-list --count origin/${{ github.event.inputs.source_branch }}..HEAD
+               ```
+
+            2. **Attempt rebase**:
+               ```bash
+               git rebase origin/${{ github.event.inputs.source_branch }}
+               ```
+
+            3. **If conflicts occur**:
+               - Use `git status` to identify conflicting files
+               - Read conflicting files with Read tool
+               - Analyze the conflict markers (<<<<<<<, =======, >>>>>>>)
+               - Resolve conflicts by choosing the correct version or merging changes
+               - Use Edit tool to fix conflicts
+               - Run `git add <resolved-file>` for each resolved file
+               - Continue with `git rebase --continue`
+               - Repeat until all conflicts are resolved
+
+            4. **Verify the result**:
+               ```bash
+               bun install
+               bun run typecheck
+               bun run lint
+               ```
+
+            5. **Push the synced branch**:
+               ```bash
+               git push origin ${{ github.event.inputs.target_branch }} --force-with-lease
+               ```
+
+            ## Conflict Resolution Guidelines:
+            - For VERSION file: Keep the source branch version (newer release)
+            - For package.json/bun.lockb: Accept source changes, then run `bun install`
+            - For code changes: Prefer target branch changes (feature work) unless they conflict with critical fixes
+            - For config files: Merge both changes if possible
+
+            ## Important:
+            - Preserve all commits from target branch that are ahead of source
+            - Don't lose any feature work
+            - If you cannot resolve a conflict, document it clearly and abort
+
+          claude_args: "--max-turns 999 --allowedTools Read,Write,Edit,Bash(gh:*),Bash(git:*),Bash(bun:*),Bash(npm:*)"
+          use_commit_signing: false
+
   auto-fix:
     # Only run on failure, skip Claude's own fix branches
     if: |
-      github.event.workflow_run.conclusion == 'failure' &&
-      !startsWith(github.event.workflow_run.head_branch, 'claude-fix-')
+      (github.event_name == 'workflow_run' &&
+       github.event.workflow_run.conclusion == 'failure' &&
+       !startsWith(github.event.workflow_run.head_branch, 'claude-fix-')) ||
+      (github.event_name == 'workflow_dispatch' && github.event.inputs.task_type == 'ci-fix')
     runs-on: ubuntu-latest
     timeout-minutes: 15
     permissions:

+ 137 - 0
.github/workflows/release.yml

@@ -370,3 +370,140 @@ jobs:
             org.opencontainers.image.source=https://github.com/${{ github.repository }}
           cache-from: type=gha
           cache-to: type=gha,mode=max
+
+      # 同步 main 分支到 dev 分支 (rebase dev onto main)
+      - name: Sync main to dev branch
+        if: steps.check.outputs.needs_bump == 'true'
+        id: sync_dev
+        continue-on-error: true
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          set -e
+
+          echo "=========================================="
+          echo "Starting dev branch sync after release..."
+          echo "=========================================="
+
+          # 配置 git
+          git config user.name "github-actions[bot]"
+          git config user.email "github-actions[bot]@users.noreply.github.com"
+
+          # 确保在 main 分支的最新状态
+          git fetch origin main
+          git checkout main
+          git reset --hard origin/main
+
+          # 获取 dev 分支
+          echo "Fetching dev branch..."
+          if ! git fetch origin dev:dev 2>/dev/null; then
+            echo "::warning::dev branch not found, skipping sync"
+            echo "sync_status=skipped" >> $GITHUB_OUTPUT
+            echo "sync_reason=dev branch not found" >> $GITHUB_OUTPUT
+            exit 0
+          fi
+
+          # 检查 dev 是否有领先于 main 的 commit
+          git checkout dev
+
+          AHEAD_COUNT=$(git rev-list --count main..dev)
+          BEHIND_COUNT=$(git rev-list --count dev..main)
+
+          echo "Dev branch status:"
+          echo "  - Ahead of main: $AHEAD_COUNT commits"
+          echo "  - Behind main: $BEHIND_COUNT commits"
+
+          # 如果 dev 没有落后于 main,跳过同步
+          if [ "$BEHIND_COUNT" -eq 0 ]; then
+            echo "::notice::dev branch is already up to date with main"
+            echo "sync_status=skipped" >> $GITHUB_OUTPUT
+            echo "sync_reason=already up to date" >> $GITHUB_OUTPUT
+            exit 0
+          fi
+
+          echo ""
+          echo "Attempting to rebase dev onto main..."
+          echo "This will preserve $AHEAD_COUNT commits from dev"
+
+          # 尝试 rebase
+          if git rebase main; then
+            echo "Rebase successful!"
+
+            # 使用 --force-with-lease 安全推送
+            echo "Pushing rebased dev branch..."
+            if git push origin dev --force-with-lease; then
+              echo "::notice::Successfully synced main to dev branch (rebased $AHEAD_COUNT commits)"
+              echo "sync_status=success" >> $GITHUB_OUTPUT
+              echo "ahead_count=$AHEAD_COUNT" >> $GITHUB_OUTPUT
+            else
+              echo "::error::Failed to push rebased dev branch"
+              echo "sync_status=push_failed" >> $GITHUB_OUTPUT
+              echo "sync_reason=push failed, possibly due to concurrent changes" >> $GITHUB_OUTPUT
+              exit 1
+            fi
+          else
+            echo "::warning::Rebase failed due to conflicts, will trigger autofix"
+            git rebase --abort
+            echo "sync_status=conflict" >> $GITHUB_OUTPUT
+            echo "sync_reason=merge conflicts detected" >> $GITHUB_OUTPUT
+            exit 1
+          fi
+
+      # 如果同步失败(冲突),触发 autofix workflow
+      - name: Trigger autofix for sync conflicts
+        if: steps.check.outputs.needs_bump == 'true' && steps.sync_dev.outputs.sync_status == 'conflict'
+        env:
+          GH_TOKEN: ${{ secrets.GH_PAT || secrets.GITHUB_TOKEN }}
+        run: |
+          echo "Triggering Claude CI Auto-Fix workflow for dev sync..."
+
+          # 使用 workflow 文件名而非名称,避免重命名后触发失败
+          if gh workflow run claude-ci-autofix.yml \
+              --field task_type=sync-dev \
+              --field target_branch=dev \
+              --field source_branch=main \
+              --field release_tag=${{ steps.next_version.outputs.new_tag }}; then
+            echo "::notice::Autofix workflow triggered to resolve conflicts"
+          else
+            echo "::error::Failed to trigger autofix workflow. Manual intervention required."
+            echo "::error::Please run: gh workflow run claude-ci-autofix.yml --field task_type=sync-dev --field target_branch=dev --field source_branch=main"
+            exit 1
+          fi
+
+      # 同步结果汇总
+      - name: Sync summary
+        if: steps.check.outputs.needs_bump == 'true' && always()
+        run: |
+          echo "=========================================="
+          echo "Dev Branch Sync Summary"
+          echo "=========================================="
+
+          SYNC_STATUS="${{ steps.sync_dev.outputs.sync_status }}"
+          SYNC_REASON="${{ steps.sync_dev.outputs.sync_reason }}"
+          AHEAD_COUNT="${{ steps.sync_dev.outputs.ahead_count }}"
+
+          case "$SYNC_STATUS" in
+            "success")
+              echo "Status: SUCCESS"
+              echo "Preserved $AHEAD_COUNT commits from dev branch"
+              ;;
+            "skipped")
+              echo "Status: SKIPPED"
+              echo "Reason: $SYNC_REASON"
+              ;;
+            "conflict")
+              echo "Status: CONFLICT - Autofix triggered"
+              echo "Reason: $SYNC_REASON"
+              echo "The Claude CI Auto-Fix workflow has been triggered to resolve conflicts"
+              ;;
+            "push_failed")
+              echo "Status: PUSH FAILED"
+              echo "Reason: $SYNC_REASON"
+              echo "Manual intervention may be required"
+              ;;
+            *)
+              echo "Status: UNKNOWN ($SYNC_STATUS)"
+              ;;
+          esac
+
+          echo "=========================================="