From f7f7db5fca9058c12e97fb5c2bbde64bd7a19e00 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 12:09:12 +0800 Subject: [PATCH 1/9] feat: Implement add_origin utils in Git wrapper --- exercise_utils/git.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/exercise_utils/git.py b/exercise_utils/git.py index 5df9919..e0d7d20 100644 --- a/exercise_utils/git.py +++ b/exercise_utils/git.py @@ -48,7 +48,7 @@ def merge(target_branch: str, ff: bool, verbose: bool) -> None: def merge_with_message( - target_branch: str, ff: bool, message: str, verbose: bool + target_branch: str, ff: bool, message: str, verbose: bool ) -> None: """Merges the current branch with the target one.""" if ff: @@ -78,3 +78,8 @@ def track_remote_branch(remote: str, branch: str, verbose: bool) -> None: def remove_remote(remote: str, verbose: bool) -> None: """Removes a given remote.""" run_command(["git", "remote", "rm", remote], verbose) + + +def add_origin(remote: str, verbose: bool) -> None: + """Adds the origin remote with the given URL.""" + run_command(["git", "remote", "add", "origin", remote], verbose) From 295500cff2090ade054445e4764bd48bf5741d97 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 12:10:13 +0800 Subject: [PATCH 2/9] feat: Implement T2L5/hp-populate-remote --- hands_on/populate_remote.py | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 hands_on/populate_remote.py diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py new file mode 100644 index 0000000..5fb257d --- /dev/null +++ b/hands_on/populate_remote.py @@ -0,0 +1,86 @@ +import os +import subprocess + +from exercise_utils.cli import run_command +from exercise_utils.file import create_or_update_file, append_to_file +from exercise_utils.git import add, init, commit, add_origin + +__requires_git__ = True +__requires_github__ = True + +REPO_NAME = "gitmastery-things" + + +def download(verbose: bool): + _setup_local_repository(verbose) + _setup_remote_repository(verbose) + _link_repositories(verbose) + + +def _setup_local_repository(verbose: bool): + _initialize_workspace() + init(verbose) + _create_and_commit_fruits_file(verbose) + _update_fruits_file(verbose) + _add_additional_files(verbose) + + +def _setup_remote_repository(verbose: bool): + username = _get_github_username(verbose) + _ensure_clean_repository(verbose) + + +def _link_repositories(verbose: bool): + remote_url = _build_remote_url(verbose) + add_origin(remote_url, verbose) + + +def _initialize_workspace(): + os.makedirs("things") + os.chdir("things") + + +def _create_and_commit_fruits_file(verbose: bool): + content = """ + apples + bananas + cherries + dragon fruits + """ + create_or_update_file("fruits.txt", content) + add(["fruits.txt"], verbose) + + +def _update_fruits_file(verbose: bool): + append_to_file("fruits.txt", "figs") + add(["fruits.txt"], verbose) + commit("Insert figs into fruits.txt", verbose) + + +def _add_additional_files(verbose: bool): + create_or_update_file("colours.txt", """ + a file for colours + """) + create_or_update_file("shapes.txt", """ + a file for shapes + """) + add(["colours.txt", "shapes.txt"], verbose) + commit("Add colours.txt, shapes.txt", verbose) + + +def _get_github_username(verbose: bool) -> str: + return run_command(["gh", "api", "user", "-q", ".login"], verbose).strip() + + +def _ensure_clean_repository(verbose: bool): + result = subprocess.run(["gh", "api", "user", "-q", ".login"], capture_output=True, text=True) + + if result.returncode == 0: + run_command(["gh", "repo", "delete", REPO_NAME, "--yes"], verbose) + + run_command(["gh", "repo", "create", REPO_NAME, "--public"], verbose) + + +def _build_remote_url(verbose: bool) -> str: + username = _get_github_username(verbose) + return f"https://github.com/{username}/{REPO_NAME}.git" From 8a10b00f04133341a5a44f34477a0c9a60241913 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 12:24:38 +0800 Subject: [PATCH 3/9] chore: Revert unintended formatter --- exercise_utils/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercise_utils/git.py b/exercise_utils/git.py index e0d7d20..653f199 100644 --- a/exercise_utils/git.py +++ b/exercise_utils/git.py @@ -48,7 +48,7 @@ def merge(target_branch: str, ff: bool, verbose: bool) -> None: def merge_with_message( - target_branch: str, ff: bool, message: str, verbose: bool + target_branch: str, ff: bool, message: str, verbose: bool ) -> None: """Merges the current branch with the target one.""" if ff: From ba2ef97b074805ddbccfa6423d354e96b07897cc Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 12:31:58 +0800 Subject: [PATCH 4/9] chore: Minor improvement in abstraction --- hands_on/populate_remote.py | 39 ++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py index 5fb257d..ce1f53a 100644 --- a/hands_on/populate_remote.py +++ b/hands_on/populate_remote.py @@ -13,7 +13,7 @@ def download(verbose: bool): _setup_local_repository(verbose) - _setup_remote_repository(verbose) + _ensure_clean_repository(verbose) _link_repositories(verbose) @@ -25,14 +25,22 @@ def _setup_local_repository(verbose: bool): _add_additional_files(verbose) -def _setup_remote_repository(verbose: bool): - username = _get_github_username(verbose) - _ensure_clean_repository(verbose) +def _ensure_clean_repository(verbose: bool): + repo_check = subprocess.run( + ["gh", "repo", "view", _get_full_repo_name(verbose)], + capture_output=True, + text=True + ) + + if repo_check.returncode == 0: + run_command(["gh", "repo", "delete", REPO_NAME, "--yes"], verbose) + + run_command(["gh", "repo", "create", REPO_NAME, "--public"], verbose) def _link_repositories(verbose: bool): - remote_url = _build_remote_url(verbose) - add_origin(remote_url, verbose) + full_repo_name = _get_full_repo_name(verbose) + add_origin(f"https://github.com/{full_repo_name}", verbose) def _initialize_workspace(): @@ -68,19 +76,6 @@ def _add_additional_files(verbose: bool): commit("Add colours.txt, shapes.txt", verbose) -def _get_github_username(verbose: bool) -> str: - return run_command(["gh", "api", "user", "-q", ".login"], verbose).strip() - - -def _ensure_clean_repository(verbose: bool): - result = subprocess.run(["gh", "api", "user", "-q", ".login"], capture_output=True, text=True) - - if result.returncode == 0: - run_command(["gh", "repo", "delete", REPO_NAME, "--yes"], verbose) - - run_command(["gh", "repo", "create", REPO_NAME, "--public"], verbose) - - -def _build_remote_url(verbose: bool) -> str: - username = _get_github_username(verbose) - return f"https://github.com/{username}/{REPO_NAME}.git" +def _get_full_repo_name(verbose: bool) -> str: + username = run_command(["gh", "api", "user", "-q", ".login"], verbose).strip() + return f"{username}/{REPO_NAME}" From a6cf95bbd0ee7aa309749607762564ef7b5195a3 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 14:28:21 +0800 Subject: [PATCH 5/9] style: Improve code formatting --- hands_on/populate_remote.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py index ce1f53a..80df930 100644 --- a/hands_on/populate_remote.py +++ b/hands_on/populate_remote.py @@ -49,18 +49,21 @@ def _initialize_workspace(): def _create_and_commit_fruits_file(verbose: bool): - content = """ + create_or_update_file("fruits.txt", """ apples bananas cherries dragon fruits - """ - create_or_update_file("fruits.txt", content) + """, + ) add(["fruits.txt"], verbose) def _update_fruits_file(verbose: bool): - append_to_file("fruits.txt", "figs") + append_to_file("fruits.txt", """ + figs + """, + ) add(["fruits.txt"], verbose) commit("Insert figs into fruits.txt", verbose) @@ -68,10 +71,12 @@ def _update_fruits_file(verbose: bool): def _add_additional_files(verbose: bool): create_or_update_file("colours.txt", """ a file for colours - """) + """, + ) create_or_update_file("shapes.txt", """ a file for shapes - """) + """, + ) add(["colours.txt", "shapes.txt"], verbose) commit("Add colours.txt, shapes.txt", verbose) From a6bb231e9e92e124b08b0ff9dcd3f8f3bf6bc6f0 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 20:49:06 +0800 Subject: [PATCH 6/9] refactor: Change add_origin to a more general add_remote --- exercise_utils/git.py | 6 +++--- hands_on/populate_remote.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/exercise_utils/git.py b/exercise_utils/git.py index 653f199..18f2462 100644 --- a/exercise_utils/git.py +++ b/exercise_utils/git.py @@ -80,6 +80,6 @@ def remove_remote(remote: str, verbose: bool) -> None: run_command(["git", "remote", "rm", remote], verbose) -def add_origin(remote: str, verbose: bool) -> None: - """Adds the origin remote with the given URL.""" - run_command(["git", "remote", "add", "origin", remote], verbose) +def add_remote(remote: str, remote_url: str, verbose: bool) -> None: + """Adds a remote with the given name and URL.""" + run_command(["git", "remote", "add", remote, remote_url], verbose) diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py index 80df930..02ddd7a 100644 --- a/hands_on/populate_remote.py +++ b/hands_on/populate_remote.py @@ -3,7 +3,7 @@ from exercise_utils.cli import run_command from exercise_utils.file import create_or_update_file, append_to_file -from exercise_utils.git import add, init, commit, add_origin +from exercise_utils.git import add, init, commit, add_remote __requires_git__ = True __requires_github__ = True @@ -40,7 +40,7 @@ def _ensure_clean_repository(verbose: bool): def _link_repositories(verbose: bool): full_repo_name = _get_full_repo_name(verbose) - add_origin(f"https://github.com/{full_repo_name}", verbose) + add_remote("origin", f"https://github.com/{full_repo_name}", verbose) def _initialize_workspace(): From de05a246e10577749992148ca1ec61d89bd84222 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 20:57:06 +0800 Subject: [PATCH 7/9] feat: Add utility function run_command_with_code --- exercise_utils/cli.py | 18 ++++++++++++++++++ hands_on/populate_remote.py | 22 +++++++++------------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/exercise_utils/cli.py b/exercise_utils/cli.py index c66057f..45fff1f 100644 --- a/exercise_utils/cli.py +++ b/exercise_utils/cli.py @@ -45,3 +45,21 @@ def run_command_no_exit(command: List[str], verbose: bool) -> Optional[str]: if verbose: print(e.stderr) return None + + +def run_command_with_code(command: List[str], verbose: bool) -> tuple[Optional[str], int]: + """Runs the given command and returns (output, return code).""" + try: + result = subprocess.run( + command, + capture_output=True, + text=True, + check=True, + ) + if verbose: + print(result.stdout) + return result.stdout, result.returncode + except subprocess.CalledProcessError as e: + if verbose: + print(e.stderr) + return e.stderr, e.returncode diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py index 02ddd7a..fdbc28b 100644 --- a/hands_on/populate_remote.py +++ b/hands_on/populate_remote.py @@ -1,7 +1,7 @@ import os import subprocess -from exercise_utils.cli import run_command +from exercise_utils.cli import run_command, run_command_with_code from exercise_utils.file import create_or_update_file, append_to_file from exercise_utils.git import add, init, commit, add_remote @@ -13,26 +13,21 @@ def download(verbose: bool): _setup_local_repository(verbose) - _ensure_clean_repository(verbose) + _create_things_repository(verbose) _link_repositories(verbose) def _setup_local_repository(verbose: bool): - _initialize_workspace() - init(verbose) + _initialize_workspace(verbose) _create_and_commit_fruits_file(verbose) _update_fruits_file(verbose) _add_additional_files(verbose) -def _ensure_clean_repository(verbose: bool): - repo_check = subprocess.run( - ["gh", "repo", "view", _get_full_repo_name(verbose)], - capture_output=True, - text=True - ) - - if repo_check.returncode == 0: +def _create_things_repository(verbose: bool): + """Create the gitmastery-things repository, deleting any existing ones.""" + _, return_code = run_command_with_code(["gh", "repo", "view", _get_full_repo_name(verbose)], verbose) + if return_code == 0: run_command(["gh", "repo", "delete", REPO_NAME, "--yes"], verbose) run_command(["gh", "repo", "create", REPO_NAME, "--public"], verbose) @@ -43,9 +38,10 @@ def _link_repositories(verbose: bool): add_remote("origin", f"https://github.com/{full_repo_name}", verbose) -def _initialize_workspace(): +def _initialize_workspace(verbose: bool): os.makedirs("things") os.chdir("things") + init(verbose) def _create_and_commit_fruits_file(verbose: bool): From abc4bf8acab9f1849687509dec854a55757e51a9 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 21:07:06 +0800 Subject: [PATCH 8/9] refactor: Remove unnecessary abstractions in _setup_local_repository --- hands_on/populate_remote.py | 56 +++++++++++++++---------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py index fdbc28b..d50e9ea 100644 --- a/hands_on/populate_remote.py +++ b/hands_on/populate_remote.py @@ -1,5 +1,4 @@ import os -import subprocess from exercise_utils.cli import run_command, run_command_with_code from exercise_utils.file import create_or_update_file, append_to_file @@ -19,32 +18,6 @@ def download(verbose: bool): def _setup_local_repository(verbose: bool): _initialize_workspace(verbose) - _create_and_commit_fruits_file(verbose) - _update_fruits_file(verbose) - _add_additional_files(verbose) - - -def _create_things_repository(verbose: bool): - """Create the gitmastery-things repository, deleting any existing ones.""" - _, return_code = run_command_with_code(["gh", "repo", "view", _get_full_repo_name(verbose)], verbose) - if return_code == 0: - run_command(["gh", "repo", "delete", REPO_NAME, "--yes"], verbose) - - run_command(["gh", "repo", "create", REPO_NAME, "--public"], verbose) - - -def _link_repositories(verbose: bool): - full_repo_name = _get_full_repo_name(verbose) - add_remote("origin", f"https://github.com/{full_repo_name}", verbose) - - -def _initialize_workspace(verbose: bool): - os.makedirs("things") - os.chdir("things") - init(verbose) - - -def _create_and_commit_fruits_file(verbose: bool): create_or_update_file("fruits.txt", """ apples bananas @@ -55,28 +28,45 @@ def _create_and_commit_fruits_file(verbose: bool): add(["fruits.txt"], verbose) -def _update_fruits_file(verbose: bool): append_to_file("fruits.txt", """ figs """, - ) + ) add(["fruits.txt"], verbose) commit("Insert figs into fruits.txt", verbose) - -def _add_additional_files(verbose: bool): create_or_update_file("colours.txt", """ a file for colours """, - ) + ) create_or_update_file("shapes.txt", """ a file for shapes """, - ) + ) add(["colours.txt", "shapes.txt"], verbose) commit("Add colours.txt, shapes.txt", verbose) +def _create_things_repository(verbose: bool): + """Create the gitmastery-things repository, deleting any existing ones.""" + _, return_code = run_command_with_code(["gh", "repo", "view", _get_full_repo_name(verbose)], verbose) + if return_code == 0: + run_command(["gh", "repo", "delete", REPO_NAME, "--yes"], verbose) + + run_command(["gh", "repo", "create", REPO_NAME, "--public"], verbose) + + +def _link_repositories(verbose: bool): + full_repo_name = _get_full_repo_name(verbose) + add_remote("origin", f"https://github.com/{full_repo_name}", verbose) + + +def _initialize_workspace(verbose: bool): + os.makedirs("things") + os.chdir("things") + init(verbose) + + def _get_full_repo_name(verbose: bool) -> str: username = run_command(["gh", "api", "user", "-q", ".login"], verbose).strip() return f"{username}/{REPO_NAME}" From 5e001c3e2724dcce5f986b5a397919b9bb030096 Mon Sep 17 00:00:00 2001 From: Phanuphat Srisukhawasu Date: Sun, 26 Oct 2025 21:10:00 +0800 Subject: [PATCH 9/9] chore: Improve code formatting --- hands_on/populate_remote.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hands_on/populate_remote.py b/hands_on/populate_remote.py index d50e9ea..885d2d5 100644 --- a/hands_on/populate_remote.py +++ b/hands_on/populate_remote.py @@ -27,22 +27,21 @@ def _setup_local_repository(verbose: bool): ) add(["fruits.txt"], verbose) - append_to_file("fruits.txt", """ figs """, - ) + ) add(["fruits.txt"], verbose) commit("Insert figs into fruits.txt", verbose) create_or_update_file("colours.txt", """ a file for colours """, - ) + ) create_or_update_file("shapes.txt", """ a file for shapes """, - ) + ) add(["colours.txt", "shapes.txt"], verbose) commit("Add colours.txt, shapes.txt", verbose)