Skip to content
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 295 additions & 0 deletions .github/workflows/pull-request-target.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,304 @@ name: PR Target Workflow

on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review]
push:
branches: [develop]

permissions:
contents: read
pull-requests: write
checks: write

jobs:
PR-Greeting:
uses: PalisadoesFoundation/.github/.github/workflows/pr-target-policy.yml@main
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
detect-merge-conflicts:
name: Detect Merge Conflicts in PRs
runs-on: ubuntu-latest

Comment on lines +19 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding concurrency control to prevent duplicate comments.

Multiple rapid pushes to develop could trigger parallel workflow runs, each posting comments on the same conflicted PRs. Adding a concurrency group would cancel in-progress runs when a new push occurs.

♻️ Proposed enhancement
   detect-merge-conflicts:
     name: Detect Merge Conflicts in PRs
     runs-on: ubuntu-latest
+    concurrency:
+      group: conflict-check-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
+      cancel-in-progress: true

     steps:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
detect-merge-conflicts:
name: Detect Merge Conflicts in PRs
runs-on: ubuntu-latest
detect-merge-conflicts:
name: Detect Merge Conflicts in PRs
runs-on: ubuntu-latest
concurrency:
group: conflict-check-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
🤖 Prompt for AI Agents
In @.github/workflows/pull-request-target.yml around lines 19 - 22, Add a
concurrency stanza to the detect-merge-conflicts job so parallel runs are
deduplicated; specifically, in the detect-merge-conflicts job (named "Detect
Merge Conflicts in PRs") add a concurrency block with a stable group identifier
(e.g., use github.workflow combined with the PR identifier or branch ref such as
github.ref or github.event.pull_request.number) and set cancel-in-progress: true
to ensure any in-progress run is cancelled when a new push triggers the
workflow.

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Log environment
run: |
echo "[SETUP] ========================================"
echo "[SETUP] Workflow triggered by: ${{ github.event_name }}"
echo "[SETUP] Repository: ${{ github.repository }}"
echo "[SETUP] Branch: ${{ github.ref }}"
echo "[SETUP] SHA: ${{ github.sha }}"

if [ "${{ github.event_name }}" = "pull_request_target" ]; then
echo "[SETUP] PR Number: ${{ github.event.pull_request.number }}"
echo "[SETUP] PR Title: ${{ github.event.pull_request.title }}"
echo "[SETUP] Base Branch: ${{ github.event.pull_request.base.ref }}"
echo "[SETUP] Base SHA: ${{ github.event.pull_request.base.sha }}"
echo "[SETUP] Head Branch: ${{ github.event.pull_request.head.ref }}"
echo "[SETUP] Head SHA: ${{ github.event.pull_request.head.sha }}"
fi

echo "[SETUP] Current Git Ref: $(git rev-parse HEAD)"
echo "[SETUP] Git Version: $(git --version)"
echo "[SETUP] ========================================"

- name: Get open PRs for base branch
if: github.event_name == 'push'
id: get-prs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "[FETCH] ========================================"
echo "[FETCH] Fetching open PRs targeting: ${{ github.ref_name }}"

# Get all open PRs targeting this branch
gh pr list \
--base "${{ github.ref_name }}" \
--state open \
--json number \
--jq '.[].number' > pr_numbers.txt

PR_COUNT=$(wc -l < pr_numbers.txt | tr -d ' ')
echo "[FETCH] Found ${PR_COUNT} open PR(s) targeting ${{ github.ref_name }}"

if [ "${PR_COUNT}" -eq 0 ]; then
echo "[FETCH] No open PRs to check"
echo "has_prs=false" >> $GITHUB_OUTPUT
else
echo "has_prs=true" >> $GITHUB_OUTPUT
echo "[FETCH] PRs to check:"
cat pr_numbers.txt | while read pr; do
echo "[FETCH] - PR #${pr}"
done
fi
echo "[FETCH] ========================================"

- name: Check single PR for conflicts
if: github.event_name == 'pull_request_target'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "[CHECK] ========================================"
echo "[CHECK] Checking PR #${{ github.event.pull_request.number }}"

# Fetch base branch
echo "[CHECK] Fetching base branch: ${{ github.event.pull_request.base.ref }}"
git fetch origin ${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}

# Get PR changed files
echo "[CHECK] Fetching changed files in PR"
gh pr view ${{ github.event.pull_request.number }} \
--json files \
--jq '.files[].path' > pr_files.txt

FILE_COUNT=$(wc -l < pr_files.txt | tr -d ' ')
echo "[CHECK] Files changed: ${FILE_COUNT}"

if [ "${FILE_COUNT}" -eq 0 ]; then
echo "[CHECK] No files changed - exiting with success"
echo "[CHECK] ========================================"
exit 0
fi

echo "[CHECK] Changed files:"
cat pr_files.txt | while read file; do
echo "[CHECK] - ${file}"
done

# Calculate merge-base
echo "[CHECK] Calculating merge-base"
MERGE_BASE=$(git merge-base ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }})
echo "[CHECK] Merge-base: ${MERGE_BASE}"

