From b71a28ee8b47bbe9a9810585775c670905666bc9 Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Fri, 9 Feb 2024 09:50:47 +0100 Subject: [PATCH 1/2] Ensure that catalog is initialized with branch `master` Before this commit, Commodore could fail to push the initial catalog for a cluster if the user's Git config sets `init.defaultBranch`. The observed error is: ``` > Commiting changes... > Pushing catalog to remote... Error: Failed to push to the catalog repository: Git exited with status code 1 The error reported was: stderr: 'error: src refspec master does not match any error: failed to push some refs to 'ssh://'' ``` This error is caused because GitPython falls back to `init.defaultBranch` when creating the catalog repo unless `initial_branch` is specified. However, since Commodore unconditionally falls back to trying to push `master` when no default branch can be identified in the remote repo (e.g. empty catalog repo), the push then fails because we're trying to push branch `master` which doesn't exist locally. This isn't an issue for `commodore component new` and `commodore package new` since we explicitly fall back to creating a `master` branch when initializing the worktree for the new dependency. --- commodore/gitrepo/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commodore/gitrepo/__init__.py b/commodore/gitrepo/__init__.py index 5963da5f..173508fb 100644 --- a/commodore/gitrepo/__init__.py +++ b/commodore/gitrepo/__init__.py @@ -115,7 +115,7 @@ def __init__( if not force_init and targetdir.exists(): self._repo = Repo(targetdir) else: - self._repo = Repo.init(targetdir, bare=bare) + self._repo = Repo.init(targetdir, bare=bare, initial_branch="master") if remote: self.remote = remote From 26c9023df5da43e02d88eed4b8eff21b19bfd27e Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Fri, 9 Feb 2024 11:12:59 +0100 Subject: [PATCH 2/2] Add test to ensure that we always create repo with branch `master` We also add a fixture which creates a predictable empty gitconfig for the tests. --- tests/conftest.py | 19 +++++++++++++++++++ tests/test_gitrepo.py | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index cbb2cc87..23f2776e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,8 @@ """ from __future__ import annotations +import os + from pathlib import Path from typing import Protocol @@ -23,6 +25,23 @@ def __call__(self, args: list[str]) -> Result: ... +@pytest.fixture(autouse=True) +def gitconfig(tmp_path: Path) -> Path: + """Ensure that tests have a predictable empty gitconfig. + + We set autouse=True, so that the fixture is automatically used for all + tests. Tests that want to access the mock gitconfig can explicitly specify + the fixutre, so they get the path to the mock gitconfig. + """ + os.environ["GIT_CONFIG_NOSYSTEM"] = "true" + os.environ["HOME"] = str(tmp_path) + os.environ["XDG_CONFIG_HOME"] = str(tmp_path / ".config") + gitconfig = tmp_path / ".config" / "git" / "config" + os.makedirs(gitconfig.parent, exist_ok=True) + + return gitconfig + + @pytest.fixture def cli_runner() -> RunnerFunc: r = CliRunner() diff --git a/tests/test_gitrepo.py b/tests/test_gitrepo.py index d8af756a..99596306 100644 --- a/tests/test_gitrepo.py +++ b/tests/test_gitrepo.py @@ -752,3 +752,14 @@ def test_gitrepo_is_ahead_of_remote_local_branch(tmp_path: Path): # verify that our local branch is ahead of both local and remote tracking master assert len(list(r.repo.iter_commits("master..local"))) == 1 assert len(list(r.repo.iter_commits("origin/master..local"))) == 1 + + +def test_gitrepo_init_always_master(gitconfig: Path, tmp_path: Path): + cfg = git.config.GitConfigParser(file_or_files=gitconfig, read_only=False) + cfg.add_value("init", "defaultBranch", "main").write() + + r = gitrepo.GitRepo(None, tmp_path / "repo.git") + r.commit("Initial commit") + + assert len(r._repo.heads) == 1 + assert r._repo.heads[0].name == "master"