Skip to content

feat(error): detect accessNotConfigured and guide users to enable APIs#33

Merged
jpoehnelt merged 2 commits intogoogleworkspace:mainfrom
jpoehnelt-bot:feat/access-not-configured-guidance
Mar 4, 2026
Merged

feat(error): detect accessNotConfigured and guide users to enable APIs#33
jpoehnelt merged 2 commits intogoogleworkspace:mainfrom
jpoehnelt-bot:feat/access-not-configured-guidance

Conversation

@jpoehnelt-bot
Copy link
Copy Markdown
Contributor

Summary

Implements #31.

When the Google API returns a 403 with reason accessNotConfigured (i.e., the required API is disabled for the GCP project), gws now surfaces a user-friendly error instead of a raw JSON blob.

Changes

src/error.rs

  • Added optional enable_url: Option<String> field to GwsError::Api variant.
  • to_json() includes enable_url in JSON output when present (backward-compatible — new optional field only).
  • print_error_json() now prints actionable guidance to stderr for accessNotConfigured errors, including the direct GCP Console link.

src/executor.rs

  • Added extract_enable_url(message: &str) -> Option<String> — parses the GCP enable URL from the error message (no external deps; pure string splitting).
  • handle_error_response() now detects accessNotConfigured reason (both errors[0].reason and top-level reason fields) and populates enable_url.
  • Updated all helper files to include enable_url: None in GwsError::Api constructors.

Tests added

  • test_extract_enable_url_typical_message — parses URL from a realistic message.
  • test_extract_enable_url_no_url — returns None for messages without a URL.
  • test_extract_enable_url_non_http — ignores non-HTTP URLs.
  • test_handle_error_response_access_not_configured_with_url — end-to-end parse with top-level reason field.
  • test_handle_error_response_access_not_configured_errors_array — end-to-end parse with errors[] array.
  • Updated error.rs tests to cover accessNotConfigured with and without enable_url.

README.md

  • Added Troubleshooting section with an accessNotConfigured example, the JSON shape change, and step-by-step fix instructions.

.changeset/access-not-configured-guidance.md

  • Changeset patch for @googleworkspace/cli (patch bump).

Example output

stdout (machine-readable, unchanged shape + optional field):

{
  "error": {
    "code": 403,
    "message": "Gmail API has not been used in project 549352339482 ...",
    "reason": "accessNotConfigured",
    "enable_url": "https://console.developers.google.com/apis/api/gmail.googleapis.com/overview?project=549352339482"
  }
}

stderr (human-readable hint):

💡 API not enabled for your GCP project.
   Enable it at: https://console.developers.google.com/apis/api/gmail.googleapis.com/overview?project=549352339482
   After enabling, wait a few seconds and retry your command.

Quality checks

  • cargo fmt --all
  • cargo test ✅ — 306 passed, 0 failed
  • cargo clippy --all-targets --all-features -- -D warnings7 pre-existing failures on upstream main (not introduced by this PR). These failures exist in the same form on the upstream main branch: bool_assert_comparison in main.rs tests, field_reassign_with_default in executor.rs tests, and manual_contains in helpers. No new clippy errors introduced.

Closes #31

When the Google API returns a 403 with reason accessNotConfigured,
gws now:
- Extracts the GCP Console enable URL from the error message.
- Adds an optional enable_url field to the JSON error output.
- Prints an actionable hint with the enable URL to stderr.

Also adds extract_enable_url() helper with tests, and a Troubleshooting
section to README.

Fixes googleworkspace#31
@jpoehnelt-bot jpoehnelt-bot requested a review from jpoehnelt as a code owner March 4, 2026 04:57
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 4, 2026

🦋 Changeset detected

Latest commit: 756de45

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 significantly enhances the user experience of the gws CLI tool by providing actionable guidance when Google APIs return accessNotConfigured errors. Instead of presenting a raw JSON error, the tool now intelligently extracts the API enablement URL and displays it to the user via stderr, alongside step-by-step instructions. This change transforms a previously cryptic error into a clear, resolvable issue, improving developer productivity and reducing frustration.

Highlights

  • Improved API Error Guidance: The CLI now provides user-friendly guidance for accessNotConfigured errors, including a direct link to enable the required Google API.
  • Structured Error Output: A new optional enable_url field has been added to the GwsError::Api variant and its JSON representation, providing machine-readable access to the API enablement link.
  • Enhanced User Experience: Human-readable hints with enablement URLs are now printed to stderr for accessNotConfigured errors, preventing dead-end experiences.
  • Robust URL Extraction: A new utility function extract_enable_url was implemented to reliably parse API enablement URLs from Google API error messages.
  • Documentation Update: The README.md has been updated with a dedicated troubleshooting section for accessNotConfigured errors, including steps to resolve them.
