|
58 | 58 | # - Does NOT push any conflicted state to the remote |
59 | 59 | # - Posts a comment on PR3 explaining the conflict |
60 | 60 | # - Adds a label "autorestack-needs-conflict-resolution" to PR3 |
61 | | -# - Updates PR3's base branch to main (even though merge failed) |
| 61 | +# - Does NOT update PR3's base branch (keeps it as feature2 for readable diff) |
| 62 | +# - Does NOT delete feature2 branch (still referenced by conflicted PR) |
62 | 63 | # - Exits with success (conflict is handled gracefully, not a failure) |
63 | 64 | # |
64 | 65 | # Verifications: |
65 | | -# - feature2 branch is deleted from remote |
66 | | -# - PR3 base branch is updated to main |
| 66 | +# - feature2 branch is NOT deleted from remote (still referenced by conflicted PR3) |
| 67 | +# - PR3 base branch stays as feature2 (not updated to main) |
67 | 68 | # - Conflict comment exists on PR3 |
68 | 69 | # - Conflict label "autorestack-needs-conflict-resolution" exists on PR3 |
69 | 70 | # - feature3 branch was NOT updated (still at pre-conflict SHA) |
|
74 | 75 | # - Push the resolved branch |
75 | 76 | # - The push triggers the 'synchronize' event on PR3 |
76 | 77 | # - The action detects the conflict label and removes it |
| 78 | +# - Updates PR3's base branch to main |
| 79 | +# - Deletes feature2 branch (no other conflicted PRs depend on it) |
77 | 80 | # - The continuation workflow updates feature4 (grandchild) recursively |
78 | | -# - Verify the label is removed, resolution comment is posted, and feature4 is updated |
| 81 | +# - Verify the label is removed, base updated, branch deleted, and feature4 is updated |
79 | 82 | # |
80 | 83 | # Grandchild Update (feature4): |
81 | 84 | # - Tests that update_branch_recursive properly handles grandchildren |
|
676 | 679 | # 11. Verification for Conflict Scenario |
677 | 680 | echo >&2 "11. Verifying the results of the conflict scenario..." |
678 | 681 | echo >&2 "Fetching latest state from remote..." |
679 | | -log_cmd git fetch origin --prune # Prune deleted branch feature2 |
| 682 | +log_cmd git fetch origin --prune |
680 | 683 |
|
681 | | -# Verify feature2 branch was deleted remotely |
| 684 | +# Verify feature2 branch was NOT deleted (still referenced by conflicted PR3) |
682 | 685 | if git show-ref --verify --quiet refs/remotes/origin/feature2; then |
683 | | - echo >&2 "❌ Verification Failed: Remote branch 'origin/feature2' still exists after merge." |
684 | | - exit 1 |
| 686 | + echo >&2 "✅ Verification Passed: Remote branch 'origin/feature2' still exists (kept for conflicted PR)." |
685 | 687 | else |
686 | | - echo >&2 "✅ Verification Passed: Remote branch 'origin/feature2' was deleted." |
| 688 | + echo >&2 "❌ Verification Failed: Remote branch 'origin/feature2' was deleted prematurely." |
| 689 | + exit 1 |
687 | 690 | fi |
688 | 691 |
|
689 | | -# Verify PR3 base branch was updated to main (action updates base even on conflict) |
| 692 | +# Verify PR3 base branch was NOT updated (stays as feature2 for readable diff) |
690 | 693 | echo >&2 "Checking PR #$PR3_NUM base branch..." |
691 | 694 | PR3_BASE_AFTER_CONFLICT=$(log_cmd gh pr view "$PR3_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
692 | | -if [[ "$PR3_BASE_AFTER_CONFLICT" == "main" ]]; then |
693 | | - echo >&2 "✅ Verification Passed: PR #$PR3_NUM base branch updated to 'main'." |
| 695 | +if [[ "$PR3_BASE_AFTER_CONFLICT" == "feature2" ]]; then |
| 696 | + echo >&2 "✅ Verification Passed: PR #$PR3_NUM base branch stays as 'feature2' (not updated during conflict)." |
694 | 697 | else |
695 | | - echo >&2 "❌ Verification Failed: PR #$PR3_NUM base branch is '$PR3_BASE_AFTER_CONFLICT', expected 'main'." |
| 698 | + echo >&2 "❌ Verification Failed: PR #$PR3_NUM base branch is '$PR3_BASE_AFTER_CONFLICT', expected 'feature2'." |
696 | 699 | exit 1 |
697 | 700 | fi |
698 | 701 |
|
@@ -789,19 +792,26 @@ else |
789 | 792 | exit 1 |
790 | 793 | fi |
791 | 794 |
|
792 | | -# Verify resolution acknowledgement comment exists on PR3 |
793 | | -echo >&2 "Checking for resolution acknowledgement comment on PR #$PR3_NUM..." |
794 | | -RESOLUTION_COMMENT=$(log_cmd gh pr view "$PR3_URL" --repo "$REPO_FULL_NAME" --json comments --jq '.comments[] | select(.body | contains("Conflict resolved")) | .body') |
795 | | -if [[ -n "$RESOLUTION_COMMENT" ]]; then |
796 | | - echo >&2 "✅ Verification Passed: Resolution acknowledgement comment found on PR #$PR3_NUM." |
| 795 | +# Verify PR3 base branch was updated to main after resolution |
| 796 | +echo >&2 "Checking PR #$PR3_NUM base branch after resolution..." |
| 797 | +PR3_BASE_AFTER_RESOLUTION=$(log_cmd gh pr view "$PR3_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
| 798 | +if [[ "$PR3_BASE_AFTER_RESOLUTION" == "main" ]]; then |
| 799 | + echo >&2 "✅ Verification Passed: PR #$PR3_NUM base branch updated to 'main' after resolution." |
797 | 800 | else |
798 | | - echo >&2 "❌ Verification Failed: Resolution acknowledgement comment not found on PR #$PR3_NUM." |
799 | | - echo >&2 "--- Comments on PR #$PR3_NUM ---" |
800 | | - gh pr view "$PR3_URL" --repo "$REPO_FULL_NAME" --json comments --jq '.comments[].body' || echo "Failed to get comments" |
801 | | - echo >&2 "-----------------------------" |
| 801 | + echo >&2 "❌ Verification Failed: PR #$PR3_NUM base branch is '$PR3_BASE_AFTER_RESOLUTION', expected 'main'." |
802 | 802 | exit 1 |
803 | 803 | fi |
804 | 804 |
|
| 805 | +# Verify feature2 was deleted after resolution (no other conflicted PRs depend on it) |
| 806 | +echo >&2 "Checking that feature2 branch was deleted after resolution..." |
| 807 | +log_cmd git fetch origin --prune |
| 808 | +if git show-ref --verify --quiet refs/remotes/origin/feature2; then |
| 809 | + echo >&2 "❌ Verification Failed: Remote branch 'origin/feature2' still exists after resolution." |
| 810 | + exit 1 |
| 811 | +else |
| 812 | + echo >&2 "✅ Verification Passed: Remote branch 'origin/feature2' was deleted after resolution." |
| 813 | +fi |
| 814 | + |
805 | 815 | echo >&2 "--- Continuation Workflow Test Completed Successfully ---" |
806 | 816 |
|
807 | 817 | # 15. Verify conflict resolution (content checks) |
|
863 | 873 | echo >&2 "--- Conflict Scenario Test Completed Successfully ---" |
864 | 874 |
|
865 | 875 |
|
| 876 | +# --- SCENARIO 3: Sibling Conflicts (Multiple PRs from same base, both conflict) --- |
| 877 | +# =================================================================================== |
| 878 | +# Tests that the old base branch is kept until ALL sibling PRs resolve their conflicts. |
| 879 | +# |
| 880 | +# Setup: |
| 881 | +# - Create a new stack: main <- feature5 <- (feature6, feature7) parallel children |
| 882 | +# - feature6 and feature7 both modify line 5 of file.txt |
| 883 | +# - main modifies line 5 differently (creating conflict with both siblings) |
| 884 | +# |
| 885 | +# Expected Behavior: |
| 886 | +# - After merging feature5, both feature6 and feature7 have conflicts |
| 887 | +# - feature5 branch is kept (referenced by both conflicted PRs) |
| 888 | +# - After resolving feature6, feature5 is still kept (feature7 still conflicted) |
| 889 | +# - After resolving feature7, feature5 is deleted (no more conflicted siblings) |
| 890 | +# =================================================================================== |
| 891 | + |
| 892 | +echo >&2 "--- Testing Sibling Conflicts Scenario ---" |
| 893 | + |
| 894 | +# 16. Create new stack for sibling conflict test |
| 895 | +echo >&2 "16. Creating new stack for sibling conflict test..." |
| 896 | +log_cmd git checkout main |
| 897 | +log_cmd git pull origin main |
| 898 | + |
| 899 | +# Create feature5 based on main (modifies line 2, no conflict with line 5) |
| 900 | +log_cmd git checkout -b feature5 main |
| 901 | +sed -i '2s/.*/Feature 5 content line 2/' file.txt |
| 902 | +log_cmd git add file.txt |
| 903 | +log_cmd git commit -m "Add feature 5" |
| 904 | +log_cmd git push origin feature5 |
| 905 | +PR5_URL=$(log_cmd gh pr create --repo "$REPO_FULL_NAME" --base main --head feature5 --title "Feature 5" --body "This is PR 5") |
| 906 | +PR5_NUM=$(echo "$PR5_URL" | awk -F'/' '{print $NF}') |
| 907 | +echo >&2 "Created PR #$PR5_NUM: $PR5_URL" |
| 908 | + |
| 909 | +# Create feature6 based on feature5 (modifies line 5, will conflict with main) |
| 910 | +log_cmd git checkout -b feature6 feature5 |
| 911 | +sed -i '5s/.*/Feature 6 conflicting content line 5/' file.txt |
| 912 | +log_cmd git add file.txt |
| 913 | +log_cmd git commit -m "Add feature 6 (modifies line 5)" |
| 914 | +log_cmd git push origin feature6 |
| 915 | +PR6_URL=$(log_cmd gh pr create --repo "$REPO_FULL_NAME" --base feature5 --head feature6 --title "Feature 6" --body "This is PR 6, sibling of PR 7") |
| 916 | +PR6_NUM=$(echo "$PR6_URL" | awk -F'/' '{print $NF}') |
| 917 | +echo >&2 "Created PR #$PR6_NUM: $PR6_URL" |
| 918 | + |
| 919 | +# Create feature7 based on feature5 (also modifies line 5, will conflict with main) |
| 920 | +log_cmd git checkout feature5 |
| 921 | +log_cmd git checkout -b feature7 |
| 922 | +sed -i '5s/.*/Feature 7 conflicting content line 5/' file.txt |
| 923 | +log_cmd git add file.txt |
| 924 | +log_cmd git commit -m "Add feature 7 (also modifies line 5)" |
| 925 | +log_cmd git push origin feature7 |
| 926 | +PR7_URL=$(log_cmd gh pr create --repo "$REPO_FULL_NAME" --base feature5 --head feature7 --title "Feature 7" --body "This is PR 7, sibling of PR 6") |
| 927 | +PR7_NUM=$(echo "$PR7_URL" | awk -F'/' '{print $NF}') |
| 928 | +echo >&2 "Created PR #$PR7_NUM: $PR7_URL" |
| 929 | + |
| 930 | +# Introduce conflicting change on main (line 5) - this will conflict with feature6/7 |
| 931 | +# when the action tries to merge SQUASH_COMMIT~ into them |
| 932 | +log_cmd git checkout main |
| 933 | +sed -i '5s/.*/Main conflicting content line 5/' file.txt |
| 934 | +log_cmd git add file.txt |
| 935 | +log_cmd git commit -m "Add conflicting change on main line 5" |
| 936 | +log_cmd git push origin main |
| 937 | + |
| 938 | +# 17. Merge feature5 to trigger conflicts on both siblings |
| 939 | +echo >&2 "17. Squash merging PR #$PR5_NUM (feature5) to trigger sibling conflicts..." |
| 940 | +merge_pr_with_retry "$PR5_URL" |
| 941 | +MERGE_COMMIT_SHA5=$(gh pr view "$PR5_URL" --repo "$REPO_FULL_NAME" --json mergeCommit -q .mergeCommit.oid) |
| 942 | +echo >&2 "PR #$PR5_NUM merged. Squash commit SHA: $MERGE_COMMIT_SHA5" |
| 943 | + |
| 944 | +# Wait for workflow |
| 945 | +echo >&2 "Waiting for workflow..." |
| 946 | +if ! wait_for_workflow "$PR5_NUM" "feature5" "$MERGE_COMMIT_SHA5" "success"; then |
| 947 | + echo >&2 "Workflow for PR5 merge did not complete successfully." |
| 948 | + exit 1 |
| 949 | +fi |
| 950 | + |
| 951 | +# 18. Verify both siblings have conflicts and feature5 is kept |
| 952 | +echo >&2 "18. Verifying sibling conflict state..." |
| 953 | +log_cmd git fetch origin |
| 954 | + |
| 955 | +# Verify feature5 branch was NOT deleted (both siblings conflicted) |
| 956 | +if git show-ref --verify --quiet refs/remotes/origin/feature5; then |
| 957 | + echo >&2 "✅ Verification Passed: Remote branch 'origin/feature5' still exists (kept for conflicted siblings)." |
| 958 | +else |
| 959 | + echo >&2 "❌ Verification Failed: Remote branch 'origin/feature5' was deleted prematurely." |
| 960 | + exit 1 |
| 961 | +fi |
| 962 | + |
| 963 | +# Verify both PRs have conflict labels |
| 964 | +PR6_HAS_LABEL=$(gh pr view "$PR6_URL" --repo "$REPO_FULL_NAME" --json labels --jq '.labels[] | select(.name == "autorestack-needs-conflict-resolution") | .name') |
| 965 | +PR7_HAS_LABEL=$(gh pr view "$PR7_URL" --repo "$REPO_FULL_NAME" --json labels --jq '.labels[] | select(.name == "autorestack-needs-conflict-resolution") | .name') |
| 966 | + |
| 967 | +if [[ "$PR6_HAS_LABEL" == "autorestack-needs-conflict-resolution" ]]; then |
| 968 | + echo >&2 "✅ Verification Passed: PR #$PR6_NUM has conflict label." |
| 969 | +else |
| 970 | + echo >&2 "❌ Verification Failed: PR #$PR6_NUM does not have conflict label." |
| 971 | + exit 1 |
| 972 | +fi |
| 973 | + |
| 974 | +if [[ "$PR7_HAS_LABEL" == "autorestack-needs-conflict-resolution" ]]; then |
| 975 | + echo >&2 "✅ Verification Passed: PR #$PR7_NUM has conflict label." |
| 976 | +else |
| 977 | + echo >&2 "❌ Verification Failed: PR #$PR7_NUM does not have conflict label." |
| 978 | + exit 1 |
| 979 | +fi |
| 980 | + |
| 981 | +# Verify both PRs still have feature5 as base |
| 982 | +PR6_BASE=$(gh pr view "$PR6_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
| 983 | +PR7_BASE=$(gh pr view "$PR7_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
| 984 | + |
| 985 | +if [[ "$PR6_BASE" == "feature5" && "$PR7_BASE" == "feature5" ]]; then |
| 986 | + echo >&2 "✅ Verification Passed: Both sibling PRs still have 'feature5' as base." |
| 987 | +else |
| 988 | + echo >&2 "❌ Verification Failed: PR6 base is '$PR6_BASE', PR7 base is '$PR7_BASE', expected both to be 'feature5'." |
| 989 | + exit 1 |
| 990 | +fi |
| 991 | + |
| 992 | +# 19. Resolve first sibling (feature6) - feature5 should still be kept |
| 993 | +echo >&2 "19. Resolving first sibling (feature6)..." |
| 994 | +log_cmd git checkout feature6 |
| 995 | +log_cmd git fetch origin |
| 996 | +if git merge origin/main; then |
| 997 | + echo >&2 "Merge succeeded unexpectedly (no conflict?)" |
| 998 | +else |
| 999 | + echo >&2 "Resolving conflict on feature6..." |
| 1000 | + log_cmd git checkout --ours file.txt |
| 1001 | + log_cmd git add file.txt |
| 1002 | + log_cmd git commit --no-edit |
| 1003 | +fi |
| 1004 | +log_cmd git push origin feature6 |
| 1005 | + |
| 1006 | +# Wait for continuation workflow |
| 1007 | +echo >&2 "Waiting for continuation workflow for feature6..." |
| 1008 | +if ! wait_for_synchronize_workflow "$PR6_NUM" "feature6" "success"; then |
| 1009 | + echo >&2 "Continuation workflow for feature6 did not complete successfully." |
| 1010 | + exit 1 |
| 1011 | +fi |
| 1012 | + |
| 1013 | +# 20. Verify feature5 is still kept (feature7 still conflicted) |
| 1014 | +echo >&2 "20. Verifying feature5 is still kept after first sibling resolution..." |
| 1015 | +log_cmd git fetch origin |
| 1016 | + |
| 1017 | +# feature5 should still exist |
| 1018 | +if git show-ref --verify --quiet refs/remotes/origin/feature5; then |
| 1019 | + echo >&2 "✅ Verification Passed: Remote branch 'origin/feature5' still exists (feature7 still conflicted)." |
| 1020 | +else |
| 1021 | + echo >&2 "❌ Verification Failed: Remote branch 'origin/feature5' was deleted prematurely (feature7 still needs it)." |
| 1022 | + exit 1 |
| 1023 | +fi |
| 1024 | + |
| 1025 | +# PR6 base should now be main |
| 1026 | +PR6_BASE_AFTER=$(gh pr view "$PR6_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
| 1027 | +if [[ "$PR6_BASE_AFTER" == "main" ]]; then |
| 1028 | + echo >&2 "✅ Verification Passed: PR #$PR6_NUM base updated to 'main' after resolution." |
| 1029 | +else |
| 1030 | + echo >&2 "❌ Verification Failed: PR #$PR6_NUM base is '$PR6_BASE_AFTER', expected 'main'." |
| 1031 | + exit 1 |
| 1032 | +fi |
| 1033 | + |
| 1034 | +# PR6 should no longer have conflict label |
| 1035 | +PR6_LABEL_AFTER=$(gh pr view "$PR6_URL" --repo "$REPO_FULL_NAME" --json labels --jq '.labels[] | select(.name == "autorestack-needs-conflict-resolution") | .name') |
| 1036 | +if [[ -z "$PR6_LABEL_AFTER" ]]; then |
| 1037 | + echo >&2 "✅ Verification Passed: PR #$PR6_NUM conflict label removed." |
| 1038 | +else |
| 1039 | + echo >&2 "❌ Verification Failed: PR #$PR6_NUM still has conflict label." |
| 1040 | + exit 1 |
| 1041 | +fi |
| 1042 | + |
| 1043 | +# PR7 should still have conflict label and feature5 as base |
| 1044 | +PR7_LABEL_STILL=$(gh pr view "$PR7_URL" --repo "$REPO_FULL_NAME" --json labels --jq '.labels[] | select(.name == "autorestack-needs-conflict-resolution") | .name') |
| 1045 | +PR7_BASE_STILL=$(gh pr view "$PR7_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
| 1046 | +if [[ "$PR7_LABEL_STILL" == "autorestack-needs-conflict-resolution" && "$PR7_BASE_STILL" == "feature5" ]]; then |
| 1047 | + echo >&2 "✅ Verification Passed: PR #$PR7_NUM still has conflict label and 'feature5' base." |
| 1048 | +else |
| 1049 | + echo >&2 "❌ Verification Failed: PR7 label='$PR7_LABEL_STILL', base='$PR7_BASE_STILL'." |
| 1050 | + exit 1 |
| 1051 | +fi |
| 1052 | + |
| 1053 | +# 21. Resolve second sibling (feature7) - now feature5 should be deleted |
| 1054 | +echo >&2 "21. Resolving second sibling (feature7)..." |
| 1055 | +log_cmd git checkout feature7 |
| 1056 | +log_cmd git fetch origin |
| 1057 | +if git merge origin/main; then |
| 1058 | + echo >&2 "Merge succeeded unexpectedly (no conflict?)" |
| 1059 | +else |
| 1060 | + echo >&2 "Resolving conflict on feature7..." |
| 1061 | + log_cmd git checkout --ours file.txt |
| 1062 | + log_cmd git add file.txt |
| 1063 | + log_cmd git commit --no-edit |
| 1064 | +fi |
| 1065 | +log_cmd git push origin feature7 |
| 1066 | + |
| 1067 | +# Wait for continuation workflow |
| 1068 | +echo >&2 "Waiting for continuation workflow for feature7..." |
| 1069 | +if ! wait_for_synchronize_workflow "$PR7_NUM" "feature7" "success"; then |
| 1070 | + echo >&2 "Continuation workflow for feature7 did not complete successfully." |
| 1071 | + exit 1 |
| 1072 | +fi |
| 1073 | + |
| 1074 | +# 22. Verify feature5 is now deleted (all siblings resolved) |
| 1075 | +echo >&2 "22. Verifying feature5 is deleted after all siblings resolved..." |
| 1076 | +log_cmd git fetch origin --prune |
| 1077 | + |
| 1078 | +if git show-ref --verify --quiet refs/remotes/origin/feature5; then |
| 1079 | + echo >&2 "❌ Verification Failed: Remote branch 'origin/feature5' still exists after all siblings resolved." |
| 1080 | + exit 1 |
| 1081 | +else |
| 1082 | + echo >&2 "✅ Verification Passed: Remote branch 'origin/feature5' was deleted after all siblings resolved." |
| 1083 | +fi |
| 1084 | + |
| 1085 | +# PR7 base should now be main |
| 1086 | +PR7_BASE_FINAL=$(gh pr view "$PR7_NUM" --repo "$REPO_FULL_NAME" --json baseRefName --jq .baseRefName) |
| 1087 | +if [[ "$PR7_BASE_FINAL" == "main" ]]; then |
| 1088 | + echo >&2 "✅ Verification Passed: PR #$PR7_NUM base updated to 'main' after resolution." |
| 1089 | +else |
| 1090 | + echo >&2 "❌ Verification Failed: PR #$PR7_NUM base is '$PR7_BASE_FINAL', expected 'main'." |
| 1091 | + exit 1 |
| 1092 | +fi |
| 1093 | + |
| 1094 | +echo >&2 "--- Sibling Conflicts Scenario Test Completed Successfully ---" |
| 1095 | + |
| 1096 | + |
866 | 1097 | # --- Test Succeeded --- |
867 | 1098 | echo >&2 "--- E2E Test Completed Successfully! ---" |
868 | 1099 |
|
|
0 commit comments