UNPKG

@architect/deploy

Version:
262 lines (237 loc) 8.31 kB
let { toLogicalID, updater, fingerprint, waterfall } = require('@architect/utils') let pkg = require('@architect/package') let create = require('@architect/create') let hydrate = require('@architect/hydrate') let print = require('./utils/print') let handlerCheck = require('../utils/handler-check') let getBucket = require('./bucket') let _compat = require('./compat') let patchCfn = require('./patches/cfn') let patchAsap = require('./patches/asap') let plugins = require('./plugins') let sizeReport = require('../utils/size-report') let staticDeploy = require('./static') let before = require('./00-before') let deploy = require('./01-deploy') let after = require('./02-after') /** * Shells out to AWS SAM for package/deploy * * @param {Object} params - parameters object * @param {Function} callback - a node-style errback * @returns {Promise} - if not callback is supplied */ module.exports = function samDeploy (params, callback) { let { aws, debug = false, eject, fast = false, inventory, isDryRun = false, name, production, prune, quiet = false, region, shouldHydrate = true, tags, update, verbose, } = params let { inv, get } = inventory let updateOptions = quiet ? { quiet } : {} if (!update) update = updater('Deploy', updateOptions) let stage = production ? 'production' : 'staging' let ts = Date.now() let log = true let pretty = print({ log, verbose }) let appname = inv.app let bucket = inv.aws.bucket let prefs = inv._project.preferences let stackname = `${toLogicalID(appname)}${production ? 'Production' : 'Staging'}` let dryRun = isDryRun || eject || false // General dry run flag for plugins let deployTargetPlugins = inventory.inv.plugins?._methods?.deploy?.target let plural = deployTargetPlugins?.length > 1 ? 's' : '' let compat, finalCloudFormation, template if (name) { stackname += toLogicalID(name) } // For plugins let stackName = stackname if (eject) { update = updater('Deploy [eject]', updateOptions) update.status('Preparing to eject Architect app') } else if (isDryRun) { update = updater('Deploy [dry-run]', updateOptions) update.status('Starting dry run!') } waterfall([ // Maybe auto-init resources function createFiles (callback) { let autocreateEnabled = prefs && prefs.create && prefs.create.autocreate if (autocreateEnabled) { // create any missing local infra create({ inventory }, callback) } else callback() }, // Check to see if we're working with a legacy API (and any other compatibility checks) function compatCheck (callback) { _compat({ aws, inv, stackname }, (err, result) => { if (err) callback(err) else { compat = result callback() } }) }, // Generate cfn, which must be completed only after fingerprinting or files may not be present function generateCloudFormation (callback) { let cloudformation = pkg(inventory) callback(null, cloudformation) }, // Patch CloudFormation with project-specific mutations function patchCloudFormation (cloudformation, callback) { patchCfn({ cloudformation, inventory, compat }, callback) }, // deploy.start plugins function runStartPlugins (cloudformation, callback) { plugins.start({ cloudformation, dryRun, inventory, stackName, stage }, callback) }, // deploy.services plugins function runServicesPlugins (cloudformation, callback) { plugins.services({ cloudformation, dryRun, inventory, stackName, stage }, callback) }, // Fingerprint static assets + ensure ASAP has static.json function fingerprintAndUpdateAsap (cloudformation, callback) { if (verbose) update.done(`Static asset fingerprinting ${get.static('fingerprint') ? 'enabled' : 'disabled'}`) // Always run full fingerprinting op to ensure remnant static.json files are deleted // This is especially important in Arc 6+ where we no longer do .arc checks for fingerprint status fingerprint({ inventory }, err => { if (err) callback(err) else { patchAsap({ cloudformation, inventory }, (err, cfn) => { if (err) callback(err) else { finalCloudFormation = cfn callback() } }) } }) }, // Check existence of handlers function checkHandlers (callback) { handlerCheck(inv.lambdaSrcDirs, update, callback) }, // Hydrate dependencies function hydrateTheThings (callback) { if (shouldHydrate) hydrate.install({ autoinstall: true }, err => callback(err)) else callback() }, // Print a size report function chonkyBois (callback) { sizeReport({ inventory, update }, callback) }, // Maybe create a new deployment bucket function bucketSetup (callback) { if (isDryRun && !eject) { bucket = 'N/A (dry-run)' callback() } else if (deployTargetPlugins) { bucket = `N/A (deploy.target plugin${plural} present)` callback() } else { if (bucket) callback() else { getBucket({ appname, aws, region, update }, (err, result) => { if (err) callback(err) else { bucket = result callback() } }) } } }, // Initialize operations function init (callback) { update.status( 'Initializing deployment', `Stack ... ${stackname}`, `Bucket .. ${bucket}`, ) callback() }, // Pre-deploy ops function beforeDeploy (callback) { let params = { aws, bucket, debug, eject, inventory, isDryRun, sam: finalCloudFormation, update } // this will write sam.json/yaml files out before(params, callback) }, // Maybe pre-deploy static assets function preDeployStatic (_template, callback) { template = _template let params = { aws, compat, eject, inventory, isDryRun, production, prune, region, stackname, verbose, update } staticDeploy(params, true, callback) }, // Deployment function theDeploy (callback) { if (eject) { let cmd = `aws cloudformation deploy --template-file sam.json --stack-name ${stackname} --s3-bucket ${bucket} --capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND --region ${region}` if (tags.length) cmd += ` --tags ${tags.join(' ')}` update.status(`Successfully generated sam.json. Deploy it with the AWS CLI by running:`, cmd) callback() } else if (isDryRun) { update.status('Skipping deployment to AWS') callback() } else if (deployTargetPlugins) { update.status(`Deploying with deploy.target plugin${plural}`) callback() } else { let params = { aws, bucket, debug, fast, region, stackname, tags, template, update, verbose } deploy(params, callback) } }, // deploy.target plugins function runTargetPlugins (callback) { let cloudformation = finalCloudFormation plugins.target({ cloudformation, dryRun, inventory, stackName, stage }, callback) }, // Post-deploy static assets function postDeployStatic (callback) { let params = { aws, compat, eject, inventory, isDryRun, production, prune, region, stackname, verbose, update } staticDeploy(params, false, callback) }, // Post-deploy ops function afterDeploy (callback) { if (eject || deployTargetPlugins) { callback() } else if (isDryRun) { update.status('Skipping post-deployment operations & cleanup') update.done('Dry run complete!') callback() } else { let params = { aws, bucket, compat, eject, fast, inventory, isDryRun, pretty, production, prune, region, stackname, stage, ts, update, verbose, } after(params, callback) } }, // deploy.end plugins function runEndPlugins (callback) { let cloudformation = finalCloudFormation plugins.end({ cloudformation, dryRun, inventory, stackName, stage }, callback) }, ], callback) }