-
Notifications
You must be signed in to change notification settings - Fork 1
Deploy cmd #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Deploy cmd #42
Changes from 4 commits
18deca4
d248ef0
70c76dc
305efa0
53925c3
68fb33b
00f48a7
8ba8262
96d3531
7ac7faa
dc383ad
c37afb8
305cb3b
19eb223
820b5f5
ad0f6f6
5687b3b
cb5650a
6b38e41
f4b79ef
3cf0366
e85ac36
baaa792
2338ead
4491092
62ea0f8
89e8821
7a288e8
28a0dc5
cfa7135
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "trailingComma": "all", | ||
| "tabWidth": 2, | ||
| "semi": true, | ||
| "singleQuote": true | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import AWS from 'aws-sdk'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's stick to either
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ugGit, I don't see the change.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just pushed the latest changes. Please check again |
||
| import s3 from 's3-node-client'; | ||
| import dotenv from 'dotenv'; | ||
|
|
||
| const path = require('path'); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| // default build directory | ||
| const BUILD = 'build/'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two options:
I think that 1 might be cleaner, but I'm up for discussing this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Currently I changed it to As the changes are easy to make, let me know if you prefer the |
||
|
|
||
| /** | ||
| * Returns an object with all variables loaded from a environment | ||
| * @param {string} environmentName is the suffix after .env.* | ||
| */ | ||
|
|
||
| const deploy = async (opts) => { | ||
| // const { path } = opts; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove? |
||
|
|
||
| const usageMessage = console.log( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need this anymore. |
||
| 'usage: $0 [-e <path/to/file>] [-v <version string>] [-b <path/to/build>]', | ||
| ); | ||
|
|
||
| console.log(`Exectued with path: ${opts.path}`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo in
or something similar. |
||
| console.log(usageMessage); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need this. |
||
|
|
||
| // fetch environment variables | ||
| dotenv.config({ path: path.resolve(process.cwd(), '.env.dev') }); | ||
| /* eslint-disable no-unused-vars */ | ||
| const { | ||
| REACT_APP_GRAASP_DEVELOPER_ID, | ||
| REACT_APP_GRAASP_APP_ID, | ||
| REACT_APP_GRAASP_DOMAIN, | ||
| REACT_APP_HOST, | ||
| REACT_APP_VERSION, | ||
| REACT_APP_BASE, | ||
| NODE_ENV, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't sure yet. It's removed now. |
||
| BUCKET, | ||
| AWS_DEFAULT_REGION, | ||
| AWS_ACCESS_KEY_ID, | ||
| AWS_SECRET_ACCESS_KEY, | ||
| DISTRIBUTION, | ||
| } = process.env; | ||
| /* eslint-enable no-unused-vars */ | ||
|
|
||
| AWS.config.getCredentials(function (err) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you using this? Maybe promisify in order not to have to shove everything inside the callback.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. This reloads the credentials from the
However, I'm still looking for a proper way to refactor this parts and maybe
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By rethinking the look we already assure that the configuration can be loaded since we're manually checking that the env variables ( |
||
| if (err) console.error(err.stack); | ||
| // credentials not loaded | ||
| else { | ||
| console.log('Access key:', AWS.config.credentials.accessKeyId); | ||
| } | ||
| }); | ||
|
|
||
| const APP_PATH = `${REACT_APP_GRAASP_DEVELOPER_ID}/${REACT_APP_GRAASP_APP_ID}/${REACT_APP_VERSION}`; | ||
|
|
||
| const client = s3.createClient({ s3Client: new AWS.S3() }); | ||
|
|
||
| const params = { | ||
| localDir: BUILD, | ||
| deleteRemoved: true, // default false, whether to remove s3 objects | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Put both lines of comment above |
||
| // that have no corresponding local file. | ||
|
|
||
| s3Params: { | ||
| Bucket: BUCKET, | ||
| Prefix: APP_PATH, | ||
| // other options supported by putObject, except Body and ContentLength. | ||
| // See: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property | ||
| }, | ||
| }; | ||
| const uploader = client.uploadDir(params); | ||
| uploader.on('error', function (err) { | ||
| console.error('unable to sync:', err.stack); | ||
| }); | ||
| uploader.on('progress', function () { | ||
| console.log('progress', uploader.progressAmount, uploader.progressTotal); | ||
| }); | ||
| uploader.on('end', function () { | ||
| console.log('done uploading'); | ||
| }); | ||
|
|
||
| console.log( | ||
| `published app to https://${REACT_APP_HOST}/${APP_PATH}/index.html`, | ||
| ); | ||
|
|
||
| return true; | ||
| }; | ||
|
|
||
| export default deploy; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| #!/bin/bash | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we still need this file?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have removed it. |
||
|
|
||
| # fail the build on any failed command | ||
| set -e | ||
|
|
||
| usage() { | ||
| echo "usage: $0 [-e <path/to/file>] [-v <version string>] [-b <path/to/build>]" 1>&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| # default build directory | ||
| BUILD="build/" | ||
|
|
||
| # default version | ||
| REACT_APP_VERSION="latest" | ||
|
|
||
| # validates versioning e.g. v0.1.0 | ||
| validate_version() { | ||
| # regex matching version numbers | ||
| rx='^v([0-9]+\.){0,2}(\*|[0-9]+)$' | ||
| if [[ $1 =~ $rx ]]; then | ||
| echo "info: validated version $1" | ||
| REACT_APP_VERSION=$1 | ||
| else | ||
| echo "error: unable to validate version '$1'" 1>&2 | ||
| echo "format is '${rx}'" | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
|
|
||
| # validates that build directory exists | ||
| validate_build() { | ||
| if [ -d $1 ]; then | ||
| echo "info: validated build directory $1" | ||
| BUILD=$1 | ||
| else | ||
| echo "error: build directory '$1' does not exist" 1>&2 | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
| # validates that environment file exists | ||
| validate_env() { | ||
| if [ -f $1 ]; then | ||
| echo "info: validated environment file $1" | ||
| source ${1} | ||
| else | ||
| echo "error: environment file '$1' does not exist" 1>&2 | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
| # parse command line arguments | ||
| while getopts "e:v:b:" opt; do | ||
| case ${opt} in | ||
| e) | ||
| e=${OPTARG} | ||
| validate_env ${e} | ||
| ;; | ||
| b) | ||
| b=${OPTARG} | ||
| validate_build ${b} | ||
| ;; | ||
| v) | ||
| v=${OPTARG} | ||
| validate_version ${v} | ||
| ;; | ||
| \?) | ||
| echo "error: invalid option '-$OPTARG'" 1>&2 | ||
| exit 1 | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| # ensure the correct variables are defined | ||
| if \ | ||
| [ -z "${REACT_APP_HOST}" ] || \ | ||
| [ -z "${REACT_APP_GRAASP_DEVELOPER_ID}" ] || \ | ||
| [ -z "${REACT_APP_GRAASP_APP_ID}" ]; then | ||
| echo "error: environment variables REACT_APP_GRAASP_APP_ID, REACT_APP_GRAASP_DEVELOPER_ID and/or REACT_APP_HOST are not defined" 1>&2 | ||
| echo "error: you can specify them through a .env file in the app root folder" 1>&2 | ||
| echo "error: or through another file specified with the -e flag" 1>&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # ensure the correct aws credentials are defined | ||
| if \ | ||
| [ -z "${BUCKET}" ] || \ | ||
| [ -z "${AWS_ACCESS_KEY_ID}" ] || \ | ||
| [ -z "${AWS_SECRET_ACCESS_KEY}" ]; then | ||
| echo "error: environment variables BUCKET, AWS_ACCESS_KEY_ID and/or AWS_SECRET_ACCESS_KEY are not defined" 1>&2 | ||
| echo "error: make sure you setup your credentials file correctly using the scripts/setup.sh script" 1>&2 | ||
| echo "error: and contact your favourite Graasp engineer if you keep running into trouble" 1>&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} | ||
| export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} | ||
|
|
||
| echo "info: publishing app ${REACT_APP_GRAASP_APP_ID} version ${REACT_APP_VERSION}" | ||
|
|
||
| APP_DIR=${BUCKET}/${REACT_APP_GRAASP_DEVELOPER_ID}/${REACT_APP_GRAASP_APP_ID}/${REACT_APP_VERSION}/ | ||
|
|
||
| # make sure you do not use the word PATH as a variable because it overrides the PATH environment variable | ||
| APP_PATH=${REACT_APP_GRAASP_DEVELOPER_ID}/${REACT_APP_GRAASP_APP_ID}/${REACT_APP_VERSION} | ||
|
|
||
| # sync s3 bucket | ||
| aws s3 sync ${BUILD} s3://${APP_DIR} --delete | ||
|
|
||
| # todo: allow cache invalidations per app once it is supported by cloudfront | ||
| # see: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html | ||
|
|
||
| # ensure the correct distribution variables are defined | ||
| if \ | ||
| [ -z "${DISTRIBUTION}" ]; then | ||
| echo "error: environment variable DISTRIBUTION is not defined" 1>&2 | ||
| echo "error: contact your favourite Graasp engineer if you keep running into trouble" 1>&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # invalidate cloudfront distribution | ||
| aws cloudfront create-invalidation --distribution-id ${DISTRIBUTION} --paths /${APP_PATH}/* | ||
|
|
||
| echo "published app to https://${REACT_APP_HOST}/${APP_PATH}/index.html" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| import execa from 'execa'; | ||
|
|
||
| // TODO: this is not optimal naming since it may cause confusion with 'spawn()' from 'child_process' module; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactor if needed to something like |
||
|
|
||
| // use execa to spawn a better child process | ||
| /* eslint-disable-next-line import/prefer-default-export */ | ||
| export const spawn = (cmd, opts = { stdio: 'inherit' }) => { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.