Skip to content
2 changes: 1 addition & 1 deletion examples/github_actions_orchestration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ zenml orchestrator register github_orchestrator --flavor=github --push=true

# You can find the repository owner and repository name from the URL of your GitHub repository,
# for example https://github.com/zenml-io/zenml -> The owner would be `zenml-io` and the repository name `zenml`
zenml secrets_manager register github_secrets_manager \
zenml secrets-manager register github_secrets_manager \
--flavor=github \
--owner=<GITHUB_REPOSITORY_OWNER> \
--repository=<GITHUB_REPOSITORY_NAME>
Expand Down
14 changes: 10 additions & 4 deletions src/zenml/cli/secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from zenml.cli.utils import (
confirmation,
error,
expand_argument_value_from_file,
parse_unknown_options,
pretty_print_secret,
print_secrets,
Expand Down Expand Up @@ -206,17 +207,22 @@ def register_secret(
for k in secret_keys:
v = getpass.getpass(f"Secret value for {k}:")
if v:
secret_contents[k] = v
secret_contents[k] = expand_argument_value_from_file(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding the ability to expand secret values from file contents, I was thinking of also doing it in the interactive mode, but then decided not to, because 1. you can't see what you're typing and 2. you don't get auto-completion to help you to point to an existing file on disk. These reasons make it really error prone to specify a path in interactive mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it's better to remove it again? I've just without checking expected the interactive version to work the same way and tried copy-pasting the paths there with a prepended @ and got confused when it didn't work, that's why I implemented it.

name=k, value=v
)
else:
click.echo(
"You have not supplied a secret schema with any "
"predefined keys. Entering interactive mode:"
)
while True:
k = click.prompt("Please enter a secret-key")
k = click.prompt("Please enter a secret key")
if k not in secret_contents:
secret_contents[k] = getpass.getpass(
f"Please enter the secret_value for the key [{k}]:"
v = getpass.getpass(
f"Please enter the secret value for the key [{k}]:"
)
secret_contents[k] = expand_argument_value_from_file(
name=k, value=v
)
else:
warning(
Expand Down
20 changes: 14 additions & 6 deletions src/zenml/cli/stack_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,9 +643,13 @@ def update_stack_component_command(
else:
continue

updated_component = component_wrapper.to_component().copy(
update=parsed_args
)
# Initialize a new component object to make sure pydantic validation
# is used
new_attributes = {
**component_wrapper.to_component().dict(),
**parsed_args,
}
Comment on lines +648 to +651
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice ! :)

updated_component = component_class(**new_attributes)

repo.update_stack_component(
name, updated_component.TYPE, updated_component
Expand Down Expand Up @@ -721,9 +725,13 @@ def remove_attribute_stack_component_command(
f"'{', '.join(optional_attributes)}'."
)

updated_component = current_component.copy(
update={arg: None for arg in parsed_args}
)
# Remove the attributes from the current component dict
new_attributes = {
**current_component.dict(),
**{arg: None for arg in parsed_args},
}

updated_component = current_component.__class__(**new_attributes)

repo.update_stack_component(
name, updated_component.TYPE, updated_component
Expand Down
6 changes: 3 additions & 3 deletions src/zenml/cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ def format_date(
MAX_ARGUMENT_VALUE_SIZE = 10240


def _expand_argument_value_from_file(name: str, value: str) -> str:
def expand_argument_value_from_file(name: str, value: str) -> str:
"""Expands the value of an argument pointing to a file into the contents of that file.

Args:
Expand All @@ -519,7 +519,7 @@ def _expand_argument_value_from_file(name: str, value: str) -> str:
return value[1:]
if not value.startswith("@"):
return value
filename = value[1:]
filename = os.path.abspath(value[1:])
logger.info(
f"Expanding argument value `{name}` to contents of file `{filename}`."
)
Expand Down Expand Up @@ -572,7 +572,7 @@ def parse_unknown_options(

if expand_args:
args_dict = {
k: _expand_argument_value_from_file(k, v)
k: expand_argument_value_from_file(k, v)
for k, v in args_dict.items()
}

Expand Down
2 changes: 2 additions & 0 deletions src/zenml/utils/docker_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def generate_dockerfile_contents(
lines.append(f"ENV {key.upper()}={value}")

if requirements:
# Quote the requirements to avoid problems with special characters
requirements = {f"'{r}'" for r in requirements}
lines.append(
f"RUN pip install --no-cache {' '.join(sorted(requirements))}"
)
Expand Down