Skip to content

Commit

Permalink
feat(config): add import command (#2995)
Browse files Browse the repository at this point in the history
  • Loading branch information
yfodil committed Apr 3, 2023
1 parent cb52f9d commit e56e8c1
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 0 deletions.
18 changes: 18 additions & 0 deletions cmd/scw/testdata/test-all-usage-config-import-usage.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
πŸŸ₯πŸŸ₯πŸŸ₯ STDERR️️ πŸŸ₯πŸŸ₯πŸŸ₯️
Import configurations from another file

USAGE:
scw config import <file ...> [arg=value ...]

ARGS:
file Path to the configuration file to import

FLAGS:
-h, --help help for import

GLOBAL FLAGS:
-c, --config string The path to the config file
-D, --debug Enable debug mode
-o, --output string Output format: json or human, see 'scw help output' for more info (default "human")
-p, --profile string The config profile to use
22 changes: 22 additions & 0 deletions docs/commands/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Read more about the config management engine at https://github.com/scaleway/scal
- [Destroy the config file](#destroy-the-config-file)
- [Dump the config file](#dump-the-config-file)
- [Get a value from the config file](#get-a-value-from-the-config-file)
- [Import configurations from another file](#import-configurations-from-another-file)
- [Get config values from the config file for the current profile](#get-config-values-from-the-config-file-for-the-current-profile)
- [Allows the deletion of a profile from the config file](#allows-the-deletion-of-a-profile-from-the-config-file)
- [Mark a profile as active in the config file](#mark-a-profile-as-active-in-the-config-file)
Expand Down Expand Up @@ -102,6 +103,27 @@ scw -p prod config get default_region



## Import configurations from another file





**Usage:**

```
scw config import <file ...> [arg=value ...]
```


**Args:**

| Name | | Description |
|------|---|-------------|
| file | Required | Path to the configuration file to import |



## Get config values from the config file for the current profile


Expand Down
67 changes: 67 additions & 0 deletions internal/namespaces/config/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func GetCommands() *core.Commands {
configResetCommand(),
configDestroyCommand(),
configInfoCommand(),
configImportCommand(),
)
}

Expand Down Expand Up @@ -628,6 +629,72 @@ func configInfoCommand() *core.Command {
}
}

// configImportCommand imports an external config
func configImportCommand() *core.Command {
type configImportArgs struct {
File string
}

return &core.Command{
Groups: []string{"config"},
Short: "Import configurations from another file",
Namespace: "config",
Resource: "import",
AllowAnonymousClient: true,
ArgsType: reflect.TypeOf(configImportArgs{}),
ArgSpecs: core.ArgSpecs{
{
Name: "file",
Short: "Path to the configuration file to import",
Required: true,
Positional: true,
},
},
Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) {
args := argsI.(*configImportArgs)
configPath := core.ExtractConfigPath(ctx)

currentConfig, err := scw.LoadConfigFromPath(configPath)
if err != nil {
return nil, err
}
currentProfileName := core.ExtractProfileName(ctx)
currentProfile, err := currentConfig.GetProfile(currentProfileName)
if err != nil {
return nil, err
}

// Read the content of the file to import
importedConfig, err := scw.LoadConfigFromPath(args.File)
if err != nil {
return nil, err
}
importedProfile := importedConfig.Profile

// Merge the imported configurations into the existing configuration
currentConfig.Profile = *scw.MergeProfiles(currentProfile, &importedProfile)

for profileName, profile := range importedConfig.Profiles {
existingProfile, exists := currentConfig.Profiles[profileName]
if exists {
currentConfig.Profiles[profileName] = scw.MergeProfiles(existingProfile, profile)
} else {
currentConfig.Profiles[profileName] = profile
}
}

err = currentConfig.SaveTo(configPath)
if err != nil {
return nil, fmt.Errorf("failed to save updated configuration: %v", err)
}

return &core.SuccessResult{
Message: "successfully import config",
}, nil
},
}
}

// Helper functions
func getProfileValue(profile *scw.Profile, fieldName string) (interface{}, error) {
field, err := getProfileField(profile, fieldName)
Expand Down
80 changes: 80 additions & 0 deletions internal/namespaces/config/commands_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package config

import (
"fmt"
"io/ioutil"
"os"
"path"
"regexp"
Expand Down Expand Up @@ -303,6 +305,38 @@ func Test_ConfigInfoCommand(t *testing.T) {
}))
}

func Test_ConfigImportCommand(t *testing.T) {
t.Run("Simple", func(t *testing.T) {
tmpFile, err := createTempConfigFile()
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpFile.Name())

core.Test(&core.TestConfig{
Commands: GetCommands(),
BeforeFunc: beforeFuncCreateFullConfig(),
Cmd: fmt.Sprintf("scw config import %s", tmpFile.Name()),
Check: core.TestCheckCombine(
core.TestCheckExitCode(0),
core.TestCheckGolden(),
checkConfig(func(t *testing.T, config *scw.Config) {
// config
assert.Equal(t, "22222222-2222-2222-2222-222222222222", *config.SecretKey)
assert.Equal(t, "nl-ams", *config.DefaultRegion)
// modified p1
assert.Equal(t, "99999999-9999-9999-9999-999999999999", *config.Profiles["p1"].SecretKey)
assert.Equal(t, "nl-ams", *config.Profiles["p1"].DefaultRegion)
// new p3
assert.Equal(t, "33333333-3333-3333-3333-333333333333", *config.Profiles["p3"].SecretKey)
assert.Equal(t, "fr-par", *config.Profiles["p3"].DefaultRegion)
}),
),
TmpHomeDir: true,
})(t)
})
}

func checkConfig(f func(t *testing.T, config *scw.Config)) core.TestCheck {
return func(t *testing.T, ctx *core.CheckFuncCtx) {
homeDir := ctx.OverrideEnv["HOME"]
Expand Down Expand Up @@ -361,3 +395,49 @@ func beforeFuncCreateFullConfig() core.BeforeFunc {
},
})
}

func createTempConfigFile() (*os.File, error) {
tmpFile, err := ioutil.TempFile("", "tmp.yaml")
if err != nil {
return nil, err
}

configContent := `
access_key: SCWXXXXXXXXXXXXXXXXX
secret_key: 22222222-2222-2222-2222-222222222222
api_url: https://mock-api-url.com
insecure: true
default_organization_id: 22222222-2222-2222-2222-222222222222
default_region: nl-ams
default_zone: nl-ams-1
send_telemetry: true
profiles:
p1:
access_key: SCWP1XXXXXXXXXXXXXXX
secret_key: 99999999-9999-9999-9999-999999999999
api_url: https://p1-mock-api-url.com
insecure: true
default_organization_id: 99999999-9999-9999-9999-999999999999
default_region: nl-ams
default_zone: nl-ams-1
send_telemetry: true
p3:
access_key: SCWP3XXXXXXXXXXXXXXX
secret_key: 33333333-3333-3333-3333-333333333333
api_url: https://p3-mock-api-url.com
insecure: true
default_organization_id: 33333333-3333-3333-3333-333333333333
default_region: fr-par
default_zone: fr-par-1
send_telemetry: true
`

if _, err := tmpFile.Write([]byte(configContent)); err != nil {
return nil, err
}
if err := tmpFile.Close(); err != nil {
return nil, err
}

return tmpFile, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
🟩🟩🟩 STDOUT️ 🟩🟩🟩️
βœ… Successfully import config.
🟩🟩🟩 JSON STDOUT 🟩🟩🟩
{
"message": "successfully import config",
"details": ""
}

0 comments on commit e56e8c1

Please sign in to comment.