Skip to content

Commit 6995098

Browse files
authored
fix(service): correctly use passed namespace in project id generation (#2958)
1 parent 3daa1ec commit 6995098

File tree

10 files changed

+194
-95
lines changed

10 files changed

+194
-95
lines changed

renku/command/checks/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .external import check_missing_external_files
2323
from .githooks import check_git_hooks_installed
2424
from .migration import check_migration
25+
from .project import check_project_id_group
2526
from .storage import check_lfs_info
2627
from .validate_shacl import check_datasets_structure, check_project_structure
2728

@@ -38,4 +39,5 @@
3839
"check_missing_external_files",
3940
"check_missing_files",
4041
"check_project_structure",
42+
"check_project_id_group",
4143
)

renku/command/checks/project.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Copyright 2020 - Swiss Data Science Center (SDSC)
4+
# A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
5+
# Eidgenössische Technische Hochschule Zürich (ETHZ).
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
"""Checks needed to determine integrity of the project."""
19+
20+
from renku.command.command_builder import inject
21+
from renku.command.echo import WARNING
22+
from renku.core.interface.project_gateway import IProjectGateway
23+
from renku.core.util import communication
24+
from renku.domain_model.project import Project
25+
26+
27+
@inject.autoparams()
28+
def check_project_id_group(client, fix, project_gateway: IProjectGateway):
29+
"""Check that projects in groups have the correct id set.
30+
31+
Args:
32+
client: ``LocalClient``.
33+
fix: Whether to fix found issues.
34+
project_gateway: Injected project gateway.
35+
Returns:
36+
Tuple of whether project id is valid.
37+
"""
38+
current_project = client.project
39+
40+
namespace, name = Project.get_namespace_and_name(client=client)
41+
42+
if namespace is None or name is None:
43+
return True, None
44+
45+
generated_id = Project.generate_id(namespace=namespace, name=name)
46+
47+
if generated_id == current_project.id:
48+
return True, None
49+
50+
if fix:
51+
communication.info(f"Fixing project id '{current_project.id}' -> '{generated_id}'")
52+
current_project.id = generated_id
53+
project_gateway.update_project(current_project)
54+
return True, None
55+
56+
return True, (
57+
WARNING
58+
+ "Project id doesn't match id created based on the current Git remote (use 'renku doctor --fix' to fix it):"
59+
f"\n\t'{current_project.id}' -> '{generated_id}'"
60+
)

renku/command/init.py

Lines changed: 55 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
# limitations under the License.
1818
"""Project initialization logic."""
1919

20+
import os
2021
from pathlib import Path
21-
from typing import Dict
22+
from typing import Dict, List, Optional
2223
from uuid import uuid4
2324

2425
import attr
@@ -44,6 +45,7 @@
4445
from renku.core.template.usecase import select_template
4546
from renku.core.util import communication
4647
from renku.core.util.os import is_path_empty
48+
from renku.domain_model.project import Project
4749
from renku.domain_model.template import Template, TemplateMetadata
4850
from renku.version import __version__, is_release
4951

