name: Forward Port to Next on: push: branches: - main concurrency: group: forward-port cancel-in-progress: false permissions: contents: write pull-requests: write jobs: forward-port: runs-on: ubuntu-latest env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_METRICS_WEBHOOK }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check for existing PR id: check-pr env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | EXISTING_PR=$(gh pr list --base next --head main --state open --json number --jq '.[0].number // empty') if [ -n "$EXISTING_PR" ]; then echo "existing_pr=$EXISTING_PR" >> $GITHUB_OUTPUT echo "PR #$EXISTING_PR already exists for main → next" else echo "existing_pr=" >> $GITHUB_OUTPUT echo "No existing PR found" fi - name: Check if main has changes not in next id: check-diff if: steps.check-pr.outputs.existing_pr == '' run: | git fetch origin next DIFF_COUNT=$(git rev-list --count origin/next..origin/main) echo "diff_count=$DIFF_COUNT" >> $GITHUB_OUTPUT if [ "$DIFF_COUNT" -gt 0 ]; then echo "Found $DIFF_COUNT commit(s) in main not in next" else echo "No new commits to forward port" fi - name: Check for merge conflicts id: check-conflicts if: steps.check-pr.outputs.existing_pr == '' && steps.check-diff.outputs.diff_count != '0' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" # Try a test merge to detect conflicts git checkout origin/next if git merge --no-commit --no-ff origin/main 2>/dev/null; then echo "has_conflicts=false" >> $GITHUB_OUTPUT echo "No merge conflicts detected" else echo "has_conflicts=true" >> $GITHUB_OUTPUT # Get list of conflicting files CONFLICTING_FILES=$(git diff --name-only --diff-filter=U | head -10) echo "conflicting_files<> $GITHUB_OUTPUT echo "$CONFLICTING_FILES" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "Merge conflicts detected in: $CONFLICTING_FILES" fi git merge --abort 2>/dev/null || true - name: Create forward-port PR id: create-pr if: steps.check-pr.outputs.existing_pr == '' && steps.check-diff.outputs.diff_count != '0' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Get the commits being forward-ported for the PR body COMMITS=$(git log origin/next..origin/main --oneline --no-decorate | head -20) COMMIT_COUNT=$(git rev-list --count origin/next..origin/main) # Build conflict warning if needed CONFLICT_WARNING="" if [ "${{ steps.check-conflicts.outputs.has_conflicts }}" = "true" ]; then CONFLICT_WARNING=" > [!WARNING] > **Merge conflicts detected.** Manual resolution required. > > Conflicting files: > \`\`\` > ${{ steps.check-conflicts.outputs.conflicting_files }} > \`\`\` ### How to resolve \`\`\`bash # Option 1: Resolve in a temporary branch (recommended) git fetch origin git checkout -b resolve-forward-port origin/next git merge origin/main # Fix conflicts in your editor, then: git add . git commit git push origin resolve-forward-port # Create PR from resolve-forward-port → next, then close this PR # Option 2: Resolve directly on next git checkout next git pull origin next git merge origin/main # Fix conflicts, commit, and push \`\`\` " fi # Create PR body BODY="## Forward Port: main → next This PR forward-ports changes from \`main\` to \`next\` to ensure hotfixes and releases are included in the next development branch. $CONFLICT_WARNING ### Commits ($COMMIT_COUNT total) \`\`\` $COMMITS \`\`\` $([ "$COMMIT_COUNT" -gt 20 ] && echo "... and $((COMMIT_COUNT - 20)) more") --- *Auto-generated by forward-port workflow*" # Create the PR PR_URL=$(gh pr create \ --base next \ --head main \ --title "chore: forward port main to next" \ --label "forward-port" \ --label "automated" \ --body "$BODY") PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT # Add conflict label if needed if [ "${{ steps.check-conflicts.outputs.has_conflicts }}" = "true" ]; then gh pr edit "$PR_NUMBER" --add-label "has-conflicts" fi - name: Send Discord notification if: steps.create-pr.outputs.pr_url != '' && env.DISCORD_WEBHOOK != '' uses: sarisia/actions-status-discord@v1 with: webhook: ${{ env.DISCORD_WEBHOOK }} status: ${{ steps.check-conflicts.outputs.has_conflicts == 'true' && 'Warning' || 'Success' }} title: "🔄 Forward Port PR Created" description: | **main → next** ${{ steps.check-conflicts.outputs.has_conflicts == 'true' && '⚠️ **Merge conflicts detected** - manual resolution required' || '✅ No conflicts - ready for review' }} **Commits:** ${{ steps.check-diff.outputs.diff_count }} **PR:** ${{ steps.create-pr.outputs.pr_url }} color: ${{ steps.check-conflicts.outputs.has_conflicts == 'true' && '0xFFA500' || '0x58AFFF' }} username: Task Master Bot avatar_url: https://raw.githubusercontent.com/eyaltoledano/claude-task-master/main/images/logo.png