Skip to content

Commit 80f70f5

Browse files
fix(cli): do not start a session when in detached HEAD state (#3636)
1 parent f4b6480 commit 80f70f5

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

renku/core/session/session.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ def session_start(
158158
"""
159159
from renku.domain_model.project_context import project_context
160160

161+
if project_context.repository.head.detached:
162+
raise errors.SessionStartError("Cannot start a session from a detached HEAD. Check out a branch first.")
163+
161164
# NOTE: The Docker client in Python requires the parameters below to be a list and will fail with a tuple.
162165
# Click will convert parameters with the flag "many" set to True to tuples.
163166
kwargs["security_opt"] = list(kwargs.get("security_opt", []))

renku/infrastructure/repository.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,11 @@ def reference(self) -> Optional[Reference]:
15541554
except (git.GitError, TypeError):
15551555
return None
15561556

1557+
@property
1558+
def detached(self) -> bool:
1559+
"""True if the reference is to a commit and not a branch."""
1560+
return self._reference.is_detached
1561+
15571562

15581563
class RemoteReference(Reference):
15591564
"""A git remote reference."""
@@ -1681,8 +1686,11 @@ def set_url(self, url: str):
16811686
_run_git_command(self._repository, "remote", "set-url", self.name, url)
16821687

16831688
@property
1684-
def head(self) -> str:
1689+
def head(self) -> Optional[str]:
16851690
"""The head commit of the remote."""
1691+
if self._repository.head.is_detached:
1692+
return None
1693+
16861694
self._remote.fetch()
16871695
return _run_git_command(self._repository, "rev-parse", f"{self._remote.name}/{self._repository.active_branch}")
16881696

tests/cli/test_session.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,18 @@ def test_session_list_format(runner, project, dummy_session_provider, format, ou
175175
assert 0 == result.exit_code, format_result_exception(result)
176176
assert length == len(result.output.splitlines())
177177
assert output in result.output
178+
179+
180+
def test_session_detached_start(runner, project, dummy_session_provider):
181+
"""Test starting a session in a detached HEAD repository."""
182+
# NOTE: Make a dummy commit for project to have two commits
183+
(project.repository.path / "README.md").write_text("changes")
184+
project.repository.add(all=True)
185+
project.repository.commit("dummy commit")
186+
187+
project.repository.checkout("HEAD~")
188+
189+
result = runner.invoke(cli, ["session", "start", "-p", "dummy"])
190+
191+
assert 1 == result.exit_code, format_result_exception(result)
192+
assert "Cannot start a session from a detached HEAD" in result.output

tests/core/metadata/test_repository.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,23 @@ def test_ignored_paths(paths, ignored, project):
326326
from renku.domain_model.project_context import project_context
327327

328328
assert project_context.repository.get_ignored_paths(*paths) == ignored
329+
330+
331+
def test_remote(git_repository):
332+
"""Test get remote of a repository."""
333+
assert 1 == len(git_repository.remotes)
334+
335+
remote = git_repository.remotes[0]
336+
337+
assert "origin" == remote.name
338+
assert "8853e0c1112e512c36db9cc76faff560b655e5d5" == remote.head
339+
340+
341+
def test_remote_detached(git_repository):
342+
"""Test get remote of a repository with detached head."""
343+
git_repository.checkout("HEAD~")
344+
345+
remote = git_repository.remotes[0]
346+
347+
assert "origin" == remote.name
348+
assert remote.head is None

0 commit comments

Comments
 (0)