diff --git a/renku/ui/service/controllers/api/mixins.py b/renku/ui/service/controllers/api/mixins.py index 3f0bf43317..d1d62a61c1 100644 --- a/renku/ui/service/controllers/api/mixins.py +++ b/renku/ui/service/controllers/api/mixins.py @@ -183,12 +183,12 @@ def local(self): raise ProgramRenkuError(error) project = LocalRepositoryCache().get( - self.cache, - self.request_data["git_url"], - self.request_data.get("branch"), - self.user, - self.clone_depth is not None, - self.request_data.get("commit_sha"), + cache=self.cache, + git_url=self.request_data["git_url"], + branch=self.request_data.get("branch"), + user=self.user, + shallow=self.clone_depth is not None, + commit_sha=self.request_data.get("commit_sha"), ) self.context["project_id"] = project.project_id diff --git a/renku/ui/service/controllers/utils/remote_project.py b/renku/ui/service/controllers/utils/remote_project.py index ae22f3c053..f3c4e404fa 100644 --- a/renku/ui/service/controllers/utils/remote_project.py +++ b/renku/ui/service/controllers/utils/remote_project.py @@ -23,7 +23,7 @@ from renku.core import errors from renku.core.util.contexts import renku_project_context -from renku.infrastructure.repository import Repository +from renku.core.util.git import clone_renku_repository from renku.ui.service.serializers.cache import ProjectCloneContext from renku.ui.service.utils import normalize_git_url @@ -46,6 +46,7 @@ def __init__(self, user_data, request_data): self.git_url = normalize_git_url(self.ctx["url_with_auth"]) self.branch = self.ctx["branch"] + self.commit_sha = self.ctx["commit_sha"] or "" @property def remote_url(self): @@ -65,7 +66,14 @@ def remote(self): """Retrieve project metadata.""" with tempfile.TemporaryDirectory() as td: try: - Repository.clone_from(self.remote_url.geturl(), td, branch=self.branch, depth=1) + clone_renku_repository( + url=self.remote_url.geturl(), + path=td, + install_lfs=False, + depth=None if self.branch or self.commit_sha else 1, + checkout_revision=self.commit_sha or self.branch, + raise_git_except=True, + ) except errors.GitCommandError as e: msg = str(e) if "is not a commit and a branch" in msg and "cannot be created from it" in msg: diff --git a/renku/ui/service/serializers/cache.py b/renku/ui/service/serializers/cache.py index 81cdb64fd9..17db739248 100644 --- a/renku/ui/service/serializers/cache.py +++ b/renku/ui/service/serializers/cache.py @@ -132,6 +132,7 @@ class RepositoryCloneRequest(RemoteRepositorySchema): """Request schema for repository clone.""" depth = fields.Integer(metadata={"description": "Git fetch depth"}, load_default=PROJECT_CLONE_DEPTH_DEFAULT) + commit_sha = fields.String(required=False, load_default=None, dump_default=None) class ProjectCloneContext(RepositoryCloneRequest): diff --git a/tests/service/fixtures/service_integration.py b/tests/service/fixtures/service_integration.py index d75bb7f11f..33bcab7edd 100644 --- a/tests/service/fixtures/service_integration.py +++ b/tests/service/fixtures/service_integration.py @@ -97,6 +97,7 @@ def integration_lifecycle( it_protected_repo_url, it_workflow_repo_url, it_remote_old_repo_url, + it_remote_public_repo_url, request, ): """Setup and teardown steps for integration tests.""" @@ -115,6 +116,8 @@ def integration_lifecycle( remote_repo = it_workflow_repo_url elif marker.args[0] == "old": remote_repo = it_remote_old_repo_url + elif marker.args[0] == "public": + remote_repo = it_remote_public_repo_url else: raise ValueError(f"Couldn't get remote repo for marker {marker.args[0]}") diff --git a/tests/service/views/test_config_views.py b/tests/service/views/test_config_views.py index f28324d4dc..5245d1a667 100644 --- a/tests/service/views/test_config_views.py +++ b/tests/service/views/test_config_views.py @@ -15,7 +15,9 @@ # limitations under the License. """Renku service config view tests.""" +import configparser import json +import uuid import pytest @@ -43,6 +45,78 @@ def test_config_view_show(svc_client_with_repo): assert 200 == response.status_code +@pytest.mark.service +@pytest.mark.integration +@retry_failed +@pytest.mark.remote_repo("public") +@pytest.mark.parametrize("anonymous", [False, True]) +def test_config_view_show_with_branch(svc_client_setup, anonymous): + """Check config show view in a different branch.""" + svc_client, headers, project_id, url_components, repository = svc_client_setup + + if anonymous: + headers = {} + + config_filepath = repository.path / ".renku" / "renku.ini" + current_branch = repository.active_branch.name + new_branch = uuid.uuid4().hex + + # Write a default config value + config = configparser.ConfigParser() + config.add_section("interactive") + config["interactive"]["default_url"] = "/lab" + config.add_section("renku") + config["renku"]["test-config"] = "current-branch" + with open(config_filepath, "w") as f: + config.write(f) + + repository.add(all=True) + repository.commit("master config") + repository.push(remote="origin", refspec=current_branch) + current_commit_sha = repository.active_branch.commit.hexsha + + # Create a new branch and a modified config + repository.branches.add(new_branch) + repository.checkout(new_branch) + config["renku"]["test-config"] = "new-branch" + with open(config_filepath, "w") as f: + config.write(f) + + repository.add(all=True) + repository.commit("new config") + repository.push(remote="origin", refspec=new_branch) + + params = { + "git_url": url_components.href, + "branch": current_branch, + } + + response = svc_client.get("/config.show", query_string=params, headers=headers) + + assert 200 == response.status_code + assert "current-branch" == response.json["result"]["config"].get("renku.test-config") + + params = { + "git_url": url_components.href, + "branch": new_branch, + } + + response = svc_client.get("/config.show", query_string=params, headers=headers) + + assert 200 == response.status_code + assert "new-branch" == response.json["result"]["config"].get("renku.test-config") + + params = { + "git_url": url_components.href, + "branch": current_commit_sha, + } + + response = svc_client.get("/config.show", query_string=params, headers=headers) + + assert 200 == response.status_code + assert "current-branch" == response.json["result"]["config"].get("renku.test-config") + + @pytest.mark.service @pytest.mark.integration @retry_failed @@ -133,7 +207,7 @@ def test_config_view_set(svc_client_with_repo): @pytest.mark.service @pytest.mark.integration @retry_failed -def test_config_view_set_nonexising_key_removal(svc_client_with_repo): +def test_config_view_set_non_existing_key_removal(svc_client_with_repo): """Check that removing a non-existing key (i.e. setting to None) is allowed.""" svc_client, headers, project_id, url_components = svc_client_with_repo @@ -160,7 +234,7 @@ def test_config_view_set_and_show_failures(svc_client_with_repo): """Check errors triggered while invoking config set.""" svc_client, headers, project_id, url_components = svc_client_with_repo - # NOTE: use sections with wrong chars introduces a readin error. Should we handle it at write time? + # NOTE: use sections with wrong chars introduces a reading error. Should we handle it at write time? payload = { "git_url": url_components.href, "config": {".NON_EXISTING": "test"},