diff --git a/glossary_branch_rename/test_verify.py b/glossary_branch_rename/test_verify.py index 1196d669..bee224f0 100644 --- a/glossary_branch_rename/test_verify.py +++ b/glossary_branch_rename/test_verify.py @@ -10,6 +10,8 @@ from repo_smith.repo_smith import RepoSmith from .verify import ( + NO_RENAME_EVIDENCE, + RESET_MESSAGE, verify, STU_LOCAL_PRESENT, STU_REMOTE_PRESENT, @@ -126,3 +128,20 @@ def test_remote_old_branch_still_exists(): output = test.run() assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [STU_REMOTE_PRESENT]) + +def test_no_rename_evidence(): + with base_setup() as (test, rs): + rs.git.checkout(EXPECTED_NEW_BRANCH_NAME, branch=True) + rs.git.push("origin", EXPECTED_NEW_BRANCH_NAME) + rs.git.branch(BRANCH_TO_RENAME, delete=True) + rs.git.push("origin", f":{BRANCH_TO_RENAME}") + + output = test.run() + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + NO_RENAME_EVIDENCE, + RESET_MESSAGE, + ], + ) \ No newline at end of file diff --git a/glossary_branch_rename/verify.py b/glossary_branch_rename/verify.py index 23f0ac8e..17de47cc 100644 --- a/glossary_branch_rename/verify.py +++ b/glossary_branch_rename/verify.py @@ -1,3 +1,4 @@ +import re from git_autograder import ( GitAutograderOutput, GitAutograderExercise, @@ -11,6 +12,32 @@ RENAMED_LOCAL_MISSING = f"Local branch {RENAMED_BRANCH} is missing." STU_REMOTE_PRESENT = f"Remote branch {STU_BRANCH} still exists." RENAMED_REMOTE_MISSING = f"Remote branch {RENAMED_BRANCH} is missing." +NO_RENAME_EVIDENCE = f"Local branch '{STU_BRANCH}' was not renamed to '{RENAMED_BRANCH}'!" +RESET_MESSAGE = 'If needed, reset the repository using "gitmastery progress reset" and start again.' + + +def branch_has_rename_evidence( + exercise: GitAutograderExercise, new_branch: str, old_branch: str +) -> bool: + """Performs a DFS on the branch renames starting with STU till S-to-Z. + + This is necessary since the renames could be performed in parts: + + STU -> S-to-U -> S-to-Z + """ + branch = exercise.repo.branches.branch(new_branch) + + rename_regex = re.compile("^renamed refs/heads/(.+) to refs/heads/(.+)$") + for entry in branch.reflog[::-1]: + match_group = rename_regex.match(entry.message) + if match_group is None: + continue + original = match_group.group(1) + new = match_group.group(2) + if original == old_branch: + old_branch = new + + return old_branch == new_branch def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: @@ -42,6 +69,9 @@ def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: if comments: raise exercise.wrong_answer(comments) + + if not branch_has_rename_evidence(exercise, RENAMED_BRANCH, STU_BRANCH): + raise exercise.wrong_answer([NO_RENAME_EVIDENCE, RESET_MESSAGE]) return exercise.to_output( ["Nice work renaming the branch locally and on the remote!"],