Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions glossary_branch_delete/.gitmastery-exercise.json
Original file line number Diff line number Diff line change
@@ -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
}
}
1 change: 1 addition & 0 deletions glossary_branch_delete/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://git-mastery.org/lessons/remoteBranchDelete/exercise-glossary-branch-delete.html
Empty file.
27 changes: 27 additions & 0 deletions glossary_branch_delete/download.py
Copy link
Copy Markdown
Collaborator

@jovnc jovnc Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, download.py doesn't fetch branch VWX as well, so local repository would only have main branch. If we want VWX in local repository as well, we can add a step to fetch it from remote as well.

While the exercise instruction does state to delete both local and remote VWX branches, I think it may not be necessary to add in this logic since the purpose of the exercise is to test students interacting with remote repositories.

@damithc Do you think we should remove deleting local branch VWX or stick to the current exercise that requires students to delete both local and remote branches?

Original file line number Diff line number Diff line change
@@ -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)
83 changes: 83 additions & 0 deletions glossary_branch_delete/test_verify.py
Original file line number Diff line number Diff line change
@@ -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],
)
34 changes: 34 additions & 0 deletions glossary_branch_delete/verify.py
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested and works well!

Image

Original file line number Diff line number Diff line change
@@ -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,
)