Skip to content

Commit 088ce15

Browse files
feat(cli): allow ignoring template rendering errors (#3697)
1 parent ae3618c commit 088ce15

File tree

4 files changed

+39
-11
lines changed

4 files changed

+39
-11
lines changed

renku/core/errors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,11 @@ class TemplateError(RenkuException):
485485

486486

487487
class InvalidTemplateError(TemplateError):
488-
"""Raised when using a non-valid template."""
488+
"""Raised when using an invalid template."""
489489

490490

491491
class TemplateMissingReferenceError(TemplateError):
492-
"""Raised when using a non-valid template."""
492+
"""Raised when a reference cannot be found in the template's repository."""
493493

494494

495495
class TemplateUpdateError(TemplateError):

renku/core/init.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def init_project(
110110
input_parameters: Dict[str, str],
111111
custom_metadata: Optional[Dict[str, Any]],
112112
force: bool,
113+
ignore_template_errors: bool,
113114
data_dir: Optional[Path],
114115
initial_branch: Optional[str],
115116
install_mergetool: bool,
@@ -129,6 +130,7 @@ def init_project(
129130
input_parameters: Template parameters.
130131
custom_metadata: Custom JSON-LD metadata for project.
131132
force: Whether to overwrite existing files and delete existing metadata.
133+
ignore_template_errors: Create project anyway even if template rendering fails.
132134
data_dir: Where to store dataset data.
133135
initial_branch: Default git branch.
134136
install_mergetool(bool): Whether to set up the renku metadata mergetool in the created project.
@@ -181,7 +183,7 @@ def init_project(
181183
# TODO: Validate input_parameters to make sure they don't contain __\w+__ keys
182184
set_template_parameters(template=template, template_metadata=template_metadata, input_parameters=input_parameters)
183185

184-
rendered_template = template.render(metadata=template_metadata)
186+
rendered_template = template.render(metadata=template_metadata, ignore_template_errors=ignore_template_errors)
185187
actions = get_file_actions(
186188
rendered_template=rendered_template, template_action=TemplateAction.INITIALIZE, interactive=False
187189
)

renku/domain_model/template.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
from renku.core import errors
3030
from renku.core.constant import RENKU_HOME
31+
from renku.core.util import communication
3132
from renku.core.util.os import get_safe_relative_path, hash_file, hash_string
3233
from renku.core.util.util import to_string
3334

@@ -343,16 +344,23 @@ def get_files(self) -> Generator[str, None, None]:
343344
if subpath.is_file():
344345
yield str(subpath.relative_to(self.path))
345346

346-
def render(self, metadata: "TemplateMetadata") -> "RenderedTemplate":
347+
def render(self, metadata: "TemplateMetadata", ignore_template_errors: bool = False) -> "RenderedTemplate":
347348
"""Render template files in a new directory."""
348349
if self.path is None:
349350
raise ValueError("Template path not set")
350351

351352
render_base = Path(tempfile.mkdtemp())
352353

353354
for relative_path in self.get_files():
354-
# NOTE: The path could contain template variables, we need to template it
355-
rendered_relative_path = jinja2.Template(relative_path).render(metadata.metadata)
355+
try:
356+
# NOTE: The path could contain template variables, we need to template it
357+
rendered_relative_path = jinja2.Template(relative_path).render(metadata.metadata)
358+
except jinja2.TemplateError as e:
359+
if ignore_template_errors:
360+
rendered_relative_path = relative_path
361+
communication.warn(f"Ignoring template error when rendering path '{relative_path}'")
362+
else:
363+
raise errors.InvalidTemplateError(f"Cannot render template file path '{relative_path}': {e}")
356364

357365
destination = render_base / rendered_relative_path
358366
destination.parent.mkdir(parents=True, exist_ok=True)
@@ -365,9 +373,20 @@ def render(self, metadata: "TemplateMetadata") -> "RenderedTemplate":
365373
content_bytes = source.read_bytes()
366374
destination.write_bytes(content_bytes)
367375
else:
368-
template = jinja2.Template(content, keep_trailing_newline=True)
369-
rendered_content = template.render(metadata.metadata)
370-
destination.write_text(rendered_content)
376+
try:
377+
rendered_content = jinja2.Template(content, keep_trailing_newline=True).render(metadata.metadata)
378+
except jinja2.TemplateError as e:
379+
if ignore_template_errors:
380+
destination.write_text(content)
381+
communication.warn(
382+
f"Ignoring template rendering error when creating '{rendered_relative_path}'"
383+
)
384+
else:
385+
raise errors.InvalidTemplateError(
386+
f"Cannot render template file '{rendered_relative_path}': {e}"
387+
)
388+
else:
389+
destination.write_text(rendered_content)
371390

372391
return RenderedTemplate(path=render_base, template=self, metadata=metadata.metadata)
373392

@@ -432,8 +451,8 @@ def from_dict(cls, name: str, value: Dict[str, Any]):
432451
@property
433452
def has_default(self) -> bool:
434453
"""Return True if a default value is set."""
435-
# NOTE: ``None`` cannot be used as the default value but it's ok since no variable type accepts it and it's not
436-
# a valid value anyways
454+
# NOTE: ``None`` cannot be used as the default value, but it's ok since no variable type accepts it, and it's
455+
# not a valid value anyway
437456
return self.default is not None
438457

439458
def validate(self, raise_errors: bool = True) -> List[str]:

renku/ui/cli/init.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
source ``--template-source`` (both local path and remote url are supported) and
5454
the reference ``--template-ref`` (branch, tag or commit).
5555
56+
If the template contains an error that prevents it from being rendered, you can
57+
ignore this error by passing ``--ignore-template-errors`` to the ``init``
58+
command.
59+
5660
You can take inspiration from the
5761
`official Renku template repository
5862
<https://github.com/SwissDataScienceCenter/renku-project-template>`_
@@ -259,6 +263,7 @@ def resolve_data_directory(data_dir, path):
259263
@click.option("-l", "--list-templates", is_flag=True, help="List templates available in the template-source.")
260264
@click.option("-d", "--describe", is_flag=True, help="Show description for templates and parameters")
261265
@click.option("--force", is_flag=True, help="Override target path.")
266+
@click.option("--ignore-template-errors", is_flag=True, help="Ignore template rendering errors.")
262267
@click.option("--initial-branch", help="Initial git branch to create.")
263268
@option_external_storage_requested
264269
@click.pass_context
@@ -277,6 +282,7 @@ def init(
277282
metadata,
278283
list_templates,
279284
force,
285+
ignore_template_errors,
280286
describe,
281287
datadir,
282288
initial_branch,
@@ -319,6 +325,7 @@ def init(
319325
input_parameters=parameters,
320326
custom_metadata=custom_metadata,
321327
force=force,
328+
ignore_template_errors=ignore_template_errors,
322329
data_dir=datadir,
323330
initial_branch=initial_branch,
324331
install_mergetool=True,

0 commit comments

Comments
 (0)