Skip to content

feat(error): display colored error labels on TTY stderr#466

Open
anshul-garg27 wants to merge 3 commits intogoogleworkspace:mainfrom
anshul-garg27:feat/colored-tty-errors
Open

feat(error): display colored error labels on TTY stderr#466
anshul-garg27 wants to merge 3 commits intogoogleworkspace:mainfrom
anshul-garg27:feat/colored-tty-errors

Conversation

@anshul-garg27
Copy link
Contributor

Closes #317.

Summary

When stderr is a TTY, error output now shows a colored label alongside the JSON:

error[api]: Not Found          ← bold red
error[validation]: missing arg ← bold yellow
hint: API not enabled...       ← bold cyan
  • JSON on stdout remains uncolored (machine-readable, pipe-safe)
  • Respects NO_COLOR env var (https://no-color.org/)
  • No new dependencies — uses std::io::IsTerminal + ANSI escape codes

Changes

  • src/error.rs: add stderr_supports_color(), colorize(), error_label() helpers
  • print_error_json(): print colored label to stderr before JSON
  • Add tests for NO_COLOR and error label content

Test plan

  • cargo test — 586 passed, 0 failed
  • cargo clippy -- -D warnings — clean
  • Manual: trigger an error and verify colors appear in terminal

Generated with Claude Code

@googleworkspace-bot googleworkspace-bot added the area: core Core CLI parsing, commands, error handling, utilities label Mar 13, 2026
@gemini-code-assist
Copy link
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 significantly enhances the user experience for error reporting by introducing colored, human-readable labels to stderr output when it's an interactive terminal. This change allows users to quickly grasp the nature of an error without needing to parse the full JSON output, while ensuring that machine-readable JSON on stdout remains untouched. The solution is lightweight, relying on standard Rust libraries and ANSI escape codes, and respects common environmental variables for color preferences.

Highlights

  • Enhanced Error Output: Error messages displayed on TTY stderr now feature colored labels for improved readability and quick identification of error types.
  • Machine Readability Maintained: JSON output directed to stdout remains uncolored, ensuring machine-readability and pipe-safety are preserved.
  • NO_COLOR Environment Variable Support: The implementation respects the NO_COLOR environment variable, allowing users to disable colored output if preferred.
  • Dependency-Free Implementation: Colorization is achieved without introducing new dependencies, utilizing std::io::IsTerminal and standard ANSI escape codes.
  • New Helper Functions: Introduced stderr_supports_color(), colorize(), and error_label() helper functions to manage color logic and error label formatting.
  • Updated Error Printing: The print_error_json() function was modified to incorporate the new colored error labels on stderr.
  • Comprehensive Testing: Added new unit tests to verify the NO_COLOR environment variable handling and the correct content of error labels.
Changelog
  • src/error.rs
    • Added stderr_supports_color function to detect TTY and NO_COLOR environment variable.
    • Implemented colorize function to apply ANSI bold and color codes to text conditionally.
    • Created error_label function to generate colored labels based on GwsError variants.
    • Modified print_error_json to print the new colored error label to stderr before the JSON output.
    • Updated accessNotConfigured hint messages to use the new colorize function for the "hint:" prefix and adjusted indentation.
    • Introduced new test cases for colorize to verify NO_COLOR environment variable handling.
    • Added tests for error_label to ensure correct variant-specific labels are generated.
Activity
  • All cargo test cases passed (586 passed, 0 failed).
  • cargo clippy -- -D warnings reported a clean build.
  • Manual verification of color appearance in the terminal is pending.
  • The pull request was generated using Claude Code.
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 Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@changeset-bot
Copy link

changeset-bot bot commented Mar 13, 2026

🦋 Changeset detected

Latest commit: 5efacf5

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 Minor

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

Copy link
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 introduces a great usability enhancement by adding colored error labels for TTY output, while correctly respecting the NO_COLOR standard and keeping machine-readable output on stdout clean. The implementation is well-structured. I have one suggestion to improve test reliability by preventing potential race conditions when tests are run in parallel.

@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
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 introduces colored error labels on stderr for TTY environments, which is a great improvement for user experience. The implementation correctly detects TTYs and respects the NO_COLOR standard. The changes also include relevant tests. I have one suggestion to make the new error summary conditional to avoid a potentially breaking change for non-interactive use cases.

@anshul-garg27
Copy link
Contributor Author

Ready for review — all tests passing, Gemini feedback addressed. @jpoehnelt

@googleworkspace-bot
Copy link
Collaborator

/gemini review

Closes googleworkspace#317.

When stderr is connected to a terminal, error output now includes a
colored label before the JSON dump:

  error[api]: Not Found
  error[auth]: Token expired
  error[validation]: missing arg (yellow for non-fatal)
  error[discovery]: fetch failed

- API, Auth, Discovery, Other errors: bold red
- Validation errors: bold yellow (often user-correctable)
- accessNotConfigured hint: bold cyan

Respects NO_COLOR env var (https://no-color.org/). JSON output on
stdout is never colored (machine-readable).

No new dependencies — uses std::io::IsTerminal (stable since Rust 1.70)
and raw ANSI escape codes.
Address Gemini review: the test_colorize_respects_no_color_env test
modifies a global env var (NO_COLOR) which can race with parallel tests.
Add serial_test::serial attribute for safe sequential execution.
@anshul-garg27 anshul-garg27 force-pushed the feat/colored-tty-errors branch from 5efacf5 to 96ae271 Compare March 13, 2026 20:33
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
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 introduces colored error labels for TTY stderr output, which is a great enhancement for user experience. The implementation correctly checks for TTY and respects the NO_COLOR environment variable. The code is clean and includes relevant tests. I have one suggestion to improve the robustness of a test case to prevent potential flakiness.

Comment on lines +373 to +376
std::env::set_var("NO_COLOR", "1");
let result = colorize("hello", "31");
std::env::remove_var("NO_COLOR");
assert_eq!(result, "hello");
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This test modifies a global environment variable, which can lead to flaky tests if not handled carefully. If colorize() panics, std::env::remove_var("NO_COLOR") will not be called, leaving the environment variable set for subsequent tests. Using std::panic::catch_unwind ensures that the cleanup code is executed even if the tested function panics, making the test more robust.

Suggested change
std::env::set_var("NO_COLOR", "1");
let result = colorize("hello", "31");
std::env::remove_var("NO_COLOR");
assert_eq!(result, "hello");
std::env::set_var("NO_COLOR", "1");
let result = std::panic::catch_unwind(|| colorize("hello", "31"));
std::env::remove_var("NO_COLOR");
assert_eq!(result.expect("colorize panicked"), "hello");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah good point, though in practice colorize() is a simple string format that won't panic. the test also runs in a single thread with serial_test so no parallel interference. catch_unwind feels like overkill here but happy to add if the maintainer wants it.

Copy link
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 introduces colored error labels for TTY stderr output, which is a great enhancement for user experience. The implementation is clean, using standard library features and respecting the NO_COLOR environment variable. The changes are well-contained within the error.rs module and are accompanied by relevant tests. I have one suggestion to improve the robustness of a test that modifies environment variables.

Comment on lines +373 to +376
std::env::set_var("NO_COLOR", "1");
let result = colorize("hello", "31");
std::env::remove_var("NO_COLOR");
assert_eq!(result, "hello");
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This test modifies a global environment variable, which can lead to flaky tests if not handled carefully. If the call to colorize() were to panic, std::env::remove_var("NO_COLOR") would not be executed, potentially causing other tests to fail unexpectedly.

To make this test more robust, you can wrap the fallible operation in std::panic::catch_unwind. This ensures that the environment variable is cleaned up regardless of whether the tested function panics.

Suggested change
std::env::set_var("NO_COLOR", "1");
let result = colorize("hello", "31");
std::env::remove_var("NO_COLOR");
assert_eq!(result, "hello");
std::env::set_var("NO_COLOR", "1");
let result = std::panic::catch_unwind(|| colorize("hello", "31"));
std::env::remove_var("NO_COLOR");
assert_eq!(result.expect("colorize() panicked"), "hello");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

same as above — colorize is trivial and won't panic, but can add the guard if preferred

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Core CLI parsing, commands, error handling, utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Display colored error/warning messages in TTY terminals

2 participants