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

✨ Migrate Command Handling to Cobra for Simplified Flag Management #1598

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

Conversation

Horiodino
Copy link

This PR fixes the issue described in #1567.


Description:

This PR migrates the command-line handling logic in the cmd/manager/main.go file to utilize the [Cobra CLI framework]. The migration simplifies flag handling, improves readability, and enhances the extensibility of the CLI for future development.


Key Changes:

  1. Cobra Root Command:

    • Introduced the rootCmd for top-level command handling, providing a clean and standardized entry point for the CLI.
  2. Flag Migration:

    • Migrated all existing flags from the standard flag package to Cobra’s cmd.Flags() and cmd.PersistentFlags().
  3. Subcommand Restructuring:

    • Refactored and restructured any existing subcommands under Cobra’s subcommand system.
  4. Helper Functions:

    • Refined the main function by extracting logic into dedicated helper functions.

@Horiodino Horiodino requested a review from a team as a code owner January 10, 2025 16:28
Copy link

netlify bot commented Jan 10, 2025

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit fc34541
🔍 Latest deploy log https://app.netlify.com/sites/olmv1/deploys/67a253bdf754a20008c2d695
😎 Deploy Preview https://deploy-preview-1598--olmv1.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@kevinrizza
Copy link
Member

👋 Thanks for the contribution! Quick question, if we're going to do this for the catalogd binary, should we do the same for the operator-controller binary? I.e. https://github.com/operator-framework/operator-controller/blob/main/cmd/operator-controller/main.go

I suspect there will be some opinions on the functional refactoring as the controllers are set up (isn't some of that handled by controller runtime and kubebuilder?) and it would probably be good for us to match in those places. I know that's outside the scope of that github issue, but I think that's an artifact of these two binaries being part of separate repositories until very recently.

@LalatenduMohanty
Copy link
Member

/assign @LalatenduMohanty

Copy link

codecov bot commented Jan 10, 2025

Codecov Report

Attention: Patch coverage is 0% with 196 lines in your changes missing coverage. Please review.

Project coverage is 67.60%. Comparing base (9b08aea) to head (950c722).
Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
catalogd/cmd/catalogd/main.go 0.00% 196 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1598      +/-   ##
==========================================
- Coverage   67.74%   67.60%   -0.15%     
==========================================
  Files          57       57              
  Lines        4620     4630      +10     
==========================================
  Hits         3130     3130              
- Misses       1265     1275      +10     
  Partials      225      225              
Flag Coverage Δ
e2e 53.44% <ø> (ø)
unit 54.38% <0.00%> (-0.12%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@grokspawn
Copy link
Contributor

Hey @Horiodino! Thanks for your PR (especially since you noticed catalogd's new home and reproduced it here).
Could you do a make verify in your local and commit the dependency updates please?

if catalogdVersion {
fmt.Printf("%#v\n", version.Version())
os.Exit(0)
cfg := &config{}
Copy link
Member

Choose a reason for hiding this comment

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

Nit: since config is used entirely inside newRootCmd, it seems like we could declare it there instead?

}

flags := cmd.PersistentFlags()
Copy link
Member

Choose a reason for hiding this comment

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

Persistent flags apply to all subcommands of this command. Since this command doesn't have any subcommands, I think it would make more sense to use cmd.Flags() here.

flags.StringVar(&cfg.globalPullSecret, "global-pull-secret", "", "Global pull secret (<namespace>/<name>)")

cmd.AddCommand(newVersionCmd())
klog.InitFlags(nil)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it is just me, but I prefer explicitly passing flag.CommandLine here instead of relying on the defaulting that happens within InitFlags.

Copy link
Member

Choose a reason for hiding this comment

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

@joelanford Do you mean you would like to have a func init() { for the flags? More info at https://github.com/spf13/cobra/blob/main/site/content/user_guide.md

Copy link
Member

Choose a reason for hiding this comment

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

I would prefer if we can move the flags to init() method. Because it is easier to maintain in long term.

Copy link
Author

Choose a reason for hiding this comment

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

Could someone please give a final review so we can make the necessary changes? Everyone seems to have different opinions.

return err
}

if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Might be nice to call ctrl.SetupSignalHandler() from the inlined Run command, and then update this run function to accept a context.Context.

Comment on lines 111 to 121
RunE: func(cmd *cobra.Command, args []string) error {
return run(cfg)
},
Copy link
Member

Choose a reason for hiding this comment

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

I've never been a fan of the RunE abstraction. In almost all cases, there are two steps to a CLI program that need different error handling

  1. Parse and validate the CLI args, env, etc. If a failure occurs here, report the error and print the usage
  2. Execute the command. If a failure occurs here, report the error, but DO NOT print the usage.

WDYT about some tweaks to align with that?

I don't recall the exact behavior of RunE, but maybe we'd get reasonable behavior for now if we set cmd.SilenceUsage, so that only the returned errors strings are ever output (but never usage)?

Copy link
Author

Choose a reason for hiding this comment

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

the run function serves as the main entry point, where all other components are initialized and invoked. Including an error statements.The cobra RunE returns err,ensures proper error handling and clarity.

Copy link
Member

Choose a reason for hiding this comment

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

My main concern is that I'd like to avoid the usage being printed if the error returned from RunE is unrelated to flag parsing/validation.

For example, if any error occurs after validateTLSConfig, I would not want to see usage output. Perhaps the way to accomplish this is to move the validation code out of run and into a separate validateConfig function. Then RunE could be something along the lines of:

func(cmd *cobra.Command, args []string) error {
        if err := validateConfig(cfg); err != nil {
		return err
	}
        cmd.SilenceUsage = true
	return run(cfg)
}

@@ -147,7 +153,7 @@ func newVersionCmd() *cobra.Command {
}
}

func run(cfg *config) error {
func run(cfg *config, ctx context.Context) error {
Copy link
Member

Choose a reason for hiding this comment

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

By convention context.Context should always be the first argument in the function signature.

flags.StringVar(&cfg.globalPullSecret, "global-pull-secret", "", "Global pull secret (<namespace>/<name>)")

cmd.AddCommand(newVersionCmd())
klog.InitFlags(nil)
Copy link
Member

Choose a reason for hiding this comment

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

I would prefer if we can move the flags to init() method. Because it is easier to maintain in long term.

grokspawn
grokspawn previously approved these changes Jan 27, 2025
@grokspawn
Copy link
Contributor

Thanks @Horiodino! We can make additional adjustments in subsequent PRs, but I'd like to keep momentum in this area. I think this achieves the original goals, so approving it.

@LalatenduMohanty LalatenduMohanty dismissed their stale review January 28, 2025 11:40

Lets merge this and we can improve the code further.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 30, 2025
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 1, 2025
@grokspawn
Copy link
Contributor

Hi @Horiodino . Sorry about the delays here, but it looks like this PR needs a rebase. Can you take care of that?

@openshift-merge-robot
Copy link

PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 6, 2025
@Horiodino
Copy link
Author

Folks, please! I've already rebased five times. If it's not good, I'll close the PR—but please don’t leave it hanging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants