From 2cbfa3557ecaced114acb4f5553a543bfc4826b4 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Sun, 7 Dec 2025 14:58:29 +0800 Subject: [PATCH 1/7] Add merge-squash scaffolding and add download --- merge_squash/.gitmastery-exercise.json | 18 +++++++++ merge_squash/README.md | 18 +++++++++ merge_squash/__init__.py | 0 merge_squash/download.py | 51 ++++++++++++++++++++++++++ merge_squash/tests/__init__.py | 0 merge_squash/tests/specs/base.yml | 6 +++ merge_squash/tests/test_verify.py | 12 ++++++ merge_squash/verify.py | 11 ++++++ 8 files changed, 116 insertions(+) create mode 100644 merge_squash/.gitmastery-exercise.json create mode 100644 merge_squash/README.md create mode 100644 merge_squash/__init__.py create mode 100644 merge_squash/download.py create mode 100644 merge_squash/tests/__init__.py create mode 100644 merge_squash/tests/specs/base.yml create mode 100644 merge_squash/tests/test_verify.py create mode 100644 merge_squash/verify.py diff --git a/merge_squash/.gitmastery-exercise.json b/merge_squash/.gitmastery-exercise.json new file mode 100644 index 00000000..3a2d7001 --- /dev/null +++ b/merge_squash/.gitmastery-exercise.json @@ -0,0 +1,18 @@ +{ + "exercise_name": "merge-squash", + "tags": [ + "git-branch", + "git-merge", + "git-reset" + ], + "requires_git": true, + "requires_github": false, + "base_files": {}, + "exercise_repo": { + "repo_type": "local", + "repo_name": "friends-cast", + "repo_title": null, + "create_fork": null, + "init": true + } +} \ No newline at end of file diff --git a/merge_squash/README.md b/merge_squash/README.md new file mode 100644 index 00000000..e733be9e --- /dev/null +++ b/merge_squash/README.md @@ -0,0 +1,18 @@ +# merge-squash + + + +## Task + + + +## Hints + + + diff --git a/merge_squash/__init__.py b/merge_squash/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/merge_squash/download.py b/merge_squash/download.py new file mode 100644 index 00000000..b54a50c1 --- /dev/null +++ b/merge_squash/download.py @@ -0,0 +1,51 @@ +from exercise_utils.file import create_or_update_file +from exercise_utils.git import add, commit, checkout + + +def setup(verbose: bool = False): + create_or_update_file( + "joey.txt", + """ + Matt LeBlanc + """, + ) + add(["."], verbose) + commit("Add Joey", verbose) + + create_or_update_file( + "phoebe.txt", + """ + Lisa Kudrow + """, + ) + add(["."], verbose) + commit("Add Phoebe", verbose) + + checkout("supporting", True, verbose) + create_or_update_file( + "mike.txt", + """ + Paul Rudd + """, + ) + add(["."], verbose) + commit("Add Mike", verbose) + + create_or_update_file( + "janice.txt", + """ + Maggie Wheeler + """, + ) + add(["."], verbose) + commit("Add Janice", verbose) + + checkout("main", False, verbose) + create_or_update_file( + "ross.txt", + """ + David Schwimmer + """, + ) + add(["."], verbose) + commit("Add Ross", verbose) diff --git a/merge_squash/tests/__init__.py b/merge_squash/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/merge_squash/tests/specs/base.yml b/merge_squash/tests/specs/base.yml new file mode 100644 index 00000000..00c3a538 --- /dev/null +++ b/merge_squash/tests/specs/base.yml @@ -0,0 +1,6 @@ +initialization: + steps: + - type: commit + empty: true + message: Empty commit + id: start diff --git a/merge_squash/tests/test_verify.py b/merge_squash/tests/test_verify.py new file mode 100644 index 00000000..ce67711c --- /dev/null +++ b/merge_squash/tests/test_verify.py @@ -0,0 +1,12 @@ +from git_autograder import GitAutograderTestLoader + +from ..verify import verify + +REPOSITORY_NAME = "merge-squash" + +loader = GitAutograderTestLoader(__file__, REPOSITORY_NAME, verify) + + +def test_base(): + with loader.load("specs/base.yml", "start"): + pass diff --git a/merge_squash/verify.py b/merge_squash/verify.py new file mode 100644 index 00000000..1288d3de --- /dev/null +++ b/merge_squash/verify.py @@ -0,0 +1,11 @@ +from git_autograder import ( + GitAutograderOutput, + GitAutograderExercise, + GitAutograderStatus, +) + + +def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: + # INSERT YOUR GRADING CODE HERE + + return exercise.to_output([], GitAutograderStatus.SUCCESSFUL) From dc4ad65ac1b2398a3e750ddb0bfed6e21dc83dd0 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Wed, 10 Dec 2025 14:32:58 +0800 Subject: [PATCH 2/7] Add autograding (incomplete) There seems to be some issue with the squash option for the merge step in repo-smith --- merge_squash/README.md | 42 +++++++++--- merge_squash/tests/specs/base.yml | 63 +++++++++++++++++- .../tests/specs/missing_main_commits.yml | 60 +++++++++++++++++ .../tests/specs/non_squash_merge_used.yml | 66 +++++++++++++++++++ merge_squash/tests/specs/not_merged.yml | 63 ++++++++++++++++++ merge_squash/tests/test_verify.py | 25 +++++-- merge_squash/verify.py | 42 +++++++++++- 7 files changed, 345 insertions(+), 16 deletions(-) create mode 100644 merge_squash/tests/specs/missing_main_commits.yml create mode 100644 merge_squash/tests/specs/non_squash_merge_used.yml create mode 100644 merge_squash/tests/specs/not_merged.yml diff --git a/merge_squash/README.md b/merge_squash/README.md index e733be9e..df947c2d 100644 --- a/merge_squash/README.md +++ b/merge_squash/README.md @@ -1,18 +1,40 @@ # merge-squash - +You are keeping notes on the cast of a sitcom you've started watching. Initially, you kept main cast and supporting cast on two separate branches. + +```mermaid +gitGraph BT: + commit id: "Add Joey" + commit id: "Add Phoebe" + branch supporting + checkout supporting + commit id: "Add Mike" + commit id: "Add Janice" + checkout main + commit id: "Add Ross" +``` + +Now you wish to keep everything in the `main` branch. ## Task - +Squash-merge the `supporting` branch onto the `main` branch. + +The result should look as follows: + +```mermaid +gitGraph BT: + commit id: "Add Joey" + commit id: "Add Phoebe" + branch supporting + checkout supporting + commit id: "Add Mike" + commit id: "Add Janice" + checkout main + commit id: "Add Ross" + commit id: "Squash commit" +``` ## Hints - - +You have to commit manually after performing the squash merge. \ No newline at end of file diff --git a/merge_squash/tests/specs/base.yml b/merge_squash/tests/specs/base.yml index 00c3a538..c42a04b6 100644 --- a/merge_squash/tests/specs/base.yml +++ b/merge_squash/tests/specs/base.yml @@ -2,5 +2,66 @@ initialization: steps: - type: commit empty: true - message: Empty commit + message: Set initial state id: start + - type: new-file + filename: joey.txt + contents: | + Matt LeBlanc + - type: add + files: + - joey.txt + - type: commit + message: Add Joey + + - type: new-file + filename: phoebe.txt + contents: | + Lisa Kudrow + - type: add + files: + - phoebe.txt + - type: commit + message: Add Phoebe + + - type: branch + branch-name: supporting + - type: checkout + branch-name: supporting + + - type: new-file + filename: mike.txt + contents: | + Paul Rudd + - type: add + files: + - mike.txt + - type: commit + message: Add Mike + + - type: new-file + filename: janice.txt + contents: | + Maggie Wheeler + - type: add + files: + - janice.txt + - type: commit + message: Add Janice + + - type: checkout + branch-name: main + + - type: new-file + filename: ross.txt + contents: | + David Schwimmer + - type: add + files: + - ross.txt + - type: commit + message: Add Ross + + - type: merge + squash: true + branch-name: supporting diff --git a/merge_squash/tests/specs/missing_main_commits.yml b/merge_squash/tests/specs/missing_main_commits.yml new file mode 100644 index 00000000..655f64ba --- /dev/null +++ b/merge_squash/tests/specs/missing_main_commits.yml @@ -0,0 +1,60 @@ +initialization: + steps: + - type: commit + empty: true + message: Set initial state + id: start + - type: new-file + filename: joey.txt + contents: | + Matt LeBlanc + - type: add + files: + - joey.txt + - type: commit + message: Add Joey + + - type: branch + branch-name: supporting + - type: checkout + branch-name: supporting + + - type: new-file + filename: mike.txt + contents: | + Paul Rudd + - type: add + files: + - mike.txt + - type: commit + message: Add Mike + + - type: new-file + filename: janice.txt + contents: | + Maggie Wheeler + - type: add + files: + - janice.txt + - type: commit + message: Add Janice + + - type: checkout + branch-name: main + + - type: new-file + filename: ross.txt + contents: | + David Schwimmer + - type: add + files: + - ross.txt + - type: commit + message: Add Ross + + - type: merge + branch-name: supporting + squash: true + + - type: commit + message: Squash commit diff --git a/merge_squash/tests/specs/non_squash_merge_used.yml b/merge_squash/tests/specs/non_squash_merge_used.yml new file mode 100644 index 00000000..71150c83 --- /dev/null +++ b/merge_squash/tests/specs/non_squash_merge_used.yml @@ -0,0 +1,66 @@ +initialization: + steps: + - type: commit + empty: true + message: Set initial state + id: start + - type: new-file + filename: joey.txt + contents: | + Matt LeBlanc + - type: add + files: + - joey.txt + - type: commit + message: Add Joey + + - type: new-file + filename: phoebe.txt + contents: | + Lisa Kudrow + - type: add + files: + - phoebe.txt + - type: commit + message: Add Phoebe + + - type: branch + branch-name: supporting + - type: checkout + branch-name: supporting + + - type: new-file + filename: mike.txt + contents: | + Paul Rudd + - type: add + files: + - mike.txt + - type: commit + message: Add Mike + + - type: new-file + filename: janice.txt + contents: | + Maggie Wheeler + - type: add + files: + - janice.txt + - type: commit + message: Add Janice + + - type: checkout + branch-name: main + + - type: new-file + filename: ross.txt + contents: | + David Schwimmer + - type: add + files: + - ross.txt + - type: commit + message: Add Ross + + - type: merge + branch-name: supporting diff --git a/merge_squash/tests/specs/not_merged.yml b/merge_squash/tests/specs/not_merged.yml new file mode 100644 index 00000000..e89e099b --- /dev/null +++ b/merge_squash/tests/specs/not_merged.yml @@ -0,0 +1,63 @@ +initialization: + steps: + - type: commit + empty: true + message: Set initial state + id: start + - type: new-file + filename: joey.txt + contents: | + Matt LeBlanc + - type: add + files: + - joey.txt + - type: commit + message: Add Joey + + - type: new-file + filename: phoebe.txt + contents: | + Lisa Kudrow + - type: add + files: + - phoebe.txt + - type: commit + message: Add Phoebe + + - type: branch + branch-name: supporting + - type: checkout + branch-name: supporting + + - type: new-file + filename: mike.txt + contents: | + Paul Rudd + - type: add + files: + - mike.txt + - type: commit + message: Add Mike + + - type: new-file + filename: janice.txt + contents: | + Maggie Wheeler + - type: add + files: + - janice.txt + - type: commit + message: Add Janice + + - type: checkout + branch-name: main + + - type: new-file + filename: ross.txt + contents: | + David Schwimmer + - type: add + files: + - ross.txt + - type: commit + message: Add Ross diff --git a/merge_squash/tests/test_verify.py b/merge_squash/tests/test_verify.py index ce67711c..bb57c959 100644 --- a/merge_squash/tests/test_verify.py +++ b/merge_squash/tests/test_verify.py @@ -1,6 +1,11 @@ -from git_autograder import GitAutograderTestLoader +from git_autograder import GitAutograderStatus, GitAutograderTestLoader, assert_output -from ..verify import verify +from ..verify import ( + SQUASH_NOT_USED, + MAIN_COMMITS_INCORRECT, + CHANGES_FROM_SUPPORTING_NOT_PRESENT, + verify +) REPOSITORY_NAME = "merge-squash" @@ -8,5 +13,17 @@ def test_base(): - with loader.load("specs/base.yml", "start"): - pass + with loader.load("specs/base.yml") as output: + assert_output(output, GitAutograderStatus.SUCCESSFUL) + +def test_non_squash_merge_used(): + with loader.load("specs/non_squash_merge_used.yml") as output: + assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [SQUASH_NOT_USED]) + +def test_not_merged(): + with loader.load("specs/not_merged.yml") as output: + assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [CHANGES_FROM_SUPPORTING_NOT_PRESENT]) + +def test_missing_main_commits(): + with loader.load("specs/missing_main_commits.yml") as output: + assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [MAIN_COMMITS_INCORRECT]) diff --git a/merge_squash/verify.py b/merge_squash/verify.py index 1288d3de..95dc9277 100644 --- a/merge_squash/verify.py +++ b/merge_squash/verify.py @@ -4,8 +4,48 @@ GitAutograderStatus, ) +ADD_JOEY = "Add Joey" +ADD_PHOEBE = "Add Phoebe" +ADD_ROSS = "Add Ross" + +SQUASH_NOT_USED = ( + "You should be using squash merge, not regular merge." +) + +MAIN_COMMITS_INCORRECT = ( + "The main branch does not contain at least one of these commits: 'Add Joey', 'Add Phoebe' or 'Add Ross'." +) + +CHANGES_FROM_SUPPORTING_NOT_PRESENT = ( + "The main branch does not contain both files 'mike.txt' and 'janice.txt'." +) + def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: - # INSERT YOUR GRADING CODE HERE + main_branch = exercise.repo.branches.branch("main") + + commit_messages_in_main = [c.commit.message.strip() for c in main_branch.commits] + + merge_commits = [c for c in main_branch.commits if len(c.parents) > 1] + if merge_commits: + print("Yo" + merge_commits[0].commit.message) + print(commit_messages_in_main) + print(merge_commits[0].parents[0].commit.message) + print(merge_commits[0].parents[1].commit.message) + print(main_branch.commits[0].stats.files) + raise exercise.wrong_answer([SQUASH_NOT_USED]) + + with exercise.repo.files.file_or_none("mike.txt") as mike_file: + if mike_file is None: + raise exercise.wrong_answer([CHANGES_FROM_SUPPORTING_NOT_PRESENT]) + + with exercise.repo.files.file_or_none("janice.txt") as janice_file: + if janice_file is None: + raise exercise.wrong_answer([CHANGES_FROM_SUPPORTING_NOT_PRESENT]) + + if not all( + msg in commit_messages_in_main for msg in [ADD_JOEY, ADD_PHOEBE, ADD_ROSS] + ): + raise exercise.wrong_answer([MAIN_COMMITS_INCORRECT]) return exercise.to_output([], GitAutograderStatus.SUCCESSFUL) From e39ecf5d7d09598f0b8f599c496942cd08cd3089 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Wed, 10 Dec 2025 15:08:07 +0800 Subject: [PATCH 3/7] Clean up autograding --- merge_squash/tests/test_verify.py | 3 +++ merge_squash/verify.py | 11 +---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/merge_squash/tests/test_verify.py b/merge_squash/tests/test_verify.py index bb57c959..ec45c002 100644 --- a/merge_squash/tests/test_verify.py +++ b/merge_squash/tests/test_verify.py @@ -16,14 +16,17 @@ def test_base(): with loader.load("specs/base.yml") as output: assert_output(output, GitAutograderStatus.SUCCESSFUL) + def test_non_squash_merge_used(): with loader.load("specs/non_squash_merge_used.yml") as output: assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [SQUASH_NOT_USED]) + def test_not_merged(): with loader.load("specs/not_merged.yml") as output: assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [CHANGES_FROM_SUPPORTING_NOT_PRESENT]) + def test_missing_main_commits(): with loader.load("specs/missing_main_commits.yml") as output: assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [MAIN_COMMITS_INCORRECT]) diff --git a/merge_squash/verify.py b/merge_squash/verify.py index 95dc9277..dfde6c50 100644 --- a/merge_squash/verify.py +++ b/merge_squash/verify.py @@ -4,10 +4,6 @@ GitAutograderStatus, ) -ADD_JOEY = "Add Joey" -ADD_PHOEBE = "Add Phoebe" -ADD_ROSS = "Add Ross" - SQUASH_NOT_USED = ( "You should be using squash merge, not regular merge." ) @@ -28,11 +24,6 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: merge_commits = [c for c in main_branch.commits if len(c.parents) > 1] if merge_commits: - print("Yo" + merge_commits[0].commit.message) - print(commit_messages_in_main) - print(merge_commits[0].parents[0].commit.message) - print(merge_commits[0].parents[1].commit.message) - print(main_branch.commits[0].stats.files) raise exercise.wrong_answer([SQUASH_NOT_USED]) with exercise.repo.files.file_or_none("mike.txt") as mike_file: @@ -44,7 +35,7 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: raise exercise.wrong_answer([CHANGES_FROM_SUPPORTING_NOT_PRESENT]) if not all( - msg in commit_messages_in_main for msg in [ADD_JOEY, ADD_PHOEBE, ADD_ROSS] + msg in commit_messages_in_main for msg in ["Add Joey", "Add Phoebe", "Add Ross"] ): raise exercise.wrong_answer([MAIN_COMMITS_INCORRECT]) From c9629ffbb94eee7803f9773cc9e27861d559fdd1 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Thu, 11 Dec 2025 17:10:14 +0800 Subject: [PATCH 4/7] Fix verification logic and add message --- merge_squash/verify.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/merge_squash/verify.py b/merge_squash/verify.py index dfde6c50..df0f085a 100644 --- a/merge_squash/verify.py +++ b/merge_squash/verify.py @@ -20,12 +20,6 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: main_branch = exercise.repo.branches.branch("main") - commit_messages_in_main = [c.commit.message.strip() for c in main_branch.commits] - - merge_commits = [c for c in main_branch.commits if len(c.parents) > 1] - if merge_commits: - raise exercise.wrong_answer([SQUASH_NOT_USED]) - with exercise.repo.files.file_or_none("mike.txt") as mike_file: if mike_file is None: raise exercise.wrong_answer([CHANGES_FROM_SUPPORTING_NOT_PRESENT]) @@ -34,9 +28,15 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: if janice_file is None: raise exercise.wrong_answer([CHANGES_FROM_SUPPORTING_NOT_PRESENT]) + commit_messages_in_main = [c.commit.message.strip() for c in main_branch.commits] + merge_commits = [c for c in main_branch.commits if len(c.parents) > 1] + + if merge_commits or ("Squash" not in commit_messages_in_main[0]): + raise exercise.wrong_answer([SQUASH_NOT_USED]) + if not all( msg in commit_messages_in_main for msg in ["Add Joey", "Add Phoebe", "Add Ross"] ): raise exercise.wrong_answer([MAIN_COMMITS_INCORRECT]) - return exercise.to_output([], GitAutograderStatus.SUCCESSFUL) + return exercise.to_output(["Good job performing a merge squash!"], GitAutograderStatus.SUCCESSFUL) From 6b868b6dad2aecf2850efa7a66658f8b7948b703 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Wed, 17 Dec 2025 21:02:28 +0800 Subject: [PATCH 5/7] Improve exercise verification --- merge_squash/README.md | 41 +---------- .../tests/specs/wrong_branch_squashed.yml | 70 +++++++++++++++++++ merge_squash/tests/test_verify.py | 5 ++ merge_squash/verify.py | 12 +++- 4 files changed, 87 insertions(+), 41 deletions(-) create mode 100644 merge_squash/tests/specs/wrong_branch_squashed.yml diff --git a/merge_squash/README.md b/merge_squash/README.md index df947c2d..1a9b00c7 100644 --- a/merge_squash/README.md +++ b/merge_squash/README.md @@ -1,40 +1 @@ -# merge-squash - -You are keeping notes on the cast of a sitcom you've started watching. Initially, you kept main cast and supporting cast on two separate branches. - -```mermaid -gitGraph BT: - commit id: "Add Joey" - commit id: "Add Phoebe" - branch supporting - checkout supporting - commit id: "Add Mike" - commit id: "Add Janice" - checkout main - commit id: "Add Ross" -``` - -Now you wish to keep everything in the `main` branch. - -## Task - -Squash-merge the `supporting` branch onto the `main` branch. - -The result should look as follows: - -```mermaid -gitGraph BT: - commit id: "Add Joey" - commit id: "Add Phoebe" - branch supporting - checkout supporting - commit id: "Add Mike" - commit id: "Add Janice" - checkout main - commit id: "Add Ross" - commit id: "Squash commit" -``` - -## Hints - -You have to commit manually after performing the squash merge. \ No newline at end of file +See https://git-mastery.github.io/lessons/merge/exercise-merge-squash.html \ No newline at end of file diff --git a/merge_squash/tests/specs/wrong_branch_squashed.yml b/merge_squash/tests/specs/wrong_branch_squashed.yml new file mode 100644 index 00000000..cf1c282c --- /dev/null +++ b/merge_squash/tests/specs/wrong_branch_squashed.yml @@ -0,0 +1,70 @@ +initialization: + steps: + - type: commit + empty: true + message: Set initial state + id: start + - type: new-file + filename: joey.txt + contents: | + Matt LeBlanc + - type: add + files: + - joey.txt + - type: commit + message: Add Joey + + - type: new-file + filename: phoebe.txt + contents: | + Lisa Kudrow + - type: add + files: + - phoebe.txt + - type: commit + message: Add Phoebe + + - type: branch + branch-name: supporting + - type: checkout + branch-name: supporting + + - type: new-file + filename: mike.txt + contents: | + Paul Rudd + - type: add + files: + - mike.txt + - type: commit + message: Add Mike + + - type: new-file + filename: janice.txt + contents: | + Maggie Wheeler + - type: add + files: + - janice.txt + - type: commit + message: Add Janice + + - type: checkout + branch-name: main + + - type: new-file + filename: ross.txt + contents: | + David Schwimmer + - type: add + files: + - ross.txt + - type: commit + message: Add Ross + + - type: checkout + branch-name: supporting + + - type: merge + squash: true + branch-name: main diff --git a/merge_squash/tests/test_verify.py b/merge_squash/tests/test_verify.py index ec45c002..4eca1ec5 100644 --- a/merge_squash/tests/test_verify.py +++ b/merge_squash/tests/test_verify.py @@ -4,6 +4,7 @@ SQUASH_NOT_USED, MAIN_COMMITS_INCORRECT, CHANGES_FROM_SUPPORTING_NOT_PRESENT, + SQUASH_ON_SUPPORTING, verify ) @@ -30,3 +31,7 @@ def test_not_merged(): def test_missing_main_commits(): with loader.load("specs/missing_main_commits.yml") as output: assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [MAIN_COMMITS_INCORRECT]) + +def test_wrong_branch_squashed(): + with loader.load("specs/wrong_branch_squashed.yml") as output: + assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [SQUASH_ON_SUPPORTING]) diff --git a/merge_squash/verify.py b/merge_squash/verify.py index df0f085a..8243ef6e 100644 --- a/merge_squash/verify.py +++ b/merge_squash/verify.py @@ -16,6 +16,10 @@ "The main branch does not contain both files 'mike.txt' and 'janice.txt'." ) +SQUASH_ON_SUPPORTING = ( + "You are working on the wrong branch! Bring the changes from supporting onto main, not the other way around." +) + def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: main_branch = exercise.repo.branches.branch("main") @@ -31,7 +35,7 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: commit_messages_in_main = [c.commit.message.strip() for c in main_branch.commits] merge_commits = [c for c in main_branch.commits if len(c.parents) > 1] - if merge_commits or ("Squash" not in commit_messages_in_main[0]): + if merge_commits: raise exercise.wrong_answer([SQUASH_NOT_USED]) if not all( @@ -39,4 +43,10 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: ): raise exercise.wrong_answer([MAIN_COMMITS_INCORRECT]) + try: + exercise.repo.repo.commit("supporting").tree / "ross.txt" + raise exercise.wrong_answer([SQUASH_ON_SUPPORTING]) + except KeyError: + pass + return exercise.to_output(["Good job performing a merge squash!"], GitAutograderStatus.SUCCESSFUL) From d9100b0c3f2fdca0a6c849e4f4a1f2510d4cb788 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Wed, 17 Dec 2025 21:04:33 +0800 Subject: [PATCH 6/7] Fix linter type issue --- merge_squash/verify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/merge_squash/verify.py b/merge_squash/verify.py index 8243ef6e..2315b55c 100644 --- a/merge_squash/verify.py +++ b/merge_squash/verify.py @@ -32,7 +32,7 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: if janice_file is None: raise exercise.wrong_answer([CHANGES_FROM_SUPPORTING_NOT_PRESENT]) - commit_messages_in_main = [c.commit.message.strip() for c in main_branch.commits] + commit_messages_in_main = [str(c.commit.message.strip()) for c in main_branch.commits] merge_commits = [c for c in main_branch.commits if len(c.parents) > 1] if merge_commits: From d9c294d04c8ddf822ce72ae0604a0542d1716024 Mon Sep 17 00:00:00 2001 From: Vikram Goyal Date: Thu, 18 Dec 2025 00:59:24 +0800 Subject: [PATCH 7/7] Add check for uncommitted files --- merge_squash/verify.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/merge_squash/verify.py b/merge_squash/verify.py index 2315b55c..5863e978 100644 --- a/merge_squash/verify.py +++ b/merge_squash/verify.py @@ -16,6 +16,10 @@ "The main branch does not contain both files 'mike.txt' and 'janice.txt'." ) +SQUASH_NOT_COMMITTED = ( + "You have not committed the staged files! Remember, you need to manually commit after a squash merge!" +) + SQUASH_ON_SUPPORTING = ( "You are working on the wrong branch! Bring the changes from supporting onto main, not the other way around." ) @@ -38,6 +42,9 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: if merge_commits: raise exercise.wrong_answer([SQUASH_NOT_USED]) + if exercise.repo.repo.is_dirty(): + raise exercise.wrong_answer([SQUASH_NOT_COMMITTED]) + if not all( msg in commit_messages_in_main for msg in ["Add Joey", "Add Phoebe", "Add Ross"] ):