`sls deploy --package` deletes .serverless directory
#7,298 opened on Feb 7, 2020
Description
For some reason, the deploy --package option causes serverless to delete the .serverless directory, even when nothing has changed or gets deployed. This behavior is unexpected, because sls deploy does not nuke the directory.
In particular, this is bad when a specially built .serverless directory is built, intending to be deployed by serverless, and the command is:
sls deploy --package .serverless
In that case, the specially built zipfiles are also deleted along with the directory!
The more common case, comparing sls deploy and sls deploy --package temp (with a copy of .serverless dir:
$ ls .serverless/
cloudformation-template-update-stack.json dumblogger.zip serverless-state.json signer.zip wrapper.zip
$ sls deploy --verbose
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Excluding development dependencies...
Serverless: Excluding development dependencies...
Serverless: Service files not changed. Skipping deployment...
Service Information
service: signer
stage: dev
region: us-east-1
stack: signer-dev
api keys:
None
endpoints:
None
functions:
dumblogger: signer-dev-dumblogger
wrapper: signer-dev-wrapper
signer: signer-dev-signer
layers:
None
Stack Outputs...
ServerlessDeploymentBucketName: ...
$ ls .serverless/
cloudformation-template-update-stack.json dumblogger.zip serverless-state.json signer.zip wrapper.zip
$ cp -R .serverless temp
$ sls deploy --verbose --package temp
Serverless: Service files not changed. Skipping deployment...
Service Information
service: signer
stage: dev
region: us-east-1
stack: signer-dev
api keys:
None
endpoints:
None
functions:
dumblogger: signer-dev-dumblogger
wrapper: signer-dev-wrapper
signer: signer-dev-signer
layers:
None
Stack Outputs...
ServerlessDeploymentBucketName: ...
$ ls .serverless/
ls: .serverless/: No such file or directory
Expected behavior: deployment never deletes the .serverless directory, regardless of options used.
Solution proposal:
(Added by maintainers):
Issue is driven by internal processing flow, in which:
- When packaging, deployment artifacts are always packaged to service local
.serverlessdirectory, and then eventually moved to target output directory (as indicated by--package) - When deploying, deployment artifacts are always moved to local
.serverlessdirectory and deployment always happens from there.
This design doesn't seem great, it definitely introduces side effects. I believe it can be fixed (but that won't be straightforward). Ideally if:
- Framework by default builds to some real temporary directory (in scope of system temp dir), and then moves generated build to target package dir (by default
.serverless) - Framework deploys from package directory directly. If custom is provided, files are not moved to
.serverlessdir but deployed directly from there.
I believe both problems can be addressed independently, spec on how to tackle this:
A. Build to system temporary directory
1.1 Preliminary refactor steps (should be addressed, before tackling next step. Ideally first PR should handle just those)
Done with #8533
Tests
If any test breaks and fix is not straightforward, ideally we should refactor given test files to runServerless variant. That again should be addressed with different PR and spec for refactor written upfront (like one proposed here: https://github.com/serverless/serverless/issues/8523) - if there's a need let me know, and I'll provide a needed spec.
1.2 Implementation
-
In
Serverlessclass configure onServerless.prototypelazypackageBuildTempDirDeferredproperty, which should simply return a temp dir as resolved byprocess-utils/tmpdir/provision(we need to also move this dependency fromdevDependenciestodependenciesthen) -
In all internal logic where we put to be packaged files into
.serverless, ensure they're put intoawait packageBuildTempDirDeferred:- In custom resource builder, ensure
zipFilePathputs archive in newly designated temp dir - Ensure that core CF template is generated to newly designated temp dir
- Ensure that compiled CF template is generated to newly designated temp dir
- Ensure that service state is stored in newly designated temp dir
- Ensure artifacts are zipped into newly designated temp dir
- In custom resource builder, ensure
-
In
moveArtifactsToPackage()ensure that content ofawait packageBuildTempDirDeferredis moved to desired package directory (by default.serverless) which is emptied upfront -
Remove
cleanupTempDir()module, and deprecate associated hooks (it was dedicated to cleaning up.serverlessdir for temporary build) -
Update test fixture plugin to respect newly designed temp dir
Tests
This should not require any new tests to be written, but due to nature of our tests, it's likely that some will break
We should not attempt to fix broken tests (in the form they are written), but instead they have to be refactored to runServerless variant, and that again should be addressed with different PR with spec for refactor written upfront (like one proposed here: https://github.com/serverless/serverless/issues/8523). I'll provide a needed spec, but let's first clarify which test files may need it
Additionally confirm that nothing got broken by running npm run integration-test-run-package and all our integration tests
B. Ensure deployment is made directly from package folder
- Remove
moveArtifactsToTemp()and deprecate associated hooks - In
checkIfDeploymentIsNecessary()refer to resolved package path (not hardcoded.serverlesspath) - In
extendedValidate()refer to resolved package path (not hardcoded.serverlesspath) - in
uploadCustomResources()refer to resolved package path (not hardcoded.serverlesspath)
Tests
This should not require any new tests to be written, but due to nature of our tests, it's likely that some will break
We should not attempt to fix broken tests (in the form they are written), but instead they have to be refactored to runServerless variant, and that again should be addressed with different PR with spec for refactor written upfront (like one proposed here: https://github.com/serverless/serverless/issues/8523). I'll provide a needed spec, but let's first clarify which test files may need it
Additionally confirm that nothing got broken by running npm run integration-test-run-package and all our integration tests