From fd2b8bee6634971a842e87b9efe0cf161e9b0f5c Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 16:22:23 +0200 Subject: [PATCH 01/14] add support for pyproject.toml parsing --- git-clone/action.yml | 3 ++- scripts/git-clone-ref.py | 43 ++++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/git-clone/action.yml b/git-clone/action.yml index ea354a5..c0247a9 100644 --- a/git-clone/action.yml +++ b/git-clone/action.yml @@ -22,5 +22,6 @@ runs: env: GIT_PAT: ${{ inputs.git-pat }} REPO_LIST: ${{ inputs.repo-list }} + DEFAULT_REPO_REF: ${{ inputs.repo-list }} run: | - uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} + uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref ${DEFAULT_REPO_REF} diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index ea3eeb2..2cb21ac 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -6,11 +6,13 @@ # ] # /// -import os import logging +import os import shutil +from typing import Annotated import git +import tomllib import typer logger = logging.getLogger(__name__) @@ -68,20 +70,39 @@ def git_clone_repos( @app.command() def main( - github_repos: list[str] = typer.Argument(..., help="GitHub repositories to clone"), - git_pat: str = typer.Option( - default="", envvar="GIT_PAT", help="GitHub Personal Access Token" - ), - default_repo_ref: str = typer.Option( - default="main", help="Default Git reference to check out" - ), + repo_list: Annotated[ + list[str] | None, typer.Argument(help="GitHub repositories to clone.") + ] = None, + git_pat: Annotated[ + str | None, typer.Option(envvar="GIT_PAT", help="GitHub Personal Access Token.") + ] = None, + default_repo_ref: Annotated[ + str | None, typer.Option(help="Default Git reference to check out.") + ] = None, + use_pyproject: Annotated[ + bool, typer.Option(help="Whether to parse and use pyproject.toml configuration") + ] = False, + pyproject_path: Annotated[ + str, typer.Option(help="Path to the pyproject.toml file.") + ] = "pyproject.toml", ): + if use_pyproject: + with open(pyproject_path, "rb") as fp: + pyproject = tomllib.load(fp) + config = pyproject.get("tool", {}).get("git-clone", {}) + if repo_list is None: + repo_list = config.get("repo-list") + if git_pat is None: + git_pat = config.get("git-pat") + if default_repo_ref is None: + default_repo_ref = config.get("default-repo-ref") + logging.basicConfig(level=logging.INFO) git_clone_repos( - github_repos, + repo_list or [], "https://{credentials}github.com/{repo_org}/{repo_name}.git", - git_pat, - default_repo_ref, + git_pat or "", + default_repo_ref or "main", ) From 480ca90e12483065a61eef89ef978ef14b51d4cd Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 16:24:32 +0200 Subject: [PATCH 02/14] cleanup --- scripts/git-clone-ref.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index 2cb21ac..d240754 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -80,7 +80,7 @@ def main( str | None, typer.Option(help="Default Git reference to check out.") ] = None, use_pyproject: Annotated[ - bool, typer.Option(help="Whether to parse and use pyproject.toml configuration") + bool, typer.Option(help="Whether to parse and use pyproject.toml configuration.") ] = False, pyproject_path: Annotated[ str, typer.Option(help="Path to the pyproject.toml file.") From 9c4f19f56370ffbb1b43e4a2fe403771beb451b2 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 16:33:28 +0200 Subject: [PATCH 03/14] allow default branch --- scripts/git-clone-ref.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index d240754..c1d685d 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -26,7 +26,8 @@ def git_clone_repo( repo_ref: str, multi_options: tuple[str, ...] = ("--depth=1", "--recurse-submodules"), ) -> str: - multi_options += (f"--branch {repo_ref}",) + if repo_ref: + multi_options += (f"--branch {repo_ref}",) if os.path.exists(repo_path): logger.info(f"removing {repo_path!r}") @@ -102,7 +103,7 @@ def main( repo_list or [], "https://{credentials}github.com/{repo_org}/{repo_name}.git", git_pat or "", - default_repo_ref or "main", + default_repo_ref or "", ) From d4689beb9bcd06e24fe19eee34b6e2d2c54d135c Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 16:37:42 +0200 Subject: [PATCH 04/14] fix var name --- git-clone/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-clone/action.yml b/git-clone/action.yml index c0247a9..22d32e5 100644 --- a/git-clone/action.yml +++ b/git-clone/action.yml @@ -22,6 +22,6 @@ runs: env: GIT_PAT: ${{ inputs.git-pat }} REPO_LIST: ${{ inputs.repo-list }} - DEFAULT_REPO_REF: ${{ inputs.repo-list }} + DEFAULT_REPO_REF: ${{ inputs.default-repo-ref }} run: | uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref ${DEFAULT_REPO_REF} From a98687c8bd2fb4df313c8d2d0ed06232b2d87bbe Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 16:57:16 +0200 Subject: [PATCH 05/14] add warning --- scripts/git-clone-ref.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index c1d685d..ca281e6 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -9,6 +9,7 @@ import logging import os import shutil +import warnings from typing import Annotated import git @@ -47,6 +48,9 @@ def git_clone_repos( git_pat: str, default_repo_ref: str, ) -> None: + if not paths: + logger.warning("No repository to clone.") + for repo_path in paths: repo_name = os.path.basename(repo_path) repo_org = os.path.basename(os.path.dirname(repo_path)) @@ -81,7 +85,8 @@ def main( str | None, typer.Option(help="Default Git reference to check out.") ] = None, use_pyproject: Annotated[ - bool, typer.Option(help="Whether to parse and use pyproject.toml configuration.") + bool, + typer.Option(help="Whether to parse and use pyproject.toml configuration."), ] = False, pyproject_path: Annotated[ str, typer.Option(help="Path to the pyproject.toml file.") From b2a8dcf8ff37a2a2d225865b061627d315b43806 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 16:59:51 +0200 Subject: [PATCH 06/14] qa --- scripts/git-clone-ref.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index ca281e6..e4a9f4c 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -76,20 +76,24 @@ def git_clone_repos( @app.command() def main( repo_list: Annotated[ - list[str] | None, typer.Argument(help="GitHub repositories to clone.") + list[str] | None, + typer.Argument(help="GitHub repositories to clone."), ] = None, git_pat: Annotated[ - str | None, typer.Option(envvar="GIT_PAT", help="GitHub Personal Access Token.") + str | None, + typer.Option(envvar="GIT_PAT", help="GitHub Personal Access Token."), ] = None, default_repo_ref: Annotated[ - str | None, typer.Option(help="Default Git reference to check out.") + str | None, + typer.Option(help="Default Git reference to check out."), ] = None, use_pyproject: Annotated[ bool, typer.Option(help="Whether to parse and use pyproject.toml configuration."), ] = False, pyproject_path: Annotated[ - str, typer.Option(help="Path to the pyproject.toml file.") + str, + typer.Option(help="Path to the pyproject.toml file."), ] = "pyproject.toml", ): if use_pyproject: From d95877909d5e2a9d89ca710d7fc0be73f7077403 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 17:12:48 +0200 Subject: [PATCH 07/14] fix action --- git-clone/action.yml | 12 +++++++++++- scripts/git-clone-ref.py | 5 ++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/git-clone/action.yml b/git-clone/action.yml index 22d32e5..27b4fd1 100644 --- a/git-clone/action.yml +++ b/git-clone/action.yml @@ -12,6 +12,14 @@ inputs: description: 'Default Git reference to check out' default: 'main' required: false + use-pyproject: + description: 'Whether to parse and use pyproject.toml configuration' + default: 'false' + required: false + pyproject-path: + description: 'Path to the pyproject.toml file' + default: 'pyproject.toml' + required: false runs: using: "composite" steps: @@ -23,5 +31,7 @@ runs: GIT_PAT: ${{ inputs.git-pat }} REPO_LIST: ${{ inputs.repo-list }} DEFAULT_REPO_REF: ${{ inputs.default-repo-ref }} + USE_PYPROJECT: ${{ inputs.use-pyproject }} + PYPROJECT_PATH: ${{ inputs.pyproject-path }} run: | - uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref ${DEFAULT_REPO_REF} + uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref ${DEFAULT_REPO_REF} --pyproject-path ${DEFAULT_REPO_REF} diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index e4a9f4c..74ca027 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -89,7 +89,10 @@ def main( ] = None, use_pyproject: Annotated[ bool, - typer.Option(help="Whether to parse and use pyproject.toml configuration."), + typer.Option( + envvar="USE_PYPROJECT", + help="Whether to parse and use pyproject.toml configuration.", + ), ] = False, pyproject_path: Annotated[ str, From 9ae5340e51820f230a91d635d88526162e708fa0 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 17:15:38 +0200 Subject: [PATCH 08/14] cleanup --- scripts/git-clone-ref.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index 74ca027..05bd604 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -9,7 +9,6 @@ import logging import os import shutil -import warnings from typing import Annotated import git From 66bd6654772cd3e9b20764686cc41c3b09f2a3c2 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 17:25:37 +0200 Subject: [PATCH 09/14] update README --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd96d86..c4a1a66 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ This action can be used in other repositories' workflows to clone multiple repos **Inputs:** - **`repo-list`** (required): Space-separated list of repositories in `org/repo` format to clone - **`git-pat`** (optional): Git Personal Access Token for authentication +- **`default-repo-ref`** (optional): Default Git reference to check out +- **`use-pyproject`** (optional): Whether to parse and use pyproject.toml configuration +- **`pyproject-path`** (optional): Path to the pyproject.toml file **Example workflow:** @@ -22,7 +25,9 @@ This action can be used in other repositories' workflows to clone multiple repos with: repo-list: "org/repo1 org/repo2" git-pat: ${{ secrets.GIT_PAT }} - default-repo-ref: "main" + default-repo-ref: main + use-pyproject: false + pyproject-path: pyproject.toml ~~~ ### Features From fb64fd8dee46094deba90198a4d9e1a42bcdebed Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 17:57:23 +0200 Subject: [PATCH 10/14] only add repo-list from pyproject --- README.md | 1 - git-clone/action.yml | 7 +------ scripts/git-clone-ref.py | 38 +++++++++++++------------------------- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c4a1a66..8f99c2d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ This action can be used in other repositories' workflows to clone multiple repos - **`repo-list`** (required): Space-separated list of repositories in `org/repo` format to clone - **`git-pat`** (optional): Git Personal Access Token for authentication - **`default-repo-ref`** (optional): Default Git reference to check out -- **`use-pyproject`** (optional): Whether to parse and use pyproject.toml configuration - **`pyproject-path`** (optional): Path to the pyproject.toml file **Example workflow:** diff --git a/git-clone/action.yml b/git-clone/action.yml index 27b4fd1..00c6109 100644 --- a/git-clone/action.yml +++ b/git-clone/action.yml @@ -12,13 +12,9 @@ inputs: description: 'Default Git reference to check out' default: 'main' required: false - use-pyproject: - description: 'Whether to parse and use pyproject.toml configuration' - default: 'false' - required: false pyproject-path: description: 'Path to the pyproject.toml file' - default: 'pyproject.toml' + default: '' required: false runs: using: "composite" @@ -31,7 +27,6 @@ runs: GIT_PAT: ${{ inputs.git-pat }} REPO_LIST: ${{ inputs.repo-list }} DEFAULT_REPO_REF: ${{ inputs.default-repo-ref }} - USE_PYPROJECT: ${{ inputs.use-pyproject }} PYPROJECT_PATH: ${{ inputs.pyproject-path }} run: | uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref ${DEFAULT_REPO_REF} --pyproject-path ${DEFAULT_REPO_REF} diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index 05bd604..9af5181 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -75,46 +75,34 @@ def git_clone_repos( @app.command() def main( repo_list: Annotated[ - list[str] | None, + list[str], typer.Argument(help="GitHub repositories to clone."), - ] = None, + ] = [], git_pat: Annotated[ - str | None, + str, typer.Option(envvar="GIT_PAT", help="GitHub Personal Access Token."), - ] = None, + ] = "", default_repo_ref: Annotated[ - str | None, + str, typer.Option(help="Default Git reference to check out."), - ] = None, - use_pyproject: Annotated[ - bool, - typer.Option( - envvar="USE_PYPROJECT", - help="Whether to parse and use pyproject.toml configuration.", - ), - ] = False, + ] = "main", pyproject_path: Annotated[ - str, + str | None, typer.Option(help="Path to the pyproject.toml file."), - ] = "pyproject.toml", + ] = None, ): - if use_pyproject: + if pyproject_path: with open(pyproject_path, "rb") as fp: pyproject = tomllib.load(fp) config = pyproject.get("tool", {}).get("git-clone", {}) - if repo_list is None: - repo_list = config.get("repo-list") - if git_pat is None: - git_pat = config.get("git-pat") - if default_repo_ref is None: - default_repo_ref = config.get("default-repo-ref") + repo_list.extend(config.get("repo-list", [])) logging.basicConfig(level=logging.INFO) git_clone_repos( - repo_list or [], + repo_list, "https://{credentials}github.com/{repo_org}/{repo_name}.git", - git_pat or "", - default_repo_ref or "", + git_pat, + default_repo_ref, ) From c87c3a9308aa69ad42ff90eb008db5c32171b634 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 18:01:48 +0200 Subject: [PATCH 11/14] avoid duplicates --- scripts/git-clone-ref.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index 9af5181..9d3d99d 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -50,7 +50,7 @@ def git_clone_repos( if not paths: logger.warning("No repository to clone.") - for repo_path in paths: + for repo_path in set(paths): repo_name = os.path.basename(repo_path) repo_org = os.path.basename(os.path.dirname(repo_path)) git_pat_org = os.getenv(f"GIT_PAT_{repo_org.upper()}", git_pat) From 678c99ad673de6df37605b38a8f53e8a27b3c4a7 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 18:04:40 +0200 Subject: [PATCH 12/14] fix README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 8f99c2d..0479b29 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,6 @@ This action can be used in other repositories' workflows to clone multiple repos repo-list: "org/repo1 org/repo2" git-pat: ${{ secrets.GIT_PAT }} default-repo-ref: main - use-pyproject: false pyproject-path: pyproject.toml ~~~ From a8c188ed21a20b15b1ac17258bcd929985280bb5 Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 18:39:58 +0200 Subject: [PATCH 13/14] no default branch --- git-clone/action.yml | 4 ++-- scripts/git-clone-ref.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/git-clone/action.yml b/git-clone/action.yml index 00c6109..bf6ee0d 100644 --- a/git-clone/action.yml +++ b/git-clone/action.yml @@ -10,7 +10,7 @@ inputs: required: false default-repo-ref: description: 'Default Git reference to check out' - default: 'main' + default: '' required: false pyproject-path: description: 'Path to the pyproject.toml file' @@ -29,4 +29,4 @@ runs: DEFAULT_REPO_REF: ${{ inputs.default-repo-ref }} PYPROJECT_PATH: ${{ inputs.pyproject-path }} run: | - uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref ${DEFAULT_REPO_REF} --pyproject-path ${DEFAULT_REPO_REF} + uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref "${DEFAULT_REPO_REF}" --pyproject-path "${DEFAULT_REPO_REF}" diff --git a/scripts/git-clone-ref.py b/scripts/git-clone-ref.py index 9d3d99d..7032df4 100755 --- a/scripts/git-clone-ref.py +++ b/scripts/git-clone-ref.py @@ -85,7 +85,7 @@ def main( default_repo_ref: Annotated[ str, typer.Option(help="Default Git reference to check out."), - ] = "main", + ] = "", pyproject_path: Annotated[ str | None, typer.Option(help="Path to the pyproject.toml file."), From bf534ea6d7b6d417a6d62e9ddfa1d1b11b36859f Mon Sep 17 00:00:00 2001 From: malmans2 Date: Fri, 26 Jun 2026 18:41:03 +0200 Subject: [PATCH 14/14] rename --- git-clone/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-clone/action.yml b/git-clone/action.yml index bf6ee0d..f0d4173 100644 --- a/git-clone/action.yml +++ b/git-clone/action.yml @@ -29,4 +29,4 @@ runs: DEFAULT_REPO_REF: ${{ inputs.default-repo-ref }} PYPROJECT_PATH: ${{ inputs.pyproject-path }} run: | - uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref "${DEFAULT_REPO_REF}" --pyproject-path "${DEFAULT_REPO_REF}" + uv run ${{ github.action_path }}/../scripts/git-clone-ref.py ${REPO_LIST} --default-repo-ref "${DEFAULT_REPO_REF}" --pyproject-path "${PYPROJECT_PATH}"