Skip to content

fix: support []interface{} in GetStringSliceValue and GetIntSliceValue for YAML arrays#351

Open
zy84338719 wants to merge 2 commits intoapolloconfig:masterfrom
zy84338719:fix/yaml-array-parsing
Open

fix: support []interface{} in GetStringSliceValue and GetIntSliceValue for YAML arrays#351
zy84338719 wants to merge 2 commits intoapolloconfig:masterfrom
zy84338719:fix/yaml-array-parsing

Conversation

@zy84338719
Copy link
Contributor

@zy84338719 zy84338719 commented Mar 10, 2026

Problem

Fixes #348

When parsing YAML namespace configurations, array fields are stored as []interface{} type (this is how Viper parses YAML arrays). However, GetStringSliceValue and GetIntSliceValue methods only handled []string and []int types directly, causing YAML arrays to be returned as stringified format like "[test111 test222]" when using GetContent(), or failing to convert when using slice accessor methods.

Solution

Extended the slice accessor methods to properly handle []interface{} type:

GetStringSliceValue / GetStringSliceValueImmediately

  • Now converts []interface{} to []string
  • Non-string elements are converted using fmt.Sprintf("%v", item)

GetIntSliceValue / GetIntSliceValueImmediately

  • Now converts []interface{} to []int
  • Handles float64 type (YAML/JSON default for numbers)
  • Handles string numbers via strconv.Atoi

Changes

  1. storage/repository.go

    • Extended GetStringSliceValue to handle []interface{}
    • Extended GetStringSliceValueImmediately to handle []interface{}
    • Extended GetIntSliceValue to handle []interface{}
    • Extended GetIntSliceValueImmediately to handle []interface{}
  2. storage/repository_test.go

    • Added TestGetStringSliceValueFromInterfaceSlice test
    • Added TestGetIntSliceValueFromInterfaceSlice test
  3. utils/parse/yaml/parser_test.go & utils/parse/yml/parser_test.go

    • Added TestYAMLParserArray / TestYMLParserArray test

Usage Example

# YAML configuration
items:
  - test111
  - test222
numbers:
  - 1
  - 2
  - 3
// Now works correctly
items := config.GetStringSliceValue("items", ",", nil)
// Returns: []string{"test111", "test222"}

numbers := config.GetIntSliceValue("numbers", ",", nil)
// Returns: []int{1, 2, 3}

Testing

All existing tests pass, new tests added for the YAML array scenario.

Summary by CodeRabbit

  • Improvements
    • Broadened array/slice parsing from YAML/JSON configs to accept more input shapes (mixed types, interface arrays, and delimited strings), with safer conversions, detailed debug logging, and reliable defaults to avoid panics.
  • Tests
    • Added tests covering array parsing and conversion scenarios (string, numeric, mixed, nested) to ensure correct behavior and fallback handling.

This fixes issue apolloconfig#348 where YAML array fields were parsed as []interface{}
but GetStringSliceValue/GetIntSliceValue methods only handled []string/[]int.

Changes:
- Extended GetStringSliceValue to convert []interface{} to []string
- Extended GetStringSliceValueImmediately to convert []interface{} to []string
- Extended GetIntSliceValue to convert []interface{} to []int (handles float64 from YAML)
- Extended GetIntSliceValueImmediately to convert []interface{} to []int
- Added test cases for YAML array parsing in parser_test.go
- Added test cases for slice conversion in repository_test.go
Copilot AI review requested due to automatic review settings March 10, 2026 19:25
@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

Enhances repository getters to accept and convert additional slice input shapes (including []interface{}, []string, []int, and delimited strings), adds robust conversion and logging on failures, and adds tests validating YAML/JSON array parsing and conversion behavior.

Changes

Cohort / File(s) Summary
Repository slice getters
storage/repository.go
Expanded GetStringSliceValue*, GetIntSliceValue* to handle []string, []int, []interface{}, and delimited single-string inputs; added conversion rules (stringify via fmt.Sprintf, parse ints from float64/string with validation), consistent debug logging, and safe fallbacks to defaults.
Repository tests
storage/repository_test.go
Added tests covering conversion from []interface{} to []string and []int, mixed-type arrays, fractional-number handling, and Immediately variants to assert correct values and defaulting behavior.
YAML parser tests
utils/parse/yaml/parser_test.go, utils/parse/yml/parser_test.go
Added tests verifying YAML arrays parse into []interface{} for string, numeric, and nested arrays and that nested dotted-path access yields expected slices and lengths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇 Nose a-twitch at parsed array sights,
I hop through slices, day and nights.
Strings or numbers, mixed or neat,
I tidy types with nimble feet.
Tests applaud — hooray, what a treat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extending slice getter methods to handle YAML arrays represented as []interface{}.
Linked Issues check ✅ Passed The PR fully addresses issue #348 by implementing native slice conversion for YAML arrays, allowing GetStringSliceValue and GetIntSliceValue to return proper []string and []int instead of stringified representations.
Out of Scope Changes check ✅ Passed All changes directly support the core objective of handling YAML arrays as native slices, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify
Copy link
Contributor

mergify bot commented Mar 10, 2026

感谢您提出Pull Request,我会尽快Review。我会在1-2日内进行查看或者回复,如果遇到节假日可能会处理较慢,敬请谅解。

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes YAML array handling by extending the Config slice accessors to properly convert Viper-parsed YAML arrays ([]interface{}) into []string / []int, preventing stringified array outputs and conversion failures for YAML-backed namespaces.

