Skip to content
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

Use Viper's built-in configuration handling #1074

Closed
wants to merge 14 commits into from

Conversation

haitham911
Copy link
Collaborator

@haitham911 haitham911 commented Feb 18, 2025

what

-refactor the InitCliConfig function to use Viper's built-in configuration loading instead of manually processing each config file

why

  • Viper allows configuration from
    Files (YAML,YML, JSON, TOML, etc.).
    Environment variables.
    Flags.
    Remote sources
    This makes it easier to extend the configuration system in the future.

references

Summary by CodeRabbit

  • New Features

    • Introduced a centralized configuration management system that aggregates settings from multiple standard locations, ensuring consistent application behavior.
    • Added default configuration options for enhanced user experience.
  • Refactor

    • Streamlined the initialization process by consolidating redundant steps and improving error handling for a more reliable configuration setup.
    • Updated configuration paths to reference specific YAML files instead of directories, enhancing clarity in configuration management.

@haitham911 haitham911 requested a review from a team as a code owner February 18, 2025 23:05
@mergify mergify bot added the triage Needs triage label Feb 18, 2025
Copy link
Contributor

coderabbitai bot commented Feb 18, 2025

📝 Walkthrough

Walkthrough

This pull request streamlines the Atmos CLI configuration process. The InitCliConfig function in pkg/config/config.go is refactored to call a new LoadConfig function instead of manually initializing and reading configuration files from various sources. A new file, pkg/config/load.go, is introduced to encapsulate the logic for loading configuration using a Viper instance, setting default values, and merging configurations from system, home, working directory, and environment variables. The public interface remains the same while the internal configuration loading mechanism is centralized.

Changes

File Change Summary
pkg/config/config.go Refactored InitCliConfig to remove detailed configuration loading logic and instead delegate to the new LoadConfig function, eliminating manual Viper initialization and error handling.
pkg/config/load.go New file that introduces LoadConfig, a Viper instance initialization, and helper functions (setDefaultConfiguration, readSystemConfig, readHomeConfig, readWorkDirConfig, readEnvAmosConfigPath, mergeConfig) to manage configuration loading.
pkg/config/default.go Introduced default configuration management with NotFound error message and defaultCliConfig variable, providing comprehensive default settings for the Atmos CLI application.
tests/snapshots/... Updated expected configuration paths in test snapshots to reflect the change from directory paths to specific YAML file paths.
tests/test-cases/env.yaml Modified expected output pattern for atmos_cli_config_path to require .yaml extension instead of an unspecified one.

Possibly related PRs

Suggested labels

minor

Suggested reviewers

  • osterman
  • aknysh
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or @auto-summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @auto-title anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
pkg/config/load.go (2)

24-105: Consider DRY improvements in LoadConfig.
LoadConfig is comprehensive. Repeated patterns for reading config from various sources could be consolidated to simplify and reduce potential errors.


178-196: Double-check function naming.
readEnvAmosConfigPath might be a small naming slip compared to "ATMOS_CLI_CONFIG_PATH". For consistency, consider aligning the naming.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9206807 and 1cfec36.

📒 Files selected for processing (2)
  • pkg/config/config.go (1 hunks)
  • pkg/config/load.go (1 hunks)
🧰 Additional context used
🪛 golangci-lint (1.62.2)
pkg/config/load.go

20-20: field paths is unused

(unused)


21-21: field atmosFileNames is unused

(unused)


211-211: func applyDefaultConfiguration is unused

(unused)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (5)
pkg/config/load.go (4)

107-115: Defaults look good.
The default configuration assignments are clear and logically grouped. They ensure sensible fallback values for logs and Terraform usage.


117-139: System config logic is straightforward.
Merging from system directories is handled cleanly. This code helps ensure that global defaults are recognized.


141-158: Home config approach is clear.
The code thoroughly checks for the config file in the user’s home directory and logs a ConfigFileNotFoundError gracefully.


160-176: WorkDir config merges.
Similar pattern as readSystemConfig and readHomeConfig. Make sure the repeated checks remain consistent if the logic evolves.

pkg/config/config.go (1)

118-118: Refactored loading is clear.
Calling LoadConfig simplifies InitCliConfig significantly. The error handling is correct, and the flow remains consistent.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
pkg/config/default.go (1)

108-125: Function Marked as Unused

The static analysis tool flags applyDefaultConfiguration as unused. If this is intentional, consider removing it. Else, ensure it’s invoked where appropriate to apply defaults.

🧰 Tools
🪛 golangci-lint (1.62.2)

109-109: func applyDefaultConfiguration is unused

(unused)

pkg/config/load.go (2)

24-105: Consider enhancing debug logging.

The LoadConfig function handles configuration well, but could benefit from additional debug logging to help troubleshoot configuration issues in production.

Add debug logging before attempting to load each configuration source:

 func LoadConfig(configAndStacksInfo schema.ConfigAndStacksInfo) (schema.AtmosConfiguration, error) {
     v := viper.New()
     var atmosConfig schema.AtmosConfiguration
+    u.LogDebug("Initializing configuration loading")
     v.SetConfigType("yaml")

108-115: Consider adding more comprehensive defaults.

The function sets essential defaults but could include additional safety defaults for timeouts and retries.

Consider adding these defaults:

 func setDefaultConfiguration(v *viper.Viper) {
     v.SetDefault("components.helmfile.use_eks", true)
     v.SetDefault("components.terraform.append_user_agent",
         fmt.Sprintf("Atmos/%s (Cloud Posse; +https://atmos.tools)", version.Version))
     v.SetDefault("settings.inject_github_token", true)
     v.SetDefault("logs.file", "/dev/stderr")
     v.SetDefault("logs.level", "Info")
+    v.SetDefault("components.terraform.operation_timeout", "30m")
+    v.SetDefault("components.terraform.retry_attempts", 3)
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1cfec36 and 3ad2d48.

📒 Files selected for processing (6)
  • pkg/config/config.go (1 hunks)
  • pkg/config/default.go (1 hunks)
  • pkg/config/load.go (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden (1 hunks)
  • tests/test-cases/env.yaml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)
Learnt from: samtholiya
PR: cloudposse/atmos#955
File: tests/snapshots/TestCLICommands_atmos_validate_editorconfig_--help.stdout.golden:0-0
Timestamp: 2025-01-19T15:49:15.593Z
Learning: In future commits, the help text for Atmos CLI commands should be limited to only show component and stack parameters for commands that actually use them. This applies to the example usage section in command help text.
🪛 golangci-lint (1.62.2)
pkg/config/default.go

109-109: func applyDefaultConfiguration is unused

(unused)

pkg/config/load.go

20-20: field paths is unused

(unused)


21-21: field atmosFileNames is unused

(unused)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (9)
pkg/config/default.go (3)

1-16: Imports and Packaging Look Good

No issues with the package statement or imports, and the dependencies are relevant and used correctly.


18-22: Well-Defined Error Variable

Defining NotFound provides a clear message. Good user guidance on where to find sample configs.


23-105: Default Configuration Initialization Appears Valid

The default configuration covers all major sections comprehensively (Stacks, Components, Logs, etc.). No immediate concerns with naming conventions, structure, or duplication. Error handling seems sufficient.

tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden (1)

46-46: Path Update for YAML Config

Referencing a specific file instead of a directory provides clarity. Confirm that references in code match this new path.

tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)

148-148: Consistent YAML Configuration Reference

Shifting to “atmos.yaml” reflects the updated configuration approach. No further concerns.

pkg/config/config.go (1)

27-28: Well done on the refactoring!

The delegation of configuration loading to LoadConfig improves code organization while maintaining the same public interface. The post-processing steps are preserved, ensuring backward compatibility.

pkg/config/load.go (2)

19-22: Remove unused fields from ConfigSources struct.

The paths and atmosFileNames fields are currently unused. Consider removing them or documenting their intended future use.

🧰 Tools
🪛 golangci-lint (1.62.2)

20-20: field paths is unused

(unused)


21-21: field atmosFileNames is unused

(unused)


198-208: Fix error handling in mergeConfig function.

The function currently discards errors from MergeInConfig. This could mask configuration issues.

tests/test-cases/env.yaml (1)

19-19: Good update to the test expectations!

The updated path pattern correctly reflects the explicit YAML file requirement, aligning with the new configuration loading mechanism.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 18, 2025
@mergify mergify bot removed the triage Needs triage label Feb 18, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
pkg/config/default.go (1)

13-15: Enhance error message with environment variable name.

The error message is helpful but could be more specific about which environment variable users can set.

-		"\nYou can download a sample config and adapt it to your requirements from " +
+		"\nYou can set ATMOS_CLI_CONFIG_PATH environment variable or download a sample config from " +
 		"https://raw.githubusercontent.com/cloudposse/atmos/main/examples/quick-start-advanced/atmos.yaml")
