Skip to content

Commit e6fa4c9

Browse files
Phlogistiqueclaude
andauthored
Fix e2e test conflict scenario and improve action debugging (#6)
* Fix e2e test conflict scenario and improve action debugging - Expand test file from 3 to 7 lines to avoid git treating adjacent line changes as overlapping hunks (was causing spurious conflicts) - Use line 7 instead of line 3 for conflict test (more separation) - Fix $CHILD -> $BRANCH typo in conflict resolution instructions - Add explicit branch parameter to gh pr comment/edit commands - Add pipefail to catch pipeline failures - Wrap git merge --abort and gh commands in log_cmd for visibility - Add debug output at script start for troubleshooting * Fix e2e test failures and action bugs Test fixes: - Expand test file from 3 to 7 lines to avoid git's adjacent-line conflict heuristic causing spurious merge conflicts - Use line 7 instead of line 3 for conflict scenario testing - Fix conflict resolution: use deterministic file creation instead of buggy sed-based conflict marker removal - Add PRESERVE_ON_FAILURE option for debugging failed tests - Use fail_test() wrapper for proper cleanup flag handling Action fixes: - Fix $CHILD -> $BRANCH typo in conflict resolution instructions - Add explicit branch parameter to gh pr comment/edit commands to ensure they work correctly in GitHub Actions context - Create autorestack-needs-conflict-resolution label before adding it to PR (gh pr edit --add-label fails if label doesn't exist) - Add pipefail to catch pipeline failures - Wrap git merge --abort and gh commands in log_cmd for visibility * Refactor e2e test script - Remove fail_test helper and TEST_FAILED mechanism since the script uses 'set -e', so failures exit automatically. Use exit code in cleanup trap instead. - Replace hardcoded conflict resolution with 'git checkout --ours' which correctly preserves feature3's changes to both line 2 and line 7 - Remove redundant 'git pull origin main' commands since we use 'origin/main' references directly and don't need local main updated --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent f79392b commit e6fa4c9

2 files changed

Lines changed: 38 additions & 30 deletions

File tree

tests/test_e2e.sh

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ WORKFLOW_FILE="update-pr-stack.yml"
2929

