-
Notifications
You must be signed in to change notification settings - Fork 18
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: Add CLI option --format to disconnect command #108
Conversation
jirihnidek
commented
May 2, 2024
- It is possible to print output of disconnect command in machine-readable format. The --format requires argument and it could be only "json" ATM. It follows practice of status command.
- Refactored code a little to share some code with status command.
I like the use of the |
BTW: I would like to add |
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := cli.NewApp()
app.Name = "rhc"
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "format",
},
}
app.Commands = []*cli.Command{
{
Name: "connect",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "username",
},
},
Action: func(ctx *cli.Context) error {
fmt.Printf("username: %v\n", ctx.String("username"))
fmt.Printf("format: %v\n", ctx.String("format"))
return nil
},
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
} When invoked like so:
However, when invoked like so: Have you considered adding |
I agree that it would be good to have What bothers me is a fact that we will break compatibility with TBH: I don't like the behavior of github.com/urfave/cli that you have to use flags of parent command immediately after main command. This is something unusual. There is alfa version (v3) of github.com/urfave/cli (we still use v2) ... I will try it if the behavior is still the same in v3. |
The v3 support persistent flags introduces in this PR: urfave/cli#1568 The code looks like this: package main
import (
"context"
"fmt"
"github.com/urfave/cli/v3"
"log"
"os"
)
func main() {
cmd := cli.Command{
Name: "rhc",
Commands: []*cli.Command{
{
Name: "connect",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "username",
},
},
Action: func(ctx context.Context, command *cli.Command) error {
fmt.Printf("username: %s\n", command.String("username"))
fmt.Printf("format: %s\n", command.String("format"))
return nil
},
},
},
Flags: []cli.Flag{
&cli.StringFlag{
Name: "format",
Persistent: true,
},
},
}
err := cmd.Run(context.Background(), os.Args)
if err != nil {
log.Fatal(err)
}
} If a flag is marked as persistent, then you can use global flag after sub-command like this:
Unfortunately this feature hasn't been back-ported to v2. |
Oh, that's exactly what we should use. Let's proceed with separate |
main.go
Outdated
// disconnectAction tries to stop rhscd service, disconnect from Red Hat Insights, and finally | ||
// it unregister system from Red Hat Subscription Management |
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.
// disconnectAction tries to stop rhscd service, disconnect from Red Hat Insights, and finally | |
// it unregister system from Red Hat Subscription Management | |
// disconnectAction tries to stop rhcd service, disconnect from Red Hat Insights, and | |
// finally it unregisters system from Red Hat Subscription Management |
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 noticed a significant amount of conditional checks on the value of uiSettings.isMachineReadable
, and some data structure transformation between DisconnectResult
and error
. I recommend looking into a way to make DisconnectResult
conform to the error
interface. I think that could result in reducing a lot of the conditional checks, and might streamline some of the code paths that are trying to transform a DisconnectResult
into and error
.
You might even consider making a generic Result
interface type that DisconnectResult
can implement. This could be expanded to other command results such as status
(with a StatusResult
) and connect
(with a ConnectResult
.
I agree that there is too many checks of The |
2fe764b
to
bda0cad
Compare
Refactored code a little bit. I hope that it is better now. |
bda0cad
to
0f31209
Compare
@subpop Hi, can you please review this PR again? |
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.
Looks good over all. I just have a couple very minor questions.
main.go
Outdated
if uiSettings.isMachineReadable { | ||
defer func(disconnectResult *DisconnectResult) { | ||
// When exit code is zero, then print machine-readable output | ||
// When exit code has non-zero value, then disconnectResult is returned as a 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.
This comment doesn't see to align with the behavior of the code. Is it left over
from some previous code? This is one of the pitfalls of using comments to
describe the algorithm of the code.
main.go
Outdated
// change returned error to CLI exit error to be able to set exit code to | ||
// a non-zero value | ||
if err != nil { | ||
panic(fmt.Errorf("unable to print status as %s document: %s", format, err.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.
Typically, it's not necessary to explicitly call Error() on an error type. This
should be sufficient.
panic(fmt.Errorf("unable to print status as %s document: %s", format, err.Error())) | |
panic(fmt.Errorf("unable to print status as %v document: %v", format, err)) |
main.go
Outdated
}(&disconnectResult) | ||
} | ||
|
||
disconnectResult.exitCode = 0 |
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 this necessary? The zero value of an int
is 0
already.
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.
Refactored code to not duplicate code. Only Error()
interface is used now.
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.
Nice refactor! I like the change and use of Error interface.
0f31209
to
ebea78b
Compare
There appear to be some valid lint errors related to printf format strings. |
main.go
Outdated
|
||
// rhcPrintf is method for printing human-readable output. It suppresses output, when | ||
// machine-readable format is used. | ||
func rhcPrintf(format string, a ...interface{}) { |
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 name of this function doesn't indicate its purpose clearly to me. Could we
call it something like interactivePrintf
?
* It is possible to print output of disconnect command in machine-readable format. The --format requires argument and it could be only "json" ATM. It follows practice of status command. * Refactored code a little to share some code with status command.
* When --format json is used, then use only Error() interface for printing disconnect result
ebea78b
to
d79ca95
Compare
* Fix some code style issues and make code linter more happy
d79ca95
to
1b53bd3
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.
OK. This looks good to me!