Skip to content
Open
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
14 changes: 14 additions & 0 deletions tags_add/.gitmastery-exercise.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"exercise_name": "tags-add",
"tags": ["git-tag"],
"requires_git": true,
"requires_github": true,
"base_files": {},
"exercise_repo": {
"repo_type": "remote",
"repo_name": "duty-roster",
"create_fork": false,
"repo_title": "gm-duty-roster",
"init": false
}
}
30 changes: 30 additions & 0 deletions tags_add/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# tags-add

The `duty-roster` repo contains text files that track which people are assigned for duties on which days of the week.

## Task

1. Add a lightweight tag `first-pilot` to the first commit of the repo.

2. Add the annotated tag `v1.0` to the commit that updates March duty roster. The tag should have the message `first full duty roster`.

## Hints

<details>
<summary>💡 Hint 1</summary>

```bash
# add lightweight tag
git tag first-pilot <FIRST_COMMIT_SHA>
```

</details>

<summary>💡 Hint 2</summary>
Comment on lines +22 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing opening <details> tag.


```bash
# add annotated tag with message
git tag -a v1.0 -m "first full duty roster" <MARCH_COMMIT_SHA>
```

</details>
Empty file added tags_add/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions tags_add/download.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def setup(verbose: bool = False):
pass
Comment on lines +1 to +2
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can change this to

def setup(verbose: bool = False): ...

Empty file added tags_add/tests/__init__.py
Empty file.
23 changes: 23 additions & 0 deletions tags_add/tests/specs/base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
initialization:
steps:
- type: commit
empty: true
message: Add January duty roster
id: start
- type: tag
tag-name: first-pilot
- type: commit
empty: true
message: Update duty roster for February
- type: commit
empty: true
message: Update roster for March
- type: tag
tag-name: v1.0
tag-message: first full duty roster
- type: commit
empty: true
message: Update duty roster for April
- type: commit
empty: true
message: Update roster for May
21 changes: 21 additions & 0 deletions tags_add/tests/specs/missing_first_pilot_tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
initialization:
steps:
- type: commit
empty: true
message: Add January duty roster
id: start
- type: commit
empty: true
message: Update duty roster for February
- type: commit
empty: true
message: Update roster for March
- type: tag
tag-name: v1.0
tag-message: first full duty roster
- type: commit
empty: true
message: Update duty roster for April
- type: commit
empty: true
message: Update roster for May
20 changes: 20 additions & 0 deletions tags_add/tests/specs/missing_v1_tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
initialization:
steps:
- type: commit
empty: true
message: Add January duty roster
id: start
- type: tag
tag-name: first-pilot
- type: commit
empty: true
message: Update duty roster for February
- type: commit
empty: true
message: Update roster for March
- type: commit
empty: true
message: Update duty roster for April
- type: commit
empty: true
message: Update roster for May
23 changes: 23 additions & 0 deletions tags_add/tests/specs/wrong_commit_first_pilot_tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
initialization:
steps:
- type: commit
empty: true
message: Add January duty roster
id: start
- type: commit
empty: true
message: Update duty roster for February
- type: tag
tag-name: first-pilot
- type: commit
empty: true
message: Update roster for March
- type: tag
tag-name: v1.0
tag-message: first full duty roster
- type: commit
empty: true
message: Update duty roster for April
- type: commit
empty: true
message: Update roster for May
23 changes: 23 additions & 0 deletions tags_add/tests/specs/wrong_commit_v1_tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
initialization:
steps:
- type: commit
empty: true
message: Add January duty roster
id: start
- type: tag
tag-name: first-pilot
- type: commit
empty: true
message: Update duty roster for February
- type: commit
empty: true
message: Update roster for March
- type: commit
empty: true
message: Update duty roster for April
- type: commit
empty: true
message: Update roster for May
- type: tag
tag-name: v1.0
tag-message: first full duty roster
23 changes: 23 additions & 0 deletions tags_add/tests/specs/wrong_message_v1_tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
initialization:
steps:
- type: commit
empty: true
message: Add January duty roster
id: start
- type: tag
tag-name: first-pilot
- type: commit
empty: true
message: Update duty roster for February
- type: commit
empty: true
message: Update roster for March
- type: tag
tag-name: v1.0
tag-message: wrong message
- type: commit
empty: true
message: Update duty roster for April
- type: commit
empty: true
message: Update roster for May
45 changes: 45 additions & 0 deletions tags_add/tests/test_verify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from git_autograder import GitAutograderStatus, GitAutograderTestLoader, assert_output

from ..verify import (
verify,
FIRST_TAG_WRONG_COMMIT,
MISSING_FIRST_TAG,
MISSING_SECOND_TAG,
SECOND_TAG_WRONG_COMMIT,
SUCCESS_MESSAGE,
WRONG_SECOND_TAG_MESSAGE,
)

REPOSITORY_NAME = "tags-add"

loader = GitAutograderTestLoader(__file__, REPOSITORY_NAME, verify)


