Created
May 15, 2020 13:24
-
-
Save erik-am/01c0d676c087fef125034e45eefd7428 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
class PrDetector { | |
constructor(serverless) { | |
this.serverless = serverless; | |
this.provider = this.serverless.getProvider('aws'); | |
this.hooks = { | |
'after:aws:package:finalize:mergeCustomProviderResources': () => | |
this.removeDeletionPolicies(), | |
'before:remove:remove': async () => await this.emptyS3Buckets(), | |
}; | |
this.log = message => serverless.cli.log(message, 'PR-Detector'); | |
} | |
removeDeletionPolicies() { | |
if (this.isPr()) { | |
this.log('Detected a Pull Request'); | |
let cfResources = this.serverless.service.provider | |
.compiledCloudFormationTemplate.Resources; | |
for (let key in cfResources) { | |
if (cfResources[key].DeletionPolicy) { | |
this.log(`Removing deletion policy from ${key}`); | |
delete cfResources[key].DeletionPolicy; | |
} | |
if (cfResources[key].UpdateReplacePolicy) { | |
this.log(`Removing update/replace policy from ${key}`); | |
delete cfResources[key].UpdateReplacePolicy; | |
} | |
} | |
} | |
} | |
isPr() { | |
const stage = this.serverless.variables.options.stage; | |
const isPr = stage.match(/^pr-([0-9]+)$/); | |
return isPr; | |
} | |
async emptyS3Buckets() { | |
if (this.isPr()) { | |
const resources = this.serverless.service.resources.Resources; | |
const buckets = Object.keys(resources) | |
.filter(x => resources[x].Type === 'AWS::S3::Bucket') | |
.map(x => resources[x].Properties.BucketName) | |
.filter(x => x !== null); | |
buckets.forEach(async bucket => { | |
this.log(`Emptying S3 bucket ${bucket}`); | |
await this.getAllKeys(bucket) | |
.then(params => this.executeRemove(params)) | |
.then(() => { | |
this.log(`Success: ${bucket} is empty.`); | |
}) | |
.catch(err => { | |
console.log(err); | |
this.log(`Failed: ${bucket} may not be empty.`); | |
}); | |
}); | |
} | |
} | |
// From https://github.com/sinofseven/serverless-s3-remover/blob/master/index.js (MIT) | |
getAllKeys(bucket) { | |
const get = (src = {}) => { | |
const data = src.data; | |
const keys = src.keys || []; | |
const param = { | |
Bucket: bucket, | |
}; | |
if (data) { | |
param.ContinuationToken = data.NextContinuationToken; | |
} | |
return this.provider | |
.request('S3', 'listObjectsV2', param) | |
.then(result => { | |
return new Promise(resolve => { | |
resolve({ | |
data: result, | |
keys: keys.concat( | |
result.Contents.map(item => { | |
return item.Key; | |
}), | |
), | |
}); | |
}); | |
}); | |
}; | |
const list = (src = {}) => { | |
return get(src).then(result => { | |
if (result.data.IsTruncated) { | |
return list(result); | |
} else { | |
const keys = result.keys; | |
const batched = []; | |
for (let i = 0; i < keys.length; i += 1000) { | |
const objects = keys.slice(i, i + 1000).map(item => { | |
return { Key: item }; | |
}); | |
batched.push({ | |
Bucket: bucket, | |
Delete: { | |
Objects: objects, | |
}, | |
}); | |
} | |
return new Promise(resolve => { | |
resolve(batched); | |
}); | |
} | |
}); | |
}; | |
return list(); | |
} | |
executeRemove(params) { | |
return Promise.all( | |
params.map(param => { | |
return this.provider.request('S3', 'deleteObjects', param); | |
}), | |
); | |
} | |
} | |
module.exports = PrDetector; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment