mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
fix(AWS Deploy): Fix handling of state file in check for changes logic
This commit is contained in:
parent
d181ee00b0
commit
12d95dcee1
@ -152,11 +152,30 @@ module.exports = {
|
||||
|
||||
// create a hash of the CloudFormation body
|
||||
const compiledCfTemplate = this.serverless.service.provider.compiledCloudFormationTemplate;
|
||||
const normCfTemplate = normalizeFiles.normalizeCloudFormationTemplate(compiledCfTemplate);
|
||||
const stateBasename = this.provider.naming.getServiceStateFileName();
|
||||
const stateObject = JSON.parse(
|
||||
await fsp.readFile(
|
||||
path.join(this.serverless.serviceDir, '.serverless', stateBasename),
|
||||
'utf-8'
|
||||
)
|
||||
);
|
||||
|
||||
const localHashesMap = new Map([
|
||||
[
|
||||
'compiled-cloudformation-template.json',
|
||||
crypto.createHash('sha256').update(JSON.stringify(normCfTemplate)).digest('base64'),
|
||||
crypto
|
||||
.createHash('sha256')
|
||||
.update(
|
||||
JSON.stringify(normalizeFiles.normalizeCloudFormationTemplate(compiledCfTemplate))
|
||||
)
|
||||
.digest('base64'),
|
||||
],
|
||||
[
|
||||
stateBasename,
|
||||
crypto
|
||||
.createHash('sha256')
|
||||
.update(JSON.stringify(normalizeFiles.normalizeState(stateObject)))
|
||||
.digest('base64'),
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@ -83,7 +83,11 @@ module.exports = {
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
const fileHash = crypto.createHash('sha256').update(content).digest('base64');
|
||||
const stateObject = JSON.parse(content);
|
||||
const fileHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(JSON.stringify(normalizeFiles.normalizeState(stateObject)))
|
||||
.digest('base64');
|
||||
|
||||
let params = {
|
||||
Bucket: this.bucketName,
|
||||
|
||||
@ -44,4 +44,12 @@ module.exports = {
|
||||
|
||||
return normalizedTemplate;
|
||||
},
|
||||
normalizeState(state) {
|
||||
const result = deepSortObjectByKey(state);
|
||||
delete result.service.initialServerlessConfig;
|
||||
delete result.service.provider.coreCloudFormationTemplate;
|
||||
delete result.service.provider.compiledCloudFormationTemplate;
|
||||
delete result.package.artifactDirectoryName;
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
||||
@ -408,6 +408,13 @@ describe('test/unit/lib/plugins/aws/deploy/index.test.js', () => {
|
||||
Size: 356,
|
||||
StorageClass: 'STANDARD',
|
||||
},
|
||||
{
|
||||
Key: 'serverless/test-package-artifact/dev/1589988704359-2020-05-20T15:31:44.359Z/serverless-state.json',
|
||||
LastModified: new Date(),
|
||||
ETag: '"5102a4cf710cae6497dba9e61b85d0a4"',
|
||||
Size: 356,
|
||||
StorageClass: 'STANDARD',
|
||||
},
|
||||
{
|
||||
Key: 'serverless/test-package-artifact/dev/1589988704359-2020-05-20T15:31:44.359Z/my-own.zip',
|
||||
LastModified: new Date(),
|
||||
@ -426,6 +433,15 @@ describe('test/unit/lib/plugins/aws/deploy/index.test.js', () => {
|
||||
.returns({
|
||||
Metadata: { filesha256: 'qxp+iwSTMhcRUfHzka4AE4XAWawS8GnEyBh1WpGb7Vw=' },
|
||||
});
|
||||
s3HeadObjectStub
|
||||
.withArgs({
|
||||
Bucket: 's3-bucket-resource',
|
||||
Key: 'serverless/test-package-artifact/dev/1589988704359-2020-05-20T15:31:44.359Z/serverless-state.json',
|
||||
})
|
||||
.returns({
|
||||
Metadata: { filesha256: 'DCociWxGeu49Gi6Ej103YnbXACySaslxTzQn19R1Q5I=' },
|
||||
});
|
||||
|
||||
s3HeadObjectStub
|
||||
.withArgs({
|
||||
Bucket: 's3-bucket-resource',
|
||||
|
||||
@ -244,7 +244,9 @@ describe('checkForChanges', () => {
|
||||
.stub(normalizeFiles, 'normalizeCloudFormationTemplate')
|
||||
.returns();
|
||||
globbySyncStub = sandbox.stub(globby, 'sync');
|
||||
readFileStub = sandbox.stub(fsp, 'readFile').returns(Promise.resolve(''));
|
||||
readFileStub = sandbox
|
||||
.stub(fsp, 'readFile')
|
||||
.returns(Promise.resolve('{"service":{"provider":{}},"package":{}}'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -279,7 +281,6 @@ describe('checkForChanges', () => {
|
||||
await awsDeploy.checkIfDeploymentIsNecessary(input);
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -312,7 +313,6 @@ describe('checkForChanges', () => {
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -341,7 +341,6 @@ describe('checkForChanges', () => {
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -372,7 +371,6 @@ describe('checkForChanges', () => {
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledTwice;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -408,7 +406,6 @@ describe('checkForChanges', () => {
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input, now)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -427,18 +424,19 @@ describe('checkForChanges', () => {
|
||||
it('should set a flag if the remote and local hashes are equal', () => {
|
||||
globbySyncStub.returns(['my-service.zip']);
|
||||
cryptoStub.createHash().update().digest.onCall(0).returns('hash-cf-template');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-zip-file-1');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-state');
|
||||
cryptoStub.createHash().update().digest.onCall(2).returns('hash-zip-file-1');
|
||||
|
||||
let fileCounter = 0;
|
||||
const input = [
|
||||
{ Metadata: { filesha256: 'hash-cf-template' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'hash-state' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'hash-zip-file-1' }, Key: `file${++fileCounter}.zip` },
|
||||
];
|
||||
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -457,7 +455,8 @@ describe('checkForChanges', () => {
|
||||
it('should set a flag if the remote and local hashes are equal, and the edit times are ordered', () => {
|
||||
globbySyncStub.returns(['my-service.zip']);
|
||||
cryptoStub.createHash().update().digest.onCall(0).returns('hash-cf-template');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-zip-file-1');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-state');
|
||||
cryptoStub.createHash().update().digest.onCall(2).returns('hash-zip-file-1');
|
||||
|
||||
const longAgo = new Date(new Date().getTime() - 100000);
|
||||
const longerAgo = new Date(new Date().getTime() - 200000);
|
||||
@ -469,6 +468,11 @@ describe('checkForChanges', () => {
|
||||
LastModified: longerAgo,
|
||||
Key: `file${++fileCounter}.zip`,
|
||||
},
|
||||
{
|
||||
Metadata: { filesha256: 'hash-state' },
|
||||
LastModified: longerAgo,
|
||||
Key: `file${++fileCounter}.zip`,
|
||||
},
|
||||
{
|
||||
Metadata: { filesha256: 'hash-zip-file-1' },
|
||||
LastModified: longerAgo,
|
||||
@ -480,7 +484,6 @@ describe('checkForChanges', () => {
|
||||
() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -500,13 +503,15 @@ describe('checkForChanges', () => {
|
||||
it('should set a flag if the remote and local hashes are duplicated and equal', () => {
|
||||
globbySyncStub.returns(['func1.zip', 'func2.zip']);
|
||||
cryptoStub.createHash().update().digest.onCall(0).returns('hash-cf-template');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-state');
|
||||
// happens when package.individually is used
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-zip-file-1');
|
||||
cryptoStub.createHash().update().digest.onCall(2).returns('hash-zip-file-1');
|
||||
cryptoStub.createHash().update().digest.onCall(3).returns('hash-zip-file-1');
|
||||
|
||||
let fileCounter = 0;
|
||||
const input = [
|
||||
{ Metadata: { filesha256: 'hash-cf-template' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'hash-state' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'hash-zip-file-1' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'hash-zip-file-1' }, Key: `file${++fileCounter}.zip` },
|
||||
];
|
||||
@ -514,7 +519,6 @@ describe('checkForChanges', () => {
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledTwice;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -540,18 +544,19 @@ describe('checkForChanges', () => {
|
||||
|
||||
globbySyncStub.returns([]);
|
||||
cryptoStub.createHash().update().digest.onCall(0).returns('hash-cf-template');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('local-my-own-hash');
|
||||
cryptoStub.createHash().update().digest.onCall(1).returns('hash-state');
|
||||
cryptoStub.createHash().update().digest.onCall(2).returns('local-my-own-hash');
|
||||
|
||||
let fileCounter = 0;
|
||||
const input = [
|
||||
{ Metadata: { filesha256: 'hash-cf-template' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'hash-state' }, Key: `file${++fileCounter}.zip` },
|
||||
{ Metadata: { filesha256: 'remote-my-own-hash' }, Key: `file${++fileCounter}.zip` },
|
||||
];
|
||||
|
||||
return expect(awsDeploy.checkIfDeploymentIsNecessary(input)).to.be.fulfilled.then(() => {
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce;
|
||||
expect(globbySyncStub).to.have.been.calledOnce;
|
||||
expect(readFileStub).to.have.been.calledOnce;
|
||||
expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly(
|
||||
awsDeploy.serverless.service.provider.compiledCloudFormationTemplate
|
||||
);
|
||||
@ -1043,6 +1048,14 @@ describe('test/unit/lib/plugins/aws/deploy/lib/checkForChanges.test.js', () => {
|
||||
.returns({
|
||||
Metadata: { filesha256: 'pZOdrt6qijT7ITsLQjPP9QwgMAfKA2RuUUSTW+l8wWs=' },
|
||||
});
|
||||
headObjectStub
|
||||
.withArgs({
|
||||
Bucket: 'deployment-bucket',
|
||||
Key: 'serverless/test-package-artifact/dev/1589988704359-2020-05-20T15:31:44.359Z/serverless-state.json',
|
||||
})
|
||||
.returns({
|
||||
Metadata: { filesha256: '+LsZPkrDKAtccClX0Uv88s71VPtsHAGeifgiRyW0/OQ=' },
|
||||
});
|
||||
|
||||
headObjectStub
|
||||
.withArgs({
|
||||
@ -1064,6 +1077,13 @@ describe('test/unit/lib/plugins/aws/deploy/lib/checkForChanges.test.js', () => {
|
||||
Size: 356,
|
||||
StorageClass: 'STANDARD',
|
||||
},
|
||||
{
|
||||
Key: 'serverless/test-package-artifact/dev/1589988704359-2020-05-20T15:31:44.359Z/serverless-state.json',
|
||||
LastModified: new Date(),
|
||||
ETag: '"5102a4cf710cae6497dba9e61b85d0a4"',
|
||||
Size: 356,
|
||||
StorageClass: 'STANDARD',
|
||||
},
|
||||
{
|
||||
Key: 'serverless/test-package-artifact/dev/1589988704359-2020-05-20T15:31:44.359Z/my-own.zip',
|
||||
LastModified: new Date(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user