pkg/config/load.go (4)

43-43: Remove redundant length check.

The condition if len(configFilePath) > 0 is redundant since configFilePath is already assigned from AtmosCliConfigPath which was checked for non-emptiness.

-		if len(configFilePath) > 0 {
			err := mergeConfig(v, configFilePath, CliConfigFileName)
-		}

116-119: Improve Windows path handling.

The Windows configuration path handling could be more robust by:

  1. Validating that the directory exists
  2. Using filepath.Join for path construction
 		appDataDir := os.Getenv(WindowsAppDataEnvVar)
 		if len(appDataDir) > 0 {
+			if _, err := os.Stat(appDataDir); err == nil {
 				configFilePath = appDataDir
+			}
 		}

126-132: Extract common error handling pattern.

The same error handling pattern for viper.ConfigFileNotFoundError is repeated in multiple places. Consider extracting it into a helper function.

+func handleConfigNotFoundError(err error) error {
+	if err != nil {
+		switch err.(type) {
+		case viper.ConfigFileNotFoundError:
+			return nil
+		default:
+			return err
+		}
+	}
+	return nil
+}

Also applies to: 145-151, 163-169, 179-186


47-47: Standardize logging patterns.

The trace logging uses inconsistent string formatting patterns. Some use fmt.Sprintf while others use string concatenation.

Standardize on fmt.Sprintf:

-				u.LogTrace(fmt.Sprintf("Not Found config file %s", configFilePath))
+				u.LogTrace(fmt.Sprintf("Config file not found: %s", configFilePath))
-				u.LogTrace(fmt.Sprintf("Not Found ENV var ATMOS_CLI_CONFIG_PATH=%s", configFilePath))
+				u.LogTrace(fmt.Sprintf("Environment variable not found: ATMOS_CLI_CONFIG_PATH=%s", configFilePath))
-		u.LogTrace(fmt.Sprintf("Found ENV var ATMOS_CLI_CONFIG_PATH=%s", configFilePath))
+		u.LogTrace(fmt.Sprintf("Found environment variable: ATMOS_CLI_CONFIG_PATH=%s", configFilePath))

Also applies to: 181-181, 187-187

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ad2d48 and 263d14a.

📒 Files selected for processing (2)
  • pkg/config/default.go (1 hunks)
  • pkg/config/load.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (2)
pkg/config/default.go (1)

95-95: Specify units for version check timeout.

The timeout value of 1000 lacks unit specification. Is this milliseconds, seconds, or something else?

Consider adding a comment or using a more explicit constant like DefaultVersionCheckTimeoutMs.

pkg/config/load.go (1)

197-203: Do not discard the error from MergeInConfig.

All outcomes of MergeInConfig return nil, ignoring potential errors. That can mask failures.

@osterman osterman changed the title Viper's built-in configuration Use Viper's built-in configuration handling Feb 19, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 19, 2025
@mergify mergify bot removed the triage Needs triage label Feb 19, 2025
@mergify mergify bot added the triage Needs triage label Feb 19, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
pkg/config/load.go (2)

184-193: ⚠️ Potential issue

Do not discard the error from MergeInConfig.

All outcomes of MergeInConfig return nil, ignoring potential errors. That can mask failures.

Apply this fix:

 func mergeConfig(v *viper.Viper, path string, fileName string) error {
   v.AddConfigPath(path)
   v.SetConfigName(fileName)
   err := v.MergeInConfig()
   if err != nil {
-    return nil
+    return err
   }
   return nil
 }

