diff --git a/README.md b/README.md index 98e03c5..1714a12 100644 --- a/README.md +++ b/README.md @@ -130,20 +130,20 @@ Utilize best practices when forming a commit message using [Commitzen](http://co ### `deploy` -Build, push to S3, and invalidate CloudFront in one command. +Build, push to S3, and invalidate CloudFront in one command. If the static-file-directory flag is set, then mastarm will not build any files with browserify, and instead it will just upload all files in the base level of the specified directory. ```shell $ mastarm deploy --help -Usage: deploy [options] [entries...] - -Bundle & Deploy JavaScript & CSS +Usage: mastarm-deploy [options] Options: - - -h, --help output usage information - --cloudfront CloudFront Distribution ID to invalidate. - --s3bucket S3 Bucket to push to. + -m, --minify Minify built files. + -O, --outdir Publish directory (default: "") + --cloudfront CloudFront Distribution ID to invalidate. + --s3bucket S3 Bucket to push to. + --static-file-directory Directory of static files to deploy in lieu of building + -h, --help output usage information ``` #### Slack Notifications diff --git a/bin/mastarm-deploy b/bin/mastarm-deploy index e446e20..98b2043 100755 --- a/bin/mastarm-deploy +++ b/bin/mastarm-deploy @@ -4,6 +4,7 @@ const path = require('path') const commander = require('commander') const execa = require('execa') +const fs = require('fs-extra') const gitRepoIsUpToDate = require('git-repo-is-up-to-date') const commit = require('this-commit')() const username = require('username') @@ -26,8 +27,9 @@ commander .option('-e, --env ', 'Environment to use.') .option('-m, --minify', 'Minify built files.') .option('-O, --outdir ', 'Publish directory', '') - .option('--cloudfront', 'CloudFront Distribution ID to invalidate.') - .option('--s3bucket', 'S3 Bucket to push to.') + .option('--cloudfront ', 'CloudFront Distribution ID to invalidate.') + .option('--s3bucket ', 'S3 Bucket to push to.') + .option('--static-file-directory ', 'Directory of static files to deploy in lieu of building') .parse(process.argv) // each of these variables are also used in the logToMsTeams function and @@ -52,18 +54,21 @@ async function deploy () { process.exit(1) } - // decrypt env file using sops to make sure old file is overwritten with - // data from encoded sops file - const configPath = path.resolve(commander.config) - console.log('decrypting env file with sops') - const {stdout} = await execa( - 'sops', - [ - '-d', - path.join(configPath, 'env.enc.yml') - ] - ) - await writeFile(path.join(configPath, 'env.yml'), stdout) + // no decryption needed during workflow to upload just static files + if (!commander.staticFileDirectory) { + // decrypt env file using sops to make sure old file is overwritten with + // data from encoded sops file + const configPath = path.resolve(commander.config) + console.log('decrypting env file with sops') + const {stdout} = await execa( + 'sops', + [ + '-d', + path.join(configPath, 'env.enc.yml') + ] + ) + await writeFile(path.join(configPath, 'env.yml'), stdout) + } // at this point, we can be certain that the local configurations repo // directory matches what has been committed and pushed to the remote repo } @@ -80,19 +85,8 @@ async function deploy () { }) } - const files = util.parseEntries([...commander.args, ...(get('entries') || [])]) - util.assertEntriesExist(files) - const sourceFiles = files.map(f => f[0]) - const outfiles = [...files.map(f => f[1]), ...files.map(f => `${f[1]}.map`)] - env = get('env') || 'development' minify = get('minify') - const buildOpts = { - config, - env, - files, - minify - } cloudfront = get('cloudfront') s3bucket = get('s3bucket') @@ -108,18 +102,52 @@ async function deploy () { :hash: *commit:* ${commit} :seedling: *env:* ${env} :compression: *minify:* ${minify} - :package: *s3bucket:* ${s3bucket} - :hammer_and_wrench: *building:* ${sourceFiles.join(', ')}` + :package: *s3bucket:* ${s3bucket}` ) - + let outfiles try { - await build(buildOpts) - await logger.log(`:rocket: *uploading:* ${sourceFiles.length * 2} file(s)`) + // If the flag staticFileDirectory is set, upload all files found in + // the base level of the given directory. + if (commander.staticFileDirectory) { + const staticDirPath = path.resolve(commander.staticFileDirectory) + process.chdir(staticDirPath) + outfiles = [] + const files = await fs.readdir(staticDirPath) + await Promise.all(files.map(async file => { + const fileStats = await fs.stat(file) + if (!fileStats.isDirectory()) { + outfiles.push(file) + } + })) + await logger.log(`:rocket: *uploading:* ${outfiles.length} file(s)`) + } else { + // Otherwise, upload the files specified with the entries arg. + const files = util.parseEntries([...commander.args, ...(get('entries') || [])]) + // assert that the files exist if not uploading from static file directory + util.assertEntriesExist(files) + // build files using mastarm build + outfiles = [...files.map(f => f[1]), ...files.map(f => `${f[1]}.map`)] + const sourceFiles = files.map(f => f[0]) + await logger.log(`:hammer_and_wrench: *building:* ${sourceFiles.join(', ')}`) + const buildOpts = { + config, + env, + files, + minify + } + await build(buildOpts) + await logger.log(`:rocket: *uploading:* ${sourceFiles.length * 2} file(s)`) + } + + // upload files to s3 and invalid cloudfront if needed await Promise.all( - outfiles.map(outfile => - readFile(outfile).then(body => pushToS3({body, outfile})) - ) + outfiles.map(async outfile => { + const body = await readFile(outfile) + await pushToS3({body, outfile}) + }) ) + + // pronounce success! await logger.log( `:tada: :confetti_ball: :tada: *deploy ${tag} complete* :tada: :confetti_ball: :tada:` ) @@ -152,7 +180,7 @@ function logToMsTeams ({ configCommit, configDir, configRemoteUrl, error }) { const potentialAction = [{ '@type': 'OpenUri', - name: `View Commit on Github`, + name: 'View Commit on Github', targets: [ { os: 'default', @@ -163,7 +191,7 @@ function logToMsTeams ({ configCommit, configDir, configRemoteUrl, error }) { if (configCommit && configRemoteUrl) { potentialAction.push({ '@type': 'OpenUri', - name: `View Config Commit on Github`, + name: 'View Config Commit on Github', targets: [ { os: 'default', @@ -185,7 +213,7 @@ function logToMsTeams ({ configCommit, configDir, configRemoteUrl, error }) { 📦 **s3bucket:** ${s3bucket}\n ${error ? `🚨 🚨 **error deploying ${error.message || error}**` - : `🎉 🎊 🎉 **deploy successful!** 🎉 🎊 🎉`}` + : '🎉 🎊 🎉 **deploy successful!** 🎉 🎊 🎉'}` return logger.notifyMsTeams({ potentialAction, diff --git a/package.json b/package.json index 3e773c7..3e2e10b 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "exorcist": "^1.0.1", "flow-bin": "0.84.0", "flow-runtime": "^0.17.0", + "fs-extra": "^8.1.0", "git-repo-is-up-to-date": "^1.1.0", "glob": "^7.1.3", "isomorphic-fetch": "^2.2.1", diff --git a/yarn.lock b/yarn.lock index e6bdacb..903779b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4283,7 +4283,7 @@ fs-extra@^7.0.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^8.0.0: +fs-extra@^8.0.0, fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==