Skip to content

Add local exercise repo fetching for testing local changes#40

Merged
VikramGoyal23 merged 6 commits intogit-mastery:mainfrom
VikramGoyal23:local-exercise-sources
Mar 16, 2026
Merged

Add local exercise repo fetching for testing local changes#40
VikramGoyal23 merged 6 commits intogit-mastery:mainfrom
VikramGoyal23:local-exercise-sources

Conversation

@VikramGoyal23
Copy link
Contributor

@VikramGoyal23 VikramGoyal23 commented Jan 20, 2026

Allows developers to set the exercise source as a local path, enabling fully local exercise testing. Backwards compatible and assumes lack of type field as remote.

@VikramGoyal23 VikramGoyal23 added the enhancement New feature or request label Jan 20, 2026
@jovnc jovnc requested a review from Copilot January 23, 2026 06:18

This comment was marked as resolved.

@jovnc
Copy link
Collaborator

jovnc commented Jan 24, 2026

@VikramGoyal23 Is this ready for review? Would also be good to resolve copilot comments if they have been addressed as well to reduce cognitive load on reviewer

@VikramGoyal23
Copy link
Contributor Author

@jovnc Yes, this is ready for another review

@jovnc
Copy link
Collaborator

jovnc commented Feb 1, 2026

@VikramGoyal23 This is more of an experimental change, so we will leave it here for now, and merge in during later weeks (or when E2E tests are ready) to prevent unnecessary regressions.

Copy link
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.

Also do include steps on how we can test this, and also relevant screenshots/videos to show it working, thanks!

repository: str
branch: str
# "remote" or "local"
type: str = "remote"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this the only non-optional field? If it doesn't exist, we can assume it to be remote, rather than set it to remote?

path: Optional[str] = None

def to_url(self) -> str:
if self.type != "remote":
Copy link
Collaborator

Choose a reason for hiding this comment

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

If doesn't exist, can assume it is remote if that's the default behaviour

return cls(type="remote", username="git-mastery", repository="exercises", branch="main")
if isinstance(raw, dict):
typ = raw.get("type")
# explicit local
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# explicit local

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do you wish to get rid of this comment?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is clear from the if statement itself, generally if the code is already self-explanatory, I don't think there's a need for comments.

if raw is None:
return cls(type="remote", username="git-mastery", repository="exercises", branch="main")
if isinstance(raw, dict):
typ = raw.get("type")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
typ = raw.get("type")
typ = raw.get("type", "remote")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is already handled by the fallthrough.

repository: Optional[str] = None
branch: Optional[str] = "main"
# local field
path: Optional[str] = None
Copy link
Collaborator

Choose a reason for hiding this comment

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

ExercisesSource.path silently dropped during JSON serialization due to name collision with exclusion filter
The to_json() method at gitmastery_config.py:62-63 uses a default lambda that excludes any key named "path" or "cds" from all serialized objects, not just the top-level GitMasteryConfig. The new ExercisesSource.path field (line 22) stores the local exercises directory path, but its key name collides with this exclusion filter.

When config.write() is called (e.g., in on.py:130 or off.py:48), the nested ExercisesSource object's path field is silently excluded from the written JSON. On the next GitMasteryConfig.read(), from_raw receives a dict without a path key, creating an ExercisesSource(type="local", path=None). The subsequent ExercisesRepo.enter then raises ValueError("Path is required for using local exercises source"), breaking all exercise commands.

This was from Devin Review, please consider this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

While this issue doesn't seem to arise in testing, I've made the change to prevent unexpected errors cropping up.

Copy link
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.

I'm ok with this now, but would be good to show a demo that it works, or allow us to test that it works as expected.

@VikramGoyal23 VikramGoyal23 merged commit 18fffc3 into git-mastery:main Mar 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants