Commit 5a7928e484 for woocommerce

commit 5a7928e48486dfb66a6ee425e990252ddcc52874
Author: Alba Rincón <albarin@users.noreply.github.com>
Date:   Thu Jan 22 16:50:44 2026 +0100

    Block cherry-picking PR from merging when they have conflicts (#62771)

    * Add cherry-pick has conflicts label

    * Block merge when conflicts

    * wip

    * Fix map description

    * Fix conflicts mapping

    * Improve cherry pick check workflow

    * Simplify list conflicts

    * Fix check-conflicts-label job

    * Remove unused vars

    * Remove debug echo

    * Add warning callout

    * Use jq to process conflicts

    * Use single quote

    * Use env vars for the conflict status

diff --git a/.github/workflows/release-cherry-pick-pr-check-conflicts.yml b/.github/workflows/release-cherry-pick-pr-check-conflicts.yml
new file mode 100644
index 0000000000..ce6b907f7f
--- /dev/null
+++ b/.github/workflows/release-cherry-pick-pr-check-conflicts.yml
@@ -0,0 +1,32 @@
+name: 'Block merge if cherry-pick conflicts exist'
+
+on:
+  pull_request:
+    types:
+      - opened
+      - reopened
+      - edited
+      - synchronize
+      - ready_for_review
+      - labeled
+      - unlabeled
+
+permissions:
+  contents: read
+  pull-requests: read
+
+jobs:
+  check-conflicts-label:
+    name: Check for conflicts label
+    runs-on: ubuntu-latest
+    if: |
+      startsWith(github.head_ref, 'cherry-pick-') &&
+      contains(github.event.pull_request.labels.*.name, 'cherry pick has conflicts')
+    permissions:
+      pull-requests: read
+      statuses: write
+    steps:
+      - name: Block merge due to conflicts
+        run: |
+          echo "❌ This PR has unresolved cherry-pick conflicts. Please resolve conflicts before merging."
+          exit 1
\ No newline at end of file
diff --git a/.github/workflows/shared-cherry-pick.yml b/.github/workflows/shared-cherry-pick.yml
index a284169faf..33b43553e1 100644
--- a/.github/workflows/shared-cherry-pick.yml
+++ b/.github/workflows/shared-cherry-pick.yml
@@ -202,12 +202,17 @@ jobs:
             echo "has_conflicts=false" >> $GITHUB_OUTPUT
             echo "Cherry-pick completed successfully"
           else
-            # Look for conflict markers in git status
-            if git status --porcelain | grep -E "^(DD|AU|UD|UA|DU|AA|UU)"; then
+            # Capture conflicted files with their status codes and build JSON array using jq
+            CONFLICT_JSON=$(git status --porcelain | grep -E "^(DD|AU|UD|UA|DU|AA|UU)" | jq -R -n -c '
+              [inputs | {status: .[0:2], file: .[3:]}]
+            ')
+
+            if [[ "$CONFLICT_JSON" != "[]" ]]; then
               echo "has_conflicts=true" >> $GITHUB_OUTPUT
-              echo "Cherry-pick had conflicts - resolving automatically"
+              echo "conflict_status=$CONFLICT_JSON" >> $GITHUB_OUTPUT
+
+              echo "Cherry-pick had conflicts - details: $CONFLICT_JSON"

-              # For modify/delete conflicts, we need to handle them specifically
               # Add all files (both conflicted and resolved)
               git add .

@@ -245,6 +250,8 @@ jobs:
       - name: Create cherry-pick pull request
         id: create-pr
         uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
+        env:
+          CONFLICT_STATUS: ${{ steps.cherry-pick.outputs.conflict_status }}
         with:
           github-token: ${{ secrets.WC_BOT_PR_CREATE_TOKEN || secrets.GITHUB_TOKEN }}
           script: |
@@ -265,7 +272,30 @@ jobs:
               let prBody = `This PR is a cherry-pick of #${prNumber} to \`${targetBranch}\`.\n\n`;

               if (hasConflicts) {
-                prBody += `⚠️ **WARNING**: This cherry-pick contained conflicts that have not been resolved. Please review the changes carefully before merging!\n\n`;
+                prBody += `> [!WARNING]\n`;
+                prBody += `> This cherry-pick contained conflicts that have not been resolved\n`;
+                prBody += `> 1. Review and resolve all conflicts\n`;
+                prBody += `> 2. Remove the \`cherry pick has conflicts\` label (required to merge)\n`;
+
+                // Parse JSON array of conflicts
+                const conflicts = JSON.parse(process.env.CONFLICT_STATUS || '[]');
+                // Map status codes to human-readable descriptions
+                const conflictTypeMap = {
+                  'DD': 'deleted by both',
+                  'UA': 'added by cherry-pick, does not exist in target branch',
+                  'UD': 'deleted by cherry-pick, modified in target branch',
+                  'AU': 'modified by cherry-pick, added in target branch',
+                  'DU': 'modified by cherry-pick, deleted in target branch',
+                  'AA': 'added by both with different content',
+                  'UU': 'modified by both'
+                };
+                prBody += `>\n`; // Empty blockquote line for spacing
+                prBody += `> **Conflicted Files:**\n`;
+                for (const { status, file } of conflicts) {
+                  const conflictType = conflictTypeMap[status] || 'unknown conflict type';
+                  prBody += `> - \`${file}\` (${conflictType})\n`;
+                }
+                prBody += `\n`;
               }

               prBody += `## Original PR Description\n\n${originalPr.body || '*No description provided*'}`;
@@ -284,6 +314,7 @@ jobs:
                 title: `[Backport to ${targetBranch}] ${originalPr.title}`,
                 body: prBody
               });
+
               await github.rest.pulls.requestReviewers({
                 owner: context.repo.owner,
                 repo: context.repo.repo,
@@ -291,6 +322,21 @@ jobs:
                 reviewers: [context.actor, originalPr.user.login]
               });

+              // Add label if there are conflicts
+              if (hasConflicts) {
+                try {
+                  await github.rest.issues.addLabels({
+                    owner: context.repo.owner,
+                    repo: context.repo.repo,
+                    issue_number: newPr.number,
+                    labels: ['cherry pick has conflicts']
+                  });
+                  core.info(`Added 'cherry pick has conflicts' label to PR #${newPr.number}`);
+                } catch (error) {
+                  core.warning(`Failed to add conflicts label: ${error.message}`);
+                }
+              }
+
               core.setOutput('pr_number', newPr.number.toString());
               core.setOutput('original_author', originalPr.user?.login || '');
               core.setOutput('original_merger', originalPr.merged_by?.login || '');
@@ -384,4 +430,4 @@ jobs:
             echo "status=success" >> $GITHUB_OUTPUT
             echo "error_message=" >> $GITHUB_OUTPUT
             echo "cherry_pick_pr_number=${{ needs.cherry-pick.outputs.cherry_pick_pr_number }}" >> $GITHUB_OUTPUT
-          fi
+          fi
\ No newline at end of file