3030
# --- Helper Functions ---
3131
cleanup() {
32+
local exit_code=$?
33+
# If PRESERVE_ON_FAILURE is set and there was an error, skip cleanup
34+
if [[ "${PRESERVE_ON_FAILURE:-}" == "1" ]] && [[ $exit_code -ne 0 ]]; then
35+
echo >&2 "--- Preserving repo for debugging (PRESERVE_ON_FAILURE=1) ---"
36+
echo >&2 "Repo: $REPO_FULL_NAME"
37+
echo >&2 "Local dir: $TEST_DIR"
38+
return 0
39+
fi
40+
3241
echo >&2 "--- Cleaning up ---"
3342
if [[ -d "$TEST_DIR" ]]; then
3443
echo >&2 "Removing local test directory: $TEST_DIR"
@@ -51,6 +60,7 @@ cleanup() {
5160
# Trap EXIT signal to ensure cleanup runs even if the script fails
5261
trap cleanup EXIT
5362

63+
5464
# Merge a PR with retry logic to handle transient "not mergeable" errors.
5565
# After pushing to a PR's base branch, GitHub's mergeability computation is async
5666
# and can take several seconds. During this time, merge attempts fail with
@@ -196,10 +206,15 @@ log_cmd git init -b main
196206
log_cmd git config user.email "test-e2e@example.com"
197207
log_cmd git config user.name "E2E Test Bot"
198208

199-
# Create initial content
209+
# Create initial content with enough lines for context separation
210+
# (Git needs ~3 lines of context between changes to avoid treating them as overlapping hunks)
200211
echo "Base file content line 1" > file.txt
201212
echo "Base file content line 2" >> file.txt
202213
echo "Base file content line 3" >> file.txt
214+
echo "Base file content line 4" >> file.txt
215+
echo "Base file content line 5" >> file.txt
216+
echo "Base file content line 6" >> file.txt
217+
echo "Base file content line 7" >> file.txt
203218
log_cmd git add file.txt
204219
log_cmd git commit -m "Initial commit"
205220
INITIAL_COMMIT_SHA=$(git rev-parse HEAD)
@@ -337,8 +352,6 @@ else
337352
fi
338353
# Verify local branches are updated to include the squash commit
339354
echo >&2 "Checking if branches incorporate the squash commit..."
340-
log_cmd git checkout main # Ensure main is up-to-date locally
341-
log_cmd git pull origin main
342355
log_cmd git checkout feature2 # Checkout local branch first
343356
log_cmd git pull origin feature2 # Pull updates pushed by the action
344357
log_cmd git checkout feature3
@@ -398,18 +411,18 @@ echo >&2 "--- Testing Conflict Scenario (Merging PR2) ---"
398411

399412
# 8. Introduce conflicting changes
400413
echo >&2 "8. Introducing conflicting changes..."
401-
# Change line 3 on feature3
414+
# Change line 7 on feature3 (far from line 2 to avoid adjacent-line conflicts)
402415
log_cmd git checkout feature3
403-
sed -i '3s/.*/Feature 3 conflicting change line 3/' file.txt
416+
sed -i '7s/.*/Feature 3 conflicting change line 7/' file.txt
404417
log_cmd git add file.txt
405-
log_cmd git commit -m "Conflict: Modify line 3 on feature3"
418+
log_cmd git commit -m "Conflict: Modify line 7 on feature3"
406419
FEATURE3_CONFLICT_COMMIT_SHA=$(git rev-parse HEAD) # Store this SHA
407420
log_cmd git push origin feature3
408-
# Change line 3 on main
421+
# Change line 7 on main differently - this will conflict when rebasing feature3 after PR2 merge
409422
log_cmd git checkout main
410-
sed -i '3s/.*/Main conflicting change line 3/' file.txt
423+
sed -i '7s/.*/Main conflicting change line 7/' file.txt
411424
log_cmd git add file.txt
412-
log_cmd git commit -m "Conflict: Modify line 3 on main"
425+
log_cmd git commit -m "Conflict: Modify line 7 on main"
413426
log_cmd git push origin main
414427

415428
# 9. Trigger Action by Squash Merging PR2 (which is now based on the updated main from step 7)
@@ -501,9 +514,6 @@ echo >&2 "12. Resolving conflict manually on feature3..."
501514
log_cmd git checkout feature3
502515
# Ensure we have the latest main which includes the PR2 merge commit AND the conflicting change on main
503516
log_cmd git fetch origin
504-
log_cmd git checkout main
505-
log_cmd git pull origin main # Make sure local main is up-to-date
506-
log_cmd git checkout feature3
507517
# Now, perform the merge that the action tried and failed
508518
echo >&2 "Attempting merge of origin/main into feature3..."
509519
if git merge origin/main; then
@@ -515,11 +525,9 @@ else
515525
echo >&2 "Merge conflict occurred as expected. Resolving..."
516526
# Check status to confirm conflict
517527
log_cmd git status
518-
# Resolve conflict - let's keep the change from feature3 ("Feature 3 conflicting change line 3")
519-
# Remove conflict markers and keep the desired line 3
520-
sed -i '/<<<<<<< HEAD/,/=======/{//!d}' file.txt # Remove lines between <<<< and ==== (inclusive of <<<<)
521-
sed -i '/=======/,/>>>>>>> origin\/main/d' file.txt # Remove lines between ==== and >>>> (inclusive of ==== and >>>>)
522-
528+
# Resolve conflict - keep feature3's version (ours) of the conflicting file
529+
# This preserves both line 2 (Feature 3 content) and line 7 (Feature 3 conflicting change)
530+
log_cmd git checkout --ours file.txt
523531
echo "Resolved file.txt content:"
524532
cat file.txt
525533
log_cmd git add file.txt
@@ -534,8 +542,6 @@ echo >&2 "Pushed resolved feature3."
534542
echo >&2 "13. Verifying conflict resolution..."
535543
# Fetch the latest state again
536544
log_cmd git fetch origin
537-
log_cmd git checkout main
538-
log_cmd git pull origin main
539545
log_cmd git checkout feature3
540546
log_cmd git pull origin feature3
541547

@@ -551,25 +557,25 @@ fi
551557
# Verify the final content of file.txt on feature3
552558
# Line 1: Original base
553559
# Line 2: From feature 3 commit ("Feature 3 content line 2")
554-
# Line 3: From feature 3 conflict commit, kept during resolution ("Feature 3 conflicting change line 3")
560+
# Line 7: From feature 3 conflict commit, kept during resolution ("Feature 3 conflicting change line 7")
555561
EXPECTED_CONTENT_LINE1="Base file content line 1"
556562
EXPECTED_CONTENT_LINE2="Feature 3 content line 2"
557-
EXPECTED_CONTENT_LINE3="Feature 3 conflicting change line 3"
563+
EXPECTED_CONTENT_LINE7="Feature 3 conflicting change line 7"
558564

559565
ACTUAL_CONTENT_LINE1=$(sed -n '1p' file.txt)
560566
ACTUAL_CONTENT_LINE2=$(sed -n '2p' file.txt)
561-
ACTUAL_CONTENT_LINE3=$(sed -n '3p' file.txt)
567+
ACTUAL_CONTENT_LINE7=$(sed -n '7p' file.txt)
562568

563569
if [[ "$ACTUAL_CONTENT_LINE1" == "$EXPECTED_CONTENT_LINE1" && \
564570
"$ACTUAL_CONTENT_LINE2" == "$EXPECTED_CONTENT_LINE2" && \
565-
"$ACTUAL_CONTENT_LINE3" == "$EXPECTED_CONTENT_LINE3" ]]; then
571+
"$ACTUAL_CONTENT_LINE7" == "$EXPECTED_CONTENT_LINE7" ]]; then
566572
echo >&2 "✅ Verification Passed: file.txt content on resolved feature3 is correct."
567573
else
568574
echo >&2 "❌ Verification Failed: file.txt content on resolved feature3 is incorrect."
569575
echo "Expected:"
570576
echo "$EXPECTED_CONTENT_LINE1"
571577
echo "$EXPECTED_CONTENT_LINE2"
572-
echo "$EXPECTED_CONTENT_LINE3"
578+
echo "$EXPECTED_CONTENT_LINE7"
573579
echo "Actual:"
574580
cat file.txt
575581
exit 1

