-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
✨ Allow Downstream Root Commands to add custom descriptions #1830
✨ Allow Downstream Root Commands to add custom descriptions #1830
Conversation
Welcome @anmol372! |
Hi @anmol372. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. 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/test-infra repository. |
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'm not sure if a single Option
that sets the three of them is the best approach. I feel that we want one option per field. So I would say either just one Option
per field or one Option
per field and a forth one that sets the three at once.
/ok-to-test |
@Adirio, I have gone with the four |
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.
/lgtm
You can resolve the conversations to collapse them.
Retesting the failing test (it itmed out and the limit has been raised to 20 from the previous 15 minutes, which used to be enough but it depends on the workload of prow from several repositories). I expect it to pass it. About the coverage decrease, could you add tests for these new options? Check how the kubebuilder/pkg/cli/cli_test.go Lines 280 to 292 in 9663fb3
After you add the tests, we can ping a member with aproval privileges and merge this. |
Hi @anmol372, The new methods need to be converted with unit tests. See: coverage/coveralls — Coverage decreased (-0.7%) to 71.827% and https://coveralls.io/builds/35041416/source?filename=pkg/cli/cli.go. |
New changes are detected. LGTM label has been removed. |
/retest |
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.
There's probably a more generic/extensible way to do this like
type cli struct {
- // Root command name. Can be injected downstream.
- commandName string
- // Root command short description, Can be injected downstream.
- short string
- // Root command long description, Can be injected downstream.
- long string
- //Root command example, Can be injected downstream.
- example string
+ // cmdCfg configures the root cobra.Command.
+ cmdCfg RootCommandConfig
...
}
type RootCommandConfig struct {
CommandName string
Short string
Long string
Example string
}
// WithRootCommandConfig configures a CLI's root command.
func WithRootCommandConfig(cfg RootCommandConfig) Option {
return func(c *cli) error {
c.cmdCfg = cfg
return nil
}
}
func (c cli) defaultCommand() *cobra.Command {
cmd := &cobra.Command{}
// Prefer the WithCommandName() option for backwards-compat.
if c.commandName != "" {
cmd.Use = c.commandName
} else {
cmd.Use = c.cmdCfg.CommandName
}
cmd.Short = c.cmdCfg.Short
if cmd.Short == "" {
cmd.Short = "Development kit for building ..."
}
cmd.Long = c.cmdCfg.Long
if cmd.Long == "" {
cmd.Long = fmt.Sprintf(`Development kit for building ...`)
}
cmd.Example = c.cmdCfg.Example
if cmd.Example == "" {
cmd.Example = fmt.Sprintf(`...`)
}
return cmd
}
A solve-all solution would set type RootCommandConfig cobra.Command
and use that as the base root command, but that may expose too much of the underlying CLI code and make users think they can set certain fields that will actually be overwritten/modified by other bits of the cli
package.
I think that not showing that we are using cobra underneath as much as we could was a way to allow to remove that dependency in a future in case we wanted to. Related to the |
Hi @estroz , @Adirio , |
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.
There are multiple places (like each command descriptions or contexts) where you are using c.cmdCfg.CommandName
when it could be empty. The only place where you are considering that it may be empty is when assigning it to c.cmd.Use
. By providing a default full c.cmdCfg
and making the option only updated the non-empty ones you ensure that it is always non-empty. The following changes are all about this except for one of them which just removed the quotes around a variable.
Hi @Adirio, |
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.
The commits require to be squashed for we are able o get this one merged here. Could you please do it?
45fc713
to
a61d369
Compare
I realize that removing
This scenario is the reason I choose to remove
That's reasonable, opinions will change over the course of a simple PR that is taking longer than expected, I guess. 😄
While the developer is expected to know the API, it seems a tad bit unnecessary to allow them to set their own descriptions in their projects with the stipulation of using a single param.😅 Tailoring the Options to provide each of the descriptors separately may also lead to the expectation of not setting the descriptors that are not provided by the command developer? |
While there is no
If you set the defaults at the start and make the
Maybe we can switch to a
You can do this any moment you want after calling the options in the loop.
Well if you want to solve this you would have to make the fields be pointers to strings, so that a |
Treating the main branch as the dev branch means breaking changes can happen between releases, which the operator-sdk team is fine with.
I like this to a degree, but wouldn't it be easier to require a command name be set? In general, the CLI shouldn't make any assumptions about what is or isn't set: fields in |
Right, but if a breaking change can be avoided, I would go for that. Also, I prefer to offer the possibility to set just one of those fields. Giving options to the user to a certain degree is nice IMO.
The issue is not the command name, @estroz, the issue is how to set it inside the description and examples. If we go for the |
If a description is provided, the description should be used verbatim, i.e. don't modify user-specified help text. The only case in which the CLI should format a string with command name is if a default string is used, because the CLI knows that formatting directives exist. |
Why special-case the default description to be fmted after calling the options (we have to wait until then to know the command name) and not provide this (already developed) capability to the user provided description? I agree that most of the time the user who provided the description will know the command name, and therefore, can provide the final description. And that would also allow to provide some alternative descriptors in the future. For example, a colored one. |
/retest |
1 similar comment
/retest |
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 couple NITs
P.S.: you can mark all the conversations in #1830 (review) as resolved to hide them.
pkg/cli/cli.go
Outdated
@@ -113,10 +168,28 @@ func (c cli) Run() error { | |||
return c.cmd.Execute() | |||
} | |||
|
|||
// WithCommandName is an Option that sets the cli's root command name. | |||
func WithCommandName(name string) Option { | |||
// WithRootCommandConfig configures a CLI's root command. |
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.
CLI
is the interface, Option
s are defined on cli
, not on CLI
.
// WithRootCommandConfig configures a CLI's root command. | |
// WithRootCommandConfig configures a cli's root command. |
pkg/cli/cli.go
Outdated
if cfg.CommandName != "" { | ||
c.cmdCfg.CommandName = cfg.CommandName | ||
} | ||
replacer := strings.NewReplacer(defaultCommandName, c.cmdCfg.CommandName) | ||
if cfg.Short != "" { | ||
c.cmdCfg.Short = cfg.Short | ||
} else { | ||
c.cmdCfg.Short = replacer.Replace(defaultShortDescription) | ||
} | ||
if cfg.Long != "" { | ||
c.cmdCfg.Long = cfg.Long | ||
} else { | ||
c.cmdCfg.Long = replacer.Replace(defaultLongDescription) | ||
} | ||
if cfg.Example != "" { | ||
c.cmdCfg.Example = cfg.Example | ||
} else { | ||
c.cmdCfg.Example = replacer.Replace(defaultExample) | ||
} |
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.
So basically only default descriptors get replaced, user-provided descriptors are expected to know the command name. I'm OK with this, it simplifies a bit the API for cli developers as we don't have to tell them that they have the %[command]s
placeholder but it still uses the correct command name in the default descriptors in case a different command name is provided.
NIT: we may want to stick to something different that kubebuilder
as the placeholder (even if the commnad name is kubebuilder
, the default descriptors will replace it by itself) as that would allow us to use the actual string "kubebuilder" in comments, e.g. to provide urls. Tests would also need to be updated.
pkg/cli/cli.go
Outdated
@@ -390,50 +463,10 @@ func (c cli) buildRootCmd() *cobra.Command { | |||
// defaultCommand returns the root command without its subcommands. | |||
func (c cli) defaultCommand() *cobra.Command { |
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.
Being now a direct return
, only a couple lines long, and just being called from one place, I wonder if it makes sense to have it as a separate function or we could just create it in place. Also, defaultCommand
does not make sense any more as the function name as previously it was providing default descriptors but now we can customize them and c.cdm
already has the "final" descriptors.
I'm fine not doing this. I'm really just trying to expose the simplest API possible: pass the CLI a struct containing help strings that will be used verbatim, with no changes. Increasing complexity with replacement semantics means more confusion for users of an already-complex plugin system. |
aafb81a
to
86ac9d4
Compare
86ac9d4
to
df485ae
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.
/approve
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: anmol372, estroz The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
@anmol372: The following tests failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. 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/test-infra repository. I understand the commands that are listed here. |
@anmol372: 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/test-infra repository. |
Root command recently received a rework:
This means that, from the 3 configurable fields that this PR is adding, only @anmol372 Do you want to update this PR just to include the |
Hi @Adirio , |
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.
Request a review from (at least) me once you get this done.
Hi @anmol372, Could you please rebase it with the master for we are able to move forward here? Also, can you close all comments that are addressed? |
Hi @anmol372, It is open for a while without be rebased with the master? Could you please rebase this one and let us know if you could address all suggestion and if it is done for another review round? OR is no longer it required? |
Added 4 Options to configure command descriptions.
Downstream Projects may want to change the preset descriptions and examples to something more relevant to their projects so I am proposing the following Options to configure those by calling
WithRootCommandConfig(cmdCfg)
The fields of
cmdCfg
can be set by usingRootCommandConfig struct
added in the cli pkg