Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): allow ignoring template rendering errors #3697

Merged
merged 1 commit into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions renku/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,11 +485,11 @@ class TemplateError(RenkuException):


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


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


class TemplateUpdateError(TemplateError):
Expand Down
4 changes: 3 additions & 1 deletion renku/core/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def init_project(
input_parameters: Dict[str, str],
custom_metadata: Optional[Dict[str, Any]],
force: bool,
ignore_template_errors: bool,
data_dir: Optional[Path],
initial_branch: Optional[str],
install_mergetool: bool,
Expand All @@ -129,6 +130,7 @@ def init_project(
input_parameters: Template parameters.
custom_metadata: Custom JSON-LD metadata for project.
force: Whether to overwrite existing files and delete existing metadata.
ignore_template_errors: Create project anyway even if template rendering fails.
data_dir: Where to store dataset data.
initial_branch: Default git branch.
install_mergetool(bool): Whether to set up the renku metadata mergetool in the created project.
Expand Down Expand Up @@ -181,7 +183,7 @@ def init_project(
# TODO: Validate input_parameters to make sure they don't contain __\w+__ keys
set_template_parameters(template=template, template_metadata=template_metadata, input_parameters=input_parameters)

rendered_template = template.render(metadata=template_metadata)
rendered_template = template.render(metadata=template_metadata, ignore_template_errors=ignore_template_errors)
actions = get_file_actions(
rendered_template=rendered_template, template_action=TemplateAction.INITIALIZE, interactive=False
)
Expand Down
35 changes: 27 additions & 8 deletions renku/domain_model/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

from renku.core import errors
from renku.core.constant import RENKU_HOME
from renku.core.util import communication
from renku.core.util.os import get_safe_relative_path, hash_file, hash_string
from renku.core.util.util import to_string

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

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

render_base = Path(tempfile.mkdtemp())

for relative_path in self.get_files():
# NOTE: The path could contain template variables, we need to template it
rendered_relative_path = jinja2.Template(relative_path).render(metadata.metadata)
try:
# NOTE: The path could contain template variables, we need to template it
rendered_relative_path = jinja2.Template(relative_path).render(metadata.metadata)
except jinja2.TemplateError as e:
if ignore_template_errors:
rendered_relative_path = relative_path
communication.warn(f"Ignoring template error when rendering path '{relative_path}'")
else:
raise errors.InvalidTemplateError(f"Cannot render template file path '{relative_path}': {e}")

destination = render_base / rendered_relative_path
destination.parent.mkdir(parents=True, exist_ok=True)
Expand All @@ -365,9 +373,20 @@ def render(self, metadata: "TemplateMetadata") -> "RenderedTemplate":
content_bytes = source.read_bytes()
destination.write_bytes(content_bytes)
else:
template = jinja2.Template(content, keep_trailing_newline=True)
rendered_content = template.render(metadata.metadata)
destination.write_text(rendered_content)
try:
rendered_content = jinja2.Template(content, keep_trailing_newline=True).render(metadata.metadata)
except jinja2.TemplateError as e:
if ignore_template_errors:
destination.write_text(content)
communication.warn(
f"Ignoring template rendering error when creating '{rendered_relative_path}'"
)
else:
raise errors.InvalidTemplateError(
f"Cannot render template file '{rendered_relative_path}': {e}"
)
else:
destination.write_text(rendered_content)

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

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

def validate(self, raise_errors: bool = True) -> List[str]:
Expand Down
7 changes: 7 additions & 0 deletions renku/ui/cli/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
source ``--template-source`` (both local path and remote url are supported) and
the reference ``--template-ref`` (branch, tag or commit).

If the template contains an error that prevents it from being rendered, you can
ignore this error by passing ``--ignore-template-errors`` to the ``init``
command.

You can take inspiration from the
`official Renku template repository
<https://github.com/SwissDataScienceCenter/renku-project-template>`_
Expand Down Expand Up @@ -259,6 +263,7 @@ def resolve_data_directory(data_dir, path):
@click.option("-l", "--list-templates", is_flag=True, help="List templates available in the template-source.")
@click.option("-d", "--describe", is_flag=True, help="Show description for templates and parameters")
@click.option("--force", is_flag=True, help="Override target path.")
@click.option("--ignore-template-errors", is_flag=True, help="Ignore template rendering errors.")
@click.option("--initial-branch", help="Initial git branch to create.")
@option_external_storage_requested
@click.pass_context
Expand All @@ -277,6 +282,7 @@ def init(
metadata,
list_templates,
force,
ignore_template_errors,
describe,
datadir,
initial_branch,
Expand Down Expand Up @@ -319,6 +325,7 @@ def init(
input_parameters=parameters,
custom_metadata=custom_metadata,
force=force,
ignore_template_errors=ignore_template_errors,
data_dir=datadir,
initial_branch=initial_branch,
install_mergetool=True,
Expand Down
Loading