Changes:

  • Extend GetStringSliceValue / GetStringSliceValueImmediately to convert []interface{} to []string.
  • Extend GetIntSliceValue / GetIntSliceValueImmediately to convert []interface{} (including numeric/string elements) to []int.
  • Add unit tests covering YAML array parsing and the new slice conversion behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
storage/repository.go Adds []interface{} handling for string/int slice getters.
storage/repository_test.go Adds tests validating conversion from []interface{} to []string / []int.
utils/parse/yaml/parser_test.go Adds a test verifying YAML arrays are parsed as []interface{} via Viper.
utils/parse/yml/parser_test.go Same as above for .yml parser variant.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +211 to +214
case float64:
// JSON/YAML 数字默认解析为 float64
result = append(result, int(v))
case string:
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

When handling float64 elements in a YAML/JSON-derived []interface{}, the code casts via int(v), which silently truncates fractional values (e.g., 1.9 -> 1) and can also produce implementation-dependent results on overflow. Consider validating that v is an integer value (no fractional part) and within int range; otherwise return defaultValue (and optionally log). Adding a test for a non-integer float element would lock in the intended behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +407 to +410
case float64:
// JSON/YAML 数字默认解析为 float64
result = append(result, int(v))
case string:
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The float64 -> int conversion uses int(v) without checking for fractional values or overflow, so values like 1.9 will be truncated to 1. It would be safer to reject non-integer floats (and out-of-range floats) and fall back to defaultValue to avoid silently returning incorrect configuration.

Copilot uses AI. Check for mistakes.
Comment on lines +170 to +186
// 尝试直接转换为 []string
if v, ok := value.([]string); ok {
return v
}
return v

// 尝试从 []interface{} 转换为 []string (YAML 数组解析后的类型)
if ifaceSlice, ok := value.([]interface{}); ok {
result := make([]string, 0, len(ifaceSlice))
for _, item := range ifaceSlice {
if s, ok := item.(string); ok {
result = append(result, s)
} else {
result = append(result, fmt.Sprintf("%v", item))
}
}
return result
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

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

The []interface{} -> []string conversion logic here is duplicated in both the immediate and non-immediate variants (and similarly for []int). Consider extracting a small private helper to keep behavior consistent and reduce maintenance overhead if conversion rules change again.

Copilot uses AI. Check for mistakes.
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@storage/repository.go`:
- Around line 208-223: The float64 branch in the switch inside
GetIntSliceValueImmediately and GetIntSliceValue currently casts float64 to int
directly, which silently truncates fractional values; modify both functions so
the float64 case first validates the value is integral (e.g., compare v to
math.Trunc(v) or check v == float64(int(v))) and if it is not integral log the
conversion failure and return defaultValue, otherwise cast to int and append to
result; update the log message references in the float64 branch to match the
existing debug style used for other failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 805c0617-16cc-470f-a4f5-509c8a9c3d3b

📥 Commits

Reviewing files that changed from the base of the PR and between a289c41 and f25a59b.

📒 Files selected for processing (4)
  • storage/repository.go
  • storage/repository_test.go
  • utils/parse/yaml/parser_test.go
  • utils/parse/yml/parser_test.go

This addresses the CodeRabbit review comment:
- float64 to int conversion previously silently truncated fractional values (e.g., 1.5 -> 1)
- Now validates that float64 values have no fractional part before conversion
- Returns defaultValue and logs a debug message if fractional part exists
- Added test cases for fractional number scenarios
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.

🧹 Nitpick comments (1)
storage/repository.go (1)

199-235: Extract the []interface{}[]int coercion into a shared helper.

The conversion rules and failure handling are duplicated in both getters. Pulling this into one helper would reduce drift and make follow-up fixes much safer.

Also applies to: 400-449

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@storage/repository.go` around lines 199 - 235, The []interface{}→[]int
conversion logic is duplicated; extract it into a shared helper (e.g.,
convertInterfaceSliceToIntSlice or parseIntSliceFromAny) that accepts the input
value and a default []int and returns the converted []int, preserving current
rules (handle int, float64 only if integer, string via strconv.Atoi, log debug
on failures and return defaultValue). Replace the inlined loops in the current
getter(s) (the code block that checks value.([]int) and value.([]interface{}))
and the other similar getter (also referenced in the comment range 400-449) to
call this helper, keeping the initial fast-path []int check in the getters if
desired but delegating []interface{} handling to the new function. Ensure the
helper uses the same log messages and returns defaultValue on any conversion
error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@storage/repository.go`:
- Around line 199-235: The []interface{}→[]int conversion logic is duplicated;
extract it into a shared helper (e.g., convertInterfaceSliceToIntSlice or
parseIntSliceFromAny) that accepts the input value and a default []int and
returns the converted []int, preserving current rules (handle int, float64 only
if integer, string via strconv.Atoi, log debug on failures and return
defaultValue). Replace the inlined loops in the current getter(s) (the code
block that checks value.([]int) and value.([]interface{})) and the other similar
getter (also referenced in the comment range 400-449) to call this helper,
keeping the initial fast-path []int check in the getters if desired but
delegating []interface{} handling to the new function. Ensure the helper uses
the same log messages and returns defaultValue on any conversion error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d2794ef0-70cd-419e-96ea-d4f14371b9f5

📥 Commits

Reviewing files that changed from the base of the PR and between f25a59b and fd123ec.

📒 Files selected for processing (2)
  • storage/repository.go
  • storage/repository_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • storage/repository_test.go

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.

yaml数组解析

2 participants