-
Notifications
You must be signed in to change notification settings - Fork 26
Implement exercise T6L2/branch-compare #115
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
jovnc
merged 22 commits into
git-mastery:main
from
lavanyagarg112:feat/exercise-branch-compare
Dec 15, 2025
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
ff275e1
initialise exercise
lavanyagarg112 6fe5566
setup task instructions and answers.txt
lavanyagarg112 0b2d808
add setup for this exercise
lavanyagarg112 ff7c730
update setup
lavanyagarg112 73c727d
update exercise json
lavanyagarg112 00cb16c
add basic verify function
lavanyagarg112 9e662fb
add base test
lavanyagarg112 9eccc4d
add unittest for invalid cases
lavanyagarg112 01b9415
modify answers.txt
lavanyagarg112 62bf2da
modify answers.txt and verify
lavanyagarg112 a63e7cc
modify verify
lavanyagarg112 43d1034
add check for changes made to the branch
lavanyagarg112 dee23e0
update has made changes
lavanyagarg112 8d4e276
remove debug statements
lavanyagarg112 b21b1e2
add tests and modify branch change function
lavanyagarg112 85505df
update questions to be more clear
lavanyagarg112 4bb57ce
update repo name in json
lavanyagarg112 45e03ea
remove unused components and update insertion
lavanyagarg112 c60152b
update readme and add link to exercise
lavanyagarg112 341808b
update questions to match issue description
lavanyagarg112 3eccd0b
[branch-compare] Run ruff format and update README
jovnc b9b6345
[branch-compare] Clean up test and verification code
jovnc 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": "branch-compare", | ||
| "tags": ["git-branch", "git-diff"], | ||
| "requires_git": true, | ||
| "requires_github": false, | ||
| "base_files": { | ||
| "answers.txt": "answers.txt" | ||
| }, | ||
| "exercise_repo": { | ||
| "repo_type": "local", | ||
| "repo_name": "data-streams", | ||
| "repo_title": null, | ||
| "create_fork": null, | ||
| "init": true | ||
| } | ||
| } |
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/branch/exercise-branch-compare.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,55 @@ | ||
| from exercise_utils.git import add, commit, checkout | ||
| from exercise_utils.file import append_to_file, create_or_update_file | ||
|
|
||
| import random | ||
|
|
||
|
|
||
| def get_sequence(n=1000, digits=8, seed=None): | ||
| rng = random.Random(seed) | ||
| lo, hi = 10 ** (digits - 1), 10**digits - 1 | ||
| return rng.sample(range(lo, hi + 1), k=n) | ||
|
|
||
|
|
||
| def get_modified_sequence(seq, digits=8, idx=None, seed=None): | ||
| rng = random.Random(seed) | ||
| n = len(seq) | ||
| if idx is None: | ||
| idx = rng.randrange(n) | ||
|
|
||
| modified = seq.copy() | ||
| seen = set(seq) | ||
| lo, hi = 10 ** (digits - 1), 10**digits - 1 | ||
|
|
||
| old = modified[idx] | ||
| new = old | ||
| while new in seen: | ||
| new = rng.randint(lo, hi) | ||
| modified[idx] = new | ||
| return modified | ||
|
|
||
|
|
||
| def setup(verbose: bool = False): | ||
| orig_data = get_sequence() | ||
| modified_data = get_modified_sequence(orig_data) | ||
|
|
||
| create_or_update_file("data.txt", "") | ||
| add(["data.txt"], verbose) | ||
| commit("Add empty data.txt", verbose) | ||
| checkout("stream-1", True, verbose) | ||
|
|
||
| join_orig_data = "\n".join(map(str, orig_data)) | ||
| append_to_file("data.txt", join_orig_data) | ||
|
|
||
| add(["data.txt"], verbose) | ||
| commit("Add data to data.txt", verbose) | ||
|
|
||
| checkout("main", False, verbose) | ||
| checkout("stream-2", True, verbose) | ||
|
|
||
| join_modified_data = "\n".join(map(str, modified_data)) | ||
| append_to_file("data.txt", join_modified_data) | ||
|
|
||
| add(["data.txt"], verbose) | ||
| commit("Add data to data.txt", verbose) | ||
|
|
||
| checkout("main", False, 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,5 @@ | ||
| Q: Which numbers are present in stream-1 but not in stream-2? | ||
| A: | ||
|
|
||
| Q: Which numbers are present in stream-2 but not in stream-1? | ||
| A: |
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,43 @@ | ||
| initialization: | ||
| steps: | ||
| - type: commit | ||
| empty: true | ||
| message: Set initial state | ||
| id: start | ||
| - type: commit | ||
| empty: true | ||
| message: Add empty data.txt | ||
|
|
||
| - type: branch | ||
| branch-name: stream-1 | ||
| - type: new-file | ||
| filename: data.txt | ||
| contents: | | ||
| 11111 | ||
| 22222 | ||
| 12345 | ||
| - type: add | ||
| files: | ||
| - data.txt | ||
| - type: commit | ||
| message: Add data to data.txt | ||
|
|
||
| - type: checkout | ||
| branch-name: main | ||
|
|
||
| - type: branch | ||
| branch-name: stream-2 | ||
| - type: new-file | ||
| filename: data.txt | ||
| contents: | | ||
| 11111 | ||
| 22222 | ||
| 98765 | ||
| - type: add | ||
| files: | ||
| - data.txt | ||
| - type: commit | ||
| message: Add data to data.txt | ||
|
|
||
| - type: checkout | ||
| branch-name: main |
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,55 @@ | ||
| initialization: | ||
| steps: | ||
| - type: commit | ||
| empty: true | ||
| message: Set initial state | ||
| id: start | ||
| - type: commit | ||
| empty: true | ||
| message: Add empty data.txt | ||
|
|
||
| - type: branch | ||
| branch-name: stream-1 | ||
| - type: new-file | ||
| filename: data.txt | ||
| contents: | | ||
| 11111 | ||
| 22222 | ||
| 12345 | ||
| - type: add | ||
| files: | ||
| - data.txt | ||
| - type: commit | ||
| message: Add data to data.txt | ||
|
|
||
| - type: checkout | ||
| branch-name: main | ||
|
|
||
| - type: branch | ||
| branch-name: stream-2 | ||
| - type: new-file | ||
| filename: data.txt | ||
| contents: | | ||
| 11111 | ||
| 22222 | ||
| 98765 | ||
| - type: add | ||
| files: | ||
| - data.txt | ||
| - type: commit | ||
| message: Add data to data.txt | ||
|
|
||
| - type: checkout | ||
| branch-name: stream-1 | ||
| - type: new-file | ||
| filename: extra.txt | ||
| contents: | | ||
| extra content | ||
| - type: add | ||
| files: | ||
| - extra.txt | ||
| - type: commit | ||
| message: Extra change on stream-1 | ||
|
|
||
| - type: checkout | ||
| branch-name: main |
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,57 @@ | ||
| from git_autograder import GitAutograderStatus, GitAutograderTestLoader, assert_output | ||
| from git_autograder.answers.rules.has_exact_value_rule import HasExactValueRule | ||
|
|
||
| from ..verify import verify, QUESTION_ONE, QUESTION_TWO, NO_CHANGES_ERROR | ||
|
|
||
| REPOSITORY_NAME = "branch-compare" | ||
|
|
||
| loader = GitAutograderTestLoader(__file__, REPOSITORY_NAME, verify) | ||
|
|
||
|
|
||
| def test_base(): | ||
| with loader.load( | ||
| "specs/base.yml", | ||
| "start", | ||
| mock_answers={ | ||
| QUESTION_ONE: "12345", | ||
| QUESTION_TWO: "98765", | ||
| }, | ||
| ) as output: | ||
| assert_output(output, GitAutograderStatus.SUCCESSFUL) | ||
|
|
||
|
|
||
| def test_wrong_stream1_diff(): | ||
| with loader.load( | ||
| "specs/base.yml", | ||
| "start", | ||
| mock_answers={ | ||
| QUESTION_ONE: "99999", | ||
| QUESTION_TWO: "98765", | ||
| }, | ||
| ) as output: | ||
| assert_output( | ||
| output, | ||
| GitAutograderStatus.UNSUCCESSFUL, | ||
| [HasExactValueRule.NOT_EXACT.format(question=QUESTION_ONE)], | ||
| ) | ||
|
|
||
|
|
||
| def test_wrong_stream2_diff(): | ||
| with loader.load( | ||
| "specs/base.yml", | ||
| "start", | ||
| mock_answers={ | ||
| QUESTION_ONE: "12345", | ||
| QUESTION_TWO: "99999", | ||
| }, | ||
| ) as output: | ||
| assert_output( | ||
| output, | ||
| GitAutograderStatus.UNSUCCESSFUL, | ||
| [HasExactValueRule.NOT_EXACT.format(question=QUESTION_TWO)], | ||
| ) | ||
|
|
||
|
|
||
| def test_changes_made_extra_commit(): | ||
| with loader.load("specs/extra_commit_on_stream1.yml", "start") as output: | ||
| assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [NO_CHANGES_ERROR]) |
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,74 @@ | ||
| from git_autograder import ( | ||
| GitAutograderBranch, | ||
| GitAutograderOutput, | ||
| GitAutograderExercise, | ||
| GitAutograderStatus, | ||
| ) | ||
|
|
||
| from git_autograder.answers.rules import HasExactValueRule, NotEmptyRule | ||
|
|
||
|
|
||
| QUESTION_ONE = "Which numbers are present in stream-1 but not in stream-2?" | ||
| QUESTION_TWO = "Which numbers are present in stream-2 but not in stream-1?" | ||
| NO_CHANGES_ERROR = ( | ||
| "No changes are supposed to be made to the two branches in this exercise" | ||
| ) | ||
|
|
||
| FILE_PATH = "data.txt" | ||
| BRANCH_1 = "stream-1" | ||
| BRANCH_2 = "stream-2" | ||
|
|
||
|
|
||
| def has_made_changes(branch: GitAutograderBranch, expected_commits: int) -> bool: | ||
| """Check branch has same number of commits as expected.""" | ||
|
|
||
| commits = branch.commits | ||
| return len(commits) != expected_commits | ||
|
|
||
|
|
||
| def get_branch_diff(exercise: GitAutograderExercise, branch1: str, branch2: str) -> str: | ||
| """Get a value present in branch1 but not in branch2.""" | ||
| exercise.repo.branches.branch(branch1).checkout() | ||
| with exercise.repo.files.file(FILE_PATH) as f1: | ||
| contents1 = f1.read() | ||
|
|
||
| exercise.repo.branches.branch(branch2).checkout() | ||
| with exercise.repo.files.file(FILE_PATH) as f2: | ||
| contents2 = f2.read() | ||
|
|
||
| exercise.repo.branches.branch("main").checkout() | ||
|
|
||
| set1 = {line.strip() for line in contents1.splitlines() if line.strip()} | ||
| set2 = {line.strip() for line in contents2.splitlines() if line.strip()} | ||
| diff = set1 - set2 | ||
| return str(diff.pop()) | ||
|
|
||
|
|
||
| def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: | ||
| branch_1 = exercise.repo.branches.branch(BRANCH_1) | ||
| branch_2 = exercise.repo.branches.branch(BRANCH_2) | ||
| if ( | ||
| not branch_1 | ||
| or not branch_2 | ||
| or has_made_changes(branch_1, 3) | ||
| or has_made_changes(branch_2, 3) | ||
| ): | ||
| raise exercise.wrong_answer([NO_CHANGES_ERROR]) | ||
|
|
||
| ans_1 = get_branch_diff(exercise, BRANCH_1, BRANCH_2) | ||
| ans_2 = get_branch_diff(exercise, BRANCH_2, BRANCH_1) | ||
|
|
||
| exercise.answers.add_validation( | ||
| QUESTION_ONE, | ||
| NotEmptyRule(), | ||
| HasExactValueRule(ans_1, is_case_sensitive=False), | ||
| ).add_validation( | ||
| QUESTION_TWO, | ||
| NotEmptyRule(), | ||
| HasExactValueRule(ans_2, is_case_sensitive=False), | ||
| ).validate() | ||
|
|
||
| return exercise.to_output( | ||
| ["Great work comparing the branches successfully!"], | ||
| 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.