@@ -172,20 +174,23 @@ def _init(
172174
if template is None:
173175
raise errors.TemplateNotFoundError(f"Couldn't find template with id {template_id}")
174176

177+
namespace, name = Project.get_namespace_and_name(client=client, name=name)
178+
name = name or os.path.basename(path.rstrip(os.path.sep))
179+
175180
metadata = dict()
176181
# NOTE: supply metadata
177182
metadata["__template_source__"] = template_source
178183
metadata["__template_ref__"] = template_ref
179184
metadata["__template_id__"] = template_id
180-
metadata["__namespace__"] = ""
185+
metadata["__namespace__"] = namespace or ""
181186
metadata["__sanitized_project_name__"] = ""
182187
metadata["__repository__"] = ""
183188
metadata["__project_slug__"] = ""
184189
metadata["__project_description__"] = description
185190
if is_release() and "__renku_version__" not in metadata:
186191
metadata["__renku_version__"] = __version__
187-
metadata["name"] = name # NOTE: kept for backwards compatibility
188192
metadata["__name__"] = name
193+
metadata["name"] = metadata["__name__"] # NOTE: kept for backwards compatibility
189194
metadata["__template_version__"] = template.version
190195
metadata["__automated_update__"] = True # TODO: This should come from a command line flag
191196

@@ -225,7 +230,6 @@ def _init(
225230
client=client,
226231
name=name,
227232
custom_metadata=custom_metadata,
228-
force=force,
229233
data_dir=data_dir,
230234
description=description,
231235
keywords=keywords,
@@ -253,30 +257,28 @@ def create_from_template(
253257
rendered_template: RenderedTemplate,
254258
actions: Dict[str, FileAction],
255259
client,
256-
name=None,
257-
custom_metadata=None,
258-
force=None,
259-
data_dir=None,
260-
user=None,
261-
commit_message=None,
262-
description=None,
263-
keywords=None,
264-
install_mergetool=False,
260+
name: Optional[str] = None,
261+
namespace: Optional[str] = None,
262+
custom_metadata: Optional[Dict] = None,
263+
data_dir: Optional[str] = None,
264+
commit_message: Optional[str] = None,
265+
description: Optional[str] = None,
266+
keywords: Optional[List[str]] = None,
267+
install_mergetool: bool = False,
265268
):
266269
"""Initialize a new project from a template.
267270
268271
Args:
269272
rendered_template(RenderedTemplate): Rendered template.
270273
actions(Dict[str, FileAction]): mapping of paths and actions to take.
271274
client: ``LocalClient``.
272-
name: Name of the project (Default value = None).
273-
custom_metadata: Custom JSON-LD metadata (Default value = None).
274-
force: Whether to overwrite files (Default value = None).
275-
data_dir: Where to store dataset data (Default value = None).
276-
user: Current user (Default value = None).
277-
commit_message: Message for initial commit (Default value = None).
278-
description: Description of the project (Default value = None).
279-
keywords: Keywords for project (Default value = None).
275+
name(Optional[str]): Name of the project (Default value = None).
276+
namespace(Optional[str]): Namespace of the project (Default value = None).
277+
custom_metadata(Optional[Dict]): Custom JSON-LD metadata (Default value = None).
278+
data_dir(Optional[str]): Where to store dataset data (Default value = None).
279+
commit_message(Optional[str]): Message for initial commit (Default value = None).
280+
description(Optional[str]): Description of the project (Default value = None).
281+
keywords(Optional[List[str]]): Keywords for project (Default value = None).
280282
install_mergetool(bool): Whether to setup renku metadata mergetool (Default value = False).
281283
"""
282284
commit_only = [f"{RENKU_HOME}/", str(client.template_checksums)] + list(rendered_template.get_files())
@@ -301,7 +303,7 @@ def create_from_template(
301303

302304
with client.commit(commit_message=commit_message, commit_only=commit_only, skip_dirty_checks=True):
303305
with client.with_metadata(
304-
name=name, description=description, custom_metadata=custom_metadata, keywords=keywords
306+
name=name, namespace=namespace, description=description, custom_metadata=custom_metadata, keywords=keywords
305307
) as project:
306308
copy_template_to_client(
307309
rendered_template=rendered_template, client=client, project=project, actions=actions
@@ -314,46 +316,42 @@ def create_from_template(
314316
client.set_value("renku", client.DATA_DIR_CONFIG_KEY, str(data_dir))
315317

316318

317-
@inject.autoparams()
319+
@inject.autoparams("client_dispatcher")
318320
def _create_from_template_local(
319-
template_path,
320-
name,
321+
template_path: Path,
322+
name: str,
323+
namespace: str,
321324
client_dispatcher: IClientDispatcher,
322-
metadata=None,
323-
custom_metadata=None,
324-
default_metadata=None,
325-
template_version=None,
326-
immutable_template_files=None,
327-
automated_template_update=True,
328-
user=None,
329-
source=None,
330-
ref=None,
331-
invoked_from=None,
332-
initial_branch=None,
333-
commit_message=None,
334-
description=None,
335-
keywords=None,
325+
metadata: Optional[Dict] = None,
326+
custom_metadata: Optional[Dict] = None,
327+
default_metadata: Optional[Dict] = None,
328+
template_version: Optional[str] = None,
329+
immutable_template_files: Optional[List[str]] = None,
330+
automated_template_update: bool = True,
331+
user: Optional[Dict[str, str]] = None,
332+
initial_branch: Optional[str] = None,
333+
commit_message: Optional[str] = None,
334+
description: Optional[str] = None,
335+
keywords: Optional[List[str]] = None,
336336
):
337337
"""Initialize a new project from a template.
338338
339339
Args:
340-
template_path: Path to template.
341-
name: project name.
340+
template_path(Path): Path to template.
341+
name(str): project name.
342+
namespace(str): project namespace.
342343
client_dispatcher(IClientDispatcher): Injected client dispatcher.
343-
metadata: Project metadata (Default value = None).
344-
custom_metadata: Custom JSON-LD metadata (Default value = None).
345-
default_metadata: Default project metadata (Default value = None).
346-
template_version: Version of the template (Default value = None).
347-
immutable_template_files: Immutable template files (Default value = None).
348-
automated_template_update: If template can be updated automatically (Default value = True).
349-
user: Git user (Default value = None).
350-
source: Template source. (Default value = None).
351-
ref: Template reference (Default value = None).
352-
invoked_from: Where this was invoked from (Default value = None).
353-
initial_branch: Name of initial/main branch (Default value = None).
354-
commit_message: Message of initial commit (Default value = None).
355-
description: Project description (Default value = None).
356-
keywords: Project keywords (Default value = None).
344+
metadata(Optional[Dict]): Project metadata (Default value = None).
345+
custom_metadata(Optional[Dict]): Custom JSON-LD metadata (Default value = None).
346+
default_metadata(Optional[Dict]): Default project metadata (Default value = None).
347+
template_version(Optional[str]): Version of the template (Default value = None).
348+
immutable_template_files(Optional[List[str]]): Immutable template files (Default value = None).
349+
automated_template_update(bool): If template can be updated automatically (Default value = True).
350+
user(Optional[Doct[str, str]]): Git user (Default value = None).
351+
initial_branch(Optional[str]): Name of initial/main branch (Default value = None).
352+
commit_message(Optional[str]): Message of initial commit (Default value = None).
353+
description(Optional[str]): Project description (Default value = None).
354+
keywords(Optional[List[str]]): Project keywords (Default value = None).
357355
"""
358356
client = client_dispatcher.current_client
359357

@@ -380,7 +378,7 @@ def _create_from_template_local(
380378
description="",
381379
parameters={},
382380
icon="",
383-
immutable_files=immutable_template_files,
381+
immutable_files=immutable_template_files or [],
384382
allow_update=automated_template_update,
385383
source=metadata["__template_source__"],
386384
reference=metadata["__template_ref__"],
@@ -403,9 +401,8 @@ def _create_from_template_local(
403401
actions=actions,
404402
client=client,
405403
name=name,
404+
namespace=namespace,
406405
custom_metadata=custom_metadata,
407-
force=False,
408-
user=user,
409406
commit_message=commit_message,
410407
description=description,
411408
keywords=keywords,

renku/core/management/repository.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from contextlib import contextmanager
2323
from fnmatch import fnmatch
2424
from pathlib import Path
25-
from typing import Any, Optional
25+
from typing import Any, Dict, List, Optional
2626
from uuid import uuid4
2727

2828
import attr
@@ -257,24 +257,42 @@ def get_in_submodules(self, commit, path):
257257
return self, commit, path
258258

259259
@contextmanager
260-
@inject.autoparams()
260+
@inject.autoparams("project_gateway", "database_gateway")
261261
def with_metadata(
262262
self,
263263
project_gateway: IProjectGateway,
264264
database_gateway: IDatabaseGateway,
265-
read_only=False,
266-
name=None,
267-
description=None,
268-
keywords=None,
269-
custom_metadata=None,
265+
read_only: bool = False,
266+
name: Optional[str] = None,
267+
namespace: Optional[str] = None,
268+
description: Optional[str] = None,
269+
keywords: Optional[List[str]] = None,
270+
custom_metadata: Optional[Dict] = None,
270271
):
271-
"""Yield an editable metadata object."""
272+
"""Yield an editable metadata object.
273+
274+
Args:
275+
project_gateway(IProjectGateway): Injected project gateway.
276+
database_gateway(IDatabaseGateway): Injected database gateway.
277+
read_only(bool): Whether to save changes or not (Default value = False).
278+
name(Optional[str]): Name of the project (when creating a new one) (Default value = None).
279+
namespace(Optional[str]): Namespace of the project (when creating a new one) (Default value = None).
280+
description(Optional[str]): Project description (when creating a new one) (Default value = None).
281+
keywords(Optional[List[str]]): Keywords for the project (when creating a new one) (Default value = None).
282+
custom_metadata(Optional[Dict]): Custom JSON-LD metadata (when creating a new project)
283+
(Default value = None).
284+
"""
272285

273286
try:
274287
project = project_gateway.get_project()
275288
except ValueError:
276289
project = Project.from_client(
277-
name=name, description=description, keywords=keywords, custom_metadata=custom_metadata, client=self
290+
name=name,
291+
namespace=namespace,
292+
description=description,
293+
keywords=keywords,
294+
custom_metadata=custom_metadata,
295+
client=self, # type: ignore
278296
)
279297

280298
yield project

0 commit comments

Comments
 (0)