Changelog
  • .changeset/access-not-configured-guidance.md
    • Added a new changeset file documenting the feature for detecting disabled APIs and guiding users to enable them.
  • README.md
    • Added a new "Troubleshooting" section specifically for accessNotConfigured errors, detailing the JSON output, stderr hint, and steps to fix.
  • src/error.rs
    • Added an enable_url: Option<String> field to the GwsError::Api enum variant.
    • Modified the to_json() method to conditionally include the enable_url in the JSON output when present.
    • Updated print_error_json() to print human-readable guidance to stderr for accessNotConfigured errors, including the enable_url.
    • Added new tests for accessNotConfigured errors with and without enable_url in JSON serialization.
  • src/executor.rs
    • Implemented extract_enable_url function to parse API enablement URLs from error messages.
    • Updated handle_error_response to detect accessNotConfigured reasons (both top-level and nested) and populate the enable_url field.
    • Added new tests for extract_enable_url covering typical messages, no URL cases, and non-HTTP URLs.
    • Added new end-to-end tests for handle_error_response with accessNotConfigured errors, covering both top-level reason and errors array scenarios.
    • Updated existing GwsError::Api constructors to pass enable_url: None.
  • src/helpers/calendar.rs
    • Updated GwsError::Api constructor in handle_agenda to include enable_url: None.
  • src/helpers/events/subscribe.rs
    • Updated GwsError::Api constructors in handle_subscribe and pull_loop to include enable_url: None.
  • src/helpers/gmail/triage.rs
    • Updated GwsError::Api constructor in handle_triage to include enable_url: None.
  • src/helpers/gmail/watch.rs
    • Updated GwsError::Api constructors in handle_watch and watch_pull_loop to include enable_url: None.
  • src/helpers/workflows.rs
    • Updated GwsError::Api constructors in get_json, handle_email_to_task, and handle_file_announce to include enable_url: None.
Activity
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 introduces a great user experience improvement for handling accessNotConfigured errors from Google APIs. By detecting this specific error, parsing the console URL from the message, and providing a helpful hint on stderr, it makes it much easier for users to resolve disabled API issues. The changes are well-structured, including updates to the error handling logic, new tests, and clear documentation in the README.

I have one suggestion to improve the robustness of the URL extraction logic to handle cases where punctuation might follow the URL in the error message.

@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!

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 UX improvement — surfacing a direct GCP console link for accessNotConfigured is exactly the kind of actionable guidance that saves users from digging through error messages.

A few notes:

  1. extract_enable_url fragility — the parser splits on the literal string "visiting " and then takes the first whitespace-delimited token. This works for the current Google error message format, but the format is not part of any stable API contract. Consider adding a comment noting this is a best-effort parse, and that enable_url: None is the graceful fallback if the format changes. A test for a message that lacks the pattern (already present: test_extract_enable_url_no_url) and one for a future format variation would strengthen confidence.

  2. stderr vs stdout — printing guidance to stderr while the JSON error goes to stdout is the right separation. Worth documenting in the README or help text that --format json output should be captured from stdout only.

  3. enable_url in JSON output — adding enable_url as an optional field to the error JSON object is a small but technically additive schema change. Machine consumers that iterate error keys could be surprised. Consider whether a "hint" wrapper object would be cleaner ("hint": {"enable_url": "..."}).

  4. Reason fallback — the new .or_else(|| err_obj.get("reason")...) fallback for top-level reason field is a good defensive addition. Test coverage for a response with only a top-level reason (no errors array) would complete the picture.

  5. Test assertion for absent enable_urlassert!(json["error"]["enable_url"].is_null()) is correct for serde_json, but only if the key is truly absent (serde_json returns Value::Null for missing keys). This is fine here; just noting it for clarity.

@jpoehnelt-bot
Copy link
Copy Markdown
Contributor Author

Addressed Gemini review feedback:\n\n- Hardened extract_enable_url to trim trailing punctuation from extracted URLs.\n- Added test coverage for punctuation trimming: test_extract_enable_url_trims_trailing_punctuation.\n\nCommit: 756de45

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 addressing the feedback!

Replacing the regex with basic string splitting and matching punctuation is much more deterministic and less prone to panicking. The additional test coverage for punctuation trimming (test_extract_enable_url_trims_trailing_punctuation) gives confidence that it correctly strips trailing dots and commas from the parsed URL.

The changes look solid to me. LGTM!

@jpoehnelt jpoehnelt merged commit de2787e into googleworkspace:main Mar 4, 2026
21 checks passed
shigechika pushed a commit to shigechika/gws-cli that referenced this pull request Mar 20, 2026
googleworkspace#33)

* feat(error): detect accessNotConfigured and guide users to enable APIs

When the Google API returns a 403 with reason accessNotConfigured,
gws now:
- Extracts the GCP Console enable URL from the error message.
- Adds an optional enable_url field to the JSON error output.
- Prints an actionable hint with the enable URL to stderr.

Also adds extract_enable_url() helper with tests, and a Troubleshooting
section to README.

Fixes googleworkspace#31

* fix(error): trim trailing punctuation from accessNotConfigured enable URL
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.

feat: detect disabled APIs and guide users to enable them

2 participants