-
Notifications
You must be signed in to change notification settings - Fork 167
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
refactor(cli): restructure commands, option flags and validation #1547
Conversation
✅ Deploy Preview for docs-kargo-akuity-io ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1547 +/- ##
==========================================
- Coverage 30.96% 30.63% -0.34%
==========================================
Files 183 183
Lines 19303 19516 +213
==========================================
Hits 5978 5978
- Misses 13058 13271 +213
Partials 267 267 ☔ View full report in Codecov by Sentry. |
b6096fa
to
c61d31c
Compare
// TODO: Factor out server flags to a higher level (root?) as they are | ||
// common to almost all commands. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya... it's tricky. Almost but not all commands use them.
Personally, I'd rather repeat ourselves sometimes that have inapplicable flags show up on commands. i.e. If we had to choose, UX wins over DRY, imho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A problem I have observed though is that we sometimes ourselves forget to actually wire them in (see e.g. https://github.com/akuity/kargo/blob/5912e5a9dfd2912fdd6a46e1b35655b6225c4454/internal/cli/cmd/approve/approve.go in current main
, which AFAIK should have the flags set).
By registering them once at root and loading them into some config which is passed to downward commands, this could be avoided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to do it at root and unregister them in spots?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can theoretically use MarkHidden
to hide them from the help menu for specific commands.
|
||
option.Filenames(cmd.Flags(), &o.Filenames, "Filename or directory to use to apply the resource(s)") | ||
|
||
if err := cmd.MarkFlagRequired(option.FilenameFlag); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are new since the last time I went deep on Cobra. I am super excited about how much this cleans things up.
internal/cli/cmd/apply/apply.go
Outdated
|
||
// Validate performs validation of the options. If the options are invalid, an | ||
// error is returned. | ||
func (o *applyOptions) Validate() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kudos for this...
I've frequently seen this pattern of using a struct to encapsulate options and have rarely seen much value in it...
Coupled with the decision to extract validation into its own function, that pattern begins to make sense.
You've converted me.
Nit: Could be unexported.
@hiddeco overall, I love the approach. I commented on "apply" with some nits, questions, and kudos. I know this is only a draft right now, but I see nothing blocking so far. |
10d26e0
to
baa7901
Compare
This adds more structure to the way option flags are being registered for a command, while also providing a more standardized way to validate the option values derived from the flags. In addition, it ensures flags are registered as required, mutually exclusive, or taking file and/or directory inputs. Which improves out-of-the-box validation, while also enriching the shell completion instructions. For more information around this, see e.g. https://pkg.go.dev/github.com/spf13/cobra#Command.MarkFlagRequired By tackling this now, we have a better foundation to more rigorously start defining a standard structure for commands, splitting out the `option.Option` configuration, etc. Signed-off-by: Hidde Beydals <hidde@hhh.computer>
As the one in `../genericclioptions` has been marked as deprecated. Signed-off-by: Hidde Beydals <hidde@hhh.computer>
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
baa7901
to
8b3f941
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not reviewed every single line, but reviewed enough of the commands to assert that the new pattern that's emerging is a major improvement.
My one nit is that run()
as a func of an "options" type seems slightly counter-intuitive. I liked an example you showed me offline yesterday where e.g. instead of applyOptions
, it may have been applyRun
. Or even something like applyCmdImpl
might be nice.
This is not in any way a blocker or a hill that I would die on.
When I started implementing that, I ran into some issues:
Given it "runs" things with the options, I then felt that this convention was not that bad and stopped looking for alternatives. |
Touches into #1163
This pull request achieves multiple things:
func
s to perform an action. Instead, they are built around "option"struct
s with methods to add flags, parse command arguments, validate, and run the actual command logic. By doing this, we introduce a separation of concerns while also allowing things to (hypothetically) be tested without relying on further Cobra functionalities.Example boilerplate new command