Skip to content
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

Deploy cmd #42

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open

Deploy cmd #42

wants to merge 30 commits into from

Conversation

ugGit
Copy link
Contributor

@ugGit ugGit commented Jul 9, 2020

Which works fine if the command is executed in the project roots directory. E.g.

uchendu@uchendu-HP-ZBook-14:~/Desktop/graasp-cli$ node ~/Desktop/graasp-cli/lib/ deploy -p as
path passed 'as'
/home/uchendu/Desktop/graasp-cli
anay

@ugGit ugGit marked this pull request as ready for review July 9, 2020 14:51
@ugGit ugGit requested a review from juancarlosfarah July 9, 2020 14:51
Copy link
Member

@juancarlosfarah juancarlosfarah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice PR @ugGit. Please have a look at my feedback.

src/createCli.js Outdated
type: 'string',
describe: 'Path to the Graasp app that shall be deployed',
}),
handler: promisify(deploy),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to promisify? The function is already a promise. Just double-checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juancarlosfarah I'm actually not sure. This is inspired by the implementation of the new command. But I tested now and the promisify() could be omitted in both cases. Please let me know if I'm missing a point here, otherwise I'll remove it in the next PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe originally the function was not a promise, thus promisify was needed. Looks like it's not needed anymore.

src/createCli.js Show resolved Hide resolved
src/deploy.js Outdated
console.error(`path passed '${path}'`);
console.log(process.cwd());
try {
await spawn('./src/test.sh');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be ./test.sh after compiling inside the lib folder.

Copy link
Contributor Author

@ugGit ugGit Jul 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juancarlosfarah the test.sh file is not copied into the lib folder. I suppose babel is only considering .js file during compilation.
But even if I move the file manually, the command is executed at the location of the terminal and the path interpreted as relative path. Hence, the file would only be found when the command is executed in the lib folder

Copy link
Member

@juancarlosfarah juancarlosfarah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ugGit, I really like this! I think this will make things so much easier to deploy. Thanks for the initiative. I left you some minor comments and questions. Please have a look. @hasanagh, copying you for awareness.

src/deploy.js Outdated
@@ -1,15 +1,85 @@
import { spawn } from './utils';
import AWS from 'aws-sdk';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's stick to either aws or Aws.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to aws

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, I don't see the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just pushed the latest changes. Please check again

src/deploy.js Outdated
import s3 from 's3-node-client';
import dotenv from 'dotenv';

const path = require('path');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use require and not import?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pathis not used anymore in the latest changes.

src/deploy.js Outdated
}
// const { path } = opts;

const usageMessage = console.log(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this anymore.

src/deploy.sh Outdated
@@ -0,0 +1,125 @@
#!/bin/bash
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed it.

src/utils.js Outdated
@@ -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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor if needed to something like spawnProcess in a future commit.

src/deploy.js Outdated
const path = require('path');

// default build directory
const BUILD = 'build/';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two options:

  1. Make default -p be ./build and -p be described as path/to/build/folder that will be deployed.
  2. Leave -p as is and allow for overriding this with a -b.

I think that 1 might be cleaner, but I'm up for discussing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Currently I changed it to -b. This keeps the syntax from the original deploy script which might be appreciated by users of the script. Furthermore, i factored the default value out into the config.js file.

As the changes are easy to make, let me know if you prefer the -p variant.

src/deploy.js Outdated
);

console.log(`Exectued with path: ${opts.path}`);
console.log(usageMessage);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this.

src/deploy.js Outdated
'usage: $0 [-e <path/to/file>] [-v <version string>] [-b <path/to/build>]',
);

