Skip to content

fix: YAML block scalar for single-line strings, and repeated CSV/table headers with --page-all#37

Merged
jpoehnelt merged 1 commit intogoogleworkspace:mainfrom
jpoehnelt-bot:fix/yaml-block-scalar-and-page-all-headers
Mar 4, 2026
Merged

fix: YAML block scalar for single-line strings, and repeated CSV/table headers with --page-all#37
jpoehnelt merged 1 commit intogoogleworkspace:mainfrom
jpoehnelt-bot:fix/yaml-block-scalar-and-page-all-headers

Conversation

@jpoehnelt-bot
Copy link
Copy Markdown
Contributor

Fixes #35 and #36.

Changes

Bug 1 — YAML block scalar for strings with # or : (fixes #35)

Strings like drive#file and https://... were being emitted as YAML block scalars:

# before (broken)
kind: |
  drive#file

# after (correct)
kind: "drive#file"

Root cause: json_to_yaml() in formatter.rs used block scalar for any string containing # or :, even single-line values. Block scalars are only appropriate for strings with genuine newline characters.

Fix: Only use block scalar (|) when the string contains \n. All other strings are double-quoted, with \\ and \" escaped.

Bug 2 — --page-all repeats CSV/table headers per page (fixes #36)

# before: headers repeated for every page
gws drive files list --page-all --format csv
# id,kind,...
# 1abc,...
# id,kind,...   ← unexpected!
# 2def,...

# after: single header, continuous data
# id,kind,...
# 1abc,...
# 2def,...

Root cause: In pagination mode, format_value_compact() delegated to format_value() for non-JSON formats, which always includes headers.

Fix: New public format_value_paginated(value, format, is_first_page) function. CSV/table formats suppress column headers on continuation pages (is_first_page = false). The now-unused format_value_compact() has been removed.

Tests

8 new unit tests added in formatter.rs:

  • test_format_yaml_hash_in_string_is_quoted_not_block
  • test_format_yaml_colon_in_string_is_quoted
  • test_format_yaml_multiline_still_uses_block
  • test_format_value_paginated_csv_first_page_has_header
  • test_format_value_paginated_csv_continuation_no_header
  • test_format_value_paginated_table_first_page_has_header
  • test_format_value_paginated_table_continuation_no_header
  • test_format_value_paginated_json_is_compact

All 321 existing tests continue to pass. Clippy clean. Formatted with cargo fmt.

@jpoehnelt-bot jpoehnelt-bot requested a review from jpoehnelt as a code owner March 4, 2026 06:35
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 4, 2026

🦋 Changeset detected

Latest commit: ddaaa29

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses two critical bugs related to output formatting and introduces a significant usability enhancement for command-line arguments. It corrects YAML serialization to prevent misinterpretation of single-line strings with special characters and refines paginated CSV/table output to ensure headers appear only once. Additionally, it adds convenient kebab-case aliases for existing camelCase API resource and method names, making the CLI more user-friendly.

Highlights

  • YAML Output Correction: Fixed an issue where single-line strings containing special characters (like '#' or ':') were incorrectly emitted as YAML block scalars, now ensuring they are double-quoted for correct parsing and escaping backslashes and double quotes.
  • Paginated Output Enhancement: Resolved a bug where CSV and table formats repeated headers on every page when using '--page-all', now displaying headers only on the first page for continuous data output.
  • Kebab-Case Aliases: Introduced support for kebab-case aliases for camelCase API resource and method names, improving CLI usability and flexibility by allowing both formats.
Changelog
  • .changeset/feat-kebab-case-aliases.md
    • Documented the new feature supporting kebab-case aliases for camelCase subcommands.
  • .changeset/fix-yaml-block-scalar-and-page-all-headers.md
    • Documented fixes for YAML block scalar misuse and repeated headers in paginated CSV/table output.
  • README.md
    • Updated the README with a tip explaining the new kebab-case alias functionality.
  • src/commands.rs
    • Implemented 'camel_to_kebab', 'kebab_to_camel', and 'resolve_name' utility functions.
    • Integrated logic to register visible kebab-case aliases for resource and method commands.
    • Added comprehensive unit tests for new utility functions and alias resolution.
  • src/executor.rs
    • Modified the pagination logic to use the new 'format_value_paginated' function, passing a flag to indicate the first page.
    • Updated a test assertion for pagination configuration.
  • src/formatter.rs
    • Refactored output formatting by introducing 'format_value_paginated' to handle conditional header emission for CSV and table formats.
    • Updated 'json_to_yaml' to correctly double-quote single-line strings with special characters and escape them, while retaining block scalars for multi-line strings.
    • Introduced new functions 'format_table_page' and 'format_csv_page' to support conditional header output.
    • Added new unit tests covering YAML string formatting and paginated CSV/table header behavior.
  • src/helpers/chat.rs
    • Refactored the test setup for 'RestResource' initialization using struct update syntax.
  • src/helpers/docs.rs
    • Refactored the test setup for 'RestResource' initialization using struct update syntax.
  • src/helpers/sheets.rs
    • Refactored the test setup for 'RestResource' initialization using struct update syntax.
  • src/main.rs
    • Updated 'resolve_method_from_matches' to leverage the new 'commands::resolve_name' function for robust resolution of resource and method names, including kebab-case aliases.
    • Enhanced the 'print_usage' output with a note about kebab-case aliases.
    • Updated test assertions for pagination configuration.
  • src/setup.rs
    • Updated a test assertion to use the 'contains' method for clarity.
Activity
  • Added 8 new unit tests to 'formatter.rs' covering YAML string formatting and paginated CSV/table output.
  • Added new unit tests to 'commands.rs' for 'camel_to_kebab', 'kebab_to_camel', and 'resolve_name' functions, as well as alias resolution.
  • Ensured all 321 existing tests continue to pass.
  • Verified Clippy clean.
  • Formatted code with 'cargo fmt'.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request delivers two important bug fixes and a significant usability improvement. The fix for YAML block scalars ensures that single-line strings with special characters are correctly quoted, improving output correctness. The change to paginated CSV and table formats, which now only print headers on the first page, is a great fix for --page-all usability. Additionally, the introduction of kebab-case aliases for camelCase commands is a thoughtful feature that enhances the CLI's ergonomics. The implementation is solid, with comprehensive tests for all new logic. I have one minor suggestion to improve code conciseness.

@jpoehnelt-bot
Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

jpoehnelt-bot added a commit to jpoehnelt-bot/cli that referenced this pull request Mar 4, 2026
Gemini review feedback (PR googleworkspace#37): since resolve_name returns a key
guaranteed to exist in the methods map, the inner if let Some() guard
was redundant. Replace with direct indexing for clarity.

Co-authored-by: gemini-code-assist[bot] <gemini-code-assist[bot]@users.noreply.github.com>
@jpoehnelt-bot
Copy link
Copy Markdown
Contributor Author

Review feedback addressed

Addressed Gemini Code Assist inline feedback (commit f01857e):

  • src/main.rs:328 — remove redundant nested if let: commands::resolve_name returns a key that is guaranteed to exist in the methods map (it iterates over .keys()), so the inner if let Some(method) = current_resource.methods.get(&method_key) guard was always Some. Replaced with direct indexing &current_resource.methods[&method_key] for clarity and conciseness, as suggested.

Copy link
Copy Markdown
Member

@jpoehnelt jpoehnelt left a comment

Choose a reason for hiding this comment

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

Good fixes for both bugs. The YAML block-scalar restriction to newline-only strings is the correct approach, and the paginated-header suppression is clean.

A few notes:

  1. YAML quoting completeness — double-quoting handles # and : well; worth verifying that strings containing " are correctly escaped (via \" substitution) in the new path before this lands.

  2. format_value_paginated public API — since this is now the public entry point for pagination, confirm that the now-removed format_value_compact had no callers outside the crate (integration tests etc.) before merging.

  3. Changeset overlap with PR #34 — this PR includes changesets for both the YAML/paging fix and the kebab-case feature. The kebab-case changeset (feat-kebab-case-aliases.md) duplicates PR #34's changeset. Confirm these won't double-apply on merge — whichever lands second should drop the duplicate changeset file.

  4. Test coverage — 8 new unit tests are excellent. The roundtrip test in test_camel_kebab_roundtrip is particularly valuable.

Overall solid and well-tested.

- YAML: only emit block scalar (|) for strings with genuine newlines;
  single-line strings containing '#' or ':' are now double-quoted instead,
  e.g. 'drive#file' renders as '"drive#file"' not a block scalar.
- --page-all: CSV/table formats no longer re-emit column headers on
  every page; headers appear only on the first page.  A new public
  format_value_paginated() helper replaces the now-removed
  format_value_compact().
- Add unit tests for both fixes (8 new test cases in formatter.rs).
@jpoehnelt-bot jpoehnelt-bot force-pushed the fix/yaml-block-scalar-and-page-all-headers branch from f01857e to ddaaa29 Compare March 4, 2026 07:15
Copy link
Copy Markdown
Member

@jpoehnelt jpoehnelt left a comment

Choose a reason for hiding this comment

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

Thanks for the updates and resolving the changeset! LGTM.

@jpoehnelt jpoehnelt merged commit e094b02 into googleworkspace:main Mar 4, 2026
21 of 22 checks passed
shigechika pushed a commit to shigechika/gws-cli that referenced this pull request Mar 20, 2026
…oogleworkspace#37)

- YAML: only emit block scalar (|) for strings with genuine newlines;
  single-line strings containing '#' or ':' are now double-quoted instead,
  e.g. 'drive#file' renders as '"drive#file"' not a block scalar.
- --page-all: CSV/table formats no longer re-emit column headers on
  every page; headers appear only on the first page.  A new public
  format_value_paginated() helper replaces the now-removed
  format_value_compact().
- Add unit tests for both fixes (8 new test cases in formatter.rs).
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.

bug: --page-all with --format csv/table repeats column headers on every page bug: YAML output emits block scalar for strings containing '#' or ':'

2 participants