fix(api): serialize arrays with non-lowercase elements

What does this MR do and why?

glab api -f/-F decides whether a bracketed value is an array with this regex:

^\[\s*([[:lower:]_]+(\s*,\s*[[:lower:]_]+)*)?\s*\]$

Every element has to be lowercase letters and underscores, so a hyphen, an uppercase letter or a digit makes the whole value fall through and get sent as a JSON string:

glab api -X PUT projects/:id -F "topics=[my-topic, GitLab]"
# sent:     {"topics":"[my-topic, GitLab]"}
# expected: {"topics":["my-topic","GitLab"]}

Project topics are the common way to hit this, since they are user-authored and routinely contain hyphens and capitals.

This MR:

  • Broadens an element to either a double-quoted string or a run of characters that cannot be confused with the list syntax itself.
  • Splits on commas that sit outside quotes, so ["one, two", three] is two elements rather than three.
  • Returns an empty slice for [], which previously produced a single empty string. Sending an empty array is how a field is cleared.

Values that only look like a list, such as a description containing nested brackets, are still sent unchanged as strings.

I went with the narrow fix rather than parsing any [/{ value as JSON. The JSON route changes types for existing users ([1, 2] would stop being strings) and reaches beyond this issue, so it seemed better raised separately.

The first version of this MR broke that promise by another route: the bare-element class matched digits, so [1, 2] newly became an array anyway. @GitLabDuo and @phikai caught it in review. A bare element must now contain at least one non-digit character, so [1, 2] stays a string exactly as on main. Quoting is how a caller opts numeric elements into array handling: ["1", "2"].

Test coverage

internal/commands/api/http_test.go:

  • Four new Test_httpRequest cases: hyphen/uppercase/digit elements, quoted elements containing spaces and commas, [], and a string that only looks like a list.
  • Test_parseStringArrayField covering the element shapes.
  • Test_strArrayRegex_rejectsNonArrays pinning what must not be treated as an array, including unbalanced brackets and an unbalanced quote.

The existing [api, read_api] case is unchanged and still passes.

Closes #8216

Edited by Lee Seonghyeon · 이성현

Merge request reports

Loading