Skip to content

Commit b26fe0a

Browse files
committed
cr suggestions
1 parent b2c5f28 commit b26fe0a

1 file changed

Lines changed: 135 additions & 24 deletions

File tree

.github/workflows/push-merge-conflict-detector.yml

Lines changed: 135 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ jobs:
99
detect-conflicts:
1010
name: Check Open PRs for Conflicts
1111
runs-on: ubuntu-latest
12-
permissions:
13-
contents: read
14-
pull-requests: read
15-
checks: write
12+
permissions:
13+
contents: read
14+
pull-requests: read
15+
checks: write
1616

1717
steps:
1818
- name: Checkout repository
@@ -26,7 +26,7 @@ jobs:
2626
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2727
run: |
2828
set -euo pipefail
29-
29+
3030
gh pr list \
3131
--base "${{ github.ref_name }}" \
3232
--state open \
@@ -46,63 +46,174 @@ jobs:
4646
FAILED=false
4747
4848
while IFS= read -r PR; do
49+
echo "========================================"
4950
echo "Checking PR #$PR"
51+
echo "========================================"
5052
51-
DATA=$(gh pr view "$PR" --json headRefName,headRefOid,baseRefName,title)
53+
# ── Fetch PR metadata ──────────────────────────────────────────
54+
DATA=$(gh pr view "$PR" --json headRefName,headRefOid,baseRefName,title,files)
5255
5356
HEAD_SHA=$(echo "$DATA" | jq -r '.headRefOid')
57+
HEAD_REF=$(echo "$DATA" | jq -r '.headRefName')
5458
BASE_REF=$(echo "$DATA" | jq -r '.baseRefName')
59+
TITLE=$(echo "$DATA" | jq -r '.title')
60+
61+
# Files actually touched by the PR (paths only)
62+
PR_FILES=$(echo "$DATA" | jq -r '.files[].path')
63+
TOTAL_FILES=$(echo "$PR_FILES" | grep -c . || true)
64+
65+
echo " Title : $TITLE"
66+
echo " Base ref : $BASE_REF"
67+
echo " Head ref : $HEAD_REF"
68+
echo " Head SHA : $HEAD_SHA"
69+
echo " PR files : $TOTAL_FILES"
5570
5671
git fetch origin "$BASE_REF"
5772
git fetch origin "$HEAD_SHA"
5873
5974
BASE_SHA=$(git rev-parse "origin/$BASE_REF")
75+
echo " Base SHA : $BASE_SHA"
6076
77+
# ── Run merge-tree ─────────────────────────────────────────────
6178
set +e
62-
OUTPUT=$(git merge-tree "$BASE_SHA" "$HEAD_SHA" 2>&1)
63-
CODE=$?
79+
MERGE_OUTPUT=$(git merge-tree "$BASE_SHA" "$HEAD_SHA" 2>&1)
80+
MERGE_CODE=$?
6481
set -e
6582
66-
HAS_CONFLICT=false
83+
# ── Collect ALL conflicted paths from merge-tree output ────────
84+
# Lines like: "CONFLICT (content): Merge conflict in path/to/file"
85+
ALL_CONFLICTED_FILES=""
86+
if [ -n "$MERGE_OUTPUT" ]; then
87+
ALL_CONFLICTED_FILES=$(echo "$MERGE_OUTPUT" \
88+
| grep -oP '(?<=Merge conflict in ).*' || true)
89+
fi
6790
68-
if echo "$OUTPUT" | grep -q "CONFLICT" || [ "$CODE" -eq 1 ]; then
69-
HAS_CONFLICT=true
91+
# ── Cross-reference: keep only files the PR actually changed ──
92+
RELEVANT_CONFLICTS=""
93+
if [ -n "$ALL_CONFLICTED_FILES" ]; then
94+
while IFS= read -r CF; do
95+
if echo "$PR_FILES" | grep -qxF "$CF"; then
96+
RELEVANT_CONFLICTS="${RELEVANT_CONFLICTS}${CF}"$'\n'
97+
fi
98+
done <<< "$ALL_CONFLICTED_FILES"
7099
fi
71100
72-
CHECK_NAME="Merge Conflict Detector"
101+
RELEVANT_CONFLICTS=$(echo "$RELEVANT_CONFLICTS" | sed '/^$/d')
102+
CONFLICT_COUNT=$(echo "$RELEVANT_CONFLICTS" | grep -c . || true)
73103
74-
if [ "$HAS_CONFLICT" = true ]; then
75-
echo "❌ Conflict in PR #$PR"
104+
HAS_RELEVANT_CONFLICT=false
105+
if [ "$CONFLICT_COUNT" -gt 0 ]; then
106+
HAS_RELEVANT_CONFLICT=true
107+
fi
108+
109+
CHECK_NAME="Merge Conflict Detector"
76110
77-
gh api repos/${{ github.repository }}/check-runs \
111+
# ── Build structured log + summary ────────────────────────────
112+
if [ "$HAS_RELEVANT_CONFLICT" = true ]; then
113+
echo "❌ PR #$PR has $CONFLICT_COUNT relevant conflict(s)"
114+
115+
# --- structured console log ---
116+
echo ""
117+
echo " [CONFLICT DETAILS]"
118+
echo " PR number : #$PR"
119+
echo " PR title : $TITLE"
120+
echo " Base ref : $BASE_REF ($BASE_SHA)"
121+
echo " Head ref : $HEAD_REF ($HEAD_SHA)"
122+
echo " Total files changed : $TOTAL_FILES"
123+
echo " Conflicted files : $CONFLICT_COUNT"
124+
while IFS= read -r CF; do
125+
echo " - $CF"
126+
done <<< "$RELEVANT_CONFLICTS"
127+
echo ""
128+
129+
# --- check-run summary (Markdown, no heredoc to avoid YAML pipe conflicts) ---
130+
CONFLICT_FILE_LIST=$(echo "$RELEVANT_CONFLICTS" | sed 's/^/ /')
131+
SUMMARY=$(printf '%s\n' \
132+
"## Merge Conflicts Detected" \
133+
"" \
134+
"| Field | Value |" \
135+
"|---|---|" \
136+
"| PR | #${PR} - ${TITLE} |" \
137+
"| Base | ${BASE_REF} @ ${BASE_SHA} |" \
138+
"| Head | ${HEAD_REF} @ ${HEAD_SHA} |" \
139+
"| Total files changed | ${TOTAL_FILES} |" \
140+
"| Conflicted files | ${CONFLICT_COUNT} |" \
141+
"" \
142+
"### Conflicted files" \
143+
'```' \
144+
"${CONFLICT_FILE_LIST}" \
145+
'```' \
146+
"" \
147+
"### Remediation" \
148+
"1. Pull the latest ${BASE_REF} into your branch:" \
149+
' ```bash' \
150+
" git fetch origin" \
151+
" git merge origin/${BASE_REF}" \
152+
" # or" \
153+
" git rebase origin/${BASE_REF}" \
154+
' ```' \
155+
"2. Resolve the conflicts listed above, then commit and push." \
156+
"3. This check will re-run automatically once your branch is updated." \
157+
)
158+
159+
gh api "repos/${{ github.repository }}/check-runs" \
78160
-X POST \
79161
-f name="$CHECK_NAME" \
80162
-f head_sha="$HEAD_SHA" \
81163
-f status="completed" \
82164
-f conclusion="failure" \
83-
-f "output[title]=Merge conflicts detected" \
84-
-f "output[summary]=Please update your branch." \
165+
-f "output[title]=Merge conflicts detected in ${CONFLICT_COUNT} file(s)" \
166+
-f "output[summary]=$SUMMARY" \
85167
--silent
86168
87169
FAILED=true
88-
else
89-
echo "✅ Clean PR #$PR"
90170
91-
gh api repos/${{ github.repository }}/check-runs \
171+
else
172+
echo "✅ PR #$PR — no relevant conflicts (merge-tree exit=$MERGE_CODE)"
173+
174+
# --- structured console log ---
175+
echo ""
176+
echo " [CLEAN DETAILS]"
177+
echo " PR number : #$PR"
178+
echo " PR title : $TITLE"
179+
echo " Base ref : $BASE_REF ($BASE_SHA)"
180+
echo " Head ref : $HEAD_REF ($HEAD_SHA)"
181+
echo " Total files changed : $TOTAL_FILES"
182+
echo " Conflicted files : 0"
183+
echo ""
184+
185+
# --- check-run summary (Markdown, no heredoc to avoid YAML pipe conflicts) ---
186+
SUMMARY=$(printf '%s\n' \
187+
"## No Merge Conflicts" \
188+
"" \
189+
"| Field | Value |" \
190+
"|---|---|" \
191+
"| PR | #${PR} - ${TITLE} |" \
192+
"| Base | ${BASE_REF} @ ${BASE_SHA} |" \
193+
"| Head | ${HEAD_REF} @ ${HEAD_SHA} |" \
194+
"| Total files changed | ${TOTAL_FILES} |" \
195+
"| Conflicted files | 0 |" \
196+
"" \
197+
"This PR merges cleanly into ${BASE_REF}." \
198+
)
199+
200+
gh api "repos/${{ github.repository }}/check-runs" \
92201
-X POST \
93202
-f name="$CHECK_NAME" \
94203
-f head_sha="$HEAD_SHA" \
95204
-f status="completed" \
96205
-f conclusion="success" \
97-
-f "output[title]=No merge conflicts" \
98-
-f "output[summary]=PR merges cleanly." \
206+
-f "output[title]=No merge conflicts - ${TOTAL_FILES} file(s) checked" \
207+
-f "output[summary]=$SUMMARY" \
99208
--silent
100209
fi
101210
102211
done < pr_numbers.txt
103212
213+
echo "========================================"
104214
if [ "$FAILED" = true ]; then
105-
echo "Some PRs have conflicts"
215+
echo "Result: one or more PRs have relevant conflicts"
216+
exit 0 # job stays green; failure signal lives on individual check-runs
106217
else
107-
echo "All PRs clean"
218+
echo "Result: all PRs are clean"
108219
fi

0 commit comments

Comments
 (0)