76-82: ⚠️ Potential issue

Guard against potential nil pointer dereference.

The code checks filepath.IsAbs(atmosConfig.CliConfigPath) without first verifying that CliConfigPath is not empty, which could lead to a panic.

Apply this fix:

-	if atmosConfig.CliConfigPath != "" && !filepath.IsAbs(atmosConfig.CliConfigPath) {
+	if atmosConfig.CliConfigPath != "" && !filepath.IsAbs(atmosConfig.CliConfigPath) {
 		absPath, err := filepath.Abs(atmosConfig.CliConfigPath)
 		if err != nil {
 			return atmosConfig, err
 		}
 		atmosConfig.CliConfigPath = absPath
 	}
🧹 Nitpick comments (1)
pkg/config/load.go (1)

24-92: Consider enhancing error messages for better debugging.

The LoadConfig function could provide more context in error messages to help users troubleshoot configuration issues. Consider wrapping errors with additional context about which configuration source failed to load.

Example enhancement:

 err := readSystemConfig(v)
 if err != nil {
-    return atmosConfig, err
+    return atmosConfig, fmt.Errorf("failed to load system config: %w", err)
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 263d14a and 9de9d7b.

📒 Files selected for processing (2)
  • pkg/config/config.go (1 hunks)
  • pkg/config/load.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (22)
  • GitHub Check: [mock-macos] tests/fixtures/scenarios/complete
  • GitHub Check: [mock-macos] examples/demo-vendoring
  • GitHub Check: [mock-macos] examples/demo-context
  • GitHub Check: [mock-macos] examples/demo-component-versions
  • GitHub Check: [mock-macos] examples/demo-atlantis
  • GitHub Check: [mock-windows] tests/fixtures/scenarios/complete
  • GitHub Check: [mock-windows] examples/demo-vendoring
  • GitHub Check: [mock-windows] examples/demo-context
  • GitHub Check: [mock-windows] examples/demo-component-versions
  • GitHub Check: [mock-windows] examples/demo-atlantis
  • GitHub Check: [mock-linux] tests/fixtures/scenarios/complete
  • GitHub Check: [mock-linux] examples/demo-vendoring
  • GitHub Check: [mock-linux] examples/demo-context
  • GitHub Check: [mock-linux] examples/demo-component-versions
  • GitHub Check: [lint] demo-context
  • GitHub Check: [k3s] demo-helmfile
  • GitHub Check: Acceptance Tests (macos-latest, macos)
  • GitHub Check: Acceptance Tests (windows-latest, windows)
  • GitHub Check: Acceptance Tests (ubuntu-latest, linux)
  • GitHub Check: Docker Lint
  • GitHub Check: [localstack] demo-localstack
  • GitHub Check: Summary
🔇 Additional comments (1)
pkg/config/config.go (1)

18-18: Well done on simplifying configuration loading!

The refactoring to use LoadConfig effectively leverages Viper's built-in configuration capabilities while maintaining the same functionality. This change aligns perfectly with the PR objectives.

@mergify mergify bot removed the triage Needs triage label Feb 19, 2025
@haitham911 haitham911 requested a review from osterman February 19, 2025 16:43
if err != nil {
switch err.(type) {
case viper.ConfigFileNotFoundError:
log.Debug("config not found ENV var ATMOS_CLI_CONFIG_PATH", "file", configFilePath)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log.Debug("config not found ENV var ATMOS_CLI_CONFIG_PATH", "file", configFilePath)
log.Debug("config not found from ENV”, “ATMOS_CLI_CONFIG_PATH", configFilePath)

Copy link

mergify bot commented Mar 2, 2025

💥 This pull request now has conflicts. Could you fix it @haitham911? 🙏

@mergify mergify bot added the conflict This PR has conflicts label Mar 2, 2025
@samtholiya
Copy link
Collaborator

While we are splitting these functions.

It would be great if we could followup with the following enhancement.
https://linear.app/cloudposse/issue/DEV-3093/create-a-cli-command-core-library

@haitham911 haitham911 closed this Mar 18, 2025
@mergify mergify bot removed the conflict This PR has conflicts label Mar 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants