From 9f12f91ef92cc485e449cbcf23f7429cc6e60adc Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Fri, 25 Aug 2023 16:47:14 +0200 Subject: [PATCH 1/7] feat(service): accept commit SHA in read endpoints --- renku/core/util/git.py | 32 ++++++++++++------- renku/infrastructure/repository.py | 8 +++-- renku/ui/service/cache/models/project.py | 14 ++++++-- renku/ui/service/cache/projects.py | 2 +- renku/ui/service/cache/serializers/project.py | 10 +++++- renku/ui/service/controllers/api/mixins.py | 1 + renku/ui/service/gateways/repository_cache.py | 32 ++++++++++++++++--- renku/ui/service/serializers/common.py | 6 ++++ renku/ui/service/serializers/config.py | 10 ++++-- renku/ui/service/serializers/datasets.py | 5 +-- renku/ui/service/serializers/graph.py | 4 +-- renku/ui/service/serializers/project.py | 3 +- renku/ui/service/serializers/workflows.py | 8 ++--- 13 files changed, 101 insertions(+), 34 deletions(-) diff --git a/renku/core/util/git.py b/renku/core/util/git.py index cd167454c8..375018791e 100644 --- a/renku/core/util/git.py +++ b/renku/core/util/git.py @@ -29,6 +29,8 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Union, cast from uuid import uuid4 +import git + from renku.core import errors from renku.infrastructure.repository import DiffChangeType @@ -712,7 +714,7 @@ def clone_repository( skip_smudge=True, recursive=True, depth=None, - progress=None, + progress: Optional[git.RemoteProgress] = None, config: Optional[dict] = None, raise_git_except=False, checkout_revision=None, @@ -746,10 +748,8 @@ def clone_repository( path = Path(path) if path else Path(get_repository_name(url)) - def handle_git_exception(): - """Handle git exceptions.""" - if raise_git_except: - return + def error_from_progress(progress: git.RemoteProgress, url: str) -> errors.GitError: + """Format a Git command error into a more user-friendly format.""" message = f"Cannot clone repo from {url}" @@ -758,7 +758,7 @@ def handle_git_exception(): error = "".join([f"\n\t{line}" for line in lines if line.strip()]) message += f" - error message:\n {error}" - raise errors.GitError(message) + return errors.GitError(message) def clean_directory(): if not clean or not path: @@ -823,17 +823,27 @@ def clone(branch, depth): try: # NOTE: Try to clone, assuming checkout_revision is a branch or a tag (if it is set) repository = clone(branch=checkout_revision, depth=depth) - except errors.GitCommandError: + except errors.GitCommandError as err: if not checkout_revision: - handle_git_exception() - raise + if raise_git_except: + raise + raise error_from_progress(progress, url) # NOTE: clone without branch set, in case checkout_revision was not a branch or a tag but a commit try: repository = clone(branch=None, depth=None) except errors.GitCommandError: - handle_git_exception() - raise + if re.match("^.* destination path .* already exists and is not an empty directory", err.stderr): + clean_directory() + try: + repository = clone(branch=None, depth=None) + except errors.GitCommandError: + if raise_git_except: + raise + raise error_from_progress(progress, url) + if raise_git_except: + raise + raise error_from_progress(progress, url) if checkout_revision is not None and not no_checkout: try: diff --git a/renku/infrastructure/repository.py b/renku/infrastructure/repository.py index 28afbdaaeb..869db19355 100644 --- a/renku/infrastructure/repository.py +++ b/renku/infrastructure/repository.py @@ -1006,12 +1006,16 @@ def clone_from( env: Optional[dict] = None, clone_options: Optional[List[str]] = None, ) -> "Repository": - """Clone a remote repository and create an instance.""" + """Clone a remote repository and create an instance. + + Since this is just a thin wrapper around GitPython note that the branch parameter + can work and accept either a branch name or a tag. But it will not work with a commit SHA. + """ try: repository = git.Repo.clone_from( url=url, to_path=path, - branch=branch, + branch=branch, # NOTE: Git python will accept tag or branch here but not SHA recursive=recursive, depth=depth, progress=progress, diff --git a/renku/ui/service/cache/models/project.py b/renku/ui/service/cache/models/project.py index 55be10ac63..5af09e744e 100644 --- a/renku/ui/service/cache/models/project.py +++ b/renku/ui/service/cache/models/project.py @@ -30,6 +30,7 @@ MAX_CONCURRENT_PROJECT_REQUESTS = 10 LOCK_TIMEOUT = 15 NO_BRANCH_FOLDER = "__default_branch__" +DETACHED_HEAD_FOLDER_PREFIX = "__detached_head_" class Project(Model): @@ -54,14 +55,21 @@ class Project(Model): description = TextField() owner = TextField() initialized = BooleanField() + commit_sha = TextField() + branch = TextField() @property def abs_path(self) -> Path: """Full path of cached project.""" - branch = self.branch + folder_name = self.branch if not self.branch: - branch = NO_BRANCH_FOLDER - return CACHE_PROJECTS_PATH / self.user_id / self.owner / self.slug / branch + if not self.commit_sha: + # NOTE: Detached head state + folder_name = f"{DETACHED_HEAD_FOLDER_PREFIX}{self.commit_sha}" + else: + # NOTE: We are on the default branch (i.e. main) + folder_name = NO_BRANCH_FOLDER + return CACHE_PROJECTS_PATH / self.user_id / self.owner / self.slug / folder_name def read_lock(self, timeout: Optional[float] = None): """Shared read lock on the project.""" diff --git a/renku/ui/service/cache/projects.py b/renku/ui/service/cache/projects.py index 4afe48a323..c48e4e4691 100644 --- a/renku/ui/service/cache/projects.py +++ b/renku/ui/service/cache/projects.py @@ -31,7 +31,7 @@ class ProjectManagementCache(BaseCache): project_schema = ProjectSchema() - def make_project(self, user, project_data, persist=True): + def make_project(self, user, project_data, persist=True) -> Project: """Store user project metadata.""" project_data.update({"user_id": user.user_id}) diff --git a/renku/ui/service/cache/serializers/project.py b/renku/ui/service/cache/serializers/project.py index ed23e4f533..97acc30c20 100644 --- a/renku/ui/service/cache/serializers/project.py +++ b/renku/ui/service/cache/serializers/project.py @@ -18,7 +18,7 @@ import uuid from datetime import datetime -from marshmallow import fields, post_load +from marshmallow import ValidationError, fields, post_load, validates_schema from renku.ui.service.cache.models.project import Project from renku.ui.service.serializers.common import AccessSchema, CreationSchema, MandatoryUserSchema @@ -39,8 +39,16 @@ class ProjectSchema(CreationSchema, AccessSchema, MandatoryUserSchema): description = fields.String(load_default=None) owner = fields.String(required=True) initialized = fields.Boolean(dump_default=False) + commit_sha = fields.String(required=False, load_default=None, dump_default=None) + branch = fields.String(required=False, load_default=None, dump_default=None) @post_load def make_project(self, data, **options): """Construct project object.""" return Project(**data) + + @validates_schema + def ensure_only_commit_sha_or_branch(self, data, **kwargs): + """Checks that only a commit SHA or branch is set and not both.""" + if data.get("commit_sha") and data.get("branch"): + raise ValidationError("You cannot specify a commit SHA and a branch, only one or the other") diff --git a/renku/ui/service/controllers/api/mixins.py b/renku/ui/service/controllers/api/mixins.py index 6b11ea66a9..c8f9ceee38 100644 --- a/renku/ui/service/controllers/api/mixins.py +++ b/renku/ui/service/controllers/api/mixins.py @@ -172,6 +172,7 @@ def local(self): self.request_data.get("branch"), self.user, self.clone_depth is not None, + self.request_data.get("commit_sha"), ) self.context["project_id"] = project.project_id diff --git a/renku/ui/service/gateways/repository_cache.py b/renku/ui/service/gateways/repository_cache.py index 08933be566..507625e716 100644 --- a/renku/ui/service/gateways/repository_cache.py +++ b/renku/ui/service/gateways/repository_cache.py @@ -44,7 +44,13 @@ class LocalRepositoryCache(IRepositoryCache): """Cache for project repos stored on local disk.""" def get( - self, cache: ServiceCache, git_url: str, branch: Optional[str], user: User, shallow: bool = True + self, + cache: ServiceCache, + git_url: str, + branch: Optional[str], + user: User, + shallow: bool = True, + commit_sha: Optional[str] = None, ) -> Project: """Get a project from cache (clone if necessary).""" if git_url is None: @@ -56,12 +62,12 @@ def get( ) except ValueError: # project not found in DB - return self._clone_project(cache, git_url, branch, user, shallow) + return self._clone_project(cache, git_url, branch, user, shallow, commit_sha) if not project.abs_path.exists(): # cache folder doesn't exist anymore project.delete() - return self._clone_project(cache, git_url, branch, user, shallow) + return self._clone_project(cache, git_url, branch, user, shallow, commit_sha) if not shallow and project.is_shallow: self._unshallow_project(project, user) @@ -98,7 +104,13 @@ def _update_project_access_date(self, project: Project): project.save() def _clone_project( - self, cache: ServiceCache, git_url: str, branch: Optional[str], user: User, shallow: bool = True + self, + cache: ServiceCache, + git_url: str, + branch: Optional[str], + user: User, + shallow: bool = True, + commit_sha: Optional[str] = None, ) -> Project: """Clone a project to cache.""" try: @@ -120,6 +132,8 @@ def _clone_project( "branch": branch, "git_url": git_url, "user_id": user.user_id, + "branch": branch, + "commit_sha": commit_sha, } project = cache.make_project(user, project_data, persist=False) @@ -135,6 +149,7 @@ def _clone_project( (Project.user_id == user.user_id) & (Project.git_url == git_url) & (Project.branch == branch) + & (Project.commit_sha == commit_sha) & (Project.project_id != project.project_id) ) except ValueError: @@ -166,7 +181,7 @@ def _clone_project( "user.email": user.email, "pull.rebase": False, }, - checkout_revision=project.branch, + checkout_revision=commit_sha or project.branch, ) ).output project.save() @@ -182,6 +197,9 @@ def _clone_project( def _unshallow_project(self, project: Project, user: User): """Turn a shallow clone into a full clone.""" + if project.commit_sha is None: + # NOTE: A project in a detached head state at a specific commit SHA does not make sense to be unshallowed + return try: with project.write_lock(), Repository(project.abs_path) as repository: try: @@ -204,6 +222,10 @@ def _maybe_update_cache(self, project: Project, user: User): if project.fetch_age < PROJECT_FETCH_TIME: return + if project.commit_sha is None: + # NOTE: A project in a detached head state at a specific commit SHA cannot be updated + return + try: with project.write_lock(), Repository(project.abs_path) as repository: try: diff --git a/renku/ui/service/serializers/common.py b/renku/ui/service/serializers/common.py index 1840da5a73..6de4acd6a5 100644 --- a/renku/ui/service/serializers/common.py +++ b/renku/ui/service/serializers/common.py @@ -59,6 +59,12 @@ def set_branch_from_ref(self, data, **kwargs): return data +class GitCommitSHA: + """Schema for a commit SHA.""" + + commit_sha = fields.String(load_default=None, metadata={"description": "Git commit SHA."}) + + class AsyncSchema(Schema): """Schema for adding a commit at the end of the operation.""" diff --git a/renku/ui/service/serializers/config.py b/renku/ui/service/serializers/config.py index e5bfac5623..2370bdc9f9 100644 --- a/renku/ui/service/serializers/config.py +++ b/renku/ui/service/serializers/config.py @@ -18,11 +18,17 @@ from marshmallow import Schema, fields -from renku.ui.service.serializers.common import AsyncSchema, MigrateSchema, RemoteRepositorySchema, RenkuSyncSchema +from renku.ui.service.serializers.common import ( + AsyncSchema, + GitCommitSHA, + MigrateSchema, + RemoteRepositorySchema, + RenkuSyncSchema, +) from renku.ui.service.serializers.rpc import JsonRPCResponse -class ConfigShowRequest(RemoteRepositorySchema): +class ConfigShowRequest(RemoteRepositorySchema, GitCommitSHA): """Request schema for config show.""" diff --git a/renku/ui/service/serializers/datasets.py b/renku/ui/service/serializers/datasets.py index a75569ae6a..c1e34f045a 100644 --- a/renku/ui/service/serializers/datasets.py +++ b/renku/ui/service/serializers/datasets.py @@ -23,6 +23,7 @@ from renku.domain_model.dataset import ImageObjectRequestJson as ImageObjectRequest from renku.ui.service.serializers.common import ( AsyncSchema, + GitCommitSHA, JobDetailsResponse, MigrateSchema, RemoteRepositorySchema, @@ -121,7 +122,7 @@ class DatasetAddResponseRPC(JsonRPCResponse): result = fields.Nested(DatasetAddResponse) -class DatasetListRequest(RemoteRepositorySchema): +class DatasetListRequest(RemoteRepositorySchema, GitCommitSHA): """Request schema for dataset list view.""" @@ -143,7 +144,7 @@ class DatasetListResponseRPC(JsonRPCResponse): result = fields.Nested(DatasetListResponse) -class DatasetFilesListRequest(DatasetNameSchema, RemoteRepositorySchema): +class DatasetFilesListRequest(DatasetNameSchema, RemoteRepositorySchema, GitCommitSHA): """Request schema for dataset files list view.""" diff --git a/renku/ui/service/serializers/graph.py b/renku/ui/service/serializers/graph.py index f7081e9be8..32217aeff3 100644 --- a/renku/ui/service/serializers/graph.py +++ b/renku/ui/service/serializers/graph.py @@ -17,11 +17,11 @@ """Renku graph serializers.""" from marshmallow import Schema, fields, validate -from renku.ui.service.serializers.common import AsyncSchema, MigrateSchema, RemoteRepositorySchema +from renku.ui.service.serializers.common import AsyncSchema, GitCommitSHA, MigrateSchema, RemoteRepositorySchema from renku.ui.service.serializers.rpc import JsonRPCResponse -class GraphExportRequest(AsyncSchema, RemoteRepositorySchema, MigrateSchema): +class GraphExportRequest(AsyncSchema, RemoteRepositorySchema, MigrateSchema, GitCommitSHA): """Request schema for dataset list view.""" callback_url = fields.URL() diff --git a/renku/ui/service/serializers/project.py b/renku/ui/service/serializers/project.py index e93fa1a41d..1bc30155bf 100644 --- a/renku/ui/service/serializers/project.py +++ b/renku/ui/service/serializers/project.py @@ -21,6 +21,7 @@ from renku.domain_model.dataset import DatasetCreatorsJson as DatasetCreators from renku.ui.service.serializers.common import ( AsyncSchema, + GitCommitSHA, MigrateSchema, RemoteRepositoryBaseSchema, RemoteRepositorySchema, @@ -29,7 +30,7 @@ from renku.ui.service.serializers.rpc import JsonRPCResponse -class ProjectShowRequest(AsyncSchema, RemoteRepositorySchema, MigrateSchema): +class ProjectShowRequest(AsyncSchema, RemoteRepositorySchema, MigrateSchema, GitCommitSHA): """Project show metadata request.""" diff --git a/renku/ui/service/serializers/workflows.py b/renku/ui/service/serializers/workflows.py index 65a2c0a8d3..be6b35110f 100644 --- a/renku/ui/service/serializers/workflows.py +++ b/renku/ui/service/serializers/workflows.py @@ -23,11 +23,11 @@ from renku.domain_model.dataset import DatasetCreatorsJson from renku.infrastructure.persistent import Persistent from renku.ui.cli.utils.plugins import get_supported_formats -from renku.ui.service.serializers.common import RemoteRepositorySchema +from renku.ui.service.serializers.common import GitCommitSHA, RemoteRepositorySchema from renku.ui.service.serializers.rpc import JsonRPCResponse -class WorkflowPlansListRequest(RemoteRepositorySchema): +class WorkflowPlansListRequest(RemoteRepositorySchema, GitCommitSHA): """Request schema for plan list view.""" @@ -86,7 +86,7 @@ class WorkflowPlansListResponseRPC(JsonRPCResponse): result = fields.Nested(WorkflowPlansListResponse) -class WorkflowPlansShowRequest(RemoteRepositorySchema): +class WorkflowPlansShowRequest(RemoteRepositorySchema, GitCommitSHA): """Request schema for plan show view.""" plan_id = fields.String(required=True) @@ -223,7 +223,7 @@ class WorkflowPlansShowResponseRPC(JsonRPCResponse): ) -class WorkflowPlansExportRequest(RemoteRepositorySchema): +class WorkflowPlansExportRequest(RemoteRepositorySchema, GitCommitSHA): """Request schema for exporting a plan.""" plan_id = fields.String(required=True) From 893c4c7728e46bed96f09327cbe4cd7a56ee8cc5 Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Mon, 28 Aug 2023 16:30:47 +0200 Subject: [PATCH 2/7] chore: keep mypy happy --- renku/core/util/git.py | 2 +- renku/infrastructure/repository.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/renku/core/util/git.py b/renku/core/util/git.py index 375018791e..6624015705 100644 --- a/renku/core/util/git.py +++ b/renku/core/util/git.py @@ -748,7 +748,7 @@ def clone_repository( path = Path(path) if path else Path(get_repository_name(url)) - def error_from_progress(progress: git.RemoteProgress, url: str) -> errors.GitError: + def error_from_progress(progress: Optional[git.RemoteProgress], url: str) -> errors.GitError: """Format a Git command error into a more user-friendly format.""" message = f"Cannot clone repo from {url}" diff --git a/renku/infrastructure/repository.py b/renku/infrastructure/repository.py index 869db19355..98523c0509 100644 --- a/renku/infrastructure/repository.py +++ b/renku/infrastructure/repository.py @@ -30,7 +30,6 @@ from pathlib import Path from typing import ( Any, - Callable, Dict, Generator, List, @@ -1001,7 +1000,7 @@ def clone_from( branch: Optional[str] = None, recursive: bool = False, depth: Optional[int] = None, - progress: Optional[Callable] = None, + progress: Optional[git.RemoteProgress] = None, no_checkout: bool = False, env: Optional[dict] = None, clone_options: Optional[List[str]] = None, @@ -1018,7 +1017,7 @@ def clone_from( branch=branch, # NOTE: Git python will accept tag or branch here but not SHA recursive=recursive, depth=depth, - progress=progress, + progress=progress, # type: ignore[arg-type] no_checkout=no_checkout, env=env, multi_options=clone_options, From 5c6e391a069725f6571df0754613c501771ea992 Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Mon, 28 Aug 2023 18:47:35 +0200 Subject: [PATCH 3/7] squshme: minor fix --- renku/ui/service/cache/models/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renku/ui/service/cache/models/project.py b/renku/ui/service/cache/models/project.py index 5af09e744e..2d4e057086 100644 --- a/renku/ui/service/cache/models/project.py +++ b/renku/ui/service/cache/models/project.py @@ -63,7 +63,7 @@ def abs_path(self) -> Path: """Full path of cached project.""" folder_name = self.branch if not self.branch: - if not self.commit_sha: + if self.commit_sha: # NOTE: Detached head state folder_name = f"{DETACHED_HEAD_FOLDER_PREFIX}{self.commit_sha}" else: From 88ff0654e2f5775e994790b48ba4fe70208a2fa2 Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Mon, 28 Aug 2023 18:47:49 +0200 Subject: [PATCH 4/7] squashme: add tests --- .../cache/test_project_management_cache.py | 43 +++++++++++++++++++ tests/service/cache/test_project_model.py | 17 ++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/service/cache/test_project_management_cache.py create mode 100644 tests/service/cache/test_project_model.py diff --git a/tests/service/cache/test_project_management_cache.py b/tests/service/cache/test_project_management_cache.py new file mode 100644 index 0000000000..a78d6f9c7d --- /dev/null +++ b/tests/service/cache/test_project_management_cache.py @@ -0,0 +1,43 @@ +from typing import cast + +import pytest +from marshmallow.exceptions import ValidationError + +from renku.ui.service.cache.projects import ProjectManagementCache, User + + +@pytest.mark.parametrize( + "commit_sha,branch,exception", + [ + (None, None, None), + ("commit_sha", None, None), + (None, "branch", None), + (None, "master", None), + ("commit_sha", "master", ValidationError), + ], +) +def test_make_project(mock_redis, commit_sha, branch, exception): + cache = ProjectManagementCache() + user = User(user_id="user_id") + project_data = { + "slug": "slug", + "name": "name", + "owner": "owner", + "branch": branch, + "commit_sha": commit_sha, + } + if exception is not None: + with pytest.raises(exception): + cache.make_project(user=user, project_data=project_data, persist=True) + else: + cache.make_project(user=user, project_data=project_data, persist=True) + projects = list(cache.get_projects(user)) + assert len(projects) == 1 + if commit_sha is None: + assert projects[0].commit_sha == "" + else: + assert projects[0].commit_sha == commit_sha + if branch is None: + assert projects[0].branch == "" + else: + assert projects[0].branch == branch diff --git a/tests/service/cache/test_project_model.py b/tests/service/cache/test_project_model.py new file mode 100644 index 0000000000..05c6b44857 --- /dev/null +++ b/tests/service/cache/test_project_model.py @@ -0,0 +1,17 @@ +import pytest + +from renku.ui.service.cache.models.project import Project, NO_BRANCH_FOLDER, DETACHED_HEAD_FOLDER_PREFIX + + +@pytest.mark.parametrize( + "commit_sha,branch,expected_folder", + [ + (None, None, NO_BRANCH_FOLDER), + ("commit_sha", None, f"{DETACHED_HEAD_FOLDER_PREFIX}commit_sha"), + (None, "branch", "branch"), + (None, "master", "master"), + ], +) +def test_project_model_path(commit_sha, branch, expected_folder): + project = Project(name="name", slug="slug", commit_sha=commit_sha, user_id="user_id", owner="owner", branch=branch) + assert project.abs_path.stem == expected_folder From f6f93c042dae87c14ffcdedec8104e404151339a Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Tue, 29 Aug 2023 15:12:28 +0200 Subject: [PATCH 5/7] squashme: fix stylecheck --- tests/service/cache/test_project_management_cache.py | 2 -- tests/service/cache/test_project_model.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/service/cache/test_project_management_cache.py b/tests/service/cache/test_project_management_cache.py index a78d6f9c7d..c5502b88fe 100644 --- a/tests/service/cache/test_project_management_cache.py +++ b/tests/service/cache/test_project_management_cache.py @@ -1,5 +1,3 @@ -from typing import cast - import pytest from marshmallow.exceptions import ValidationError diff --git a/tests/service/cache/test_project_model.py b/tests/service/cache/test_project_model.py index 05c6b44857..07ff557efa 100644 --- a/tests/service/cache/test_project_model.py +++ b/tests/service/cache/test_project_model.py @@ -1,6 +1,6 @@ import pytest -from renku.ui.service.cache.models.project import Project, NO_BRANCH_FOLDER, DETACHED_HEAD_FOLDER_PREFIX +from renku.ui.service.cache.models.project import DETACHED_HEAD_FOLDER_PREFIX, NO_BRANCH_FOLDER, Project @pytest.mark.parametrize( From acfa5144254e201a5b43d1d15e1442a64324993a Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Tue, 17 Oct 2023 17:23:22 +0200 Subject: [PATCH 6/7] squashme: address comments --- renku/core/util/git.py | 8 -------- renku/ui/service/gateways/repository_cache.py | 5 ++--- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/renku/core/util/git.py b/renku/core/util/git.py index 04ed95c945..43a1b4e88d 100644 --- a/renku/core/util/git.py +++ b/renku/core/util/git.py @@ -836,14 +836,6 @@ def clone(branch, depth): try: repository = clone(branch=None, depth=None) except errors.GitCommandError: - if re.match("^.* destination path .* already exists and is not an empty directory", err.stderr): - clean_directory() - try: - repository = clone(branch=None, depth=None) - except errors.GitCommandError: - if raise_git_except: - raise - raise error_from_progress(progress, url) if raise_git_except: raise raise error_from_progress(progress, url) diff --git a/renku/ui/service/gateways/repository_cache.py b/renku/ui/service/gateways/repository_cache.py index 6afa4e2c80..c228a73ba7 100644 --- a/renku/ui/service/gateways/repository_cache.py +++ b/renku/ui/service/gateways/repository_cache.py @@ -136,7 +136,6 @@ def _clone_project( "branch": branch, "git_url": git_url, "user_id": user.user_id, - "branch": branch, "commit_sha": commit_sha, } project = cache.make_project(user, project_data, persist=False) @@ -201,7 +200,7 @@ def _clone_project( def _unshallow_project(self, project: Project, user: User): """Turn a shallow clone into a full clone.""" - if project.commit_sha is None: + if project.commit_sha is not None: # NOTE: A project in a detached head state at a specific commit SHA does not make sense to be unshallowed return try: @@ -226,7 +225,7 @@ def _maybe_update_cache(self, project: Project, user: User): if project.fetch_age < PROJECT_FETCH_TIME: return - if project.commit_sha is None: + if project.commit_sha is not None: # NOTE: A project in a detached head state at a specific commit SHA cannot be updated return From 355ad3b284f7385055461cf42f915ac35883b1ca Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Tue, 17 Oct 2023 17:51:16 +0200 Subject: [PATCH 7/7] squashme: fix tests --- renku/core/util/git.py | 2 +- renku/ui/service/cache/models/project.py | 1 - renku/ui/service/cache/serializers/project.py | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/renku/core/util/git.py b/renku/core/util/git.py index 43a1b4e88d..348d87e9b6 100644 --- a/renku/core/util/git.py +++ b/renku/core/util/git.py @@ -823,7 +823,7 @@ def clone(branch, depth): try: # NOTE: Try to clone, assuming checkout_revision is a branch or a tag (if it is set) repository = clone(branch=checkout_revision, depth=depth) - except errors.GitCommandError as err: + except errors.GitCommandError: if not checkout_revision: if raise_git_except: raise diff --git a/renku/ui/service/cache/models/project.py b/renku/ui/service/cache/models/project.py index f0680bf841..b26b5d7815 100644 --- a/renku/ui/service/cache/models/project.py +++ b/renku/ui/service/cache/models/project.py @@ -26,7 +26,6 @@ from renku.ui.service.cache.base import BaseCache from renku.ui.service.config import CACHE_PROJECTS_PATH -from renku.ui.service.utils import normalize_git_url MAX_CONCURRENT_PROJECT_REQUESTS = 10 LOCK_TIMEOUT = 15 diff --git a/renku/ui/service/cache/serializers/project.py b/renku/ui/service/cache/serializers/project.py index 199f48fb11..d9e484ebc6 100644 --- a/renku/ui/service/cache/serializers/project.py +++ b/renku/ui/service/cache/serializers/project.py @@ -45,7 +45,8 @@ class ProjectSchema(CreationSchema, AccessSchema, MandatoryUserSchema): @post_load def make_project(self, data, **options): """Construct project object.""" - data["git_url"] = normalize_git_url(data["git_url"]) + if data.get("git_url"): + data["git_url"] = normalize_git_url(data["git_url"]) data["name"] = normalize_git_url(data["name"]) data["slug"] = normalize_git_url(data["slug"]) return Project(**data)