Skip to content

fix issues in acceptance #357

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

Merged
merged 8 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,24 @@ func NewRootCmd(version, date string, p *print.Printer) *cobra.Command {
configFilePath := viper.ConfigFileUsed()
p.Debug(print.DebugLevel, "configuration is persisted and read from: %s", configFilePath)

activeProfile, err := config.GetProfile()
profileSet, activeProfile, configMethod, err := config.GetConfiguredProfile()
if err != nil {
return fmt.Errorf("get profile: %w", err)
return fmt.Errorf("get configured profile: %w", err)
}

profileExists, err := config.ProfileExists(activeProfile)
if err != nil {
return fmt.Errorf("check if profile exists: %w", err)
}
if !profileExists {
p.Warn("active profile does not exist, the default profile configuration will be used\n")
p.Debug(print.DebugLevel, "read configuration profile %q via %s", profileSet, configMethod)

if activeProfile != profileSet {
if configMethod == "" {
p.Debug(print.DebugLevel, "no profile is configured in env var or profile file")
} else {
p.Debug(print.DebugLevel, "the configured profile %q does not exist: folder %q is missing", profileSet, config.GetProfileFolderPath(profileSet))
}
p.Debug(print.DebugLevel, "the %q profile will be used", activeProfile)

p.Warn("configured profile %q does not exist, the %q profile configuration will be used\n", profileSet, activeProfile)
}

p.Debug(print.DebugLevel, "active configuration profile: %s", activeProfile)

configKeys := viper.AllSettings()
Expand Down
39 changes: 4 additions & 35 deletions internal/pkg/auth/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,7 @@ func setAuthFieldInEncodedTextFile(activeProfile string, key authFieldKey, value
if err != nil {
return err
}

configDir, err := os.UserConfigDir()
if err != nil {
return fmt.Errorf("get config dir: %w", err)
}

profileTextFileFolderName := textFileFolderName
if activeProfile != "" {
profileTextFileFolderName = filepath.Join(textFileFolderName, activeProfile)
}

textFileDir := filepath.Join(configDir, profileTextFileFolderName)
textFileDir := config.GetProfileFolderPath(activeProfile)
textFilePath := filepath.Join(textFileDir, textFileName)

contentEncoded, err := os.ReadFile(textFilePath)
Expand Down Expand Up @@ -178,17 +167,7 @@ func getAuthFieldFromEncodedTextFile(activeProfile string, key authFieldKey) (st
return "", err
}

configDir, err := os.UserConfigDir()
if err != nil {
return "", fmt.Errorf("get config dir: %w", err)
}

profileTextFileFolderName := textFileFolderName
if activeProfile != "" {
profileTextFileFolderName = filepath.Join(textFileFolderName, activeProfile)
}

textFileDir := filepath.Join(configDir, profileTextFileFolderName)
textFileDir := config.GetProfileFolderPath(activeProfile)
textFilePath := filepath.Join(textFileDir, textFileName)

contentEncoded, err := os.ReadFile(textFilePath)
Expand All @@ -215,20 +194,10 @@ func getAuthFieldFromEncodedTextFile(activeProfile string, key authFieldKey) (st
// If it doesn't, creates it with the content "{}" encoded.
// If it does, does nothing (and returns nil).
func createEncodedTextFile(activeProfile string) error {
configDir, err := os.UserConfigDir()
if err != nil {
return fmt.Errorf("get config dir: %w", err)
}

profileTextFileFolderName := textFileFolderName
if activeProfile != "" {
profileTextFileFolderName = filepath.Join(textFileFolderName, activeProfile)
}

textFileDir := filepath.Join(configDir, profileTextFileFolderName)
textFileDir := config.GetProfileFolderPath(activeProfile)
textFilePath := filepath.Join(textFileDir, textFileName)

err = os.MkdirAll(textFileDir, os.ModePerm)
err := os.MkdirAll(textFileDir, os.ModePerm)
if err != nil {
return fmt.Errorf("create file dir: %w", err)
}
Expand Down
64 changes: 49 additions & 15 deletions internal/pkg/auth/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/zalando/go-keyring"

"github.com/stackitcloud/stackit-cli/internal/pkg/config"
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
)

func TestSetGetAuthField(t *testing.T) {
Expand Down Expand Up @@ -183,7 +184,7 @@ func TestSetGetAuthFieldKeyring(t *testing.T) {
}{
{
description: "simple assignments with default profile",
activeProfile: "",
activeProfile: config.DefaultProfileName,
valueAssignments: []valueAssignment{
{
key: testField1,
Expand All @@ -201,7 +202,7 @@ func TestSetGetAuthFieldKeyring(t *testing.T) {
},
{
description: "overlapping assignments with default profile",
activeProfile: "",
activeProfile: config.DefaultProfileName,
valueAssignments: []valueAssignment{
{
key: testField1,
Expand Down Expand Up @@ -267,6 +268,12 @@ func TestSetGetAuthFieldKeyring(t *testing.T) {
t.Run(tt.description, func(t *testing.T) {
keyring.MockInit()

// Make sure profile name is valid
err := config.ValidateProfile(tt.activeProfile)
if err != nil {
t.Fatalf("Profile name \"%s\" is invalid: %v", tt.activeProfile, err)
}

for _, assignment := range tt.valueAssignments {
err := setAuthFieldInKeyring(tt.activeProfile, assignment.key, assignment.value)
if err != nil {
Expand Down Expand Up @@ -317,7 +324,7 @@ func TestSetGetAuthFieldEncodedTextFile(t *testing.T) {
}{
{
description: "simple assignments with default profile",
activeProfile: "",
activeProfile: config.DefaultProfileName,
valueAssignments: []valueAssignment{
{
key: testField1,
Expand All @@ -335,7 +342,7 @@ func TestSetGetAuthFieldEncodedTextFile(t *testing.T) {
},
{
description: "overlapping assignments with default profile",
activeProfile: "",
activeProfile: config.DefaultProfileName,
valueAssignments: []valueAssignment{
{
key: testField1,
Expand Down Expand Up @@ -399,6 +406,26 @@ func TestSetGetAuthFieldEncodedTextFile(t *testing.T) {

for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
// Make sure profile name is valid
err := config.ValidateProfile(tt.activeProfile)
if err != nil {
t.Fatalf("Profile name \"%s\" is invalid: %v", tt.activeProfile, err)
}

// Create profile if it does not exist
// Will be deleted at the end of the test
profileExists, err := config.ProfileExists(tt.activeProfile)
if err != nil {
t.Fatalf("Failed to check if profile exists: %v", err)
}
if !profileExists {
p := print.NewPrinter()
err := config.CreateProfile(p, tt.activeProfile, true, true)
if err != nil {
t.Fatalf("Failed to create profile: %v", err)
}
}

for _, assignment := range tt.valueAssignments {
err := setAuthFieldInEncodedTextFile(tt.activeProfile, assignment.key, assignment.value)
if err != nil {
Expand All @@ -424,6 +451,11 @@ func TestSetGetAuthFieldEncodedTextFile(t *testing.T) {
t.Errorf("Post-test cleanup failed: remove field \"%s\" from text file: %v. Please remove it manually", key, err)
}
}

err = deleteAuthFieldProfile(tt.activeProfile, profileExists)
if err != nil {
t.Errorf("Post-test cleanup failed: remove profile \"%s\": %v. Please remove it manually", tt.activeProfile, err)
}
})
}
}
Expand All @@ -443,17 +475,7 @@ func deleteAuthFieldInEncodedTextFile(activeProfile string, key authFieldKey) er
return err
}

configDir, err := os.UserConfigDir()
if err != nil {
return fmt.Errorf("get config dir: %w", err)
}

profileTextFileFolderName := textFileFolderName
if activeProfile != "" {
profileTextFileFolderName = filepath.Join(textFileFolderName, activeProfile)
}

textFileDir := filepath.Join(configDir, profileTextFileFolderName)
textFileDir := config.GetProfileFolderPath(activeProfile)
textFilePath := filepath.Join(textFileDir, textFileName)

contentEncoded, err := os.ReadFile(textFilePath)
Expand Down Expand Up @@ -483,3 +505,15 @@ func deleteAuthFieldInEncodedTextFile(activeProfile string, key authFieldKey) er
}
return nil
}

func deleteAuthFieldProfile(activeProfile string, profileExisted bool) error {
textFileDir := config.GetProfileFolderPath(activeProfile)
if !profileExisted {
// Remove the entire directory if the profile does not exist
err := os.RemoveAll(textFileDir)
if err != nil {
return fmt.Errorf("remove directory: %w", err)
}
}
return nil
}
39 changes: 26 additions & 13 deletions internal/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ const (
ServiceAccountCustomEndpointKey = "service_account_custom_endpoint"
SKECustomEndpointKey = "ske_custom_endpoint"

ProjectNameKey = "project_name"
ProjectNameKey = "project_name"
DefaultProfileName = "default"

AsyncDefault = false
SessionTimeLimitDefault = "2h"
)

const (
configFolder = "stackit"
defaultProfileName = "default"
configFolder = "stackit"

configFileName = "cli-config"
configFileExtension = "json"
Expand Down Expand Up @@ -83,21 +83,15 @@ var configFolderPath string
var profileFilePath string

func InitConfig() {
configDir, err := os.UserConfigDir()
cobra.CheckErr(err)

defaultConfigFolderPath = filepath.Join(configDir, configFolder)
profileFilePath = filepath.Join(defaultConfigFolderPath, fmt.Sprintf("%s.%s", profileFileName, profileFileExtension)) // Profile file path is in the default config folder
defaultConfigFolderPath = getInitialConfigDir()
profileFilePath = getInitialProfileFilePath() // Profile file path is in the default config folder

configProfile, err := GetProfile()
cobra.CheckErr(err)

configFolderPath = defaultConfigFolderPath
if configProfile != defaultProfileName {
configFolderPath = filepath.Join(configFolderPath, profileRootFolder, configProfile) // If a profile is set, use the profile config folder
}
configFolderPath = GetProfileFolderPath(configProfile)

configFilePath := filepath.Join(configFolderPath, fmt.Sprintf("%s.%s", configFileName, configFileExtension))
configFilePath := getConfigFilePath(configFolderPath)

// This hack is required to allow creating the config file with `viper.WriteConfig`
// see https://github.com/spf13/viper/issues/851#issuecomment-789393451
Expand Down Expand Up @@ -151,3 +145,22 @@ func setConfigDefaults() {
viper.SetDefault(ServiceAccountCustomEndpointKey, "")
viper.SetDefault(SKECustomEndpointKey, "")
}

func getConfigFilePath(configFolder string) string {
return filepath.Join(configFolder, fmt.Sprintf("%s.%s", configFileName, configFileExtension))
}

func getInitialConfigDir() string {
configDir, err := os.UserConfigDir()
cobra.CheckErr(err)

return filepath.Join(configDir, configFolder)
}

func getInitialProfileFilePath() string {
configFolderPath := defaultConfigFolderPath
if configFolderPath == "" {
configFolderPath = getInitialConfigDir()
}
return filepath.Join(configFolderPath, fmt.Sprintf("%s.%s", profileFileName, profileFileExtension))
}
56 changes: 56 additions & 0 deletions internal/pkg/config/config_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"fmt"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -69,3 +70,58 @@ func TestWrite(t *testing.T) {
})
}
}

func TestGetInitialConfigDir(t *testing.T) {
tests := []struct {
description string
}{
{
description: "base",
},
}

for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
actual := getInitialConfigDir()

userConfig, err := os.UserConfigDir()
if err != nil {
t.Fatalf("expected error to be nil, got %v", err)
}

expected := filepath.Join(userConfig, "stackit")
if actual != expected {
t.Fatalf("expected %s, got %s", expected, actual)
}
})
}
}

func TestGetInitialProfileFilePath(t *testing.T) {
tests := []struct {
description string
configFolderPath string
}{
{
description: "base",
configFolderPath: getInitialConfigDir(),
},
{
description: "empty config folder path",
configFolderPath: "",
},
}

for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
configFolderPath = getInitialConfigDir()

actual := getInitialProfileFilePath()

expected := filepath.Join(configFolderPath, fmt.Sprintf("%s.%s", profileFileName, profileFileExtension))
if actual != expected {
t.Fatalf("expected %s, got %s", expected, actual)
}
})
}
}
Loading