Skip to content

feat: add --dry-run support to events helper commands#455

Closed
joeVenner wants to merge 1 commit intogoogleworkspace:mainfrom
joeVenner:feature/add-dry-run-to-helpers
Closed

feat: add --dry-run support to events helper commands#455
joeVenner wants to merge 1 commit intogoogleworkspace:mainfrom
joeVenner:feature/add-dry-run-to-helpers

Conversation

@joeVenner
Copy link

Add dry-run mode to gws events +renew and gws events +subscribe commands. When --dry-run is specified, the commands print what actions would be taken without making any API calls. This allows agents to simulate requests and learn without reaching the server.

Description

Please include a summary of the change and which issue is fixed. If adding a new feature or command, please include the output of running it with --dry-run to prove the JSON request body matches the Discovery Document schema.

Dry Run Output:

// Paste --dry-run output here if applicable

Checklist:

  • My code follows the AGENTS.md guidelines (no generated google-* crates).
  • I have run cargo fmt --all to format the code perfectly.
  • I have run cargo clippy -- -D warnings and resolved all warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have provided a Changeset file (e.g. via pnpx changeset) to document my changes.

@changeset-bot
Copy link

changeset-bot bot commented Mar 13, 2026

🦋 Changeset detected

Latest commit: 3515881

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

@google-cla
Copy link

google-cla bot commented Mar 13, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@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 introduces a --dry-run mode for the gws events +renew and gws events +subscribe helper commands. This feature allows users to simulate the actions these commands would take, such as reactivating subscriptions or creating Pub/Sub resources, without actually making any API calls. This enhances user confidence and provides a safe way to understand command behavior before execution.

Highlights

  • Dry Run Support for gws events +renew: The gws events +renew command now supports a --dry-run flag, allowing users to preview subscription reactivation actions without making actual API calls.
  • Dry Run Support for gws events +subscribe: The gws events +subscribe command has been enhanced with a --dry-run flag, enabling users to simulate the creation of Pub/Sub topics, subscriptions, and Workspace Events subscriptions.
  • Conditional API Calls and Resource Creation: Logic has been added to both commands to conditionally execute API requests and file system operations (like directory creation) only when the --dry-run flag is not present, ensuring no side effects during simulation.
Changelog
  • .changeset/add-dry-run-to-event-helpers.md
    • Added a new changeset file documenting the addition of --dry-run support to event helper commands.
  • src/helpers/events/renew.rs
    • Introduced a dry_run flag check at the beginning of the handle_renew function.
    • Modified token retrieval to be optional (Option<String>) when dry_run is true, avoiding unnecessary authentication.
    • Wrapped API calls for reactivating specific subscriptions and listing/renewing multiple subscriptions within if !dry_run blocks.
    • Added a dry-run specific output for the case where multiple subscriptions would be renewed, detailing the intended action.
  • src/helpers/events/subscribe.rs
    • Introduced a dry_run flag check at the beginning of the handle_subscribe function.
    • Wrapped the directory creation (std::fs::create_dir_all) within an if !dry_run block.
    • Modified Pub/Sub token retrieval to be optional (Option<String>) when dry_run is true.
    • Added a dry-run specific output block that prints what Pub/Sub topics, subscriptions, and Workspace Events subscriptions would be created, then exits.
    • Ensured API calls for creating Pub/Sub topics and subscriptions only execute when dry_run is false, using the unwrapped token.
Activity
  • No human activity has been recorded on this pull request yet.
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.

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 --dry-run mode for the events +renew and events +subscribe helper commands. The implementation is a good start, but there are a couple of issues with the dry-run logic. In renew.rs, the dry-run output is missing for single-subscription renewals, making it inconsistent. More critically, in subscribe.rs, the dry-run mode doesn't work when using an existing subscription, leading to unexpected live API calls. My review includes suggestions to fix these issues to ensure the --dry-run feature behaves as expected across all scenarios.

Comment on lines +125 to +133
let pubsub_token = if dry_run {
None
} else {
Some(
auth::get_token(&[PUBSUB_SCOPE])
.await
.map_err(|e| GwsError::Auth(format!("Failed to get Pub/Sub token: {e}")))?,
)
};
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The --dry-run implementation is incomplete and leads to unexpected API calls. When using an existing subscription (--subscription), the code proceeds to the pull_loop, which attempts to fetch a real token and pull messages from Pub/Sub. This defeats the purpose of a dry run.

This happens because there's no dry-run check for the existing subscription path. The pull_loop is called unconditionally, and it uses pubsub_token_provider which is not aware of the dry-run mode.

A possible fix is to handle the dry-run case for existing subscriptions early in the function and return before pull_loop is called, similar to how it's done for new subscriptions. For example, you could add a check after parsing arguments:

