-
Notifications
You must be signed in to change notification settings - Fork 56
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 subdirectory for stage in application package #1916
base: main
Are you sure you want to change the base?
Conversation
…kedb/snowflake-cli into pj-subartifacts-subdirs
# TODO: get all apps created from this application package from snowflake, compare, confirm and drop. | ||
# TODO: add messaging/confirmation here for extra apps found as part of above |
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.
Kept current teardown functionality. Next PR, we will get and drop all app objects created from this package, not just what's listed in pdf.
src/snowflake/cli/_plugins/nativeapp/codegen/templates/templates_processor.py
Outdated
Show resolved
Hide resolved
diff = ws.perform_action( | ||
package_id, | ||
EntityActions.BUNDLE, | ||
) | ||
stage_fqn = f"{package.fqn.name}.{package.stage}" | ||
diff: DiffResult = compute_stage_diff( | ||
local_root=Path(package.deploy_root), stage_fqn=stage_fqn | ||
EntityActions.DIFF, | ||
print_to_console=cli_context.output_format != OutputFormat.JSON, | ||
) | ||
if cli_context.output_format == OutputFormat.JSON: | ||
return ObjectResult(diff.to_dict()) | ||
else: | ||
print_diff_to_console(diff, bundle_map) | ||
return None # don't print any output | ||
|
||
return 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.
Made diff
its own entity action. action_diff
src/snowflake/cli/_plugins/nativeapp/entities/application_package.py
Outdated
Show resolved
Hide resolved
@property | ||
def scratch_stage_fqn(self) -> str: | ||
return f"{self.name}.{self._entity_model.scratch_stage}" | ||
def stage_path(self) -> DefaultStagePathParts: |
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: should it be cached? I don't expect recreating is too expensive, but ...
@@ -592,7 +592,7 @@ def upgrade_application( | |||
|
|||
@param name: Name of the application object | |||
@param install_method: Method of installing the application | |||
@param stage_fqn: FQN of the stage housing the application artifacts | |||
@param stage_path_to_artifacts: Path to directory in stage housing the application artifacts |
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: it's called version directory in the public docs
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.
ah I debated using that but I didn't. updated.
for package_entity in project.get_entities_by_type( | ||
ApplicationPackageEntityModel.get_type() | ||
).values() | ||
if package_entity.identifier == app_package_entity.identifier |
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.
Does this work with identifiers (quoted/unquoted)? or is this ==
overridden to do that, and if so, identifier could be String or Identifier.
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.
alternatively, you can take a look into package_entity.fqn
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.
good point, replaced with same_identifier
@@ -123,6 +128,11 @@ class ApplicationPackageEntityModel(EntityModelBase): | |||
default="", | |||
) | |||
|
|||
stage_subdirectory: Optional[str] = Field( | |||
title="Subfolder in 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.
Can we elaborate a bit here? something along the line: "Subfolder in stage where artifacts are uploaded"?
return ( | ||
self.project_root | ||
/ self._entity_model.deploy_root | ||
/ self._entity_model.stage_subdirectory |
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.
why is this changing? Seems like an unnecessary complication
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.
The deploy_root is now deploy_root/subdir. So all the actions (bundle, deploy, etc) that need to refer to deploy root to write/read artifacts look at this subdir.
I don't think I understand what you mean by unnecessary complication.
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 mean why is the deploy root now deploy_root/subdir?
def scratch_stage_fqn(self) -> str: | ||
return f"{self.name}.{self._entity_model.scratch_stage}" | ||
@cached_property | ||
def stage_path(self) -> DefaultStagePathParts: |
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.
minor: I know DefaultStagePathParts existed before - but would have been simpler if named something like "StageLocation" or "StagePath"
stage_fqn = f"{self.name}.{self._entity_model.stage}" | ||
subdir = self._entity_model.stage_subdirectory | ||
full_path = f"{stage_fqn}/{subdir}" if subdir else stage_fqn | ||
return DefaultStagePathParts(full_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.
we could also accept different constructors in DefaultStagePathParts, so DefaultStagePathParts to undo the concat.
""" | ||
@param path: file path on the stage. | ||
@param stage_subirectory: subdirectory of stage. | ||
@return: path of file relative to the stage_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.
there is no stage_path in input.
wo_stage_name = StagePathType(*path.split("/")[1:]) | ||
relative_path = str(wo_stage_name).removeprefix(stage_subirectory).lstrip("/") |
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.
can't tell what these are doing. I see the first command removing first part left of /, and the second line doing something similar.
- Adding comments might help.
- Curious if Path can somehow be leveraged to calculate relative path instead?
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.
Added comment and updated method.
Can't use Path at all since stage name can be a quoted identifier which can have any character including a "/" in its name
""" | ||
Returns a mapping of relative stage paths to their md5sums. | ||
Returns a mapping of file paths to their md5sums. File paths are relative to the stage_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.
ditto about stage_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.
done, thank you
""" | ||
Diffs the files in a stage with a local folder. | ||
Diffs the files in the local_root with files in the stage path that is stage_path_parts's full_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.
stage_path_parts?
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.
done
stage_name = self.stage.split(".")[-1] | ||
match = re.fullmatch(STAGE_PATH_REGEX, stage_path) | ||
if match is None: | ||
raise ClickException("Invalid stage 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.
this validation should be done in Pydantic model. For users, this might not be clear where this exception is coming from.
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.
we have validations in the pydantic model for NA. this is for other uses of this stage object.
@@ -0,0 +1,31 @@ | |||
definition_version: 2 |
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.
can't we use PDF factory instead of these?
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.
you caught me haha
I didn't want to re-write a bunch of our tests or add more fixtures to accommodate them. I understand that is not the greatest pattern but sadly the factories work way better for unit tests and have been harder to adopt for integ tests.
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 am not asking to rewrite existing tests. New tests added 2 new directories (napp_stage_subdirs*). We shouldn't add any more of these test directories if the factory can do that.
@@ -0,0 +1,31 @@ | |||
definition_version: 2 |
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 am not asking to rewrite existing tests. New tests added 2 new directories (napp_stage_subdirs*). We shouldn't add any more of these test directories if the factory can do that.
@@ -254,15 +255,15 @@ def get_account_event_table(self, role: str | None = None) -> str | None: | |||
def create_version_in_package( | |||
self, | |||
package_name: str, | |||
stage_fqn: str, | |||
path_to_version_directory: 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.
i am confused about the naming here. Why we mention version_directory here (while the rest uses stage_subdirectory), and doesn't this also include stage info? Is stage_fqn not accurate anymore? Or stage_with_subdirectory? or StageParts class?
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.
or stage_full_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.
path_to_version_directory is the naming used in the official docs for these two operations, so the facade naming is matching that.
Pre-review checklist
Changes description
Added an optional
stage_subdirectory
to the application package.This change means that the root of the stage is no longer the assumed path to finding the artifacts and the
manifest.yml
. If specified, the application package will only ever operate onstage/stage_subdirectory
. This includesdeploy
,diff
, andversion create
.For detailed information on how this affects each command, if specified, refer to the design document.