Skip to content

Implement include_remote_repo option#246

Merged
jovnc merged 12 commits intogit-mastery:mainfrom
jiaxinnns:feature/include-remote-repo
Jan 26, 2026
Merged

Implement include_remote_repo option#246
jovnc merged 12 commits intogit-mastery:mainfrom
jiaxinnns:feature/include-remote-repo

Conversation

@jiaxinnns
Copy link
Copy Markdown
Contributor

@jiaxinnns jiaxinnns commented Jan 23, 2026

Fixes #247

Add support for include_remote_repo option to create two repo-smith objects.

Potential future improvement: allow creation of more than two repo-smith objects

Example usage in test_verify.py:

REPOSITORY_NAME = "test-remote"

loader = GitAutograderTestLoader(REPOSITORY_NAME, verify)


@contextmanager
def base_setup() -> Iterator[Tuple[GitAutograderTest, RepoSmith, RepoSmith]]:
    with loader.start(include_remote_repo=True) as (test, rs, rs_remote):
        rs.git.commit(message="Initial commit", allow_empty=True)
        rs.helper(GitMasteryHelper).create_start_tag()
        yield test, rs, rs_remote


def test_has_origin():
    """Test that origin remote can be added successfully."""
    with base_setup() as (test, rs, rs_remote):
        # Add remote using RepoSmith
        remote_url = str(rs_remote.repo.git_dir)
        rs.repo.create_remote("origin", remote_url) # can name any remote
        rs.git.push("origin", "main") # will support in repo-smith in separate PR
        
        output = test.run()
        assert_output(output, GitAutograderStatus.SUCCESSFUL, [HAS_ORIGIN_REMOTE])

@github-actions
Copy link
Copy Markdown

Hi @jiaxinnns, thank you for your contribution! 🎉

This PR comes from your fork jiaxinnns/exercises on branch feature/include-remote-repo.

Before you request for a review, please ensure that you have tested your changes locally!

Important

The previously recommended way of using ./test-download.py is no longer the best way to test your changes locally.

Please read the following instructions for the latest instructions.

Prerequisites

Ensure that you have the gitmastery app installed locally (instructions)

Testing steps

If you already have a local Git-Mastery root to test, you can skip the following step.

Create a Git-Mastery root locally:

gitmastery setup

Navigate into the Git-Mastery root (defaults to gitmastery-exercises/):

cd gitmastery-exercises/

Edit the .gitmastery.json configuration file. You need to set the following values under the exercises_source key.

{
    # other fields...
    "exercises_source": {
        "username": "jiaxinnns",
        "repository": "exercises",
        "branch": "feature/include-remote-repo"
    }
}

Then, you can use the gitmastery app to download and verify your changes locally.

gitmastery download <your new change>
gitmastery verify

Checklist

  • (For exercises and hands-ons) I have verified that the downloading behavior works
  • (For exercises only) I have verified that the verification behavior is accurate

Important

To any reviewers of this pull request, please use the same instructions above to test the changes.

@jiaxinnns jiaxinnns marked this pull request as ready for review January 23, 2026 10:04
@jiaxinnns jiaxinnns requested a review from Copilot January 23, 2026 10:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements an include_remote_repo option for the test utilities, allowing tests to optionally create and manage a remote repository alongside the main repository. This feature is intended to support testing scenarios that require interaction between local and remote repositories.

Changes:

  • Added include_remote_repo parameter to GitAutograderTest and GitAutograderTestLoader.start() method
  • Modified __enter__ to optionally create and return a remote RepoSmith instance
  • Added type overloads to start() method to provide correct type hints based on whether remote repo is included

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

self.__rs.add_helper(GitMasteryHelper)

return self, self.rs
return self, self.rs, self.rs_remote
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

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

The __enter__ method now always returns three values (test, rs, rs_remote) regardless of whether include_remote_repo is True or False. When include_remote_repo is False, rs_remote will be None. This design decision means all callers must handle three return values, even when they don't need the remote repo. While this simplifies the implementation, it breaks backward compatibility with existing code that unpacks only two values (e.g., with test as (ctx, rs):). Consider whether this breaking change is acceptable, or if a different design would be better.

Suggested change
return self, self.rs, self.rs_remote
if self.include_remote_repo:
return self, self.rs, self.rs_remote
return self, self.rs

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This makes type arguments complicated and results in failure in mypy test cases, so we only extract out the relevant variables at start() based on include_remote_repo

Copy link
Copy Markdown
Collaborator

@jovnc jovnc left a comment

Choose a reason for hiding this comment

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

Overall LGTM! Thanks for the work, as it seems that the typing is tricky here since we have 2 possible yield permutations now.

We will need to think about how we can extend this in the future, if we want to support more remotes, but let's not over-engineer for now and this is good enough for what we need.

mock_answers: Optional[Dict[str, str]] = None,
) -> Iterator[Tuple[GitAutograderTest, RepoSmith]]:
include_remote_repo: bool = False,
) -> Iterator[Any]:
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.

Generally, I would avoid using Any as type, but it seems to make the most sense here.

I tried returning Tuple[GitAutograderTest, RepoSmith, RepoSmith] | Tuple[GitAutograderTest, RepoSmith] but it seems that Python's type system can't narrow a union return type based on instance attributes at call time.

Having the @overload here seems to be the best solution for type safety.

Copy link
Copy Markdown
Contributor

@SAN-MUYUN SAN-MUYUN Jan 25, 2026

Choose a reason for hiding this comment

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

Agree, without @overload, users lose the precision of return type when include_remote_repo is set to True/False.

@jovnc
Copy link
Copy Markdown
Collaborator

jovnc commented Jan 24, 2026

@desmondwong1215 @SAN-MUYUN @VikramGoyal23 Do feel free to also leave a review as well, and see if this change fits your exercise. We can merge it in once we are ready, so that it can unblock you guys

Copy link
Copy Markdown
Contributor

@SAN-MUYUN SAN-MUYUN left a comment

Choose a reason for hiding this comment

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

Thanks so much for the contribution! Apart from the 1 tiny coding style issue, everything else LGTM. This should be sufficient for the current exercises. 👍

remote_repo_path = remote_temp_path / repo_name
os.makedirs(remote_repo_path, exist_ok=True)
self.__rs_remote_context = create_repo_smith(
False, existing_path=remote_repo_path.absolute().as_posix()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a small remark, for consistency, existing_path... should be on a new line.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The code be auto-formatted by ruff

mock_answers: Optional[Dict[str, str]] = None,
) -> Iterator[Tuple[GitAutograderTest, RepoSmith]]:
include_remote_repo: bool = False,
) -> Iterator[Any]:
Copy link
Copy Markdown
Contributor

@SAN-MUYUN SAN-MUYUN Jan 25, 2026

Choose a reason for hiding this comment

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

Agree, without @overload, users lose the precision of return type when include_remote_repo is set to True/False.

@jovnc jovnc merged commit 51e5f52 into git-mastery:main Jan 26, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement include_remote_repo option

4 participants