# Run git merge-tree to detect conflicts
echo "[CHECK] Running git merge-tree to detect conflicts"
set +e
MERGE_OUTPUT=$(git merge-tree ${MERGE_BASE} ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} 2>&1)
MERGE_EXIT_CODE=$?
set -e

echo "[CHECK] Merge-tree exit code: ${MERGE_EXIT_CODE}"

# Parse conflicts from merge-tree output
touch all_conflicts.txt

# Look for CONFLICT markers
echo "${MERGE_OUTPUT}" | grep "^CONFLICT" | \
sed -E 's/^CONFLICT \([^)]+\): Merge conflict in (.+)$/\1/' | \
grep -v "^CONFLICT" >> all_conflicts.txt || true

# Also check for "changed in both" indicators
echo "${MERGE_OUTPUT}" | grep -E "^\+<<<<<|^Auto-merging" | \
grep -oP "(?<=Auto-merging )\S+" >> all_conflicts.txt || true
Comment on lines +137 to +139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

False positive detection from Auto-merging lines.

Auto-merging in git merge-tree output indicates that git is attempting to merge a file, not that a conflict occurred. Successful auto-merges will not produce a CONFLICT line. Grepping for Auto-merging will incorrectly flag files that merged cleanly.

Remove this logic to avoid false positives:

🐛 Proposed fix
           # Look for CONFLICT markers
           echo "${MERGE_OUTPUT}" | grep "^CONFLICT" | \
             sed -E 's/^CONFLICT \([^)]+\): Merge conflict in (.+)$/\1/' | \
             grep -v "^CONFLICT" >> all_conflicts.txt || true
-
-          # Also check for "changed in both" indicators
-          echo "${MERGE_OUTPUT}" | grep -E "^\+<<<<<|^Auto-merging" | \
-            grep -oP "(?<=Auto-merging )\S+" >> all_conflicts.txt || true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Also check for "changed in both" indicators
echo "${MERGE_OUTPUT}" | grep -E "^\+<<<<<|^Auto-merging" | \
grep -oP "(?<=Auto-merging )\S+" >> all_conflicts.txt || true
🤖 Prompt for AI Agents
In @.github/workflows/pull-request-target.yml around lines 137 - 139, The
current logic appends filenames matched by Auto-merging to all_conflicts.txt
causing false positives; remove the Auto-merging check and only capture actual
conflict indicators (e.g., the +<<<<< conflict marker or explicit CONFLICT
lines) from MERGE_OUTPUT, i.e., stop grepping for "Auto-merging" and update the
pipeline that writes to all_conflicts.txt to only extract filenames when real
conflict markers are present (use the existing /^\+<<<<</ or other explicit
CONFLICT patterns on MERGE_OUTPUT instead of Auto-merging).


# Remove duplicates and empty lines
sort -u all_conflicts.txt | grep -v "^$" > all_conflicts_unique.txt || touch all_conflicts_unique.txt
mv all_conflicts_unique.txt all_conflicts.txt
Comment on lines +129 to +143
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

git merge-tree output format CONFLICT markers different types

💡 Result:

Short answer — format and marker types

  • git-merge-tree overall output: three sections — OID of toplevel tree, a Conflicted-file-info list (lines: " ") and an Informational-messages block. Use --name-only or -z to change quoting/NUL termination. [1]

  • Informational messages (human form) show conflict notices like "Auto-merging " or "CONFLICT (rename/delete): …". With -z they are structured records: NULNULNUL. is a stable short string such as "Auto-merging", "CONFLICT (rename/delete)", "CONFLICT (submodule lacks merge base)", "CONFLICT (binary)". These messages are intended for humans (non-stable text without -z). [1][2][3]

  • Conflict markers embedded in the toplevel tree file blobs:

    • Default (merge style):
      <<<<<<< (ours)
      ...your side...

      ...their side...

      (other)

    • diff3 style (merge.conflictStyle = diff3) adds the original/base section with a ||||||| marker between original and =======. [3]
  • Important parsing guidance:

    • Do not try to infer conflict types only from the Conflicted-file-info lines; use the Informational-messages section (or -z structured records). Many logical conflict kinds exist (modify/delete, rename conflicts, binary, submodule, file/dir), and mappings can be many-to-many. [1][2]
  • Sources

    • git-merge-tree documentation (OUTPUT, -z and informational messages). [1]
    • manpage / Ubuntu docs explaining -z record format and example conflict-type strings. [2]
    • git-merge / merge.conflictStyle docs describing <<<<<<< / ||||||| / ======= / >>>>>>> markers. [3]

    🌐 Web query:

    git merge-tree exit code conflicts auto-merging output format

    💡 Result:

    Summary — exit codes

    • Normal (no conflicts): exit code 0. [1]
    • Conflicts: exit code 1. [1]
    • Error (could not start/complete): exit code ≠ 0 and ≠ 1 (unspecified). [1]
    • When using --stdin: the process returns 0 for both clean and conflicted merges; a non-0/≠1 means some merges could not be completed. [1][2]

    Output format (default)

    • Clean merge: single line containing the OID of the toplevel tree. [2]
    • Conflicted merge: three parts in order:
      1. OID of toplevel tree (represents what would be checked out; conflicted files may contain conflict markers). [2]
      2. Conflicted file info: lines of " " (or just filenames with --name-only). [2]
      3. Informational messages: a blank line then free-form messages such as "Auto-merging " or "CONFLICT …" (these are not stable strings for machine parsing). [2][3]
      4. Zero-terminated / machine-friendly variants

        • -z switches most separators/newlines to NULs and changes the informational-message encoding (records: NULNULNUL). [2]
        • --name-only omits mode/object/stage and lists only filenames. [2]
        • --[no-]messages controls whether the informational messages are emitted. [2]

        Notes

        • The OID is always emitted; when exit ≠ 0 the printed tree output contains more than just the tree OID. [1][2]

        Sources: Git documentation (git-merge-tree manpage) and upstream Git docs. [1][2][3]


        🌐 Web query:

        git merge-tree rename delete modify delete conflict messages documentation

        💡 Result:

        Summary — how git-merge-tree reports rename/delete and modify/delete conflicts, and how to interpret them:

        • git-merge-tree outputs a toplevel tree OID; when there are conflicts it also emits a "Conflicted file info" section (mode, object, stage, filename) and an "Informational messages" block containing human-readable messages such as "CONFLICT (rename/delete): …" or "CONFLICT (binary)". These free-form messages are for humans and not stable for scripting; use the Conflicted file info section (stages) to determine file-level conflict state. [1][2]

        • Typical conflict message forms you’ll see in the informational block:

          • "CONFLICT (rename/delete): renamed… but deleted in…"
          • "Auto-merging "
            These describe rename/delete, modify/delete, rename/rename, etc., but exact wording may change across Git versions. [1][2]
        • Practical notes:

          • Do not try to discover conflict types by scanning the resultant tree; parse the Conflicted file info (stages) instead. Some tree-level conflicts (modify/delete, rename/delete, directory–file, rename/rename permutations) are not representable by simple conflict markers and require manual resolution. [1]
          • Modify/delete (one side modified a file, the other deleted it) and rename/delete (one side renamed, the other deleted) are “tree/high-level” conflicts that generally require manual decision (keep modified/renamed version or accept deletion). Tools like git mergetool present choices (created vs deleted). [1][3]
          • If you need machine-readable output, use git-merge-tree with -z and inspect the conflicted-file entries (modes/objects/stages); don’t rely on the human messages block. [1][2]

        References

        • git-merge-tree man page (output, conflicted file info, informational messages). [1]
        • git-merge-tree examples / details showing "CONFLICT (rename/delete)" messaging. [2]
        • Discussion / practical advice about modify/delete and rename/delete conflicts (resolving manually). [3]

        Use git merge-tree exit code or structured output instead of parsing informational messages.

        The current approach of parsing the Informational-messages block (lines 132-138) is fundamentally unreliable. According to Git documentation, these messages are human-readable, non-stable strings intended for display only—not machine parsing. The exact wording varies across Git versions, making patterns like grep "^CONFLICT" and grep -oP "(?<=Auto-merging )\S+" fragile.

        Additionally, including Auto-merging files introduces false positives since auto-merged files aren't necessarily conflicted.

        Instead, use one of these more reliable approaches:

        • Check exit code: git merge-tree returns exit code 1 when conflicts exist
        • Parse structured output: Use git merge-tree -z to get machine-readable records with stable conflict-type strings
        • Examine conflicted-file info: The Conflicted-file-info section (mode/object/stage) directly indicates conflict state; stages 2 or 3 indicate conflicts


