From 73bc6e15fc8d5d17b5acf890f4aed9a676c31345 Mon Sep 17 00:00:00 2001
From: Youngjin Jo <youngjinjo@megazone.com>
Date: Thu, 14 Nov 2024 11:46:20 +0900
Subject: [PATCH 1/5] feat: add sync subcommand, which sync config.yaml and
 environments

Signed-off-by: Youngjin Jo <youngjinjo@megazone.com>
---
 cmd/config.go | 78 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 61 insertions(+), 17 deletions(-)

diff --git a/cmd/config.go b/cmd/config.go
index 9afff34..541493b 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -49,8 +49,8 @@ var configInitCmd = &cobra.Command{
 		// Determine environment name
 		var envName string
 		if localEnv != "" {
-			// Use local environment name directly
-			envName = localEnv
+			// Use local environment name directly with '-user' suffix
+			envName = fmt.Sprintf("%s-user", localEnv)
 			if urlStr == "" {
 				urlStr = "http://localhost:8080"
 			}
@@ -151,9 +151,11 @@ var envCmd = &cobra.Command{
 
 		// Handle environment switching
 		if switchEnv != "" {
-			configPath := filepath.Join(getConfigDir(), "environments", switchEnv+".yaml")
-			if _, err := os.Stat(configPath); os.IsNotExist(err) {
-				log.Fatalf("Environment '%s' not found.", switchEnv)
+			// Check for both .yaml and .yml extensions
+			if _, err := os.Stat(filepath.Join(getConfigDir(), "environments", switchEnv+".yaml")); os.IsNotExist(err) {
+				if _, err := os.Stat(filepath.Join(getConfigDir(), "environments", switchEnv+".yml")); os.IsNotExist(err) {
+					log.Fatalf("Environment '%s' not found.", switchEnv)
+				}
 			}
 
 			// Update the environment in ~/.spaceone/config.yaml
@@ -183,9 +185,11 @@ var envCmd = &cobra.Command{
 
 		// Handle environment removal with confirmation
 		if removeEnv != "" {
-			configPath := filepath.Join(getConfigDir(), "environments", removeEnv+".yaml")
-			if _, err := os.Stat(configPath); os.IsNotExist(err) {
-				log.Fatalf("Environment '%s' not found.", removeEnv)
+			// Check for both .yaml and .yml extensions
+			if _, err := os.Stat(filepath.Join(getConfigDir(), "environments", removeEnv+".yaml")); os.IsNotExist(err) {
+				if _, err := os.Stat(filepath.Join(getConfigDir(), "environments", removeEnv+".yml")); os.IsNotExist(err) {
+					log.Fatalf("Environment '%s' not found.", removeEnv)
+				}
 			}
 
 			// Ask for confirmation before deletion
@@ -194,11 +198,10 @@ var envCmd = &cobra.Command{
 			fmt.Scanln(&response)
 			response = strings.ToLower(strings.TrimSpace(response))
 
-			if response == "Y" || response == "y" {
+			if response == "y" {
 				// Remove the environment file
-				if err := os.Remove(configPath); err != nil {
-					log.Fatalf("Failed to remove environment '%s': %v", removeEnv, err)
-				}
+				os.Remove(filepath.Join(getConfigDir(), "environments", removeEnv+".yaml"))
+				os.Remove(filepath.Join(getConfigDir(), "environments", removeEnv+".yml"))
 
 				// Check if this environment is set in config.yaml and clear it if so
 				configFilePath := filepath.Join(getConfigDir(), "config.yaml")
@@ -208,7 +211,7 @@ var envCmd = &cobra.Command{
 				// Update environment to "no-env" if the deleted environment was the current one
 				if viper.GetString("environment") == removeEnv {
 					viper.Set("environment", "no-env")
-					pterm.Info.WithShowLineNumber(false).Printfln("Cleared current environment(default: %s/config.yaml)", getConfigDir())
+					pterm.Info.WithShowLineNumber(false).Printfln("Cleared current environment (default: %s/config.yaml)", getConfigDir())
 				}
 
 				// Remove the environment from the environments map if it exists
@@ -249,7 +252,7 @@ var envCmd = &cobra.Command{
 			pterm.Println("Available Environments:")
 			for _, entry := range entries {
 				name := entry.Name()
-				name = name[:len(name)-len(filepath.Ext(name))] // Remove ".yaml" extension
+				name = strings.TrimSuffix(name, filepath.Ext(name)) // Remove ".yaml" or ".yml" extension
 				if name == currentEnv {
 					pterm.FgGreen.Printf("  > %s (current)\n", name)
 				} else {
@@ -315,6 +318,46 @@ var showCmd = &cobra.Command{
 	},
 }
 
+// syncCmd syncs the environments in ~/.spaceone/environments with ~/.spaceone/config.yaml
+var syncCmd = &cobra.Command{
+	Use:   "sync",
+	Short: "Sync environments from the environments directory to config.yaml",
+	Long:  "Sync all environment files from the ~/.spaceone/environments directory to ~/.spaceone/config.yaml",
+	Run: func(cmd *cobra.Command, args []string) {
+		// Define paths
+		envDir := filepath.Join(getConfigDir(), "environments")
+		configPath := filepath.Join(getConfigDir(), "config.yaml")
+
+		// Ensure the config file is loaded
+		viper.SetConfigFile(configPath)
+		_ = viper.ReadInConfig()
+
+		// Iterate over each .yaml file in the environments directory
+		entries, err := os.ReadDir(envDir)
+		if err != nil {
+			log.Fatalf("Unable to read environments directory: %v", err)
+		}
+
+		for _, entry := range entries {
+			if !entry.IsDir() && (filepath.Ext(entry.Name()) == ".yaml" || filepath.Ext(entry.Name()) == ".yml") {
+				envName := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name()))
+
+				// Check if the environment already has a URL; if not, set it to an empty string
+				if viper.GetString(fmt.Sprintf("environments.%s.url", envName)) == "" {
+					viper.Set(fmt.Sprintf("environments.%s.url", envName), "")
+				}
+			}
+		}
+
+		// Save updated config to config.yaml
+		if err := viper.WriteConfig(); err != nil {
+			log.Fatalf("Failed to write updated config.yaml: %v", err)
+		}
+
+		pterm.Success.Println("Successfully synced environments from environments directory to config.yaml.")
+	},
+}
+
 // getConfigDir returns the directory where config files are stored
 func getConfigDir() string {
 	home, err := os.UserHomeDir()
@@ -395,7 +438,7 @@ func parseEnvNameFromURL(urlStr string) (string, error) {
 		re := regexp.MustCompile(`^(.*?)\.spaceone`)
 		matches := re.FindStringSubmatch(hostname)
 		if len(matches) == 2 {
-			return fmt.Sprintf("prd-%s", matches[1]), nil
+			return fmt.Sprintf("prd-%s-user", matches[1]), nil
 		}
 	}
 
@@ -404,7 +447,7 @@ func parseEnvNameFromURL(urlStr string) (string, error) {
 		re := regexp.MustCompile(`(.*)\.console\.dev\.spaceone\.dev`)
 		matches := re.FindStringSubmatch(hostname)
 		if len(matches) == 2 {
-			return fmt.Sprintf("dev-%s", matches[1]), nil
+			return fmt.Sprintf("dev-%s-user", matches[1]), nil
 		}
 		pterm.Error.WithShowLineNumber(false).Println("Invalid URL format for dev environment. Expected format: '<prefix>.console.dev.spaceone.dev'")
 		return "", fmt.Errorf("invalid dev URL format")
@@ -415,7 +458,7 @@ func parseEnvNameFromURL(urlStr string) (string, error) {
 		re := regexp.MustCompile(`(.*)\.console\.stg\.spaceone\.dev`)
 		matches := re.FindStringSubmatch(hostname)
 		if len(matches) == 2 {
-			return fmt.Sprintf("stg-%s", matches[1]), nil
+			return fmt.Sprintf("stg-%s-user", matches[1]), nil
 		}
 		pterm.Error.WithShowLineNumber(false).Println("Invalid URL format for stg environment. Expected format: '<prefix>.console.stg.spaceone.dev'")
 		return "", fmt.Errorf("invalid stg URL format")
@@ -431,6 +474,7 @@ func init() {
 	configCmd.AddCommand(configInitCmd)
 	configCmd.AddCommand(envCmd)
 	configCmd.AddCommand(showCmd)
+	configCmd.AddCommand(syncCmd)
 
 	// Defining flags for configInitCmd
 	configInitCmd.Flags().StringP("environment", "e", "", "Override environment name")

From 1967c154b9afd89692334977423f852dc2601a98 Mon Sep 17 00:00:00 2001
From: Youngjin Jo <youngjinjo@megazone.com>
Date: Thu, 14 Nov 2024 11:46:57 +0900
Subject: [PATCH 2/5] feat: read all .yaml and .yml

Signed-off-by: Youngjin Jo <youngjinjo@megazone.com>
---
 cmd/exec.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmd/exec.go b/cmd/exec.go
index 2759ba1..df61f30 100644
--- a/cmd/exec.go
+++ b/cmd/exec.go
@@ -57,7 +57,7 @@ func init() {
 }
 
 func loadConfig(environment string) (*Config, error) {
-	configPath := fmt.Sprintf("%s/.spaceone/environments/%s.yml", os.Getenv("HOME"), environment)
+	configPath := fmt.Sprintf("%s/.spaceone/environments/%s.yaml", os.Getenv("HOME"), environment)
 	data, err := os.ReadFile(configPath)
 	if err != nil {
 		return nil, fmt.Errorf("could not read config file: %w", err)
@@ -72,7 +72,7 @@ func loadConfig(environment string) (*Config, error) {
 }
 
 func fetchCurrentEnvironment() (string, error) {
-	envPath := fmt.Sprintf("%s/.spaceone/environment.yml", os.Getenv("HOME"))
+	envPath := fmt.Sprintf("%s/.spaceone/config.yaml", os.Getenv("HOME"))
 	data, err := os.ReadFile(envPath)
 	if err != nil {
 		return "", fmt.Errorf("could not read environment file: %w", err)

From 377898133e01030464523589869889b5ad90a744 Mon Sep 17 00:00:00 2001
From: Youngjin Jo <youngjinjo@megazone.com>
Date: Thu, 14 Nov 2024 14:14:35 +0900
Subject: [PATCH 3/5] feat: update config when user set up

Signed-off-by: Youngjin Jo <youngjinjo@megazone.com>
---
 cmd/config.go | 86 ++++++++++++++++++++-------------------------------
 config.yaml   |  0
 2 files changed, 34 insertions(+), 52 deletions(-)
 delete mode 100644 config.yaml

diff --git a/cmd/config.go b/cmd/config.go
index 541493b..4457f6e 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -40,26 +40,21 @@ var configInitCmd = &cobra.Command{
 		urlStr, _ := cmd.Flags().GetString("url")
 		localEnv, _ := cmd.Flags().GetString("local")
 
-		// If both url and local flags are empty, show help and return
 		if urlStr == "" && localEnv == "" {
 			cmd.Help()
 			return
 		}
 
-		// Determine environment name
 		var envName string
 		if localEnv != "" {
-			// Use local environment name directly with '-user' suffix
 			envName = fmt.Sprintf("%s-user", localEnv)
 			if urlStr == "" {
 				urlStr = "http://localhost:8080"
 			}
 		} else {
-			// Ensure URL has a scheme; default to "https" if missing
 			if !strings.HasPrefix(urlStr, "http://") && !strings.HasPrefix(urlStr, "https://") {
 				urlStr = "https://" + urlStr
 			}
-			// Parse environment name from URL
 			parsedEnvName, err := parseEnvNameFromURL(urlStr)
 			if err != nil {
 				pterm.Error.WithShowLineNumber(false).Println("Invalid URL format:", err)
@@ -69,73 +64,60 @@ var configInitCmd = &cobra.Command{
 			envName = parsedEnvName
 		}
 
-		// Override the parsed name if an explicit environment is provided
 		if environment != "" {
 			envName = environment
 		}
 
 		// Ensure environments directory exists
-		configPath := filepath.Join(getConfigDir(), "config.yaml")
+		configDir := filepath.Join(getConfigDir(), "environments")
+		if err := os.MkdirAll(configDir, 0755); err != nil {
+			pterm.Error.WithShowLineNumber(false).Println("Failed to create environments directory:", err)
+			return
+		}
+		envFilePath := filepath.Join(configDir, envName+".yaml")
+
+		// Create an empty environment file if it doesn't already exist
+		if _, err := os.Stat(envFilePath); os.IsNotExist(err) {
+			file, err := os.Create(envFilePath)
+			if err != nil {
+				pterm.Error.WithShowLineNumber(false).Println("Failed to create environment file:", err)
+				return
+			}
+			file.Close()
+		}
 
-		// Load existing config if it exists
+		// Set configuration in config.yaml
+		configPath := filepath.Join(getConfigDir(), "config.yaml")
 		viper.SetConfigFile(configPath)
 		_ = viper.ReadInConfig()
 
-		// Add or update the environment entry in viper
-		if urlStr != "" {
+		// Add or update the environment entry in config.yaml
+		if !viper.IsSet(fmt.Sprintf("environments.%s", envName)) {
 			viper.Set(fmt.Sprintf("environments.%s.url", envName), urlStr)
-		} else {
-			viper.Set(fmt.Sprintf("environments.%s", envName), "local")
 		}
 
-		// Set the default environment to the new envName
-		viper.Set("environment", envName)
-
-		// Serialize config data with 2-space indentation
-		configData := viper.AllSettings()
-		yamlData, err := yaml.Marshal(configData)
-		if err != nil {
-			pterm.Error.WithShowLineNumber(false).Println("Failed to encode YAML data:", err)
-			return
+		var baseURL string
+		if strings.HasPrefix(envName, "dev") {
+			baseURL = "grpc+ssl://identity.api.dev.spaceone.dev:443/v1"
+		} else if strings.HasPrefix(envName, "stg") {
+			baseURL = "grpc+ssl://identity.api.stg.spaceone.dev:443/v1"
 		}
 
-		// Write the serialized YAML to file with 2-space indentation
-		file, err := os.Create(configPath)
-		if err != nil {
-			pterm.Error.WithShowLineNumber(false).Println("Failed to write to config.yaml:", err)
-			return
+		if baseURL != "" {
+			viper.Set(fmt.Sprintf("environments.%s.endpoint", envName), baseURL)
 		}
-		defer file.Close()
 
-		if _, err := file.Write(yamlData); err != nil {
-			pterm.Error.WithShowLineNumber(false).Println("Failed to write YAML data to file:", err)
+		// Set the current environment
+		viper.Set("environment", envName)
+
+		// Write the updated configuration to config.yaml
+		if err := viper.WriteConfig(); err != nil {
+			pterm.Error.WithShowLineNumber(false).Println("Failed to write updated config.yaml:", err)
 			return
 		}
 
 		pterm.Success.WithShowLineNumber(false).
-			Printfln("Environment '%s' successfully initialized and set as the current environment in '%s/config.yaml'", envName, getConfigDir())
-
-		// After successfully writing to config.yaml, create the environment-specific YAML file
-		envFilePath := filepath.Join(getConfigDir(), "environments", fmt.Sprintf("%s.yaml", envName))
-
-		// Ensure the environments directory exists
-		environmentsDir := filepath.Dir(envFilePath)
-		if _, err := os.Stat(environmentsDir); os.IsNotExist(err) {
-			os.MkdirAll(environmentsDir, os.ModePerm)
-		}
-
-		// Create a blank environment-specific file if it doesn't exist
-		if _, err := os.Stat(envFilePath); os.IsNotExist(err) {
-			file, err := os.Create(envFilePath)
-			if err != nil {
-				pterm.Error.WithShowLineNumber(false).Println("Failed to create environment file:", err)
-				return
-			}
-			defer file.Close()
-			pterm.Success.WithShowLineNumber(false).Printfln("Created environment-specific file: %s", envFilePath)
-		} else {
-			pterm.Info.WithShowLineNumber(false).Printfln("Environment file already exists: %s", envFilePath)
-		}
+			Printfln("Environment '%s' successfully initialized with configuration in '%s/config.yaml'", envName, getConfigDir())
 	},
 }
 
diff --git a/config.yaml b/config.yaml
deleted file mode 100644
index e69de29..0000000

From 10c0428f59e6d3f8a1c9da3e206392e1005040f0 Mon Sep 17 00:00:00 2001
From: Youngjin Jo <youngjinjo@megazone.com>
Date: Thu, 14 Nov 2024 14:24:20 +0900
Subject: [PATCH 4/5] feat: modify login code, which is getting from
 config.yaml

Signed-off-by: Youngjin Jo <youngjinjo@megazone.com>
---
 cmd/login.go | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/cmd/login.go b/cmd/login.go
index f55a8c0..c0502f1 100644
--- a/cmd/login.go
+++ b/cmd/login.go
@@ -32,6 +32,7 @@ It will prompt you for your User ID, Password, and fetch the Domain ID automatic
 }
 
 func executeLogin(cmd *cobra.Command, args []string) {
+	// Load the environment-specific configuration
 	loadEnvironmentConfig()
 
 	token := viper.GetString("token")
@@ -44,12 +45,6 @@ func executeLogin(cmd *cobra.Command, args []string) {
 		pterm.Warning.Println("Saved token is invalid, proceeding with login.")
 	}
 
-	// If no URL is provided, check if this is a first login
-	if providedUrl == "" {
-		pterm.Error.Println("URL must be provided with the -u flag for initial login or a valid token must be provided.")
-		exitWithError()
-	}
-
 	userID, password := promptCredentials()
 
 	re := regexp.MustCompile(`https://(.*?)\.`)
@@ -125,7 +120,7 @@ func loadEnvironmentConfig() {
 	}
 
 	// Load the main environment file to get the current environment
-	viper.SetConfigFile(filepath.Join(homeDir, ".spaceone", "environment.yml"))
+	viper.SetConfigFile(filepath.Join(homeDir, ".spaceone", "config.yaml"))
 	if err := viper.ReadInConfig(); err != nil {
 		pterm.Error.Println("Failed to read environment file:", err)
 		exitWithError()
@@ -133,16 +128,24 @@ func loadEnvironmentConfig() {
 
 	currentEnvironment := viper.GetString("environment")
 	if currentEnvironment == "" {
-		pterm.Error.Println("No environment specified in environment.yml")
+		pterm.Error.Println("No environment specified in config.yaml")
 		exitWithError()
 	}
 
-	// Load the environment-specific configuration file
-	viper.SetConfigFile(filepath.Join(homeDir, ".spaceone", "environments", currentEnvironment+".yml"))
-	if err := viper.MergeInConfig(); err != nil {
-		pterm.Error.Println("Failed to read environment-specific configuration file:", err)
+	// Load the environment-specific file to get the endpoint
+	envConfig := viper.Sub(fmt.Sprintf("environments.%s", currentEnvironment))
+	if envConfig == nil {
+		pterm.Error.Printf("No configuration found for environment '%s' in config.yaml\n", currentEnvironment)
 		exitWithError()
 	}
+
+	providedUrl = envConfig.GetString("endpoint")
+	if providedUrl == "" {
+		pterm.Error.Printf("No endpoint found for the current environment '%s' in config.yaml\n", currentEnvironment)
+		exitWithError()
+	}
+
+	pterm.Info.Printf("Using endpoint: %s\n", providedUrl)
 }
 
 func determineScope(roleType string, workspaceCount int) string {
@@ -426,19 +429,19 @@ func saveToken(newToken string) {
 	}
 
 	// Load the main environment file to get the current environment
-	viper.SetConfigFile(filepath.Join(homeDir, ".spaceone", "environment.yml"))
+	viper.SetConfigFile(filepath.Join(homeDir, ".spaceone", "config.yaml"))
 	if err := viper.ReadInConfig(); err != nil {
 		pterm.Error.Println("Failed to read environment file:", err)
 		exitWithError()
 	}
 	currentEnvironment := viper.GetString("environment")
 	if currentEnvironment == "" {
-		pterm.Error.Println("No environment specified in environment.yml")
+		pterm.Error.Println("No environment specified in environment.yaml")
 		exitWithError()
 	}
 
 	// Path to the environment-specific file
-	envFilePath := filepath.Join(homeDir, ".spaceone", "environments", currentEnvironment+".yml")
+	envFilePath := filepath.Join(homeDir, ".spaceone", "environments", currentEnvironment+".yaml")
 
 	// Read the file line by line, replacing or adding the token line if needed
 	file, err := os.Open(envFilePath)

From 6f5a7d520de7791e99a11ac6d869c8e967a8eab9 Mon Sep 17 00:00:00 2001
From: Youngjin Jo <youngjinjo@megazone.com>
Date: Thu, 14 Nov 2024 14:56:15 +0900
Subject: [PATCH 5/5] feat: modify login process

Signed-off-by: Youngjin Jo <youngjinjo@megazone.com>
---
 cmd/login.go | 46 +++++++++++++++++++++++++---------------------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/cmd/login.go b/cmd/login.go
index c0502f1..0c02eae 100644
--- a/cmd/login.go
+++ b/cmd/login.go
@@ -11,7 +11,6 @@ import (
 	"net/http"
 	"os"
 	"path/filepath"
-	"regexp"
 	"strings"
 	"time"
 
@@ -35,6 +34,13 @@ func executeLogin(cmd *cobra.Command, args []string) {
 	// Load the environment-specific configuration
 	loadEnvironmentConfig()
 
+	// Set baseUrl directly from providedUrl loaded in loadEnvironmentConfig
+	baseUrl := providedUrl
+	if baseUrl == "" {
+		pterm.Error.Println("No token endpoint specified in the configuration file.")
+		exitWithError()
+	}
+
 	token := viper.GetString("token")
 	if token != "" && !isTokenExpired(token) {
 		pterm.Info.Println("Existing token found and it is still valid. Attempting to authenticate with saved credentials.")
@@ -47,44 +53,44 @@ func executeLogin(cmd *cobra.Command, args []string) {
 
 	userID, password := promptCredentials()
 
-	re := regexp.MustCompile(`https://(.*?)\.`)
-	matches := re.FindStringSubmatch(providedUrl)
-	if len(matches) < 2 {
-		pterm.Error.Println("Invalid URL format.")
-		exitWithError()
-	}
-	name := matches[1]
-
-	baseUrl := viper.GetString("base_url")
-	if baseUrl == "" {
-		pterm.Error.Println("No token endpoint specified in the configuration file.")
+	// Extract the middle part of the environment name for `name`
+	currentEnvironment := viper.GetString("environment")
+	nameParts := strings.Split(currentEnvironment, "-")
+	if len(nameParts) < 3 {
+		pterm.Error.Println("Environment name format is invalid.")
 		exitWithError()
 	}
+	name := nameParts[1] // Extract the middle part, e.g., "cloudone" from "dev-cloudone-user"
 
+	// Fetch Domain ID using the base URL and domain name
 	domainID, err := fetchDomainID(baseUrl, name)
 	if err != nil {
 		pterm.Error.Println("Failed to fetch Domain ID:", err)
 		exitWithError()
 	}
 
+	// Issue tokens (access token and refresh token) using user credentials
 	accessToken, refreshToken, err := issueToken(baseUrl, userID, password, domainID)
 	if err != nil {
 		pterm.Error.Println("Failed to retrieve token:", err)
 		exitWithError()
 	}
 
+	// Fetch workspaces available to the user
 	workspaces, err := fetchWorkspaces(baseUrl, accessToken)
 	if err != nil {
 		pterm.Error.Println("Failed to fetch workspaces:", err)
 		exitWithError()
 	}
 
+	// Fetch Domain ID and Role Type using the access token
 	domainID, roleType, err := fetchDomainIDAndRole(baseUrl, accessToken)
 	if err != nil {
 		pterm.Error.Println("Failed to fetch Domain ID and Role Type:", err)
 		exitWithError()
 	}
 
+	// Determine the appropriate scope and workspace ID based on the role type
 	scope := determineScope(roleType, len(workspaces))
 	var workspaceID string
 	if roleType == "DOMAIN_ADMIN" {
@@ -100,12 +106,14 @@ func executeLogin(cmd *cobra.Command, args []string) {
 		scope = "WORKSPACE"
 	}
 
+	// Grant a new access token using the refresh token and selected scope
 	newAccessToken, err := grantToken(baseUrl, refreshToken, scope, domainID, workspaceID)
 	if err != nil {
 		pterm.Error.Println("Failed to retrieve new access token:", err)
 		exitWithError()
 	}
 
+	// Save the new access token
 	saveToken(newAccessToken)
 	pterm.Success.Println("Successfully logged in and saved token.")
 }
@@ -122,24 +130,20 @@ func loadEnvironmentConfig() {
 	// Load the main environment file to get the current environment
 	viper.SetConfigFile(filepath.Join(homeDir, ".spaceone", "config.yaml"))
 	if err := viper.ReadInConfig(); err != nil {
-		pterm.Error.Println("Failed to read environment file:", err)
+		pterm.Error.Println("Failed to read config.yaml:", err)
 		exitWithError()
 	}
 
+	// Get the currently selected environment
 	currentEnvironment := viper.GetString("environment")
 	if currentEnvironment == "" {
 		pterm.Error.Println("No environment specified in config.yaml")
 		exitWithError()
 	}
 
-	// Load the environment-specific file to get the endpoint
-	envConfig := viper.Sub(fmt.Sprintf("environments.%s", currentEnvironment))
-	if envConfig == nil {
-		pterm.Error.Printf("No configuration found for environment '%s' in config.yaml\n", currentEnvironment)
-		exitWithError()
-	}
-
-	providedUrl = envConfig.GetString("endpoint")
+	// Retrieve the endpoint for the current environment
+	endpointKey := fmt.Sprintf("environments.%s.endpoint", currentEnvironment)
+	providedUrl = viper.GetString(endpointKey)
 	if providedUrl == "" {
 		pterm.Error.Printf("No endpoint found for the current environment '%s' in config.yaml\n", currentEnvironment)
 		exitWithError()