Skip to content

Commit 7c11826

Browse files
committed
fix(runcommand): do not create API client for offline commands
This allows running offline commands, such as upctl version, without having to define credentials.
1 parent f909b8d commit 7c11826

5 files changed

Lines changed: 29 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Fixed
1313
- Improved errors relating to argument resolver failures
14+
- Print version info, instead of missing credentials error, when runnning `upctl version` without credentials
1415

1516
## [1.1.3] - 2022-02-24
1617
### Changed

internal/commands/command.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ type Command interface {
3030
CobraCommand
3131
}
3232

33+
// OfflineCommand is a command that does not need connect to the API, e.g. upctl version.
34+
type OfflineCommand interface {
35+
DoesNotUseServices()
36+
}
37+
3338
// NoArgumentCommand is a command that does not care about the positional arguments.
3439
type NoArgumentCommand interface {
3540
Command
@@ -95,6 +100,11 @@ func BuildCommand(child Command, parent *cobra.Command, config *config.Config) C
95100

96101
// Set run
97102
child.Cobra().RunE = func(cmd *cobra.Command, args []string) error {
103+
// Do not create service for offline commands, e.g. upctl version
104+
if _, ok := child.(OfflineCommand); ok {
105+
return commandRunE(child, nil, config, args)
106+
}
107+
98108
service, err := config.CreateService()
99109
if err != nil {
100110
return fmt.Errorf("cannot create service: %w", err)

internal/commands/root/completion.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ func (s *CompletionCommand) ExecuteSingleArgument(_ commands.Executor, arg strin
2626

2727
return nil, fmt.Errorf("completion for %s is not supported", arg)
2828
}
29+
30+
// DoesNotUseServices implements commands.OfflineCommand as this command does not use services
31+
func (s *CompletionCommand) DoesNotUseServices() {}

internal/commands/root/version.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ type VersionCommand struct {
1717
func (s *VersionCommand) ExecuteWithoutArguments(_ commands.Executor) (output.Output, error) {
1818
return output.Details{Sections: []output.DetailSection{
1919
{Rows: []output.DetailRow{
20-
{Title: "Version", Key: "version", Value: config.Version},
20+
{Title: "Version:", Key: "version", Value: config.Version},
2121
{Title: "Build date:", Key: "build_date", Value: config.BuildDate},
2222
{Title: "Built with:", Key: "built_with", Value: runtime.Version()},
2323
},
2424
}},
2525
}, nil
2626
}
27+
28+
// DoesNotUseServices implements commands.OfflineCommand as this command does not use services
29+
func (s *VersionCommand) DoesNotUseServices() {}

internal/commands/runcommand_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,17 @@ func TestRunCommand(t *testing.T) {
210210
}
211211
}
212212

213+
func TestExecute_Offline(t *testing.T) {
214+
cmd := &mockNone{Command: &cobra.Command{}}
215+
cmd.On("ExecuteWithoutArguments", mock.Anything).Return(output.OnlyMarshaled{Value: "mock"}, nil)
216+
217+
cfg := config.New()
218+
cfg.Viper().Set(config.KeyOutput, config.ValueOutputJSON)
219+
220+
err := commandRunE(cmd, nil, cfg, []string{})
221+
assert.NoError(t, err)
222+
}
223+
213224
func TestExecute_Resolution(t *testing.T) {
214225
cmd := &mockMultiResolver{Command: &cobra.Command{}}
215226
mService := &smock.Service{}

0 commit comments

Comments
 (0)