TOTAL_CONFLICTS=$(wc -l < all_conflicts.txt | tr -d ' ')
echo "[CHECK] Total files with potential conflicts: ${TOTAL_CONFLICTS}"

if [ "${TOTAL_CONFLICTS}" -gt 0 ]; then
echo "[CHECK] Conflicted files detected:"
cat all_conflicts.txt | while read file; do
echo "[CHECK] - ${file}"
done
fi

# Filter to only PR changed files
touch pr_conflicts.txt
if [ -f all_conflicts.txt ] && [ -s all_conflicts.txt ]; then
while IFS= read -r conflict_file; do
if grep -Fxq "${conflict_file}" pr_files.txt; then
echo "${conflict_file}" >> pr_conflicts.txt
fi
done < all_conflicts.txt
fi

FILTERED_COUNT=0
if [ -f pr_conflicts.txt ] && [ -s pr_conflicts.txt ]; then
FILTERED_COUNT=$(wc -l < pr_conflicts.txt | tr -d ' ')
fi

echo "[CHECK] Files with conflicts in this PR: ${FILTERED_COUNT}"

# Generate result
echo "[RESULT] ========================================"
echo "[RESULT] CONFLICT DETECTION SUMMARY"
echo "[RESULT] ========================================"
echo "[RESULT] PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}"
echo "[RESULT] Base: ${{ github.event.pull_request.base.ref }} @ ${{ github.event.pull_request.base.sha }}"
echo "[RESULT] Head: ${{ github.event.pull_request.head.ref }} @ ${{ github.event.pull_request.head.sha }}"
echo "[RESULT] ----------------------------------------"
echo "[RESULT] Total files changed in PR: ${FILE_COUNT}"
echo "[RESULT] Files with conflicts in PR: ${FILTERED_COUNT}"
echo "[RESULT] ========================================"