update-pr-stack.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# MERGED_BRANCH - The name of the branch that was merged and will be deleted
88
# TARGET_BRANCH - The name of the branch that the PR was merged into
99

10-
set -ue # Exit immediately if a command exits with a non-zero status.
10+
set -ueo pipefail # Exit on error, undefined var, or pipeline failure
1111

1212
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
1313
source "$SCRIPT_DIR/command_utils.sh"
@@ -60,11 +60,11 @@ update_direct_target() {
6060
log_cmd git update-ref BEFORE_MERGE HEAD
6161
if ! log_cmd git merge --no-edit "origin/$MERGED_BRANCH"; then
6262
CONFLICTS+=("origin/$MERGED_BRANCH")
63-
git merge --abort
63+
log_cmd git merge --abort
6464
fi
6565
if ! log_cmd git merge --no-edit SQUASH_COMMIT~; then
6666
CONFLICTS+=( "$(git rev-parse SQUASH_COMMIT~)" )
67-
git merge --abort
67+
log_cmd git merge --abort
6868
fi
6969

7070
if [[ "${#CONFLICTS[@]}" -gt 0 ]]; then
@@ -79,7 +79,7 @@ update_direct_target() {
7979
echo "#### How to resolve"
8080
echo '```bash'
8181
echo "git fetch origin"
82-
echo "git switch $CHILD"
82+
echo "git switch $BRANCH"
8383
for conflict in "${CONFLICTS[@]}"; do
8484
echo "git merge $conflict"
8585
echo "# ..."
@@ -89,8 +89,10 @@ update_direct_target() {
8989
done
9090
echo "git push"
9191
echo '```'
92-
} | gh pr comment -F -
93-
gh pr edit --add-label autorestack-needs-conflict-resolution
92+
} | log_cmd gh pr comment "$BRANCH" -F -
93+
# Create the label if it doesn't exist, then add it to the PR
94+
gh label create autorestack-needs-conflict-resolution --description "PR needs manual conflict resolution" --color "d73a4a" 2>/dev/null || true
95+
log_cmd gh pr edit "$BRANCH" --add-label autorestack-needs-conflict-resolution
9496
else
9597
log_cmd git merge --no-edit -s ours "$SQUASH_COMMIT"
9698
log_cmd git update-ref MERGE_RESULT "HEAD^{tree}"

0 commit comments

Comments
 (0)