def test_base():
with loader.load("specs/base.yml", "start") as output:
assert_output(output, GitAutograderStatus.SUCCESSFUL, [SUCCESS_MESSAGE])


def test_missing_first_pilot_tag():
with loader.load("specs/missing_first_pilot_tag.yml", "start") as output:
assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [MISSING_FIRST_TAG])


def test_missing_v1_tag():
with loader.load("specs/missing_v1_tag.yml", "start") as output:
assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [MISSING_SECOND_TAG])


def test_wrong_message_v1_tag():
with loader.load("specs/wrong_message_v1_tag.yml", "start") as output:
assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [WRONG_SECOND_TAG_MESSAGE])


def test_wrong_commit_first_pilot_tag():
with loader.load("specs/wrong_commit_first_pilot_tag.yml", "start") as output:
assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [FIRST_TAG_WRONG_COMMIT])


def test_wrong_commit_v1_tag():
with loader.load("specs/wrong_commit_v1_tag.yml", "start") as output:
assert_output(output, GitAutograderStatus.UNSUCCESSFUL, [SECOND_TAG_WRONG_COMMIT])
65 changes: 65 additions & 0 deletions tags_add/verify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from typing import List, Optional
from git_autograder import GitAutograderCommit, GitAutograderExercise, GitAutograderOutput, GitAutograderStatus

FIRST_TAG = "first-pilot"
SECOND_TAG = "v1.0"
SECOND_TAG_MSG = "first full duty roster"
MARCH_MSG_FRAGMENT = "Update roster for March"

MISSING_FIRST_TAG = f'Missing lightweight tag "{FIRST_TAG}".'
MISSING_SECOND_TAG = f'Missing annotated tag "{SECOND_TAG}".'
WRONG_SECOND_TAG_MESSAGE = f'"{SECOND_TAG}" message must be exactly "{SECOND_TAG_MSG}".'
FIRST_TAG_WRONG_COMMIT = f'"{FIRST_TAG}" should point to the first commit.'
SECOND_TAG_WRONG_COMMIT = f'"{SECOND_TAG}" should point to the commit that updates March duty roster.'
MISSING_FIRST_COMMIT = "Missing commit that adds January duty roster."
MISSING_MARCH_COMMIT = "Missing commit that updates March duty roster."
SUCCESS_MESSAGE = "Great work using git tag to annotate various commits in the repository!"


def get_commit_from_message(commits: List[GitAutograderCommit], message: str) -> Optional[GitAutograderCommit]:
"""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 verify(exercise: GitAutograderExercise) -> GitAutograderOutput:
# Verify lightweight tag "first-pilot" on the first commit
tags = exercise.repo.repo.tags
if FIRST_TAG not in tags:
raise exercise.wrong_answer([MISSING_FIRST_TAG])

main_branch = exercise.repo.branches.branch("main")
main_branch_commits = main_branch.commits
if len(main_branch_commits) == 0:
raise exercise.wrong_answer([MISSING_FIRST_COMMIT])

first_commit = main_branch_commits[-1]
Comment on lines +35 to +38
Copy link
Collaborator

Choose a reason for hiding this comment

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

You seem to have combined the logic for checking for the presence of the first commit and ensuring the indexing does not throw an out-of-bounds error. I suppose this fits with the spirit of the exercise since we're looking for the absolute earliest commit.

first_pilot_tag_commit = tags[FIRST_TAG].commit
if first_pilot_tag_commit.hexsha != first_commit.hexsha:
raise exercise.wrong_answer([FIRST_TAG_WRONG_COMMIT])

# Verify annotated tag "v1.0" on March commit with correct message
if SECOND_TAG not in tags:
raise exercise.wrong_answer([MISSING_SECOND_TAG])

v1_tag = tags[SECOND_TAG]
if v1_tag is None:
raise exercise.wrong_answer([MISSING_SECOND_TAG])
Comment on lines +47 to +49
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you trying to ensure that the tag is an annotated tag? If so, you should be checking:

    v1_tag = tags[SECOND_TAG]
    if v1_tag.tag is None:
        raise exercise.wrong_answer([MISSING_SECOND_TAG])

Also, I'd prefer if we had a separate error message for creating a lightweight tag instead of an annotated tag.


march_commit = get_commit_from_message(main_branch_commits, MARCH_MSG_FRAGMENT)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd prefer not to abstract the MARCH_MSG_FRAGMENT since we're only using it once.

if march_commit is None:
raise exercise.wrong_answer([MISSING_MARCH_COMMIT])

v1_tag_commit = v1_tag.commit
if v1_tag_commit.hexsha != march_commit.hexsha:
raise exercise.wrong_answer([SECOND_TAG_WRONG_COMMIT])

if v1_tag.tag.message.strip() != SECOND_TAG_MSG:
raise exercise.wrong_answer([WRONG_SECOND_TAG_MESSAGE])

return exercise.to_output(
[SUCCESS_MESSAGE],
GitAutograderStatus.SUCCESSFUL,
)