if [ "${FILTERED_COUNT}" -eq 0 ]; then
echo "[RESULT] ✅ STATUS: PASSED"
echo "[RESULT] No merge conflicts detected"
echo "[RESULT] ========================================"
exit 0
else
echo "[RESULT] ❌ STATUS: FAILED"
echo "[RESULT] Merge conflicts detected in ${FILTERED_COUNT} file(s):"
cat pr_conflicts.txt | while read file; do
echo "[RESULT] ⚠️ ${file}"
done
echo "[RESULT]"
echo "[RESULT] ACTION REQUIRED:"
echo "[RESULT] Please update your branch to resolve these conflicts:"
echo "[RESULT] git fetch origin"
echo "[RESULT] git checkout ${{ github.event.pull_request.head.ref }}"
echo "[RESULT] git merge origin/${{ github.event.pull_request.base.ref }}"
Comment on lines +199 to +202
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Script injection risk with head.ref in shell script.

While this is inside an echo statement making exploitation harder, directly interpolating github.event.pull_request.head.ref in shell scripts is flagged by static analysis as a security risk. A crafted branch name could potentially break the script logic.

Pass it through an environment variable:

🔒 Proposed fix

Update the step's env section:

       - name: Check single PR for conflicts
         if: github.event_name == 'pull_request_target'
         env:
           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
+          PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
         run: |

Then update the references in the script:

-            echo "[RESULT]   git checkout ${{ github.event.pull_request.head.ref }}"
-            echo "[RESULT]   git merge origin/${{ github.event.pull_request.base.ref }}"
+            echo "[RESULT]   git checkout ${PR_HEAD_REF}"
+            echo "[RESULT]   git merge origin/${PR_BASE_REF}"
🤖 Prompt for AI Agents
In @.github/workflows/pull-request-target.yml around lines 199 - 202, Replace
direct interpolation of github.event.pull_request.head.ref/base.ref in the shell
script with environment variables to avoid script-injection risk: add env
entries (e.g., PR_HEAD_REF and PR_BASE_REF) for ${{
github.event.pull_request.head.ref }} and ${{ github.event.pull_request.base.ref
}} in the job/step, then update the echo/merge lines that reference head.ref and
base.ref to use those env vars (ensuring they are quoted/escaped when used)
instead of interpolating the event values directly.

echo "[RESULT] ========================================"
exit 1
fi

- name: Check all open PRs for conflicts
if: github.event_name == 'push' && steps.get-prs.outputs.has_prs == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "[CHECK-ALL] ========================================"
echo "[CHECK-ALL] Checking all open PRs for conflicts after merge to ${{ github.ref_name }}"

FAILED_PRS=""
FAILED_COUNT=0

while IFS= read -r pr_number; do
echo "[CHECK-ALL] ----------------------------------------"
echo "[CHECK-ALL] Checking PR #${pr_number}"

# Get PR details
PR_DATA=$(gh pr view ${pr_number} --json headRefName,headRefOid,baseRefName,baseRefOid,title)
PR_TITLE=$(echo "${PR_DATA}" | jq -r '.title')
PR_HEAD_REF=$(echo "${PR_DATA}" | jq -r '.headRefName')
PR_HEAD_SHA=$(echo "${PR_DATA}" | jq -r '.headRefOid')
PR_BASE_REF=$(echo "${PR_DATA}" | jq -r '.baseRefName')
PR_BASE_SHA=$(echo "${PR_DATA}" | jq -r '.baseRefOid')

echo "[CHECK-ALL] PR #${pr_number}: ${PR_TITLE}"
echo "[CHECK-ALL] Base: ${PR_BASE_REF} @ ${PR_BASE_SHA}"
echo "[CHECK-ALL] Head: ${PR_HEAD_REF} @ ${PR_HEAD_SHA}"

# Fetch branches
git fetch origin ${PR_BASE_REF}:refs/remotes/origin/${PR_BASE_REF} 2>/dev/null || true
git fetch origin ${PR_HEAD_REF}:refs/remotes/origin/${PR_HEAD_REF} 2>/dev/null || true

# Get PR files
gh pr view ${pr_number} --json files --jq '.files[].path' > "pr_${pr_number}_files.txt"
FILE_COUNT=$(wc -l < "pr_${pr_number}_files.txt" | tr -d ' ')

if [ "${FILE_COUNT}" -eq 0 ]; then
echo "[CHECK-ALL] No files changed - skipping"
continue
fi

