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

feat: make strict variables parsing #23

Merged
merged 3 commits into from
Apr 7, 2025
Merged

feat: make strict variables parsing #23

merged 3 commits into from
Apr 7, 2025

Conversation

eynopv
Copy link
Owner

@eynopv eynopv commented Apr 7, 2025

Summary by CodeRabbit

  • Refactor
    • Updated internal variable handling for improved type safety and clarity in command execution and configuration resolution.
  • New Features
    • Introduced a structured variable type for enhanced management and validation of variable values.
    • Added error handling for unsupported variable types to improve user feedback.
  • Tests
    • Added comprehensive test coverage for JSON and YAML parsing to ensure robust and reliable variable processing.

Copy link

coderabbitai bot commented Apr 7, 2025

Walkthrough

This pull request refactors the handling of variable types across multiple components by replacing generic maps (map[string]any) with a new custom type (variables.Variables). Function and method signatures in CLI commands and template resolution logic have been updated accordingly. Additionally, a new error variable is added for unsupported variable types. A dedicated package for variables.Variables is introduced with JSON and YAML unmarshalling capabilities along with corresponding tests. Minor changes to error handling in the main command file are also included.

Changes

File(s) Change Summary
cmd/root.go, cmd/run.go, pkg/param/param.go, pkg/request/template.go Updated variable type declarations and function/method signatures from map[string]any to variables.Variables.
internal/errorsx/errorsx.go Added new error variable ErrUnsupportedVariablesValue with the message "unsupported variables type".
main.go Removed local error handling for cmd.Execute(), delegating error management to Cobra.
pkg/variables/variables.go, pkg/variables/variables_test.go Introduced the custom variables.Variables type with UnmarshalJSON and UnmarshalYAML methods for JSON/YAML decoding and added tests for these methods.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Variables

    Note over Caller,Variables: JSON Unmarshalling
    Caller->>Variables: UnmarshalJSON(data)
    Variables->>Variables: Parse JSON into temp map
    Variables->>Variables: Validate value types (string, float64, bool, nil)
    Variables-->>Caller: Return parsed Variables or error

    Note over Caller,Variables: YAML Unmarshalling
    Caller->>Variables: UnmarshalYAML(yamlNode)
    Variables->>Variables: Convert YAML to JSON
    Variables->>Variables: Call UnmarshalJSON(convertedData)
    Variables-->>Caller: Return parsed Variables or error
Loading

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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 to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai 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

@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 (4)
pkg/variables/variables.go (2)

14-32: Strict validation for variable types in UnmarshalJSON

The implementation correctly limits variable values to primitive types (string, float64, bool, nil) and rejects complex types like arrays and objects. This aligns with the PR objective of making variable parsing more strict.

Consider enhancing the error message to include the actual type that was rejected, not just the key name, to make debugging easier.

-			return fmt.Errorf("%w: key %s", errorsx.ErrUnsupportedVariablesValue, key)
+			return fmt.Errorf("%w: key %s has unsupported type %T", errorsx.ErrUnsupportedVariablesValue, key, value)

34-46: UnmarshalYAML implementation via JSON conversion

The approach of converting YAML to JSON before using UnmarshalJSON ensures consistent validation, but introduces an extra marshalling step. This is a reasonable trade-off for code simplicity and consistency.

Consider adding comments explaining why this approach was chosen over direct YAML validation.

 func (v *Variables) UnmarshalYAML(value *yaml.Node) error {
+	// Convert YAML to JSON to reuse the same type validation logic in UnmarshalJSON
 	var raw any
 	if err := value.Decode(&raw); err != nil {
 		return err
 	}
pkg/variables/variables_test.go (2)

10-65: Test cases for UnmarshalJSON cover relevant scenarios

The test cases appropriately verify that:

  • Primitive types (boolean, integer, float, string) are accepted
  • Complex types (lists, nested objects) are rejected with appropriate error messages

Consider adding a verification of the actual content of the Variables map after successful unmarshalling to ensure the data is preserved correctly.

 			} else {
 				assert.NoError(t, err)
+				// Verify the content of the parsed variables
+				switch tt.name {
+				case "boolean":
+					assert.Equal(t, true, v["boolean"])
+				case "integer":
+					assert.Equal(t, float64(3), v["integer"])
+				case "float":
+					assert.Equal(t, 3.21, v["float"])
+				case "string":
+					assert.Equal(t, "hello, world", v["string"])
+				}
 			}

124-131: Helper function for YAML node creation

The yamlNode function simplifies test setup, but it panics on unmarshalling errors which could make test failures harder to debug.

Consider handling errors more gracefully in this test helper.

 func yamlNode(s string) *yaml.Node {
 	var node yaml.Node
 	if err := yaml.Unmarshal([]byte(s), &node); err != nil {
-		panic(err)
+		// In a test helper, we can use t.Fatalf, but since we don't have access to t here,
+		// we'll return a nil node, which will cause the test to fail with a clear error.
+		return nil
 	}
 
 	return node.Content[0]
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 933b3a8 and 6360949.

📒 Files selected for processing (8)
  • cmd/root.go (2 hunks)
  • cmd/run.go (2 hunks)
  • internal/errorsx/errorsx.go (1 hunks)
  • main.go (1 hunks)
  • pkg/param/param.go (1 hunks)
  • pkg/request/template.go (2 hunks)
  • pkg/variables/variables.go (1 hunks)
  • pkg/variables/variables_test.go (1 hunks)
🧰 Additional context used
🧬 Code Definitions (7)
main.go (1)
cmd/root.go (1)
  • Execute (74-76)
pkg/request/template.go (2)
pkg/variables/variables.go (1)
  • Variables (12-12)
cmd/root.go (1)
  • Variables (53-53)
pkg/variables/variables_test.go (3)
pkg/variables/variables.go (1)
  • Variables (12-12)
cmd/root.go (1)
  • Variables (53-53)
internal/assert/assert.go (2)
  • ErrorContains (49-55)
  • NoError (41-47)
pkg/param/param.go (2)
pkg/variables/variables.go (1)
  • Variables (12-12)
cmd/root.go (1)
  • Variables (53-53)
cmd/run.go (2)
pkg/variables/variables.go (1)
  • Variables (12-12)
cmd/root.go (1)
  • Variables (53-53)
cmd/root.go (1)
pkg/variables/variables.go (1)
  • Variables (12-12)
pkg/variables/variables.go (2)
cmd/root.go (1)
  • Variables (53-53)
internal/errorsx/errorsx.go (1)
  • ErrUnsupportedVariablesValue (13-13)
🔇 Additional comments (13)
main.go (1)

8-9:

❓ Verification inconclusive

Ensure error handling is sufficient for strict variable parsing

The change delegates error handling to the Cobra library instead of explicitly handling it in main.go. While this simplifies the code, make sure Cobra's error handling behavior is appropriate for your use case, especially considering the focus on stricter variable parsing in this PR.

I recommend running the following script to verify how Cobra handles errors and if it properly displays variable parsing errors to the user:


🏁 Script executed:

#!/bin/bash
# Verify how Cobra handles errors in the application

# Find examples of how Execute() is used in the codebase
rg -A 5 "Execute\(\)" --type go

# Check for error handling patterns in Cobra initialization
rg "cobra\.Command" -A 10 -B 10 --type go | grep -E "Error|err"

# Look for Cobra error handling documentation references
cat README.md | grep -i "error" || echo "No error handling documentation in README"

Length of output: 780


Ensure Cobra's Error Handling Covers Strict Variable Parsing

After verifying the codebase:

  • The output confirms that error handling for strict variable parsing is primarily managed in cmd/root.go via callbacks like prepareVariables() and prepareHeaders().
  • In main.go, delegating error handling using _ = cmd.Execute() is acceptable given that Cobra's internal mechanisms catch and propagate errors.
  • Please ensure that errors from strict variable parsing are presented clearly to the user. If custom error output is required for better clarity, consider enhancing the error logging or message formatting in the Cobra command callbacks.
internal/errorsx/errorsx.go (1)

13-13: LGTM: New error type for unsupported variables

The addition of ErrUnsupportedVariablesValue aligns with the PR objective of implementing stricter variable parsing. This error will be useful for providing clear error messages when users attempt to use unsupported variable types with the new variables.Variables structure.

pkg/param/param.go (2)

7-8: LGTM: Clean import addition

The import of the variables package is correctly added with a blank line for separation from the standard library imports, maintaining good code organization.


13-13:

✅ Verification successful

LGTM: Updated parameter type to use the new Variables type

Changing the parameter type from map[string]any to variables.Variables is consistent with the PR's objective of implementing stricter variable parsing. Since the function body treats the parameter as a map with string keys, this change should maintain the existing functionality while improving type safety.

Let's verify that the Variables type is used consistently throughout the codebase:


🏁 Script executed:

#!/bin/bash
# Check for consistent usage of variables.Variables type

# Find all occurrences of variables.Variables in type declarations
echo "Searching for variables.Variables usage in type declarations..."
rg "variables\.Variables" --type go

# Find all occurrences of map[string]any which might need to be updated
echo "Searching for potential map[string]any that might need updating..."
rg "map\[string\]any" --type go

# Check the definition of variables.Variables
echo "Checking the definition of variables.Variables..."
rg "type Variables" --type go

Length of output: 2209


LGTM: Verified consistent usage of variables.Variables across the codebase.

  • The function signatures in both pkg/param/param.go and pkg/request/template.go, as well as other parts of the project, correctly use variables.Variables.
  • The type definition (type Variables map[string]any in pkg/variables/variables.go) confirms that this alias encapsulates the expected behavior while enhancing type clarity.
  • Occasional references to map[string]any in tests (e.g., in pkg/param/param_test.go and elsewhere) are acceptable since they directly construct test data, relying on the underlying definition of variables.Variables.

No further changes are required.

cmd/root.go (2)

16-16: LGTM: Added import for variables package

The import of the variables package is correctly added, allowing the use of the specialized variables.Variables type.


53-53:

❓ Verification inconclusive

LGTM: Updated Variables declaration to use the new type

Changing the Variables declaration from a generic map[string]any{} to variables.Variables aligns with the PR objective of implementing stricter variable parsing. This provides better type safety and makes the code more maintainable.

Let's verify that Variables is properly initialized:


🏁 Script executed:

#!/bin/bash
# Check if Variables is properly initialized

# Look for Variables initialization
echo "Searching for Variables initialization..."
rg "Variables\s*=" --type go

# Check if there are any places where Variables needs to be initialized
echo "Checking if there are any functions that might need to initialize Variables..."
rg "func.*init" -A 15 --type go | grep -A 10 -B 10 "Variables"

# Check the definition of variables.Variables constructor if any
echo "Checking for any constructor methods for variables.Variables..."
rg "func New.*Variables" --type go

Length of output: 1398


Verification: Ensure Proper Initialization of variables.Variables

The updated declaration in cmd/root.go (line 53) successfully changes Variables from a generic map to the stricter variables.Variables type. This aligns with the PR objective of enforcing better type safety. However, our search did not reveal any explicit initialization (e.g. an assignment or a constructor call) for this field. It appears that the code relies on its zero-value (or deferred initialization) behavior. Please manually verify that this implicit initialization is intentional and that any subsequent usage of Variables correctly handles its uninitialized state if it’s a map or similar container.

  • File: cmd/root.go
    • Line: 53 – Declaration updated to variables.Variables
  • Observations:
    • No explicit assignment (i.e. Variables = ...) was found.
    • No constructor like New…Variables is being used.
    • The init() function sets flags for related input variables (e.g. VariablesInput) but does not explicitly initialize the Variables field.
  • Action: Manually verify that the intended zero-value (or deferred initialization) of variables.Variables is correct per the design of the PR.
pkg/request/template.go (2)

12-12: Added import for the new variables package

The new import is consistent with the updated function signature in line 32, where generic map types are being replaced with variables.Variables for stricter type validation.


32-32: LGTM: Updated parameter type to use the custom Variables type

This change replaces map[string]any with variables.Variables, improving type safety by restricting allowed variable types. This is consistent with the PR objective of making variable parsing more strict.

pkg/variables/variables.go (1)

12-12: New Variables type definition as map alias

This type alias forms the foundation for adding custom behavior to variable maps while maintaining compatibility with existing code that expects a map structure.

cmd/run.go (3)

13-13: Added import for variables package

Consistent with the function signature changes in the file.


18-18: Updated variables parameter type in runCommandFunction

Changed from map[string]any to variables.Variables, consistent with the PR objective of standardizing on the new type throughout the codebase.


47-47: Updated variables parameter type in runRequest

Changed from map[string]any to variables.Variables, consistent with the PR objective of standardizing on the new type throughout the codebase.

pkg/variables/variables_test.go (1)

67-122: Test cases for UnmarshalYAML mirror JSON tests

Good practice to have equivalent test cases for both JSON and YAML unmarshalling, ensuring consistent behavior regardless of input format.

Copy link

@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 (5)
pkg/variables/variables_test.go (5)

10-51: Consider expanding test coverage for JSON unmarshalling.

The test cases for JSON unmarshalling cover basic primitive types and correctly verify that unsupported types like lists and nested objects are rejected. However, you might want to consider a few additional test cases:

  1. Empty objects ({})
  2. Null values ({"key": null})
  3. Multiple fields in a single object
  4. Very large numbers that might cause overflow
// Additional test cases to consider
{
    name:    "empty object",
    data:    []byte(`{}`),
    wantErr: false,
},
{
    name:    "null value",
    data:    []byte(`{"null": null}`),
    wantErr: false, // or true depending on your requirements
},
{
    name:    "multiple fields",
    data:    []byte(`{"a": 1, "b": "hello", "c": true}`),
    wantErr: false,
}

53-65: Consider verifying the actual parsed values.

The tests correctly verify error conditions, but they don't check that the actual values were parsed correctly in the success cases. Consider adding assertions to verify that the parsed values match the expected values.

// Example addition to success case testing
if !tt.wantErr {
    assert.NoError(t, err)
    
    // Verify the parsed values
    switch tt.name {
    case "boolean":
        assert.Equal(t, true, v["boolean"])
    case "integer":
        assert.Equal(t, float64(3), v["integer"]) // JSON numbers are parsed as float64
    // Add cases for other types
    }
}

110-122: Consider verifying the actual parsed values for YAML as well.

Similar to the JSON tests, the YAML tests could benefit from assertions that verify the actual parsed values in addition to checking for errors.

// Example addition to success case testing
if !tt.wantErr {
    assert.NoError(t, err)
    
    // Verify the parsed values
    switch tt.name {
    case "boolean":
        assert.Equal(t, true, v["boolean"])
    case "integer":
        assert.Equal(t, int(3), v["integer"]) // YAML numbers might be parsed differently
    // Add cases for other types
    }
}

124-131: Improve error handling in the yamlNode helper function.

The yamlNode function silently returns nil if YAML unmarshalling fails, which could make test failures harder to debug. Consider adding a panic or returning the error to make potential issues more visible.

-func yamlNode(s string) *yaml.Node {
+func yamlNode(s string) *yaml.Node {
 	var node yaml.Node
 	if err := yaml.Unmarshal([]byte(s), &node); err != nil {
-		return nil
+		panic(fmt.Sprintf("failed to unmarshal YAML: %v", err))
 	}
 
 	return node.Content[0]
 }

10-131: Document the strict type restrictions for Variables.

The tests show that the Variables type only supports primitive types (boolean, integer, float, string) and rejects lists and nested objects. This important constraint should be documented in the implementation file and possibly in these tests.

Consider adding a comment at the beginning of each test function to explain the purpose and restrictions:

// TestVariables_UnmarshalJSON tests that the Variables type correctly unmarshals
// JSON data, accepting only primitive types (boolean, integer, float, string)
// and rejecting lists and nested objects.
func TestVariables_UnmarshalJSON(t *testing.T) {
    // ...
}

// TestVariables_UnmarshalYAML tests that the Variables type correctly unmarshals
// YAML data, accepting only primitive types (boolean, integer, float, string)
// and rejecting lists and nested objects.
func TestVariables_UnmarshalYAML(t *testing.T) {
    // ...
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6360949 and e1c64d7.

📒 Files selected for processing (2)
  • pkg/variables/variables.go (1 hunks)
  • pkg/variables/variables_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/variables/variables.go
🧰 Additional context used
🧬 Code Definitions (1)
pkg/variables/variables_test.go (2)
pkg/variables/variables.go (1)
  • Variables (12-12)
internal/assert/assert.go (2)
  • ErrorContains (49-55)
  • NoError (41-47)
🔇 Additional comments (2)
pkg/variables/variables_test.go (2)

1-8: Good package organization and imports.

The package declaration and imports look clean and organized, with appropriate use of the assert package from the internal directory and the yaml.v3 package with an alias.


67-108: Consistent test structure for YAML unmarshalling.

The test structure for YAML unmarshalling mirrors the JSON tests, which is good for consistency. The same suggestions for additional test cases apply here as well.

@eynopv eynopv merged commit 5eaadaa into master Apr 7, 2025
3 checks passed
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.

1 participant