-
Notifications
You must be signed in to change notification settings - Fork 58
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
Add optional deploy files argument #933
Add optional deploy files argument #933
Conversation
An additional comment: your description states that the deploy root is CWD, but that's inaccurate, it's the project root that is current. Deploy root is typically a subdirectory of the project root. I still believe that falling back to look for files relative to the project root is a valuable addition to this command. |
symlink_or_copy(source_path, dest_path / source_path.name) | ||
dest_child_path = dest_path / source_path.name | ||
symlink_or_copy(source_path, dest_child_path) | ||
mapped_files[source_path.resolve()] = dest_child_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be related to the discussion above, but why:
- Is
source_path
being resolved? - Is only
source_path
being resolved but notdest_child_path
?
Also, can you clarify the following:
If the user specified a glob pattern, then source_path
will be the directories or files that qualify the source pattern. In case of directories, even though their contents are symlinked as well, mapped_files
will only contain a kv pair of the directory to the dest, and not its contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Both src/dest parts in
ArtifactDeploymentMap
are resolved, mostly to canonicalize windows paths:C:\Users\RUNNER~1\
->C:\Users\runneradmin\
dest_child_path
is also resolved (dest_path
is resolved a few lines above)
Yes, mapped_files
won't contain the contents of symlinked directories. It's only the files that we actually copied to the deploy directory.
You can see the logic in project_path_to_deploy_path()
for cases where we look for a file under a symlinked directory.
|
||
|
||
def project_path_to_deploy_path( | ||
project_path: Path, mapped_files: ArtifactDeploymentMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: is this project_path
or source_path
? project_path
can be misleading to only mean the path to the project, i.e. root of the project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I think source_path
is a better name.
if prune: | ||
diff.only_on_stage = [i for i in diff.only_on_stage if i in paths_to_sync] | ||
else: | ||
files_not_removed = [i for i in diff.only_on_stage if i in paths_to_sync] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lines 167 and 169 rely on the same list comprehension. Consider assigning it to a placeholder/variable before checking for prune, to reduce duplicating code.
from snowflake.cli.api.constants import DEFAULT_SIZE_LIMIT_MB | ||
from snowflake.cli.api.project.schemas.native_app.path_mapping import PathMapping | ||
from snowflake.cli.api.secure_path import SecurePath | ||
from yaml import safe_load | ||
|
||
# Map from source directories and files in the project directory to their path in the deploy directory. Both paths are absolute. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In an ideal world, these would be relative to their respective roots, but it's documented well and if we need them we can always use relative_to
.
|
||
|
||
def project_path_to_deploy_path( | ||
project_path: Path, mapped_files: ArtifactDeploymentMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I think source_path
is a better name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some thoughts for your consideration
RELEASE-NOTES.md
Outdated
@@ -6,6 +6,7 @@ | |||
|
|||
## New additions | |||
* `snow sql` command supports now client-side templating of queries. | |||
* Added the option to specify specific files and directories to sync when running `snow app deploy`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be helpful to include the name of the option
def source_path_to_deploy_path( | ||
source_path: Path, mapped_files: ArtifactDeploymentMap | ||
) -> Path: | ||
"""Given a source path and the files created during bundle, returns the absolute deploy destination path.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally better to start with what it does.
Returns the absolute path where the specified application bundle was deployed. ??? (just guessing here)
""" | ||
Prepares a local folder (deploy_root) with configured app artifacts. | ||
This folder can then be uploaded to a stage. | ||
Returns a mapping of the copied source files, pointing to where they were copied to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copied. (remove "to")
Also, is it a mapping or a map that gets returned? From the code, it looks like it returns a Map.
@@ -229,17 +230,44 @@ def app_teardown( | |||
@app.command("deploy", requires_connection=True) | |||
@with_project_definition("native_app") | |||
def app_deploy( | |||
prune: Optional[bool] = typer.Option( | |||
default=None, | |||
help=f"""If set, matched files that do not exist locally will also be deleted from the stage.""", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whether to delete specified files from the stage if they don't exist locally. If set, the command deletes files that exist in the stage, but not in the local filesystem.
None, | ||
"--recursive", | ||
"-r", | ||
help=f"""Controls whether the specified directories should be deployed including all of their contents. If false, only the immediate files will be deployed, ignoring any sub-directories.""", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whether to traverse and deploy files from subdirectories. If set, the command deploys all files and subdirectories; otherwise, only files in the current directory are deployed.
files: Optional[List[Path]] = typer.Argument( | ||
default=None, | ||
show_default=False, | ||
help=f"""Paths of the files, relative to the project root, to be uploaded to a stage. [default: sync all local changes to the stage]""", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Paths, relative to the the project root, of files you want to upload to a stage. If unspecified, the command syncs all local changes to the stage.
**options, | ||
) -> CommandResult: | ||
""" | ||
Creates an application package in your Snowflake account and syncs the local changes to the stage without creating or updating the application. | ||
Running this command with no arguments at all is a shorthand for "snow app deploy --prune --recursive". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... at all, as in snow app deploy
, ...
I think we use `` for commands. The scripts then convert it to the proper RST code format.
@@ -100,6 +106,20 @@ def ensure_correct_owner(row: dict, role: str, obj_name: str) -> None: | |||
raise UnexpectedOwnerError(obj_name, role, actual_owner) | |||
|
|||
|
|||
def _get_paths_to_sync(paths_to_sync: List[Path], deploy_root: Path) -> List[str]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an internal function (so the doc string is not customer-visible)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, not visible to the customer using the CLI. But visible to the public in general since this is open source.
Regardless, good idea to still have some information on what this function does.
help=f"""Whether to delete specified files from the stage if they don't exist locally. If set, the command deletes files that exist in the stage, but not in the local filesystem.""", | ||
), | ||
recursive: Optional[bool] = typer.Option( | ||
None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I would use False
as default for boolean value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed it to be None
here because there is the special flow of running snow app deploy
with no arguments, in which case the default value is True
* add deploy files argument * add --prune flag * add --recursive flag
Pre-review checklist
Changes description
Following up on #921, this PR introduces the following changes:
snow app deploy
--prune
/--no-prune
option-r
/--recursive
optionbuild_md5_map()
When determining the deploy path from source path, we use the mapping of the files created in the build step. Since we symlink entire directories, nested files will not exist in the mapping. In such cases, we traverse the parents chain until a mapped directory is found.
Usage
If no files are specified, all files will be synced to stage (existing behavior).
The file paths are assumed to be relative to the project root.
Absolute paths, directories and patterns are currently not supported.
Pruning
When pruning is enabled, files that exist only on the stage will be removed.
When deploying all changes,
--prune
is the default value (existing behavior).When deploying specific files,
--no-prune
is the default value and the user has to explicitly specify--prune
to avoid accidentally removing files.Recursive
Same as
cp
command, when specifying specific directories to deploy, the-r
flag must be provided. When a directory is deployed, all of its content will be synced recursively.When deploying all changes,
-r
is implied (existing behavior).