-
Notifications
You must be signed in to change notification settings - Fork 25
Implement T8L2/glossary-branch-pull #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
VikramGoyal23
merged 18 commits into
git-mastery:main
from
desmondwong1215:e-glossary-branch-pull
Feb 6, 2026
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
032dc4a
Implement download.py
desmondwong1215 4ae24d0
Update README.md
desmondwong1215 568337b
Implement setup logic
desmondwong1215 a52163f
Implement verify logic
desmondwong1215 2eddc7a
Improve verify logic
desmondwong1215 913d02b
Merge branch 'main' of https://github.com/git-mastery/exercises into …
desmondwong1215 30b0750
Remove resources
desmondwong1215 6e81193
Add wrong_answer
desmondwong1215 b5fe84c
Fix bug
desmondwong1215 54176d3
Merge branch 'main' of https://github.com/git-mastery/exercises into …
desmondwong1215 375a2b8
Improve logic
desmondwong1215 e023ba2
Change e.txt to d.txt
desmondwong1215 190bc3a
Improve verify logic
desmondwong1215 1378c76
Implement test_verify
desmondwong1215 7d3c756
Change pull to fetch and merge
desmondwong1215 90436a1
Merge branch 'main' of https://github.com/git-mastery/exercises into …
desmondwong1215 5e0bb35
Change to clone_repo_with_gh
desmondwong1215 004ab7f
Improve verify logic
desmondwong1215 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "exercise_name": "glossary-branch-pull", | ||
| "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 | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| See https://git-mastery.github.io/lessons/remoteBranchPull/exercise-glossary-branch-pull.html |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| from exercise_utils.cli import run_command | ||
| from exercise_utils.file import create_or_update_file | ||
| from exercise_utils.git import add, checkout, commit, remove_remote | ||
| from exercise_utils.github_cli import ( | ||
| clone_repo_with_gh, | ||
| get_github_username, | ||
| fork_repo, | ||
| has_repo, | ||
| delete_repo, | ||
| ) | ||
|
|
||
| TARGET_REPO = "git-mastery/samplerepo-funny-glossary" | ||
| FORK_NAME = "gitmastery-samplerepo-funny-glossary" | ||
|
|
||
|
|
||
| def setup(verbose: bool = False): | ||
| username = get_github_username(verbose) | ||
| full_repo_name = f"{username}/{FORK_NAME}" | ||
|
|
||
| if has_repo(full_repo_name, True, verbose): | ||
| delete_repo(full_repo_name, verbose) | ||
|
|
||
| fork_repo(TARGET_REPO, FORK_NAME, verbose, False) | ||
| clone_repo_with_gh(f"{username}/{FORK_NAME}", verbose, ".") | ||
| remove_remote("upstream", verbose) | ||
|
|
||
| run_command(["git", "branch", "-dr", "origin/VWX"], verbose) | ||
|
|
||
| checkout("ABC", False, verbose) | ||
| run_command(["git", "reset", "--hard", "HEAD~1"], verbose) | ||
|
|
||
| checkout("DEF", False, verbose) | ||
| run_command(["git", "reset", "--hard", "HEAD~1"], verbose) | ||
| create_or_update_file( | ||
| "d.txt", | ||
| """ | ||
| documentation: Evidence that someone once cared. | ||
| """) | ||
| add(["d.txt"], verbose) | ||
| commit("Add 'documentation'", verbose) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| 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 ( | ||
| verify, | ||
| BRANCH_MISSING, | ||
| BRANCH_NOT_TRACKING, | ||
| REMOTE_COMMIT_MISSING, | ||
| LOCAL_COMMIT_MISSING, | ||
| ) | ||
|
|
||
| REPOSITORY_NAME = "glossary-branch-pull" | ||
|
|
||
| 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) | ||
|
|
||
| rs.git.commit(allow_empty=True, message="Initial commit") | ||
|
|
||
| rs.git.checkout("ABC", branch=True) | ||
| rs.git.commit(allow_empty=True, message="Add 'cache'") | ||
| rs.git.push("origin", "ABC", set_upstream=True) | ||
| rs.git.reset("HEAD~1", hard=True) | ||
|
|
||
| rs.git.checkout("DEF", branch=True) | ||
| rs.git.commit(allow_empty=True, message="Add 'exception'") | ||
| rs.git.push("origin", "DEF", set_upstream=True) | ||
| rs.git.reset("HEAD~1", hard=True) | ||
| rs.git.commit(allow_empty=True, message="Add 'documentation'") | ||
|
|
||
| yield (test, rs) | ||
|
|
||
| def test_no_changes(): | ||
| with base_setup() as (test, rs): | ||
| output = test.run() | ||
| assert_output( | ||
| output, | ||
| GitAutograderStatus.UNSUCCESSFUL, | ||
| [ | ||
| BRANCH_MISSING.format(branch="STU"), | ||
| BRANCH_MISSING.format(branch="VWX"), | ||
| REMOTE_COMMIT_MISSING.format(branch="ABC"), | ||
| REMOTE_COMMIT_MISSING.format(branch="DEF") | ||
| ]) | ||
|
|
||
|
|
||
| def test_branch_not_tracking(): | ||
| with base_setup() as (test, rs): | ||
| rs.git.checkout("STU", branch=True) | ||
| rs.git.checkout("VWX", branch=True) | ||
|
|
||
| output = test.run() | ||
| assert_output( | ||
| output, | ||
| GitAutograderStatus.UNSUCCESSFUL, | ||
| [ | ||
| BRANCH_NOT_TRACKING.format(branch="STU"), | ||
| BRANCH_NOT_TRACKING.format(branch="VWX"), | ||
| REMOTE_COMMIT_MISSING.format(branch="ABC"), | ||
| REMOTE_COMMIT_MISSING.format(branch="DEF") | ||
| ]) | ||
|
|
||
|
|
||
| def test_def_local_commit_missing(): | ||
| with base_setup() as (test, rs): | ||
| rs.git.checkout("STU", branch=True) | ||
| rs.git.push("origin", "STU") | ||
|
|
||
| rs.git.checkout("VWX", branch=True) | ||
| rs.git.push("origin", "VWX") | ||
|
|
||
| rs.git.checkout("ABC") | ||
| rs.git.commit(allow_empty=True, message="Add 'cache'") | ||
|
|
||
| rs.git.checkout("DEF") | ||
| rs.git.reset("HEAD~1", hard=True) | ||
| rs.git.fetch("origin") | ||
| rs.git.merge("origin/DEF") | ||
|
|
||
| output = test.run() | ||
| assert_output( | ||
| output, | ||
| GitAutograderStatus.UNSUCCESSFUL, | ||
| [LOCAL_COMMIT_MISSING]) | ||
|
|
||
|
|
||
| def test_successful_changes(): | ||
| with base_setup() as (test, rs): | ||
| rs.git.checkout("VWX", branch=True) | ||
| rs.git.push("origin", "VWX", set_upstream=True) | ||
|
|
||
| rs.git.checkout("STU", branch=True) | ||
| rs.git.push("origin", "STU", set_upstream=True) | ||
|
|
||
| rs.git.checkout("ABC") | ||
| rs.git.fetch("origin") | ||
| rs.git.merge("origin/ABC") | ||
|
|
||
| rs.git.checkout("DEF") | ||
| rs.git.fetch("origin") | ||
| rs.git.merge("origin/DEF") | ||
|
|
||
| output = test.run() | ||
| assert_output(output, GitAutograderStatus.SUCCESSFUL) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| from typing import List | ||
| from git_autograder import ( | ||
| GitAutograderCommit, | ||
| GitAutograderOutput, | ||
| GitAutograderExercise, | ||
| GitAutograderStatus, | ||
| ) | ||
|
|
||
| BRANCH_MISSING = "The local {branch} branch is not created." | ||
| BRANCH_NOT_TRACKING = "The local {branch} branch does not track origin/{branch}." | ||
| REMOTE_COMMIT_MISSING = "New commit in the remote {branch} branch is not pulled to the local {branch} branch." | ||
| LOCAL_COMMIT_MISSING = "The original local commit on DEF is missing. " \ | ||
| "You may have lost your work instead of merging." | ||
|
|
||
|
|
||
| def get_commit_from_message(commits: List[GitAutograderCommit], message: str) \ | ||
| -> GitAutograderCommit | None: | ||
| """Find a commit with the given message from a list of commits.""" | ||
| for commit in commits: | ||
| if message.strip() == commit.commit.message.strip(): | ||
| return commit | ||
| return None | ||
|
|
||
| def get_commit_from_hexsha(commits: List[GitAutograderCommit], hexsha: str) \ | ||
| -> GitAutograderCommit | None: | ||
| """Find a commit with the given hexsha from a list of commits.""" | ||
| for commit in commits: | ||
| if hexsha.strip() == commit.commit.hexsha.strip(): | ||
| return commit | ||
| return None | ||
|
|
||
| def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: | ||
| repo = exercise.repo | ||
| comments = [] | ||
|
|
||
| if not repo.branches.has_branch("STU"): | ||
| comments.append(BRANCH_MISSING.format(branch="STU")) | ||
| else: | ||
| stu_branch = repo.branches.branch("STU").branch | ||
| remote_stu = stu_branch.tracking_branch() | ||
| if not remote_stu or remote_stu.name != "origin/STU": | ||
| comments.append(BRANCH_NOT_TRACKING.format(branch="STU")) | ||
|
|
||
| if not repo.branches.has_branch("VWX"): | ||
| comments.append(BRANCH_MISSING.format(branch="VWX")) | ||
| else: | ||
| vwx_branch = repo.branches.branch("VWX").branch | ||
| remote_vwx = vwx_branch.tracking_branch() | ||
| if not remote_vwx or remote_vwx.name != "origin/VWX": | ||
| comments.append(BRANCH_NOT_TRACKING.format(branch="VWX")) | ||
|
|
||
| if not repo.branches.has_branch("ABC"): | ||
| comments.append(BRANCH_MISSING.format(branch="ABC")) | ||
| else: | ||
| abc_commits = repo.branches.branch("ABC").commits | ||
| abc_branch = repo.branches.branch("ABC").branch | ||
| remote_abc = abc_branch.tracking_branch() | ||
| if not remote_abc or remote_abc.name != "origin/ABC": | ||
| comments.append(BRANCH_NOT_TRACKING.format(branch="ABC")) | ||
| elif not get_commit_from_hexsha(abc_commits, remote_abc.commit.hexsha): | ||
| comments.append(REMOTE_COMMIT_MISSING.format(branch="ABC")) | ||
|
|
||
| if not repo.branches.has_branch("DEF"): | ||
| comments.append(BRANCH_MISSING.format(branch="DEF")) | ||
| else: | ||
| def_commits = repo.branches.branch("DEF").commits | ||
| if not get_commit_from_message(def_commits, "Add 'documentation'"): | ||
| comments.append(LOCAL_COMMIT_MISSING) | ||
| def_branch = repo.branches.branch("DEF").branch | ||
| remote_def = def_branch.tracking_branch() | ||
| if not remote_def or remote_def.name != "origin/DEF": | ||
| comments.append(BRANCH_NOT_TRACKING.format(branch="DEF")) | ||
| elif not get_commit_from_hexsha(def_commits, remote_def.commit.hexsha): | ||
| comments.append(REMOTE_COMMIT_MISSING.format(branch="DEF")) | ||
|
|
||
| if comments: | ||
| raise exercise.wrong_answer(comments) | ||
| return exercise.to_output([ | ||
| "Great work! All required branches are present and correctly set up." | ||
| ], GitAutograderStatus.SUCCESSFUL) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.