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

[feat:] Added Config Command to Kitops CLI #523

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

Conversation

SkySingh04
Copy link

Description

This PR introduces the new config command for the KitOps CLI. It allows users to manage the configuration of CLI settings more easily. With this command, users can set, get, list, and reset configuration values for persistent options like storage paths, credentials, logging levels, and other preferences.

Key additions:

  • Config command: Introduced the config command with four subcommands:

    • set: Allows users to set configuration values.
    • get: Retrieves the value of a specified configuration key.
    • list: Lists all current configuration options and their values.
    • reset: Resets all configurations back to default values.
  • Persistent root flags: The root command now uses configuration settings from the config.json file for default values like --log-level, --progress, and --verbose, while still allowing overrides via command-line arguments.

Note: This PR supports Config for only root command flags, as it is not clearly mentioned if it should be implemented for all flags.

Linked Issues

Closes issue #419

@SkySingh04 SkySingh04 changed the title Config cmd [feat:] Added Config Command to Kitops CLI Oct 9, 2024
@SkySingh04
Copy link
Author

@amisevsk Could you please review this PR and suggest upon how we can improve it?

Signed-off-by: Akash Singh <[email protected]>
Copy link
Contributor

@amisevsk amisevsk left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! I have a few initial comments

cmd/root.go Outdated Show resolved Hide resolved
cmd/root.go Outdated Show resolved Hide resolved
cmd/root.go Show resolved Hide resolved
pkg/cmd/config/cmd.go Outdated Show resolved Hide resolved
pkg/cmd/config/cmd.go Outdated Show resolved Hide resolved
pkg/cmd/config/config.go Outdated Show resolved Hide resolved
// DefaultConfig returns a Config struct with default values.
func DefaultConfig() *Config {
return &Config{
LogLevel: "info",
Copy link
Contributor

Choose a reason for hiding this comment

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

This should use the constants from the output package

Copy link
Author

Choose a reason for hiding this comment

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

Could you confirm if we should also do this for Progress and ConfigDir as well? If so, we will need to change the var names in output package for Progress to Capitalise and export

@SkySingh04
Copy link
Author

@amisevsk Your requested changes have been made :D

cmd/root.go Outdated Show resolved Hide resolved
cmd/root.go Outdated Show resolved Hide resolved
pkg/cmd/config/config.go Outdated Show resolved Hide resolved
pkg/cmd/config/config.go Outdated Show resolved Hide resolved
pkg/cmd/config/config.go Outdated Show resolved Hide resolved
This commit refactors the code related to loading and saving the configuration file. It introduces a new function `ConfigFilePath` in the `consts.go` file to generate the path for the configuration file based on the `configHome` directory. The `LoadConfig` function now returns the default configuration if the file doesn't exist, and the `SaveConfig` function creates the directory before saving the file. These changes improve the reliability and maintainability of the configuration handling.

Fixes jozu-ai#419
@SkySingh04
Copy link
Author

@amisevsk Your requested changes have been made!

@gorkem
Copy link
Contributor

gorkem commented Oct 17, 2024

Can you add the license header for config.go?

@SkySingh04
Copy link
Author

@gorkem license header has been added!

@SkySingh04
Copy link
Author

@amisevsk @gorkem Waiting for a response on this so that we can proceed further!

Copy link
Contributor

@gorkem gorkem left a comment

Choose a reason for hiding this comment

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

The code that manually parses subcommands and arguments has logic errors that needs to be fixed. The code manually inspects args[0] to determine the subcommand, which is not the standard practice. It is better to Define each subcommand (set, get, list, reset) as separate Cobra commands.

if len(args) == 0 {
return fmt.Errorf("no configuration key provided")
}
opts.key = args[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

The way that config command is implemented is set/get/list/reset are not subcommands but rather args. Therefore the args[0] in here receives the value of the subcommand (get/set/list/reset). This works for no argument subcommands (list/reset) but everything else does not work.

I think a better way to do this would be to add the (set/get/list/reset) as subcommands.

Copy link
Author

Choose a reason for hiding this comment

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

Refactored to include set/get/list/reset as subcommands.

cfg = DefaultConfig()
}

v := reflect.ValueOf(cfg).Elem().FieldByName(strings.Title(opts.key))
Copy link
Contributor

Choose a reason for hiding this comment

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

Replace strings.Title with cases.Title from the golang.org/x/text/cases package.

Copy link
Author

Choose a reason for hiding this comment

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

Refactored!

pkg/cmd/config/config.go Outdated Show resolved Hide resolved
}

cmd.Args = cobra.MinimumNArgs(1)
cmd.Flags().SortFlags = false
Copy link
Contributor

Choose a reason for hiding this comment

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

Not needed if there are no flags.

Copy link
Author

Choose a reason for hiding this comment

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

Refactored

@SkySingh04
Copy link
Author

@gorkem Your requested changes have been made, could you kindly review?

Copy link
Contributor

@gorkem gorkem left a comment

Choose a reason for hiding this comment

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

Much better but setting the logLevel did not work for me. Using reflection to find keys maybe too fragile.

return "", err
}

v := reflect.ValueOf(cfg).Elem().FieldByName(strings.Title(opts.key))
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you also update this to use cases.Title?

Copy link
Author

Choose a reason for hiding this comment

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

refactored

Comment on lines 54 to 58
caser := cases.Title(language.Und)
v := reflect.ValueOf(cfg).Elem().FieldByName(caser.String(opts.key))
if !v.IsValid() {
return fmt.Errorf("unknown configuration key: %s", opts.key)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Caser is causing issues here; since we're using camelcase for config settings (LogLevel), attempting to modify case will mangle fields, turning LogLevel, logLevel, etc. into Loglevel

Copy link
Author

Choose a reason for hiding this comment

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

This has been fixed!
image

return fmt.Errorf("failed to complete options: %w", err)
}
if err := setConfig(ctx, opts); err != nil {
return fmt.Errorf("failed to set config: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

A quirk of how we've implemented error handling in commands means that returned errors here are gobbled up (we have to do this to avoid Cobra's default error printing, prints the usage doc every time -- see here)

This means the caser issue I mentioned is getting silently eaten, and the CLI is just exiting with status code 1. Instead, you want to replace the returns from RunE functions with output.Fatalf or output.Fatalln (using %s for errors instead of %w), both here and in the other subcommands.

With the change:

❯ kit config set LogLevel debug
[ERROR] Failed to set config: unknown configuration key: LogLevel

Copy link
Author

Choose a reason for hiding this comment

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

That is a super interesting implementation! I have refactored and fixed this!

@SkySingh04
Copy link
Author

@amisevsk Your requested changes have been made!

@amisevsk amisevsk mentioned this pull request Nov 5, 2024
This was linked to issues Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow CLI configuration to be saved to a file Brew issues
4 participants