Skip to content

Commit 2d0a4b7

Browse files
joaopaletDiogoFerraovicentepinto98GokceGKstackit-pipeline
authored
Add support for config profiles (#334)
* Implement `GetProfile` (#309) * Extract file utils and implement readFileIfExists * Write unit tests for file utils * Implement GetProfile * Fix test * Fix typo * Remove unnecesary condition * Fix lint * Adjustments after review * Choose config folder based on profile in InitConfig (#310) * Implement `stackit config profile` commands (#312) * Implement config profile set * Implement config profile unset * Extend config list to show active profile * Adjustments after review * Improvements to profiles functionality (#315) * Add --used and --unused flags to `load-balancer list` (#308) * initial implementation * add testing, finish functionality * generate docs, minor improvements * more testing * refactor implementation, simplify RunE * remove unused func * address PR comments * generate-docs * change filtercredentials to use enum for operation type * address PR comments * Onboard `load-balancer observability-credentials cleanup` (#311) * command implementation, add testing * rename var, generate docs * address PR comments * fix no credentials listing (#313) * Integrate WinGet distribution in release pipeline (#305) * Integrate WinGet distribution in release pipeline * Add comment regarding skipping prereleases * Fix link * Configure table titles (#314) * Update tables * Configure colors in the less pager * Fix title wrapping, add titles to lb * Re-add -w argument and add titles to mongodb and pgflex options * Add table title to config list * Fixes and improvements to profiles functionality --------- Co-authored-by: Diogo Ferrão <diogo.ferrao@freiheit.com> Co-authored-by: Vicente Pinto <vicente.pinto@freiheit.com> * Implement profiles for auth settings (#326) * add profiles for auth settings * adapt unit tests * Use filepath.Join for keyring path too --------- Co-authored-by: João Palet <joao.palet@freiheit.com> * Add warnings when set/unset profile with no auth (#327) * initial implementation for auth warning on new profiles * add debug logs * simplify code, improve messages * address acceptance comments (#328) * Rework active profile handling in auth (#329) * move reading profile to caller functions * adapt unit tests * adapt unit tests * adapt unit tests * Merge latest updates from `main` into `feature/multi-config` (#330) * Add --used and --unused flags to `load-balancer list` (#308) * initial implementation * add testing, finish functionality * generate docs, minor improvements * more testing * refactor implementation, simplify RunE * remove unused func * address PR comments * generate-docs * change filtercredentials to use enum for operation type * address PR comments * Onboard `load-balancer observability-credentials cleanup` (#311) * command implementation, add testing * rename var, generate docs * address PR comments * fix no credentials listing (#313) * Integrate WinGet distribution in release pipeline (#305) * Integrate WinGet distribution in release pipeline * Add comment regarding skipping prereleases * Fix link * Configure table titles (#314) * Update tables * Configure colors in the less pager * Fix title wrapping, add titles to lb * Re-add -w argument and add titles to mongodb and pgflex options * fix(deps): update stackit sdk modules to v0.14.0 (#317) Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com> * MongoDB backup list, describe, restore-jobs (#307) * Draft implementation mongodb backup list, describe, restore-jobs * Fix descriptions * Add expire date§ g * Add docs * Fix examples * Add restore status * Refactor getRestoreStatus * Sort restore jobs array * Add another date format to unit test§ * Implement YAML output format (#298) * initial implementation yamlOutputFormal * sort imports * change yaml library * add yaml output format * tidy up imports * tidy up imports * update docs * add yaml output for project and organization role lists * extend contribution.md * change yaml library * Mongodb backup schedule, update-schedule, restore (#316) * initial update schedule implementation * implement update and list schedule commands, add testing * restore command and testing * add waiters * generate docs * merge changes * address PR comments * add custom error, fix restore examples * Add yaml output format to mongodbflex backup commands (#319) * add yaml output to mongodbflex commands * update docs * Update internal/cmd/mongodbflex/backup/describe/describe.go Co-authored-by: João Palet <joao.palet@outlook.com> * change error log --------- Co-authored-by: João Palet <joao.palet@outlook.com> * Add yaml output to lb commands (#321) * update docs * add yaml output * fix(deps): update stackit sdk modules (#318) Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com> * Add SKE login command (#157) * Add SKE login command Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com> * Different improvement from code review * remove unused function * rearrange functions and improve error messages * Add tests for cache pkg * Extend kubeconfig create command with flag to retrieve login kubeconfig * small extension to the kubeconfig login description * improve descriptions and examples * fix yaml output * codereview: use os.UserCacheDir instead of external lib * codereview: drop parseInput and use parseClusterConfig directly; move cacheKey into clusterConfig * codereview: add one nil check * codereview: print user facing error that explains that the login command should not be used directly * fixup! codereview: use os.UserCacheDir instead of external lib * codereview: first try at improving the description * generate-docs * Add tests for login (buildRequest & parseKubeConfigToExecCredential * cache: call Init func directly and return err * use p.Outputf instead of cmd.Print --------- Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com> * Fix outputF call (#322) * Add custom pager handling (#299) * add custom pager handling * ignore linter temporarily * change condition * add debug line * add debug log * add pager infos to README * Update README.md Co-authored-by: João Palet <joao.palet@outlook.com> * edit README.md * edit README.md * Update README.md Co-authored-by: Vicente Pinto <vicente.pinto@freiheit.com> * Update README.md Co-authored-by: Vicente Pinto <vicente.pinto@freiheit.com> --------- Co-authored-by: João Palet <joao.palet@outlook.com> Co-authored-by: Vicente Pinto <vicente.pinto@freiheit.com> * change marshal function to add indentation (#323) * upgrade dependency to fix high vulnerability (#324) * Replace createFolderIfNotExists with MkdirAll --------- Co-authored-by: Diogo Ferrão <diogo.ferrao@freiheit.com> Co-authored-by: Vicente Pinto <vicente.pinto@freiheit.com> Co-authored-by: stackit-pipeline <142982727+stackit-pipeline@users.noreply.github.com> Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com> Co-authored-by: GokceGK <161626272+GokceGK@users.noreply.github.com> Co-authored-by: Kumm-Kai <70690427+Kumm-Kai@users.noreply.github.com> Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com> * Fix encoded file path for profiles (#333) * Fix file path for the encoded text file * fix unit test --------- Co-authored-by: Diogo Ferrão <diogo.ferrao@freiheit.com> Co-authored-by: Vicente Pinto <vicente.pinto@freiheit.com> Co-authored-by: GokceGK <161626272+GokceGK@users.noreply.github.com> Co-authored-by: stackit-pipeline <142982727+stackit-pipeline@users.noreply.github.com> Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com> Co-authored-by: Kumm-Kai <70690427+Kumm-Kai@users.noreply.github.com> Co-authored-by: Maximilian Geberl <48486938+dergeberl@users.noreply.github.com>
1 parent 32ac24b commit 2d0a4b7

28 files changed

+923
-97
lines changed

docs/stackit_config.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ Provides functionality for CLI configuration options
44

55
### Synopsis
66

7-
Provides functionality for CLI configuration options
8-
The configuration is stored in a file in the user's config directory, which is OS dependent.
9-
Windows: %APPDATA%\stackit
10-
Linux: $XDG_CONFIG_HOME/stackit
11-
macOS: $HOME/Library/Application Support/stackit
12-
The configuration file is named `cli-config.json` and is created automatically in your first CLI run.
7+
Provides functionality for CLI configuration options.
8+
You can set and unset different configuration options via the "stackit config set" and "stackit config unset" commands.
9+
10+
Additionally, you can configure the CLI to use different profiles, each with its own configuration.
11+
Additional profiles can be configured via the "STACKIT_CLI_PROFILE" environment variable or using the "stackit config profile set PROFILE" and "stackit config profile unset" commands.
12+
The environment variable takes precedence over what is set via the commands.
1313

1414
```
1515
stackit config [flags]
@@ -35,6 +35,7 @@ stackit config [flags]
3535

3636
* [stackit](./stackit.md) - Manage STACKIT resources using the command line
3737
* [stackit config list](./stackit_config_list.md) - Lists the current CLI configuration values
38+
* [stackit config profile](./stackit_config_profile.md) - Manage the CLI configuration profiles
3839
* [stackit config set](./stackit_config_set.md) - Sets CLI configuration options
3940
* [stackit config unset](./stackit_config_unset.md) - Unsets CLI configuration options
4041

docs/stackit_config_profile.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## stackit config profile
2+
3+
Manage the CLI configuration profiles
4+
5+
### Synopsis
6+
7+
Manage the CLI configuration profiles.
8+
The profile to be used can be managed via the "STACKIT_CLI_PROFILE" environment variable or using the "stackit config profile set PROFILE" and "stackit config profile unset" commands.
9+
The environment variable takes precedence over what is set via the commands.
10+
When no profile is set, the default profile is used.
11+
12+
```
13+
stackit config profile [flags]
14+
```
15+
16+
### Options
17+
18+
```
19+
-h, --help Help for "stackit config profile"
20+
```
21+
22+
### Options inherited from parent commands
23+
24+
```
25+
-y, --assume-yes If set, skips all confirmation prompts
26+
--async If set, runs the command asynchronously
27+
-o, --output-format string Output format, one of ["json" "pretty" "none"]
28+
-p, --project-id string Project ID
29+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
30+
```
31+
32+
### SEE ALSO
33+
34+
* [stackit config](./stackit_config.md) - Provides functionality for CLI configuration options
35+
* [stackit config profile set](./stackit_config_profile_set.md) - Set a CLI configuration profile
36+
* [stackit config profile unset](./stackit_config_profile_unset.md) - Unset the current active CLI configuration profile
37+

docs/stackit_config_profile_set.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
## stackit config profile set
2+
3+
Set a CLI configuration profile
4+
5+
### Synopsis
6+
7+
Set a CLI configuration profile as the active profile.
8+
The profile to be used can be managed via the STACKIT_CLI_PROFILE environment variable or using the "stackit config profile set PROFILE" and "stackit config profile unset" commands.
9+
The environment variable takes precedence over what is set via the commands.
10+
A new profile is created automatically if it does not exist.
11+
When no profile is set, the default profile is used.
12+
13+
```
14+
stackit config profile set PROFILE [flags]
15+
```
16+
17+
### Examples
18+
19+
```
20+
Set the configuration profile "my-profile" as the active profile
21+
$ stackit config profile set my-profile
22+
```
23+
24+
### Options
25+
26+
```
27+
-h, --help Help for "stackit config profile set"
28+
```
29+
30+
### Options inherited from parent commands
31+
32+
```
33+
-y, --assume-yes If set, skips all confirmation prompts
34+
--async If set, runs the command asynchronously
35+
-o, --output-format string Output format, one of ["json" "pretty" "none"]
36+
-p, --project-id string Project ID
37+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
38+
```
39+
40+
### SEE ALSO
41+
42+
* [stackit config profile](./stackit_config_profile.md) - Manage the CLI configuration profiles
43+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## stackit config profile unset
2+
3+
Unset the current active CLI configuration profile
4+
5+
### Synopsis
6+
7+
Unset the current active CLI configuration profile.
8+
When no profile is set, the default profile will be used.
9+
10+
```
11+
stackit config profile unset [flags]
12+
```
13+
14+
### Examples
15+
16+
```
17+
Unset the currently active configuration profile. The default profile will be used.
18+
$ stackit config profile unset
19+
```
20+
21+
### Options
22+
23+
```
24+
-h, --help Help for "stackit config profile unset"
25+
```
26+
27+
### Options inherited from parent commands
28+
29+
```
30+
-y, --assume-yes If set, skips all confirmation prompts
31+
--async If set, runs the command asynchronously
32+
-o, --output-format string Output format, one of ["json" "pretty" "none"]
33+
-p, --project-id string Project ID
34+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
35+
```
36+
37+
### SEE ALSO
38+
39+
* [stackit config profile](./stackit_config_profile.md) - Manage the CLI configuration profiles
40+

docs/stackit_load-balancer_observability-credentials_cleanup.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,4 @@ stackit load-balancer observability-credentials cleanup [flags]
3535

3636
### SEE ALSO
3737

38-
* [stackit load-balancer observability-credentials](./stackit_load-balancer_observability-credentials.md) - Provides functionality for Load Balancer observability credentials
39-
38+
- [stackit load-balancer observability-credentials](./stackit_load-balancer_observability-credentials.md) - Provides functionality for Load Balancer observability credentials

internal/cmd/config/config.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55

66
"github.com/stackitcloud/stackit-cli/internal/cmd/config/list"
7+
"github.com/stackitcloud/stackit-cli/internal/cmd/config/profile"
78
"github.com/stackitcloud/stackit-cli/internal/cmd/config/set"
89
"github.com/stackitcloud/stackit-cli/internal/cmd/config/unset"
910
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
@@ -17,12 +18,12 @@ func NewCmd(p *print.Printer) *cobra.Command {
1718
cmd := &cobra.Command{
1819
Use: "config",
1920
Short: "Provides functionality for CLI configuration options",
20-
Long: fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", "Provides functionality for CLI configuration options",
21-
"The configuration is stored in a file in the user's config directory, which is OS dependent.",
22-
"Windows: %APPDATA%\\stackit",
23-
"Linux: $XDG_CONFIG_HOME/stackit",
24-
"macOS: $HOME/Library/Application Support/stackit",
25-
"The configuration file is named `cli-config.json` and is created automatically in your first CLI run.",
21+
Long: fmt.Sprintf("%s\n%s\n\n%s\n%s\n%s",
22+
"Provides functionality for CLI configuration options.",
23+
`You can set and unset different configuration options via the "stackit config set" and "stackit config unset" commands.`,
24+
"Additionally, you can configure the CLI to use different profiles, each with its own configuration.",
25+
`Additional profiles can be configured via the "STACKIT_CLI_PROFILE" environment variable or using the "stackit config profile set PROFILE" and "stackit config profile unset" commands.`,
26+
"The environment variable takes precedence over what is set via the commands.",
2627
),
2728
Args: args.NoArgs,
2829
Run: utils.CmdHelp,
@@ -35,4 +36,5 @@ func addSubcommands(cmd *cobra.Command, p *print.Printer) {
3536
cmd.AddCommand(list.NewCmd(p))
3637
cmd.AddCommand(set.NewCmd(p))
3738
cmd.AddCommand(unset.NewCmd(p))
39+
cmd.AddCommand(profile.NewCmd(p))
3840
}

internal/cmd/config/list/list.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ func NewCmd(p *print.Printer) *cobra.Command {
5151
configData := viper.AllSettings()
5252

5353
model := parseInput(p, cmd)
54-
return outputResult(p, model.OutputFormat, configData)
54+
55+
activeProfile, err := config.GetProfile()
56+
if err != nil {
57+
return fmt.Errorf("get profile: %w", err)
58+
}
59+
60+
return outputResult(p, model.OutputFormat, configData, activeProfile)
5561
},
5662
}
5763
return cmd
@@ -65,9 +71,12 @@ func parseInput(p *print.Printer, cmd *cobra.Command) *inputModel {
6571
}
6672
}
6773

68-
func outputResult(p *print.Printer, outputFormat string, configData map[string]any) error {
74+
func outputResult(p *print.Printer, outputFormat string, configData map[string]any, activeProfile string) error {
6975
switch outputFormat {
7076
case print.JSONOutputFormat:
77+
if activeProfile != "" {
78+
configData["profile"] = activeProfile
79+
}
7180
details, err := json.MarshalIndent(configData, "", " ")
7281
if err != nil {
7382
return fmt.Errorf("marshal config list: %w", err)
@@ -83,6 +92,7 @@ func outputResult(p *print.Printer, outputFormat string, configData map[string]a
8392

8493
return nil
8594
default:
95+
8696
// Sort the config options by key
8797
configKeys := make([]string, 0, len(configData))
8898
for k := range configData {
@@ -91,6 +101,9 @@ func outputResult(p *print.Printer, outputFormat string, configData map[string]a
91101
sort.Strings(configKeys)
92102

93103
table := tables.NewTable()
104+
if activeProfile != "" {
105+
table.SetTitle(fmt.Sprintf("Profile: %q", activeProfile))
106+
}
94107
table.SetHeader("NAME", "VALUE")
95108
for _, key := range configKeys {
96109
value := configData[key]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package profile
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/stackitcloud/stackit-cli/internal/cmd/config/profile/set"
7+
"github.com/stackitcloud/stackit-cli/internal/cmd/config/profile/unset"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
11+
12+
"github.com/spf13/cobra"
13+
)
14+
15+
func NewCmd(p *print.Printer) *cobra.Command {
16+
cmd := &cobra.Command{
17+
Use: "profile",
18+
Short: "Manage the CLI configuration profiles",
19+
Long: fmt.Sprintf("%s\n%s\n%s\n%s",
20+
"Manage the CLI configuration profiles.",
21+
`The profile to be used can be managed via the "STACKIT_CLI_PROFILE" environment variable or using the "stackit config profile set PROFILE" and "stackit config profile unset" commands.`,
22+
"The environment variable takes precedence over what is set via the commands.",
23+
"When no profile is set, the default profile is used.",
24+
),
25+
Args: args.NoArgs,
26+
Run: utils.CmdHelp,
27+
}
28+
addSubcommands(cmd, p)
29+
return cmd
30+
}
31+
32+
func addSubcommands(cmd *cobra.Command, p *print.Printer) {
33+
cmd.AddCommand(set.NewCmd(p))
34+
cmd.AddCommand(unset.NewCmd(p))
35+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package set
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
7+
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
11+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
12+
13+
"github.com/spf13/cobra"
14+
)
15+
16+
const (
17+
profileArg = "PROFILE"
18+
)
19+
20+
type inputModel struct {
21+
*globalflags.GlobalFlagModel
22+
Profile string
23+
}
24+
25+
func NewCmd(p *print.Printer) *cobra.Command {
26+
cmd := &cobra.Command{
27+
Use: fmt.Sprintf("set %s", profileArg),
28+
Short: "Set a CLI configuration profile",
29+
Long: fmt.Sprintf("%s\n%s\n%s\n%s\n%s",
30+
"Set a CLI configuration profile as the active profile.",
31+
`The profile to be used can be managed via the STACKIT_CLI_PROFILE environment variable or using the "stackit config profile set PROFILE" and "stackit config profile unset" commands.`,
32+
"The environment variable takes precedence over what is set via the commands.",
33+
"A new profile is created automatically if it does not exist.",
34+
"When no profile is set, the default profile is used.",
35+
),
36+
Args: args.SingleArg(profileArg, nil),
37+
Example: examples.Build(
38+
examples.NewExample(
39+
`Set the configuration profile "my-profile" as the active profile`,
40+
"$ stackit config profile set my-profile"),
41+
),
42+
RunE: func(cmd *cobra.Command, args []string) error {
43+
model, err := parseInput(p, cmd, args)
44+
if err != nil {
45+
return err
46+
}
47+
48+
err = config.SetProfile(p, model.Profile)
49+
if err != nil {
50+
return fmt.Errorf("set profile: %w", err)
51+
}
52+
53+
p.Info("Successfully set active profile to %q\n", model.Profile)
54+
55+
flow, err := auth.GetAuthFlow()
56+
if err != nil {
57+
p.Debug(print.WarningLevel, "both keyring and text file storage failed to find a valid authentication flow for the active profile")
58+
p.Warn("The active profile %q is not authenticated, please login using the 'stackit auth login' command.\n", model.Profile)
59+
return nil
60+
}
61+
p.Debug(print.DebugLevel, "found valid authentication flow for active profile: %s", flow)
62+
63+
return nil
64+
},
65+
}
66+
return cmd
67+
}
68+
69+
func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
70+
profile := inputArgs[0]
71+
72+
err := config.ValidateProfile(profile)
73+
if err != nil {
74+
return nil, err
75+
}
76+
77+
globalFlags := globalflags.Parse(p, cmd)
78+
79+
model := inputModel{
80+
GlobalFlagModel: globalFlags,
81+
Profile: profile,
82+
}
83+
84+
if p.IsVerbosityDebug() {
85+
modelStr, err := print.BuildDebugStrFromInputModel(model)
86+
if err != nil {
87+
p.Debug(print.ErrorLevel, "convert model to string for debugging: %v", err)
88+
} else {
89+
p.Debug(print.DebugLevel, "parsed input values: %s", modelStr)
90+
}
91+
}
92+
93+
return &model, nil
94+
}

0 commit comments

Comments
 (0)