# Calculate merge-base
MERGE_BASE=$(git merge-base origin/${PR_BASE_REF} origin/${PR_HEAD_REF} 2>/dev/null || echo "")

if [ -z "${MERGE_BASE}" ]; then
echo "[CHECK-ALL] ⚠️ Could not calculate merge-base - skipping"
continue
fi

# Run merge-tree
set +e
MERGE_OUTPUT=$(git merge-tree ${MERGE_BASE} origin/${PR_BASE_REF} origin/${PR_HEAD_REF} 2>&1)
set -e

# Parse conflicts
touch "pr_${pr_number}_conflicts.txt"
echo "${MERGE_OUTPUT}" | grep "^CONFLICT" | \
sed -E 's/^CONFLICT \([^)]+\): Merge conflict in (.+)$/\1/' | \
grep -v "^CONFLICT" >> "pr_${pr_number}_conflicts.txt" || true

sort -u "pr_${pr_number}_conflicts.txt" | grep -v "^$" > "pr_${pr_number}_conflicts_unique.txt" || touch "pr_${pr_number}_conflicts_unique.txt"
mv "pr_${pr_number}_conflicts_unique.txt" "pr_${pr_number}_conflicts.txt"
Comment on lines 260 to 273
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Conflict parsing is correct here but inconsistent with single PR check.

This step correctly parses only CONFLICT lines. However, the "Check single PR for conflicts" step (lines 136-138) incorrectly includes Auto-merging lines. Align both implementations for consistency.

🤖 Prompt for AI Agents
In @.github/workflows/pull-request-target.yml around lines 257 - 264, The
single-PR conflict check is including "Auto-merging" lines while this multi-PR
block parses only lines starting with "CONFLICT"; update the single-PR check to
use the same parsing pipeline as the shown block: read from MERGE_OUTPUT, grep
only "^CONFLICT", use sed -E 's/^CONFLICT \([^)]+\): Merge conflict in
(.+)$/\1/' to extract file paths, filter empty lines, sort -u and write to the
pr_<number>_conflicts file; remove any grep or pattern that matches
"Auto-merging" so both checks behave consistently.


# Filter to PR files
touch "pr_${pr_number}_filtered.txt"
if [ -f "pr_${pr_number}_conflicts.txt" ] && [ -s "pr_${pr_number}_conflicts.txt" ]; then
while IFS= read -r conflict_file; do
if grep -Fxq "${conflict_file}" "pr_${pr_number}_files.txt"; then
echo "${conflict_file}" >> "pr_${pr_number}_filtered.txt"
fi
done < "pr_${pr_number}_conflicts.txt"
fi

CONFLICT_COUNT=0
if [ -f "pr_${pr_number}_filtered.txt" ] && [ -s "pr_${pr_number}_filtered.txt" ]; then
CONFLICT_COUNT=$(wc -l < "pr_${pr_number}_filtered.txt" | tr -d ' ')
fi

if [ "${CONFLICT_COUNT}" -gt 0 ]; then
echo "[CHECK-ALL] ❌ PR #${pr_number} has ${CONFLICT_COUNT} conflicted file(s)"
cat "pr_${pr_number}_filtered.txt" | while read file; do
echo "[CHECK-ALL] ⚠️ ${file}"
done
FAILED_PRS="${FAILED_PRS}${pr_number},"
FAILED_COUNT=$((FAILED_COUNT + 1))

# Post comment on PR2
gh pr comment ${pr_number} --body "⚠️ **Merge Conflict Detected**

This PR has merge conflicts with the base branch \`${PR_BASE_REF}\` after recent changes were merged.

**Conflicted files:**
$(cat "pr_${pr_number}_filtered.txt" | sed 's/^/- /')

**Action required:** Please update your branch to resolve these conflicts:
\`\`\`bash
git fetch origin
git checkout ${PR_HEAD_REF}
git merge origin/${PR_BASE_REF}
# Resolve conflicts, then:
git push
\`\`\`"
fi
Loading