-
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 all 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,200 @@ | ||
| import aws from 'aws-sdk'; | ||
| import s3 from 's3-node-client'; | ||
| import dotenv from 'dotenv'; | ||
| import fs from 'fs'; | ||
| import cliProgress from 'cli-progress'; | ||
| import _ from 'lodash'; | ||
| // import { promisify } from './utils'; | ||
|
|
||
| const validateTag = (tag) => { | ||
| // Both compilation hints because of backslashes used in RegExp but unecessary by conception in JS Strings | ||
| // Furthermore, the escaption is needed so RegExp will interpret the String correctly. | ||
| // prettier-ignore | ||
| // eslint-disable-next-line no-useless-escape | ||
| const pattern = new RegExp('^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\-[0-9A-Za-z]*)?$') | ||
| if (tag === 'latest' || pattern.test(tag)) { | ||
| console.info(`validated tag ${tag}`); | ||
| return true; | ||
| } | ||
| console.error(`unable to validate version '${tag}'`); | ||
| return false; | ||
| }; | ||
|
|
||
| const validateEnv = (env) => { | ||
| if (fs.existsSync(env)) { | ||
| console.info(`validated environment file ${env}`); | ||
| return true; | ||
| } | ||
| console.error(`environment file '${env}' does not exist`); | ||
| return false; | ||
| }; | ||
|
|
||
| const validateBuild = (build) => { | ||
| if (fs.existsSync(build)) { | ||
| console.info(`validated build directory ${build}`); | ||
| return true; | ||
| } | ||
| console.error(`build directory '${build}' does not exist`); | ||
| return false; | ||
| }; | ||
|
|
||
| const validateAppVariables = ({ | ||
| REACT_APP_HOST, | ||
| REACT_APP_GRAASP_DEVELOPER_ID, | ||
| REACT_APP_GRAASP_APP_ID, | ||
| }) => { | ||
| if ( | ||
| _.isUndefined(REACT_APP_HOST) || | ||
| _.isUndefined(REACT_APP_GRAASP_DEVELOPER_ID) || | ||
| _.isUndefined(REACT_APP_GRAASP_APP_ID) | ||
| ) { | ||
| console.error( | ||
| `environment variables REACT_APP_GRAASP_APP_ID, REACT_APP_GRAASP_DEVELOPER_ID and/or REACT_APP_HOST are not defined \n | ||
| you can specify them through a .env file in the app root folder or through another file specified with the -e flag`, | ||
| ); | ||
| return false; | ||
| } | ||
| return true; | ||
| }; | ||
|
|
||
| const validateAwsCredentialsVariables = ({ | ||
| BUCKET, | ||
| AWS_ACCESS_KEY_ID, | ||
| AWS_SECRET_ACCESS_KEY, | ||
| }) => { | ||
| if ( | ||
| _.isUndefined(BUCKET) || | ||
| _.isUndefined(AWS_ACCESS_KEY_ID) || | ||
| _.isUndefined(AWS_SECRET_ACCESS_KEY) | ||
| ) { | ||
| console.error( | ||
| `environment variables BUCKET, AWS_ACCESS_KEY_ID and/or AWS_SECRET_ACCESS_KEY are not defined. \n | ||
| make sure you setup your credentials file correctly using the scripts/setup.sh script and contact your favourite Graasp engineer if you keep running into trouble`, | ||
| ); | ||
| return false; | ||
| } | ||
| return true; | ||
| }; | ||
|
|
||
| const loadAwsCredentials = async () => { | ||
| const awsCredentials = new aws.Credentials(); | ||
| await awsCredentials.getPromise().then( | ||
| async () => true, | ||
| (err) => { | ||
| console.error(err.stack); | ||
| return false; | ||
| }, | ||
| ); | ||
| // set the AWS credentials into the global object | ||
| aws.config.credentials = awsCredentials; | ||
| }; | ||
|
|
||
| const deploy = async (opts) => { | ||
| const { tag, env, build } = opts; | ||
|
|
||
| // validate command options | ||
| if (!validateTag(tag) || !validateEnv(env) || !validateBuild(build)) { | ||
| console.error('aborting deployment...'); | ||
| return false; | ||
| } | ||
|
|
||
| // load environment variables | ||
| dotenv.config({ path: env }); | ||
|
|
||
| // validate environment variables | ||
| if ( | ||
| !validateAppVariables(process.env) || | ||
| !validateAwsCredentialsVariables(process.env) | ||
| ) { | ||
| return false; | ||
| } | ||
|
|
||
| const { | ||
| REACT_APP_GRAASP_DEVELOPER_ID, | ||
| REACT_APP_GRAASP_APP_ID, | ||
| REACT_APP_HOST, | ||
| REACT_APP_VERSION, | ||
| BUCKET, | ||
| DISTRIBUTION, | ||
| } = process.env; | ||
|
|
||
| console.info( | ||
| `publishing app ${REACT_APP_GRAASP_APP_ID} version ${REACT_APP_VERSION}`, | ||
| ); | ||
|
|
||
| loadAwsCredentials(); | ||
|
|
||
| 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, | ||
|
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. Did not see comment on left side for the delete removed comments:
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. @juancarlosfarah Please let me know if here is still something pending |
||
| 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 progressBar = new cliProgress.SingleBar( | ||
| {}, | ||
| cliProgress.Presets.shades_classic, | ||
| ); | ||
| const uploader = client.uploadDir(params); | ||
| uploader.on('error', (err) => { | ||
| console.error('unable to sync:', err.stack); | ||
| }); | ||
| uploader.on('progress', () => { | ||
| progressBar.start(uploader.progressTotal, 0); | ||
| progressBar.update(uploader.progressAmount); | ||
| }); | ||
| uploader.on('end', () => { | ||
| progressBar.stop(); | ||
| // TODO: insert here code that should be executed once the upload is done | ||
|
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. This should be done. You can always create helper functions.
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. @juancarlosfarah Yes, you are right. But I would require more time to do this. Might consider implementing this when finalizing the |
||
| // e.g. invalidate cache | ||
| }); | ||
|
|
||
| console.info( | ||
| `published app to https://${REACT_APP_HOST}/${APP_PATH}/index.html`, | ||
| ); | ||
|
|
||
| // ensure the correct distribution variables are defined | ||
| if (_.isUndefined(DISTRIBUTION)) { | ||
|
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. everything after line 159 should be inside the |
||
| console.error('environment variable DISTRIBUTION is not defined'); | ||
| console.error( | ||
| 'contact your favourite Graasp engineer if you keep running into trouble', | ||
| ); | ||
| return false; | ||
| } | ||
|
|
||
| // invalidate cloudfront distribution | ||
| const pathsToInvalidate = [`/${APP_PATH}/*`]; | ||
| const invalidationParams = { | ||
| DistributionId: DISTRIBUTION, | ||
| InvalidationBatch: { | ||
| CallerReference: new Date().toString(), | ||
| Paths: { | ||
| Quantity: pathsToInvalidate.length, | ||
| Items: pathsToInvalidate, | ||
| }, | ||
| }, | ||
| }; | ||
| const cloudfront = new aws.CloudFront(); | ||
| cloudfront.createInvalidation(invalidationParams, (err, data) => { | ||
| if (err) { | ||
| // an error occurred | ||
| console.error(err, err.stack); | ||
| } else { | ||
| // successful response | ||
| console.info(data); | ||
| } | ||
| }); | ||
|
|
||
| return true; | ||
| }; | ||
|
|
||
| export default deploy; | ||
Uh oh!
There was an error while loading. Please reload this page.