if dry_run && config.subscription.is_some() {
    // Print dry-run JSON for existing subscription and return Ok(())
}

Comment on lines +55 to +74
if !dry_run {
let token = ws_token.as_ref().expect("Token should be present in non-dry-run mode");
let resp = client
.post(format!(
"https://workspaceevents.googleapis.com/v1/{name}:reactivate"
))
.bearer_auth(token)
.header("Content-Type", "application/json")
.body("{}")
.send()
.await
.context("Failed to reactivate subscription")?;

let body: Value = resp.json().await.context("Failed to parse response")?;

println!(
"{}",
serde_json::to_string_pretty(&body).unwrap_or_default()
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Inconsistent dry-run behavior. When --dry-run is used with a specific subscription name (--name), the command doesn't produce any JSON output indicating what would have happened. This is inconsistent with the behavior when --all is used. An else block should be added to provide a descriptive JSON output for the single-subscription dry-run case.

        if !dry_run {
            let token = ws_token.as_ref().expect("Token should be present in non-dry-run mode");
            let resp = client
                .post(format!(
                    "https://workspaceevents.googleapis.com/v1/{name}:reactivate"
                ))
                .bearer_auth(token)
                .header("Content-Type", "application/json")
                .body("{}")
                .send()
                .await
                .context("Failed to reactivate subscription")?;

            let body: Value = resp.json().await.context("Failed to parse response")?;

            println!(
                "{}",
                serde_json::to_string_pretty(&body).unwrap_or_default()
            );
        } else {
            let result = json!({
                "dry_run": true,
                "action": "Would reactivate subscription",
                "name": name,
                "note": "Run without --dry-run to actually reactivate the subscription"
            });
            println!(
                "{}",
                serde_json::to_string_pretty(&result).unwrap_or_default()
            );
        }

Add dry-run mode to gws events +renew and gws events +subscribe commands.
When --dry-run is specified, the commands print what actions would be
taken without making any API calls. This allows agents to simulate
requests and learn without reaching the server.
@joeVenner joeVenner force-pushed the feature/add-dry-run-to-helpers branch from e907467 to 3515881 Compare March 13, 2026 02:33
@joeVenner joeVenner closed this Mar 13, 2026
@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 a --dry-run mode for the events +renew and events +subscribe helper commands. The implementation is mostly correct, but there are a couple of issues where the dry-run logic is incomplete, causing inconsistencies or leading to unintended API calls. I've left specific comments with suggestions to address these issues. Once fixed, this will be a great enhancement for simulating requests.

Comment on lines +55 to +74
if !dry_run {
let token = ws_token.as_ref().expect("Token should be present in non-dry-run mode");
let resp = client
.post(format!(
"https://workspaceevents.googleapis.com/v1/{name}:reactivate"
))
.bearer_auth(token)
.header("Content-Type", "application/json")
.body("{}")
.send()
.await
.context("Failed to reactivate subscription")?;

let body: Value = resp.json().await.context("Failed to parse response")?;

println!(
"{}",
serde_json::to_string_pretty(&body).unwrap_or_default()
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The dry-run mode for reactivating a specific subscription is incomplete. It prints a message to stderr but doesn't produce the JSON output describing the action, which is inconsistent with the behavior for renewing multiple subscriptions. To ensure consistent behavior and fully implement the dry-run feature, you should add an else block to output a JSON summary for this case.

        if !dry_run {
            let token = ws_token.as_ref().expect("Token should be present in non-dry-run mode");
            let resp = client
                .post(format!(
                    "https://workspaceevents.googleapis.com/v1/{name}:reactivate"
                ))
                .bearer_auth(token)
                .header("Content-Type", "application/json")
                .body("{}")
                .send()
                .await
                .context("Failed to reactivate subscription")?;

            let body: Value = resp.json().await.context("Failed to parse response")?;

            println!(
                "{}",
                serde_json::to_string_pretty(&body).unwrap_or_default()
            );
        } else {
            let result = json!({
                "dry_run": true,
                "action": "Would reactivate subscription",
                "name": name,
                "note": "Run without --dry-run to actually reactivate this subscription"
            });
            println!(
                "{}",
                serde_json::to_string_pretty(&result).unwrap_or_default()
            );
        }

Comment on lines +109 to +113
let dry_run = matches.get_flag("dry-run");

if dry_run {
eprintln!("🏃 DRY RUN — no changes will be made\n");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The dry-run implementation is incomplete for existing subscriptions. When the --subscription flag is used in dry-run mode, the command proceeds to call pull_loop, which makes real API calls to Pub/Sub. This defeats the purpose of a dry run.

A check should be added to handle this scenario. When dry_run is true and an existing subscription is provided, the command should print what it would do and exit, rather than entering the pull_loop.

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.

3 participants