diff --git a/glossary_branch_delete/.gitmastery-exercise.json b/glossary_branch_delete/.gitmastery-exercise.json new file mode 100644 index 00000000..aaacf5e6 --- /dev/null +++ b/glossary_branch_delete/.gitmastery-exercise.json @@ -0,0 +1,16 @@ +{ + "exercise_name": "glossary-branch-delete", + "tags": [ + "git-push" + ], + "requires_git": true, + "requires_github": true, + "base_files": {}, + "exercise_repo": { + "repo_type": "local", + "repo_name": "funny-glossary", + "repo_title": null, + "create_fork": null, + "init": false + } +} \ No newline at end of file diff --git a/glossary_branch_delete/README.md b/glossary_branch_delete/README.md new file mode 100644 index 00000000..c32afa84 --- /dev/null +++ b/glossary_branch_delete/README.md @@ -0,0 +1 @@ +https://git-mastery.org/lessons/remoteBranchDelete/exercise-glossary-branch-delete.html \ No newline at end of file diff --git a/glossary_branch_delete/__init__.py b/glossary_branch_delete/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/glossary_branch_delete/download.py b/glossary_branch_delete/download.py new file mode 100644 index 00000000..c40ea884 --- /dev/null +++ b/glossary_branch_delete/download.py @@ -0,0 +1,27 @@ +from exercise_utils.git import checkout +from exercise_utils.github_cli import ( + clone_repo_with_gh, + delete_repo, + fork_repo, + get_github_username, + has_repo, +) + +REPO_OWNER = "git-mastery" +REPO_NAME = "samplerepo-funny-glossary" + + +def setup(verbose: bool = False): + username = get_github_username(verbose) + FORK_NAME = f"{username}-gitmastery-samplerepo-funny-glossary" + + if has_repo(FORK_NAME, True, verbose): + delete_repo(FORK_NAME, verbose) + + fork_repo(f"{REPO_OWNER}/{REPO_NAME}", FORK_NAME, verbose, False) + + clone_repo_with_gh(f"https://github.com/{username}/{FORK_NAME}", verbose, ".") + + # creates VWX branch locally, tracking remote branch + checkout("VWX", False, verbose) + checkout("main", False, verbose) diff --git a/glossary_branch_delete/test_verify.py b/glossary_branch_delete/test_verify.py new file mode 100644 index 00000000..8d0fba25 --- /dev/null +++ b/glossary_branch_delete/test_verify.py @@ -0,0 +1,83 @@ +from contextlib import contextmanager +from typing import Iterator, Tuple + +from exercise_utils.test import ( + GitAutograderTest, + GitAutograderTestLoader, + assert_output, +) +from git_autograder import GitAutograderStatus +from repo_smith.repo_smith import RepoSmith + +from .verify import ( + VWX_BRANCH_EXISTS_LOCALLY, + VWX_BRANCH_EXISTS_REMOTELY, + verify, +) + +REPOSITORY_NAME = "glossary-branch-delete" + +loader = GitAutograderTestLoader(REPOSITORY_NAME, verify) + + +@contextmanager +def base_setup() -> Iterator[Tuple[GitAutograderTest, RepoSmith]]: + with loader.start(include_remote_repo=True) as (test, rs, rs_remote): + remote_path = str(rs_remote.repo.git_dir) + rs.git.remote_add("origin", remote_path) + + # doesnt create a branch on remote + rs_remote.git.commit(allow_empty=True, message="Initial commit") + rs_remote.git.checkout("TEST", branch=True) + + # works + rs.git.checkout("VWX", branch=True) + rs.git.commit(allow_empty=True, message="Empty commit") + rs.git.push("origin", "VWX") + + rs.git.checkout("main") + + yield test, rs + + +def test_base(): + with base_setup() as (test, rs): + rs.git.push("origin", ":VWX") + rs.repo.delete_head("VWX", force=True) + + output = test.run() + assert_output(output, GitAutograderStatus.SUCCESSFUL) + + +def test_vwx_exists_remotely(): + with base_setup() as (test, rs): + output = test.run() + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [VWX_BRANCH_EXISTS_REMOTELY], + ) + + +def test_vwx_exists_locally(): + with base_setup() as (test, rs): + rs.git.checkout("VWX") + + output = test.run() + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [VWX_BRANCH_EXISTS_LOCALLY], + ) + + +def test_vwx_exists_both(): + with base_setup() as (test, rs): + rs.git.checkout("VWX") + + output = test.run() + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [VWX_BRANCH_EXISTS_LOCALLY, VWX_BRANCH_EXISTS_REMOTELY], + ) diff --git a/glossary_branch_delete/verify.py b/glossary_branch_delete/verify.py new file mode 100644 index 00000000..353e85a0 --- /dev/null +++ b/glossary_branch_delete/verify.py @@ -0,0 +1,34 @@ +from typing import List +from git_autograder import ( + GitAutograderOutput, + GitAutograderExercise, + GitAutograderStatus, +) + +VWX_BRANCH_EXISTS_REMOTELY = ( + "Branch 'VWX' still exists on the remote! Remember to delete it from the remote." +) + +VWX_BRANCH_EXISTS_LOCALLY = "Branch 'VWX' still exists locally! Remember to delete it from your local repository." + + +def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: + comments: List[str] = [] + + local_branches = [h.name for h in exercise.repo.repo.heads] + if "VWX" in local_branches: + comments.append(VWX_BRANCH_EXISTS_LOCALLY) + + try: + exercise.repo.repo.refs["origin/VWX"] + comments.append(VWX_BRANCH_EXISTS_REMOTELY) + except (IndexError, KeyError): + pass # Branch doesn't exist on remote, which is what we want + + if comments: + raise exercise.wrong_answer(comments) + + return exercise.to_output( + ["Great job deleting the VWX branch!"], + GitAutograderStatus.SUCCESSFUL, + )