Created
June 25, 2019 22:58
-
-
Save mrcoles/1a252ccffca03cebd9376ffe0612e944 to your computer and use it in GitHub Desktop.
A script for deleting old amplify builds in s3 and keeping the 5 most recent ones.
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
const AWS = require('aws-sdk'); | |
const PREFIX = 'amplify-builds/'; | |
const DEFAULT_KEEP_N = 5; | |
const DEFAULT_DRY_RUN = false; | |
const s3 = new AWS.S3(); | |
// ## Main | |
const main = async ( | |
bucket, | |
keepN = DEFAULT_KEEP_N, | |
dryRun = DEFAULT_DRY_RUN | |
) => { | |
const prefix = PREFIX; | |
const result = await s3 | |
.listObjects({ Bucket: bucket, Prefix: prefix }) | |
.promise(); | |
const files = result.Contents; | |
const groupedFiles = _groupByFirstToken(files, prefix); | |
_forEach(groupedFiles, (key, val) => { | |
const was = val.length; | |
val = _sort(val); | |
val = _excludeLastN(val, keepN); | |
groupedFiles[key] = val; | |
}); | |
// | |
console.log('Builds to delete:'); | |
_forEach(groupedFiles, (key, val) => { | |
console.log(`* ${key}: ${val.length} file${val.length === 1 ? '' : 's'}`); | |
}); | |
if (dryRun) { | |
console.log('skipping for dry-run'); | |
} else { | |
console.log(''); | |
for ([key, val] of Object.entries(groupedFiles)) { | |
await s3DeleteObjects(bucket, val.map(file => file.Key)); | |
console.log( | |
`deleted ${val.length} file${val.length === 1 ? '' : 's'} from ${key}` | |
); | |
} | |
} | |
}; | |
// ## Helpers | |
const s3DeleteObjects = async (bucket, keys) => { | |
// TODO - handle > 1000 keys | |
if (!keys.length) { | |
return; | |
} | |
const params = { | |
Bucket: bucket, | |
Delete: { | |
Objects: keys.map(key => ({ Key: key })), | |
Quiet: true | |
} | |
}; | |
return s3.deleteObjects(params).promise(); | |
}; | |
const _forEach = (obj, callback) => | |
Object.entries(obj).forEach(([key, val]) => callback(key, val)); | |
// ### Group By First Token | |
// | |
// Takes the Key field and removes prefix and takes the first | |
// value, e.g., "myfunction/users-abcdef-1235.zip" -> "users" | |
// @param files: S3File[] | |
// @param prefix: string | |
// @returns { [key: string]: val: S3File[] } | |
// | |
const _groupByFirstToken = (files, prefix = '') => { | |
const keyToFiles = {}; | |
files.forEach(file => { | |
const key = file.Key.substring(prefix.length).split('-')[0]; | |
if (keyToFiles[key] === undefined) { | |
keyToFiles[key] = []; | |
} | |
keyToFiles[key].push(file); | |
}); | |
return keyToFiles; | |
}; | |
// ### Sort Files | |
// | |
// Sorts by the LastModified field ascending (oldest first) | |
// @returns files: S3File[] - a new files array | |
const _sort = files => { | |
files = [...files]; | |
files.sort((a, b) => a.LastModified - b.LastModified); | |
return files; | |
}; | |
// ### Exclude Last N | |
// | |
// @param arr: any[] | |
// @param n: number | |
// @returns any[] - a new array excluding the last n values | |
// or an empty one if there are not enough | |
const _excludeLastN = (arr, n) => { | |
const len = arr.length; | |
const end = Math.max(0, len - n); | |
return arr.slice(0, end); | |
}; | |
// ## CLI | |
if (require.main === module) { | |
const commandWrapper = prom => | |
prom.catch(err => { | |
console.error(err); | |
process.exit(1); | |
}); | |
const argv = require('yargs') | |
.usage('Usage: $0 <bucketName>') | |
.command( | |
'$0 <bucketName>', | |
'Clean up old amplify-builds', | |
yargs => | |
yargs | |
.positional('bucketName', { | |
type: 'string', | |
describe: 'The key for your AWS S3 bucket', | |
required: true | |
}) | |
.option('dryRun', { | |
alias: 'n', | |
type: 'boolean', | |
demandOption: false, | |
describe: 'perform a dry run', | |
default: DEFAULT_DRY_RUN | |
}) | |
.option('keep', { | |
alias: 'k', | |
type: 'number', | |
demandOption: false, | |
default: DEFAULT_KEEP_N | |
}), | |
argv => commandWrapper(main(argv.bucketName, argv.keep, argv.dryRun)) | |
) | |
.strict() | |
.help().argv; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment