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

Enhancements #16

Merged
merged 20 commits into from
Aug 5, 2019
Merged

Enhancements #16

merged 20 commits into from
Aug 5, 2019

Conversation

Hazzard17h
Copy link
Contributor

To enhance automation capabilities, I standardized parameters retrieval from config, options and questions, for login and logout commands. If the solution fit, we can enlarge it to others commands.

@githubsaturn
Copy link
Collaborator

Thanks @Hazzard17h !

It's a rather large PR. I won't be able to get to in next 2 weeks as my schedule is pretty tight. But I had a brief look at it and here is my thoughts:

  • Using a config file was a choice by design. The goal is provide the gear for automation, at the same time, not shooting ourselves in the foot by making the maintenance complex. Using the explicit approach may look simpler, however, it causes confusion for general audience of CapRover (you'd be surprised!)
  • So instead of breaking down the config parameters, let's create a helper function that "creates" the config file using the explicit parameters, then automation can simply use that command in conjunction with --configFile and take best of both worlds!! Otherwise, any config file schema update requires multiple places to be updated in the code (higher maintenance cost)
  • The stateful commands should never be automated. Commands such as login and logout are stateful and are meant to be used by real humans. Action commands, such as deploy, can be used in automation and they do not require a logged in user.
  • I like some of the refactoring that you did! Cleanups are the best!

Last but not least, awesome work! If you're interested in automation improvement, there is a ticket that's sitting there and it's on my high priority list for a while now:
#12 (comment)

Are you interested in taking that over?

@Hazzard17h
Copy link
Contributor Author

My end goal is to implement that generic command that you mention in #12, but I first started with some enhancements to become familiar with the code.

  • About config file, explicit command options and command line question, my thought is: if --configFile is specified as option, read that file for parameters, than overwrite any parameter passed as explicit command option, at last ask through command line question any missing (and required) parameter.
    That approach requires that names for command options coincide with questions' names, but also allows to know config file schema by looking command help.
    Any parameter update requires two places to be updated in the code: the command option and the command line question. I'm thinking to generate both from an object that define all useful properties to increase maintainability and have a unique source of truth.
  • About stateful commands automation: login already has automation through config file. I believe that could be useful to login (maybe even on multiple machines) at the beginning of automation and do multiple commands using logged-in machine name parameter, instead of login for any command.

@Hazzard17h
Copy link
Contributor Author

@githubsaturn if you have a chance to review the code, now the enhancements are completed with standardized behaviors for all commands, fully backward compatibility with the current functionalities, and also support environment variables.

Next I'll start to implement some sort of generic command.

@githubsaturn
Copy link
Collaborator

@Hazzard17h

Apologies for the delay. I'm still struggling to find some time - by the end of June my schedule will be more flexible. But this is definitely at the top of my list. Changes look okay. I just need to do a deeper dive into the code and run some tests to make sure that the existing behavior isn't broken.

Have you tested all the functionalities?

PS: If you're planning on extending this work and adding more functionality, please create another branch. This branch is already very crowded and it's hard to code review added functionalities if they are brought to the mix.

Thanks,
Kasra

@Hazzard17h
Copy link
Contributor Author

Not worry.

I tested all the functionalities, but surely another review is recommended.

@Hazzard17h Hazzard17h mentioned this pull request Jun 25, 2019
@githubsaturn
Copy link
Collaborator

githubsaturn commented Jul 29, 2019

I've noticed there are many duplication in the code. For example, caprover deploy --help is now very crowded - unnecessary aliases for host, password and etc. We can't merge this PR as it is right now.

When I first saw the PR, I thought of it as some reordering of method and etc. But I am seeing more changes in it. I'm going to park this PR as is. There are definitely some good changes and cleanups such as the inheritance that you added for Command. But due to a larger scope of changes we can't merge this as is. We can either, publish this (and effectively the one with generic API) as a more configurable/advanced client, or just start cutting down on changes and go step by step.

There are many good changes in this PR that I wanted to keep if we can reduce the scope of changes in this PR. Specifically, we want to keep the changes to the public API to zero during a big refactoring like this.

@Hazzard17h
Copy link
Contributor Author

Indeed the changes to the public API are zero, even though the big refactoring of the CLI.
Also all command options and config of the previous version are still compatible, for this purpose I introduced the aliases, and applied them to the deploy command.
Moreover I think that all open issues are handled by this PR, so following a careful review and test by you, it could be surely merged.

@githubsaturn
Copy link
Collaborator

@Hazzard17h

I found some discrepencies, for example, machineName is renamed to caproverName. Also, other commands have many redundant aliases now. For example, caprover deploy takes --appName and --caproverApp. Can you elaborate why these aliases are added? Maybe what you're saying is that the scope of changes is limited?

@Hazzard17h
Copy link
Contributor Author

All commands now are standardized:

  • common options have same names (--configFile, --caproverUrl, --caproverPassword, --caproverName, ...), I just selected the names by the most common already in use, and added aliases to those I changed to keep backward compatibility;
  • can take config file via -c option, parameters names in the file respect the command options;
  • can take environment variables;
  • needed values not provided are asked on the command line.

With this new flow, one user could create a common config file with every value needed, from server setup, to app deploy. And already in use deploy scripts will continue to work, also updating the CLI.

@githubsaturn
Copy link
Collaborator

I see. In that case, I'll go over this again. I might have some more questions which I will post here. Thanks

"caprover-login": "./built/commands/login.js",
"caprover-logout": "./built/commands/logout.js",
"caprover-serversetup": "./built/commands/serversetup.js"
"caprover": "./built/commands/caprover.js"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was there a particular reason that these were removed? They were added to fix an issue with yarn.

a1ff473

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only entry point is caprover cli; sub commands need to be built by the main cli and they can't be called directly. I don't think it could be a problem.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's what I expected as well, but it turned out that, if installed using yarn, it becomes a problem. See this:
caprover/caprover#338 (comment)

"emailForHttps": "[email protected]",
"currentPassword": "captain42"
"certificateEmail": "[email protected]",
"caproverName": "my-machine-123-123-123-123",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's avoid renaming these properties (all of them). This renaming would break the existing automation pipeline.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is only the readme with new standardized names for new users.
As you can see in the options definition for serversetup command (and other too), many options have aliases to preserve compatibility with previous version, for example here.
If I've forgotten something we could surely add more aliases.

{
"hasRootHttps": "true",
"caproverPassword": "captain42",
"caproverUrl": "captain.root.domain.com",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not all installations have SSL certs. Some people install CapRover on local domain names. Let's bring the hasRootHttps back. Or better than that, we can allow the "https://" or "http" be present in the URL, and we can use the implicit value

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See cleanAdminDomainUrl: we allow "http" and "https" (default if not specified), and also support hasRootHttps in login config file for backward compatibility, as you can see here.

You can also deploy directly with one command:
```bash
caprover deploy -h https://captain.root.domain.com -a app-name -p password -b branchName
caprover deploy -n machine-name -a app-name -b branchName
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why the deploy command has changed its signature? -h and -p are gone. The main purpose of this command was automated deploys without having to be logged in.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I said before, I changed the readme with the new standardized options, but all of them previously present are also supported.
As you can see in deploy command help, you can use deploy -u url -p password to deploy to a not logged in server.

export interface IOption extends inquirer.Question, IOptionAlias {
name: string,
aliases?: IOptionAlias[]
tap?: (param?: IParam) => void
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's tap? Maybe a more descriptive name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tap is a function called after the value of the option is acquired, to perform side effect on that option. Name is inspired from the tap operator of RxJs Obsevable...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Got it. I don't think tap is the best name, it makes sense in Rx world due to "streams" and "pipes". I think we should rename it to onOptionSelected or something similar... I can make this change later, it's not a public API - so all go for now.

return true
}
const K = Utils.extendCommonKeys({
https: 'hasRootHttps'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why don't we move everything to the main common keys object. That way, we can make sure that there is no duplication of literal strings anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea is to have in the constants only common options keys, not that ones that are only in one command.

{
name: K.ip,
char: 'i',
env: 'CAPROVER_IP',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move all env vars to an EnvKeys constant for better documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can create in constants file the base option definition for all common options, to have consistency with name, char, env, across all commands.

},

isValidEmail(email: string): boolean {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's add some unit tests for these utils 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.

Could be done, but no unit test was done before, so I don't added anyone now.

@@ -1,29 +1,22 @@
#!/usr/bin/env node
Copy link
Collaborator

Choose a reason for hiding this comment

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

These shouldn't be removed. See my comment in package.json

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As I said before, the only entry point is caprover cli, so we don't need this.

await CliApiManager.get(machine).getAllApps() // Get data with stored token
} catch (e) { // Error getting data: token expired
StdOutUtil.printWarning(`Your auth token for ${StdOutUtil.getColoredMachine(machine)} is not valid anymore, try to login again...`)
StorageHelper.get().removeMachine(machineName) // Remove saved credentials
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we removing the machine entirely? This was not the case before. In this case, if the user fails to login again, the machine is completely lost and they have to re-enter the cred.

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'm going to fix this one.

@githubsaturn
Copy link
Collaborator

Great, thanks @Hazzard17h

Lots of my comments and confusion was caused by aliases, so we should be good. Some other modifications are still to be made, but they aren't public API, so we'll leave them for now. Cheers.

@githubsaturn githubsaturn merged commit bdfc602 into caprover:master Aug 5, 2019
@Hazzard17h Hazzard17h deleted the enhancements branch August 6, 2019 08:33
})

cmd.action(async (cmdLineOptions: ICommandLineOptions) => {
cmdLineOptions = await this.preAction(cmdLineOptions)
Copy link
Collaborator

Choose a reason for hiding this comment

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

@Hazzard17h

Unfortunately, I only found out about this after I release the new version.

This, cmdLineOptions: ICommandLineOptions, seems to be wrong. The argument to the action method is not an array of options. It's the whole Command object. I believe what you wanted to use is cmdLineOptions.options which translate to an object that has simple (key:string) => (value: string | boolean) structure.

Would you be able to fix the issue? Otherwise, let me know and I'll look into it. From what I can see, it's only being used to override the actual parameters with the new aliases that you've added. Right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

PS: Another issue in the same pipeline is that running an unknown command causes a problem. For example caprover deploy random

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As you can see here, the action of a program sub-command takes a function which has as many arguments as the positional parameters of the sub-command, and at least the entire sub-command object, with the options added as keys.
So, the code works if called normally, but as you had noted, if we pass a positional argument to a sub-command (e.g. caprover deploy asd), it is broken.
I'm fixing it, by trowing an error, if user provided a position parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See #23

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.

2 participants