console.log(`Exectued with path: ${opts.path}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in executed. Also, we use all small caps in logs. I would suggest:

deploying app in {...} directory

or something similar.

src/deploy.js Outdated
REACT_APP_HOST,
REACT_APP_VERSION,
REACT_APP_BASE,
NODE_ENV,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need NODE_ENV?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure yet. It's removed now.

src/deploy.js Outdated
} = process.env;
/* eslint-enable no-unused-vars */

AWS.config.getCredentials(function (err) {
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

@ugGit ugGit Jul 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This reloads the credentials from the .env.xxx set before. Hence, the below dev note in the sdk doc does not apply.

Note: If you configure the SDK with static or environment credentials, the credential data should already be present in credentials attribute. This method is primarily necessary to load credentials from asynchronous sources, or sources that can refresh credentials periodically.

However, I'm still looking for a proper way to refactor this parts and maybe promisify will help me to do so. The challenge thereby is to check for the error and stop the further promise chain execution properly...

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) exist. I will implement a first draft that we might discuss during the next meeting.

@hasanagh
Copy link

Hey @ugGit, I really like this! I think this will make things so much easier to deploy. Thanks for the initiative. I left you some minor comments and questions. Please have a look. @hasanagh, copying you for awareness.

@juancarlosfarah Just checked the PR! thanks for copying me.

Copy link
Member

@juancarlosfarah juancarlosfarah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ugGit, thanks for the changes. We're almost there! Some minor comments below. Also, I didn't see some of the changes you mentioned, like the aws change. Please have a look.

src/deploy.js Outdated
@@ -1,15 +1,85 @@
import { spawn } from './utils';
import AWS from 'aws-sdk';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, I don't see the change.

src/deploy.js Outdated
// Both compilation hints because of backslashes used in RegExp but unecessary by conception in JS Strings
// prettier-ignore
// eslint-disable-next-line no-useless-escape
const pattern = new RegExp('v\\d+(\.\\d+){0,2}$');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this patter is the same as the one in the bash file. Consider this one:

// matches v<major>.<minor>.<patch>[-<meta>] version format
^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\-[0-9A-Za-z]*)?$

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that I haven't checked if it's JS compliant. Might be good to add some basic tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, please consider this comment.

.eslintrc Show resolved Hide resolved
.eslintrc Outdated
@@ -12,6 +12,7 @@
"allow": ["_id"]
}
],
"import/no-named-as-default": 0
"no-console": "off",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to turn this off, as it is a warning. I like to keep this on b/c it reminds me that we should use a logger, but for now it's fine. There are very nice loggers for CLIs, but you can leave it off for now if you want.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered here #42 (comment)

src/config.js Outdated
// deploy settings
export const DEFAULT_BUILD_DIR = 'build/';
export const DEFAULT_APP_VERSION = 'latest';
export const DEFAULT_ENV = '.env.dev';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is dev default?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, please consider this comment.

Copy link
Contributor Author

@ugGit ugGit Jul 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juancarlosfarah Good question. As this was not the case in the previous deploy.sh script, I will remove this default option. Should I make the flag required as a consequence?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just saw that this can't be enforced. So, I suggest to simply let the validation error to pop up.

src/deploy.js Outdated
});

console.log(
`published app to https://${REACT_APP_HOST}/${APP_PATH}/index.html`,
`info: published app to https://${REACT_APP_HOST}/${APP_PATH}/index.html`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for info.

src/deploy.js Outdated
};
const cloudfront = new AWS.CloudFront();
cloudfront.createInvalidation(invalidationParams, (err, data) => {
if (err) console.log(err, err.stack);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always use {} for if statements, especially with else.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, put comments above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, please consider this comment.

src/deploy.js Outdated
);

// configure the deployment
AWS.config.getCredentials((err) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to promisify and await here, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juancarlosfarah Absolutely correct. But currently not enough time to include it in this PR. Consequently, the commands risk not to be executed in the correct chronological order.

console.log('done uploading');
uploader.on('end', () => {
progressBar.stop();
// TODO: insert here code that should be executed once the upload is done
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be done. You can always create helper functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 deploy command.

src/deploy.js Outdated
console.log(usageMessage);
// Validate command options
if (!validateTag(tag) || !validateEnv(env) || !validateBuild(build)) {
console.error('Abort...');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aborting deployment...

Copy link
Member

@juancarlosfarah juancarlosfarah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ugGit for the changes. I think a bunch of my comments from the previous commits got overridden b/w when I made them and when you made the changes. I have tagged you in some. Please have a look at them. Also, no need to prefix logs with error: or info:. That was for Bash's echo function. Here you can use console.info or console.error, or eventually use a fancier logging tool.

src/utils.js Outdated
const [file, ...args] = cmd.split(/\s+/);
return execa(file, args, opts);
};

export const isDefined = (variable) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also a _.isUndefined function that you could use from lodash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't aware that this function existed. I have replaced it.

src/config.js Outdated
// deploy settings
export const DEFAULT_BUILD_DIR = 'build/';
export const DEFAULT_APP_VERSION = 'latest';
export const DEFAULT_ENV = '.env.dev';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, please consider this comment.

src/deploy.js Outdated

// validate command options
if (!validateTag(tag) || !validateEnv(env) || !validateBuild(build)) {
console.error('Abort...');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In previous comment I suggest you change this message to aborting deployment.

src/deploy.js Outdated
};
const cloudfront = new AWS.CloudFront();
cloudfront.createInvalidation(invalidationParams, (err, data) => {
if (err) console.log(err, err.stack);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, please consider this comment.

src/deploy.js Outdated

console.log(
`info: publishing app ${REACT_APP_GRAASP_APP_ID} version ${REACT_APP_VERSION}`,
);

// configure the deployment
AWS.config.getCredentials((err) => {
aws.config.getCredentials((err) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if you guarantee that the correct variables are present, don't you need to wait for the setup to be done?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed the execution relies currently on a fast execution of this async method. A next PR must handle this problematic and properly chain the execution.

@juancarlosfarah
Copy link
Member

@ugGit, did you manage to look into the requested changes?

@ugGit
Copy link
Contributor Author

ugGit commented Jul 17, 2020

@juancarlosfarah Yes. Apart of the handling for the async calls, all feedback is implemented

Copy link
Member

@juancarlosfarah juancarlosfarah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ugGit, I did some more research, and the node S3 client that you have used is pretty outdated:

https://github.com/shreyawhiz/node-s3-client#readme

We should be using everything from AWS where possible and use the promises in order to avoid getting stuck in complex callback situations.

Let me know if you want to discuss this.

src/deploy.js Outdated
!isDefined(REACT_APP_GRAASP_DEVELOPER_ID) ||
!isDefined(REACT_APP_GRAASP_APP_ID)
) {
console.error(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, you forgot to remove the error: bit.

src/deploy.js Outdated
@@ -112,7 +113,7 @@ const deploy = async (opts) => {
} = process.env;

console.log(
`info: publishing app ${REACT_APP_GRAASP_APP_ID} version ${REACT_APP_VERSION}`,
`publishing app ${REACT_APP_GRAASP_APP_ID} version ${REACT_APP_VERSION}`,
);

// configure the deployment
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ugGit, I think that you can use this promise version of getting the credentials.

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Credentials.html#getPromise-property

@@ -162,7 +163,7 @@ const deploy = async (opts) => {
);

// ensure the correct distribution variables are defined
if (!isDefined(DISTRIBUTION)) {
if (_.isUndefined(DISTRIBUTION)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everything after line 159 should be inside the on('end', () => { call in order to work. Preferably you can use the promises version of the native s3 client from AWS.

@juancarlosfarah juancarlosfarah self-assigned this Aug 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants