Skip to content

Conversation

@ReneWerner87
Copy link
Member

@ReneWerner87 ReneWerner87 commented Dec 6, 2025

Summary

  • add support for migrating AcquireAgent blocks that only parse requests into client calls
  • ensure client import is added for the new migration path and adjust rewrite logic accordingly
  • cover the new scenario with a dedicated test case

Testing

  • make lint
  • make test

Codex Task

Summary by CodeRabbit

  • New Features

    • Migration rewrites now track and propagate request bodies and default error names, and inject conditional error-handling scaffolding when needed.
  • Bug Fixes

    • Rewrites preserve headers, methods and additional lines, avoid error-name collisions, and only mutate error handling when legacy patterns are detected; responses emit a single error field on failure.
  • Tests

    • Expanded coverage for body/header propagation, client-request/send migrations, legacy-error scenarios, collision avoidance, and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@ReneWerner87 ReneWerner87 requested a review from a team as a code owner December 6, 2025 08:00
Copilot AI review requested due to automatic review settings December 6, 2025 08:00
@ReneWerner87 ReneWerner87 requested review from efectn, gaby and sixcolors and removed request for a team December 6, 2025 08:00
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ReneWerner87, 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 refines the client migration tool by introducing support for AcquireAgent blocks that are solely responsible for parsing requests. The changes ensure that such blocks are accurately transformed into modern client calls, complete with necessary import statements and robust error handling, thereby improving the migrator's comprehensive capabilities.

Highlights

  • Enhanced Client Migrator: The client migrator now supports the migration of AcquireAgent blocks that are exclusively used for parsing requests, converting them into appropriate client calls.
  • Import Management: The migration logic has been updated to ensure that the client import is correctly added when AcquireAgent blocks are transformed into client calls.
  • Rewrite Logic Adjustment: The internal rewrite logic has been adjusted to properly handle the conversion of parse-only AcquireAgent blocks, including the generation of error handling for the new client calls.
  • New Test Case: A dedicated test case has been added to cover this new migration scenario, ensuring the correctness and robustness of the updated migrator.
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

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for migrating AcquireAgent blocks that only call Parse() without subsequent data retrieval operations (like Bytes(), String(), or Struct()). Previously, such blocks would not be migrated; now they are converted to simple client method calls that discard the response with _.

  • Adds a default case handler in the switch statement to migrate parse-only agent blocks
  • Includes comprehensive test coverage for the new migration path
  • Ensures the client import is properly added when migrations are applied

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
cmd/internal/migrations/v3/client_usage.go Implements the default case in rewriteAcquireAgentBlocksWithAlias to handle parse-only agent blocks by generating client calls with discarded responses
cmd/internal/migrations/v3/client_usage_test.go Adds Test_MigrateClientUsage_AcquireAgentOnlyParse to verify the migration of agent blocks that only parse requests without data retrieval

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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 correctly extends the client usage migrator to handle AcquireAgent blocks that only perform a Parse() call without retrieving the response body. The logic for this new case is sound and follows the existing patterns in the function. A new test case has been added that effectively covers this scenario.

However, I've identified a potential issue with how the err variable is declared in the generated code. The migration uses :=, which can lead to compilation errors if err is already in scope. I've left a comment with more details. While this seems to be an existing issue in the migrator, it would be beneficial to address it to make the migration more robust.

@coderabbitai
Copy link

coderabbitai bot commented Dec 6, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds body-aware request handling and threaded, non-conflicting error-identifier propagation through client-usage migration rewrites; injects conditional error-handling scaffolding, many private error-scoping helpers, and expands tests validating AcquireAgent → client.Request/Send rewrites (body, errs→err, name collisions).

Changes

Cohort / File(s) Summary
Migration logic & helpers
cmd/internal/migrations/v3/client_usage.go
Adds requestBodyPattern; tracks bodyExpr/bodyIsString; threads errName/errAssign through rewrite/build flows; reworks block reconstruction to preserve lines and inject conditional error-handling; adds many private helpers (chooseErrName, errAssignmentOperator, futureErrConflictExists, replaceErrIdentifier, hasBlankAssignment, identifierDeclared*, declaredInVarBlockLine, methodLiteral); defines defaultErrName; removes/relocates buildConfig.
Tests & internal examples
cmd/internal/migrations/v3/client_usage_test.go, cmd/internal/migrations/v3/client_usage_internal_test.go
Updates tests to expect rewrites producing client.New() + client.Request/Send() flows; exercises body/header/query/timeout/Parse/Bytes/String/Struct variants; validates err-name collision avoidance and changes from errserr response shape.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review focus:
    • correctness and edge cases in chooseErrName and futureErrConflictExists
    • errAssignmentOperator handling across var blocks vs single-line assignments
    • propagation of errName/errAssign through AcquireAgent and SimpleAgent rewrite paths
    • regexes like requestBodyPattern for false positives/negatives
    • test expectation accuracy for imports and response errserr changes

Possibly related PRs

Suggested labels

✏️ Feature

Suggested reviewers

  • gaby
  • sixcolors
  • efectn

Poem

🐇 I hopped through code where err might collide,
I threaded bodies and kept the lines wide.
I built requests, caught responses with cheer,
I renamed and guarded so errors stayed clear,
A rabbit's small migration — tidy and spry.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding support for handling parse-only AcquireAgent blocks in the client migrator, which aligns with the primary objective and code changes.
Description check ✅ Passed The PR description includes a summary of changes and testing steps, though it lacks detailed explanations of the problem being solved and technical justification for the changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/2025-12-06-08-00-08

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
cmd/internal/migrations/v3/client_usage.go (1)

403-423: Minor performance consideration: Regex compilation inside loop.

identifierDeclaredInLines compiles new regex patterns on each invocation (lines 408-409). For a migration CLI tool, this is likely acceptable. If performance becomes a concern with large files, consider caching compiled patterns or using string-based matching.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5551710 and eaf8f1d.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (9 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/internal/migrations/v3/client_usage_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, windows-latest)
🔇 Additional comments (7)
cmd/internal/migrations/v3/client_usage.go (7)

25-26: LGTM!

The regex patterns correctly detect short declarations (err :=) and var declarations (var err) for determining whether err is already in scope.


356-378: LGTM!

The errAssignmentOperator function correctly determines whether to use := or = based on whether err is already in scope and whether new variables need to be declared. This addresses the previously flagged issue about redeclaring err.


334-344: LGTM!

The default branch correctly handles the parse-only agent blocks scenario. Since no response variable is captured (_), the errAssignmentOperator is called without new variables, correctly determining whether err needs := or =.


609-641: LGTM!

The logic correctly determines newVar based on the original assignment operator (m[4]). If the original code used :=, the variables were being declared fresh, so varName is passed to errAssignmentOperator. This ensures the generated code uses the appropriate assignment operator.


661-665: LGTM!

The function signature update and errAssign usage in the response line correctly generate either := or = based on the computed assignment operator.


380-393: LGTM!

The errDeclared helper correctly iterates through lines and checks for both short and var-style err declarations.


242-263: LGTM!

The errAssignmentOperator is correctly invoked with "resp" as the new variable being introduced, and the computed errAssign is properly used in the generated response line.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/internal/migrations/v3/client_usage.go (1)

425-438: Consider moving regex compilation to package level.

The pattern \berr\b is compiled on every call to replaceErrIdentifier. For better performance, compile it once at package level.

+var errIdentifierPattern = regexp.MustCompile(`\berr\b`)
+
 func replaceErrIdentifier(lines []string, errName string) []string {
 	if errName == defaultErrName {
 		return lines
 	}
 
 	replaced := make([]string, len(lines))
-	pattern := regexp.MustCompile(`\berr\b`)
 
 	for i, line := range lines {
-		replaced[i] = pattern.ReplaceAllString(line, errName)
+		replaced[i] = errIdentifierPattern.ReplaceAllString(line, errName)
 	}
 
 	return replaced
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eaf8f1d and a30e352.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (12 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/internal/migrations/v3/client_usage_test.go (1)
cmd/internal/migrations/v3/client_usage.go (1)
  • MigrateClientUsage (74-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
  • GitHub Check: Build (1.25.x, windows-latest)
🔇 Additional comments (10)
cmd/internal/migrations/v3/client_usage.go (7)

69-72: LGTM - Constants for error name handling.

Good addition of constants to centralize the default error variable name and call type identifier.


382-404: Good approach for avoiding error variable conflicts.

The logic correctly handles three scenarios: reusing an existing err, safely declaring a new err when no conflicts exist, and falling back to alternative names when needed.


448-468: LGTM - Dynamic identifier detection.

The regex patterns are necessarily dynamic since they depend on the variable name being checked. For a migration tool that runs once per file, this overhead is acceptable.


358-380: Good solution for the assignment operator selection.

This properly addresses the past review concern about err redeclared in this block. The function correctly determines when to use := (new variables introduced) vs = (all variables already in scope).


336-346: LGTM - Handles parse-only AcquireAgent blocks.

This correctly migrates blocks that only call Parse() without subsequent response handling. The blank identifier _ for the unused response and proper error propagation look correct.


240-293: Error variable handling improved, but status/body redeclaration risk remains.

The errName and errAssign logic is correct. However, the unconditional var declarations at lines 273-277 could still cause compilation errors if statusVar or bodyVar are already declared in scope (as seen in test Test_MigrateClientUsage_RewritesAcquireAgentStruct where retCode/retBody are pre-declared). Consider applying similar scope-checking logic to these variables.


707-744: LGTM - Updated signature properly threads error handling.

The function correctly uses the provided errName and errAssign parameters throughout the generated code blocks.

cmd/internal/migrations/v3/client_usage_test.go (3)

932-991: LGTM - Good coverage for parse-only migration.

This test validates the new default case where AcquireAgent().Parse() is used without subsequent Bytes()/String()/Struct() calls. The expected output correctly shows _, err := client.Post(...) pattern.


993-1052: LGTM - Tests existing error variable reuse.

Good test coverage for the case where err is already declared. The expected output correctly shows _, err = client.Post(...) with = instead of :=.


1054-1117: LGTM - Tests collision avoidance.

This test validates the chooseErrName function when a future var err declaration exists. The expected output correctly uses clientErr as the alternative name.

@ReneWerner87
Copy link
Member Author

/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 enhances the client usage migrator by adding support for AcquireAgent blocks that only parse requests, and by making the error variable handling more robust to avoid naming collisions. The changes are well-structured and include comprehensive test cases for the new functionality.

I've found a potential issue in the futureErrConflictExists function that might fail to detect some variable conflicts, and a typo in one of the new test cases. My review includes suggestions to address these points.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a30e352 and 8fdabd1.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (16 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/internal/migrations/v3/client_usage_test.go (1)
cmd/internal/migrations/v3/client_usage.go (1)
  • MigrateClientUsage (76-114)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, windows-latest)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
🔇 Additional comments (24)
cmd/internal/migrations/v3/client_usage.go (19)

32-36: requestBodyPattern looks correct and matches both SetBody and SetBodyString.

The new requestBodyPattern cleanly captures calls to req.SetBody(...) and req.SetBodyString(...) with the same capture groups as the other request patterns, which is consistent with how you later use it when populating bodyExpr. No issues here.


38-53: New generic agent patterns are consistent and non-overlapping.

The added patterns (headerSetSimplePattern, queryStringPattern, timeoutPattern, jsonBodyPattern, bodyPattern, basicAuthPattern, tlsConfigPattern, debugPattern, reusePattern, agentBytesCallPattern, agentStringCallPattern, agentStructCallPattern, futureErrConflictPattern) use the same capture style as the rest of the file and match the expected call shapes. In particular, futureErrConflictPattern = ^(?:var\s+err\b|err\s*:=) resolves the earlier false-positive concern around "var error" / "var errMsg" while focusing on real err declarations.


71-74: Centralizing callTypeString and defaultErrName is a nice cleanup.

Using callTypeString and defaultErrName constants keeps the later code paths (buildSimpleAgentReplacement, chooseErrName) clearer and avoids magic strings.


172-199: Body extraction from AcquireAgent request is wired correctly.

The new bodyExpr handling with requestBodyPattern integrates cleanly into the existing scan loop: only lines tied to the same reqVar are used, and bodyExpr is trimmed before being passed through to buildConfig. This matches how URI and headers are handled and should cover both SetBody and SetBodyString cases.


246-247: Config now correctly carries headers and body into client.Config.

configLine := buildConfig(headers, bodyExpr) threads both collected headers and optional body expression into the client call. This is what enables the new Parse+Body test, and the interface (headers map[string]string, body string) is straightforward.


272-277: Struct-case AcquireAgent rewrite correctly maps Parse+Struct to client + JSON.

The generated sequence:

  • resp, <errName> <errAssign> client.<Method>(uri, config)
  • if <errName> != nil { <parseBody> }
  • Declaration of status/body vars.
  • if <errName> == nil { ...; <errName> = resp.JSON(target) }
  • Final if <errName> != nil { <structBody> }

preserves the original control flow while avoiding nil dereferences and reusing the parse/struct error-handling bodies (with replaceErrIdentifier to adjust the identifier as needed). This is a solid transformation.


285-296: Struct-case post-call error-path reuse is correct and identifier-safe.

Reusing the original struct error block via:

  • if <errName> == nil { ... } to guard JSON decoding.
  • Final if <errName> != nil { replaceErrIdentifier(structBody[..], errName)... }.

ensures you keep the original response-handling semantics (status codes, JSON error response, etc.), and replaceErrIdentifier only touches standalone err tokens, leaving any other identifiers intact.


302-317: Bytes-case AcquireAgent rewrite mirrors struct-case semantics appropriately.

The bytes path:

  • Uses errAssignmentOperator with "resp" and the same <errName> logic.
  • Declares statusVar and bodyVar explicitly.
  • Only reads from resp when <errName> == nil.

This matches the intended “Parse+Bytes” behavior while keeping error-handling centralized on the chosen error variable.


323-338: String-case AcquireAgent rewrite is consistent with bytes/struct branches.

The string variant uses:

  • bodyVar as string, not []byte.
  • resp.String() instead of resp.Body().

and otherwise follows the same flow as the bytes case, which is exactly what we want.


389-411: Err-name selection strategy is robust and avoids most real collisions.

chooseErrName:

  • Prefers defaultErrName when it’s already declared (to reuse the existing error variable).
  • Otherwise, uses defaultErrName if no future var err / err := is detected in the remaining lines.
  • When a future conflict exists, cycles through {"clientErr","agentErr","parseErr",...} and then err1, err2, ... until it finds a name not declared before idx or later in original[idx:].

This approach nicely handles:

  • Shared error variables across multiple rewrites.
  • Late declarations of err that might clash with generated code.
  • Avoiding collisions with locals introduced after the rewrite insertion point.

Given the complexity trade-offs without a real AST, this is a reasonable and pragmatic design.


413-430: futureErrConflictExists correctly filters out control statements and comments.

By trimming, skipping empty/comment lines, and ignoring lines starting with if / for / switch , futureErrConflictExists avoids misclassifying inline if err := ... patterns and focuses on “naked” var err / err := statements. Combined with futureErrConflictPattern, this should minimize false positives while still catching real future conflicts.


432-445: replaceErrIdentifier is safe within the rewritten blocks.

The helper:

  • Early-returns if errName is defaultErrName, avoiding unnecessary work.
  • Uses \berr\b so it won’t touch errs, errMsg, etc.
  • Operates only on the slice of lines explicitly passed from the parse/struct bodies (excluding the closing brace).

Given Go’s scoping for if err := ...; err != nil { ... }, the err inside these blocks always refers to the inner error, so renaming all err tokens in those slices is semantically correct.


447-475: identifierDeclared / identifierDeclaredInLines are well-scoped and avoid “err-like” names.

The combined behavior:

  • Checks both existing (already-emitted code) and original before idx.
  • Uses two regexes:
    • shortPattern for <name> := (with delimiters).
    • varPattern for ^var <name>....

These won’t accidentally match errMsg, error, etc., and they correctly ignore comments/blank lines. This is exactly what you want for the err-name and assignment heuristics.


495-520: buildConfig(headers, body) correctly assembles client.Config, including body.

The function:

  • Returns "" when there’s no header and no body, preserving the “no config” case.
  • Sorts header keys and emits Header: map[string]string{...} with stable ordering.
  • Adds Body: <bodyExpr> verbatim when non-empty.
  • Wraps everything as , client.Config{...} (matching existing callers’ expectations).

This lines up with how buildSimpleConfig works and is exactly what the new Parse+Body and AcquireAgent tests expect.


592-593: Choosing a shared errName for simple agent blocks improves consistency.

Calling errName := chooseErrName(out, lines, i) at the start of rewriteSimpleAgentBlocksWithAlias lets all the transformed calls in that block share a coherent error variable, while still avoiding conflicts with pre-existing or future err declarations. This makes multi-call functions easier to read post-migration.


673-702: Simple-agent call branches correctly coordinate err assignment with potential new agent vars.

For each of the agentBytesCallPattern, agentStringCallPattern, and agentStructCallPattern matches:

  • newVar is set to varName only when the original call uses :=, signaling that the agent itself may be newly introduced there.
  • errAssignmentOperator then decides between := and = based on whether errName is already declared and whether varName is a genuinely new identifier at this point.
  • The resulting errAssign is threaded into buildSimpleAgentReplacement, which uses <varName>, <errName> <errAssign> client....

This should address the earlier concern about spurious err redeclarations in simple-agent flows while still handling cases where the agent variable is reused.


725-762: buildSimpleAgentReplacement integrates errName cleanly and keeps behavior.

The updated helper:

  • Emits <varName>, <errName> <errAssign> client.<Method>(url, config).
  • Initializes status/body either as var declarations or by resetting existing variables when assignOp == "=".
  • Uses if <errName> == nil { ... } to guard response reads.
  • For struct calls, adds errName = <varName>.JSON(target) inside the success branch.

This generalizes nicely across bytes/string/struct cases and respects both “redeclare” and “reuse existing” scenarios for the status/body variables.


247-252: Err-name selection and assignment operator for struct-case AcquireAgent look sound.

errName := chooseErrName(out, lines, i) plus errAssign := errAssignmentOperator(errName, out, lines, i, "resp") mean:

  • You reuse an existing err-like identifier when safe.
  • You fall back to = instead of := when that identifier is already declared and there are no new vars on the LHS.
  • For this branch, "resp" is considered as a potential new variable, which helps avoid unnecessary name changes or shadowing.

In Go, a multi-variable short declaration like resp, err := client.Post(...) is valid when err is already declared in the same block, as long as resp is a new identifier. The error "no new variables on left side of :=" only occurs when all identifiers on the LHS are already declared. This approach should eliminate most of the err-redeclaration pitfalls while keeping the generated code idiomatic.


365-387: Current implementation already handles err-variable safety correctly.

errAssignmentOperator is sound as written. The underlying concern about future err declarations is already addressed: chooseErrName uses futureErrConflictExists to detect downstream var err or err := declarations and selects an alternative error variable name if needed. Once a safe error variable is chosen, errAssignmentOperator correctly decides between = and := based on whether that variable is already declared and whether new variables are being introduced. No refactor is necessary.

cmd/internal/migrations/v3/client_usage_test.go (5)

538-607: Parse+Bytes+Body test correctly exercises header+body propagation.

Test_MigrateClientUsage_RewritesParseBytesFlowWithBody:

  • Starts from an AcquireAgent + Parse + Bytes flow that sets Content-Type and body on the request.
  • Expects a client.Post call with client.Config{Header: map[string]string{"Content-Type": "application/json"}, Body: "{\"demo\":true}"}.
  • Verifies the standard resp, err / status/body extraction / if err != nil { panic(err) } pattern.

This is a solid regression test for the new requestBodyPattern + buildConfig behavior.


1005-1064: AcquireAgent-only Parse test validates the new parse-only migration path.

Test_MigrateClientUsage_AcquireAgentOnlyParse:

  • Starts from an AcquireAgent that only calls Parse() and logs on error.
  • Expects _, err := client.Post(..., client.Config{Header: ...}) and a simple if err != nil { log.Errorf(...) }.

This verifies that the new default branch in rewriteAcquireAgentBlocksWithAlias handles “parse-only” blocks without requiring a subsequent Bytes/Struct call.


1066-1125: Existing-err Parse-only test confirms = path and no redeclaration.

Test_MigrateClientUsage_AcquireAgentOnlyParseWithExistingErr:

  • Declares var err error before the AcquireAgent block.
  • Expects the migration to emit _, err = client.Post(...) (assignment, not short declaration) and reuse that err in the subsequent if err != nil check.

This nicely confirms that errAssignmentOperator detects an in-scope error variable and avoids := when there are no new non-blank LHS variables.


1127-1190: Collision test for future var err correctly exercises alternate errName logic.

Test_MigrateClientUsage_AcquireAgentOnlyParseAvoidsErrCollisions:

  • Has an AcquireAgent-only Parse block with logging, and then later declares var err error.
  • Expects the migration to use clientErr (not err) for the client call and logging (_, clientErr := client.Post(...); if clientErr != nil { log.Errorf(..., clientErr) }).

This directly validates the futureErrConflictExists + chooseErrName logic and ensures the generated error identifier doesn’t collide with a future var err in the same function.


1192-1255: “Err-like” name test ensures identifierDeclared doesn’t overmatch.

Test_MigrateClientUsage_AcquireAgentOnlyParseIgnoresErrLikeNames:

  • Defines var errMsg string after the Parse-only block.
  • Expects the migration to still use the default err identifier (_, err := client.Post(...)), and to leave errMsg alone.

This confirms that identifierDeclared and identifierDeclaredInLines respect full identifier names and don’t treat errMsg as an err collision, addressing the earlier false-positive concern from prior reviews.

@ReneWerner87
Copy link
Member Author

/gemini review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fdabd1 and 3956cfb.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (16 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/internal/migrations/v3/client_usage.go
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/internal/migrations/v3/client_usage_test.go (1)
cmd/internal/migrations/v3/client_usage.go (1)
  • MigrateClientUsage (77-115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
  • GitHub Check: Build (1.25.x, windows-latest)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
🔇 Additional comments (5)
cmd/internal/migrations/v3/client_usage_test.go (5)

538-609: Parse+Bytes with body migration test looks solid

The sample/expected pair for Test_MigrateClientUsage_RewritesParseBytesFlowWithBody (Line [538]-[609]) correctly exercises the new client.Post path, including propagation of method, Content-Type header, and body, and reuses the established error-handling pattern from the other Parse+Bytes tests. No issues from my side here.


1005-1064: Good coverage of parse-only AcquireAgent with logging

Test_MigrateClientUsage_AcquireAgentOnlyParse (Line [1005]-[1064]) nicely verifies the new path where a Parse-only AcquireAgent block is rewritten into a client.Post call, preserving the original logging behavior and ensuring the client import is added while keeping the log import. This matches the intended semantics.


1066-1125: Reusing existing err variable is appropriate

In Test_MigrateClientUsage_AcquireAgentOnlyParseWithExistingErr (Line [1066]-[1125]), the expected code reuses the predeclared var err error and assigns the client.Post error into it. That’s consistent with the test’s intent (“WithExistingErr”) and will generally integrate better with real-world handlers that already use a shared err. Looks good.


1127-1190: Nice edge‑case test for avoiding err name collisions

Test_MigrateClientUsage_AcquireAgentOnlyParseAvoidsErrCollisions (Line [1127]-[1190]) correctly checks that the migrator introduces a distinct clientErr when a separate var err error is declared later in the function, preventing name clashes. This is a valuable regression test for name-selection logic.


1192-1255: Correct handling of err-like but non-err identifiers

Test_MigrateClientUsage_AcquireAgentOnlyParseIgnoresErrLikeNames (Line [1192]-[1255]) ensures that identifiers such as errMsg don’t interfere with choosing err as the error variable for the migrated client.Post call. The expected output keeps errMsg untouched and uses err for the client call, which is the right behavior.

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 extends the client usage migrator to handle AcquireAgent blocks that only parse requests without subsequent result extraction calls (e.g., .Bytes()). It also introduces sophisticated logic to avoid error variable name collisions by choosing non-conflicting names like clientErr and correctly using = or := for assignment. The changes are well-tested with several new test cases covering various scenarios.

However, I've found a couple of significant issues:

  1. A critical flaw in the rewriteClientErrorHandling function causes it to perform a blind replacement of errs with err. This can break user code that uses an errs variable for other purposes, leading to uncompilable code. A new test case unfortunately asserts this incorrect behavior.
  2. The logic for determining the assignment operator (:= vs =) in rewriteSimpleAgentBlocksWithAlias is overly complex and incorrect when dealing with shadowed variables, which can also lead to compilation errors.

I've left detailed comments with suggestions on how to address these issues. Once these are fixed, this will be a great improvement to the migration tool.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
cmd/internal/migrations/v3/client_usage.go (1)

498-513: Heuristic in declaredInVarBlockLine may be fragile.

The function checks if a line starts with the identifier name and lacks assignment operators. However, this approach might not correctly handle all declaration formats, especially:

  • Multi-line var blocks with alignment
  • Declarations with complex types
  • Lines with comments

Consider adding test coverage for edge cases like:

var (
    err error    // comment
    errs []error
)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3956cfb and be2484f.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (17 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/internal/migrations/v3/client_usage_test.go (1)
cmd/internal/migrations/v3/client_usage.go (1)
  • MigrateClientUsage (77-115)
🔇 Additional comments (14)
cmd/internal/migrations/v3/client_usage.go (8)

32-32: Pattern definitions look good.

The new regex patterns correctly use word boundaries (\b) to avoid false positives when matching error variable declarations, addressing concerns from previous reviews.

Also applies to: 40-54


72-75: LGTM!

The constants are well-defined and improve code clarity.


177-177: Body extraction and error-name selection properly integrated.

The body expression is correctly extracted from the request setup and passed through to the config builder, while the error name is chosen to avoid conflicts.

Also applies to: 197-200, 247-249


366-388: Assignment operator logic correctly handles existing error variables.

The function properly determines when to use = vs := based on scope analysis, addressing the redeclaration concerns from previous reviews. When err is already in scope and no new variables are being introduced, it correctly uses = to avoid compilation errors.


390-412: Error name selection logic is thorough.

The function systematically checks for conflicts with both existing and future declarations, falling back to a list of candidate names. This should prevent most collision scenarios.


414-443: Future conflict detection handles most cases correctly.

The function appropriately skips block-scoped declarations (if/for/switch) since they won't conflict with function-level error variables. The regex patterns with word boundaries help avoid false positives.


533-558: Body parameter correctly integrated into config builder.

The function now properly includes the body in the generated client.Config when provided, supporting the parse-only migration path with request bodies.


994-1009: Guard clause prevents mutating unrelated error slices.

The check for legacy error patterns (hasLegacyErrs) before rewriting ensures that custom errs slices unrelated to the v2 client API are preserved. This addresses concerns from previous reviews about breaking valid user code.

cmd/internal/migrations/v3/client_usage_test.go (6)

538-609: Test correctly validates body migration for AcquireAgent+Parse flow.

The test verifies that request bodies set via SetBodyString are properly extracted and included in the client.Config, ensuring the parse-with-body migration path works as intended.


1005-1064: Parse-only migration test validates core functionality.

The test confirms that AcquireAgent blocks containing only Parse() (without subsequent Bytes()/String()/Struct() calls) are correctly migrated to client.Post with the response assigned to _ since it's unused.


1066-1125: Test validates assignment operator selection with existing error variable.

The test correctly verifies that when err is already declared, the migration uses = instead of := for the assignment, preventing "no new variables on left side of :=" compilation errors.


1127-1190: Test confirms collision avoidance with future error declarations.

The test validates that the migration detects future err declarations and chooses an alternative error variable name (clientErr) to prevent redeclaration errors, demonstrating proper forward-looking conflict detection.


1192-1255: Test validates precise error name conflict detection.

The test confirms that variables with err as a prefix (like errMsg) don't trigger false positives in conflict detection, thanks to the word-boundary checks in the regex patterns.


1257-1311: Test correctly preserves custom error slices.

The test validates that custom errs []error slices (not using legacy v2 client patterns) are preserved during migration, with the migrated code introducing a separate err variable. This addresses concerns from previous reviews and ensures custom error handling logic remains intact.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
cmd/internal/migrations/v3/client_usage.go (1)

234-285: AcquireAgent struct/bytes/string + parse‑only rewrites: structure is sound but leaves unused errs locals

The expanded AcquireAgent handling correctly:

  • Preserves comments and non‑err/errs var declarations between Parse and the Struct/Bytes/String call.
  • Introduces a computed errName and errAssign, using errAssignmentOperator so := vs = is chosen based on prior declarations and new response vars.
  • Guards response field access and JSON decoding behind if <errName> == nil to avoid nil dereferences.
  • Adds a default branch that rewrites parse‑only blocks into a single client.<Method> call followed by an if <errName> != nil { ... } containing the original Parse error body.

However, for struct‑based flows (e.g., Test_MigrateClientUsage_RewritesAcquireAgentStruct), the migration leaves errs []error declared in the function’s var block while all uses of errs are removed in favor of the single <errName> variable. This results in migrated code with an unused local errs, which is a compile‑time error in Go.

You’ll need to either:

  • Also rewrite the corresponding var errs []error declaration to a single err (or <errName>) declaration when you perform the struct rewrite, or
  • Ensure rewriteClientErrorHandling still runs for these cases and rewrites the declaration and remaining errs usages, without regressing the new “errs slice” preservation tests.

Right now, after the struct rewrite, there are no remaining len(errs)/"errs": errs patterns, so hasLegacyErrs stays false and rewriteClientErrorHandling never touches the now‑orphaned errs declaration.

Also applies to: 287-352, 355-433, 434-443

cmd/internal/migrations/v3/client_usage_test.go (1)

256-342: Tests correctly exercise AcquireAgent struct flows but encode an unused errs local

The RewritesAcquireAgentStruct and RewritesAcquireAgentStructWithVarsBetweenParseAndCall tests do a good job of:

  • Asserting that AcquireAgent+Struct flows are rewritten to a single client.Post call with guarded status/body extraction and JSON decoding.
  • Verifying that interleaved var declarations between Parse and Struct are preserved appropriately, and that error identifiers (err vs clientErr) are chosen to avoid collisions with later var err error.

However, the expected code in RewritesAcquireAgentStruct still declares errs []error in the function’s var block while all its usages have been removed in favor of a single err value. That mirrors the production behavior noted in client_usage.go and would cause migrated user code not to compile (errs declared but not used).

Once the underlying migrator is updated to drop or rewrite that declaration, these expectations should be adjusted to match the new, compile‑correct output.

Also applies to: 344-426

🧹 Nitpick comments (1)
cmd/internal/migrations/v3/client_usage.go (1)

534-566: replaceErrIdentifier and hasBlankAssignment are reasonable heuristics

  • replaceErrIdentifier cleanly rewrites err and (optionally) errs usages inside migrated blocks to the chosen errName, with replaceErrs selectively enabled where a slice of errors is intentionally collapsed.
  • hasBlankAssignment scans the original file for _ = <name> to avoid injecting duplicate blank assignments when synthesizing _ = statusVar/_ = bodyVar safety lines.

The trade‑off (potentially skipping a needed blank assignment if one only appears in a comment, and sometimes adding redundant _ = for variables that end up used later) is acceptable for a migration tool and is covered by tests.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be2484f and b582a77.

📒 Files selected for processing (3)
  • cmd/internal/migrations/v3/client_usage.go (15 hunks)
  • cmd/internal/migrations/v3/client_usage_internal_test.go (1 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
  • GitHub Check: Build (1.25.x, windows-latest)
🔇 Additional comments (8)
cmd/internal/migrations/v3/client_usage_internal_test.go (1)

68-81: AcquireAgent→client.Post struct rewrite expectation looks consistent

The new expected block matches the struct-case rewrite in rewriteAcquireAgentBlocksWithAlias: early return on transport error, guarded population of retCode/retBody, then resp.JSON(&t) and a final err != nil branch returning a 500 JSON. Behavior is consistent with the single‑error model used elsewhere and is a good fit for the production rewrite.

cmd/internal/migrations/v3/client_usage.go (5)

31-36: Regex additions for body and agent methods align with intended patterns

The new requestBodyPattern and the expanded agent‑method patterns (headerSetSimplePattern, bodyPattern, agent*CallPatterns, etc.) are consistent with the existing style and correctly capture the SetBody/SetBodyString and other method invocations needed by the migrator. They give rewriteAcquireAgentBlocksWithAlias and rewriteSimpleAgentBlocksWithAlias the necessary hooks without over‑matching obvious non‑agent code.

Also applies to: 38-54


173-201: Body-aware AcquireAgent config looks correct

Capturing SetBody/SetBodyString into bodyExpr and threading it into buildConfig(headers, bodyExpr) produces the expected client.Config{Header: ..., Body: ...} literals (as exercised by the new RewritesParseBytesFlowWithBody test). The matching logic ensures only the current request variable is considered, so unrelated SetBody* calls won’t be pulled into the config.

Also applies to: 279-285


479-532: Err-name selection and future-conflict detection behave well for new tests

The chooseErrName + futureErrConflictExists combo correctly supports the new test cases:

  • Defaulting to "err" when neither err nor errs exists in the current scope and no future var err/err :=/var errs/errs := appears (e.g., AcquireAgentOnlyParse, AcquireAgentOnlyParseRespectsErrsSlice).
  • Falling back to alternate names like clientErr when a future var err error would otherwise collide (AcquireAgentOnlyParseAvoidsErrCollisions).
  • Treating var errMsg string and other “err‑like” identifiers as non‑conflicting (AcquireAgentOnlyParseIgnoresErrLikeNames).

The additional checks for var‑block entries via declaredInVarBlockLine are a good touch to catch var (...) declarations without over‑matching.


641-666: buildConfig’s new body support matches expected client.Config literals

Extending buildConfig to accept a body expression and append Body: <expr> into the client.Config{...} literal works as intended, including:

  • Sorting headers for deterministic output.
  • Emitting Body: <expr> only when a body was actually captured (e.g., from SetBodyString), which is validated by RewritesParseBytesFlowWithBody.

This keeps the simple-agent and AcquireAgent code paths consistent in how they construct configs.


738-833: Simple-agent rewrites now use a fixed := for response/err, avoiding shadowing bugs

rewriteSimpleAgentBlocksWithAlias now:

  • Picks an errName with chooseErrName.
  • Always passes ":=" for errAssign into buildSimpleAgentReplacement.

And buildSimpleAgentReplacement emits:

<indent><varName>, <errName> := client.Method(...)

This avoids the earlier risk of using = when the response variable shadows the original agent variable (causing type mismatches), and matches how Go permits reusing err alongside a newly introduced <varName>. It’s a good simplification and aligns with previous review feedback on this path.

Also applies to: 856-893

cmd/internal/migrations/v3/client_usage_test.go (2)

622-695: New tests around parse-only AcquireAgent and errs-slice behavior are well targeted

The added tests:

  • AcquireAgentOnlyParse, AcquireAgentOnlyParseWithExistingErr, AcquireAgentOnlyParseAvoidsErrCollisions, and AcquireAgentOnlyParseIgnoresErrLikeNames collectively validate:
    • Basic parse‑only migration to client.Post.
    • Correct reuse of an existing err variable (_= client.Post with =).
    • Selection of alternate names like clientErr to avoid future var err collisions.
    • Ignoring err‑like identifiers such as errMsg when choosing the error variable.
  • AcquireAgentOnlyParseRespectsErrsSlice ensures that a legitimate []error accumulator (var errs []error + errs = append(errs, err)) remains a slice and is not rewritten to a single err, addressing the earlier semantic concern around multi‑error collectors.

These tests give very good coverage of the new error‑naming and slice‑preservation logic around parse‑only blocks, and will help prevent regressions in future tweaks.

Also applies to: 1093-1399


622-695: Body-handling tests validate AcquireAgent parse+Bytes migration

RewritesParseBytesFlowWithBody (and the existing RewritesParseBytesFlow) nicely confirm that:

  • AcquireAgent flows using req.SetBodyString(...) and a.Bytes() migrate to a client.Post call with a client.Config{Header: ..., Body: ...} argument.
  • Status and body are populated only when err == nil, and error paths still propagate via panic(err).

This aligns with the new requestBodyPattern + buildConfig behavior and confirms the body-aware changes are wired through correctly.

Also applies to: 537-617

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
cmd/internal/migrations/v3/client_usage.go (4)

649-664: declaredInVarBlockLine only detects grouped var block declarations.

This function checks for lines starting with the identifier name (e.g., err error inside var (...)), not standalone var err error declarations. This is intentional since standalone declarations are handled by varPattern in identifierDeclaredInLines. The logic is correct but the function name could be slightly misleading.

Consider adding a brief doc comment clarifying this handles grouped var (...) block entries:

+// declaredInVarBlockLine checks if a line within a grouped var block
+// declares the given identifier (e.g., "err error" for name="err").
 func declaredInVarBlockLine(name, trimmed string) bool {

1008-1008: Hardcoded err identifier in replacement builders may cause conflicts.

Functions like buildBytesWithBodyReplacement and others in this section hardcode err in the generated output. Unlike the rewriteAcquireAgentBlocksWithAlias path which uses chooseErrName, these don't adapt to existing err declarations in scope.

This is pre-existing behavior, but for consistency with the new error-naming logic, consider threading errName through these replacement functions in a follow-up.


562-578: replaceErrIdentifier creates new regex on every call.

The function compiles errPattern and errsPattern regexes on each invocation. Since this may be called multiple times during migration, consider moving these to package-level compiled patterns for efficiency.

+var (
+	errWordPattern  = regexp.MustCompile(`\berr\b`)
+	errsWordPattern = regexp.MustCompile(`\berrs\b`)
+)
+
 func replaceErrIdentifier(lines []string, errName string, replaceErrs bool) []string {
 	replaced := make([]string, len(lines))
-	errPattern := regexp.MustCompile(`\berr\b`)
-	errsPattern := regexp.MustCompile(`\berrs\b`)

 	for i, line := range lines {
-		updated := errPattern.ReplaceAllString(line, errName)
+		updated := errWordPattern.ReplaceAllString(line, errName)
 		if replaceErrs {
-			replaced[i] = errsPattern.ReplaceAllString(updated, errName)
+			replaced[i] = errsWordPattern.ReplaceAllString(updated, errName)
 			continue
 		}

 		replaced[i] = updated
 	}

 	return replaced
 }

585-585: Regex compiled inside loop in hasBlankAssignment.

Similar to replaceErrIdentifier, this function compiles a regex on each call. For a small number of calls this is acceptable, but if performance becomes a concern, consider caching or restructuring.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 016685d and 46205df.

📒 Files selected for processing (1)
  • cmd/internal/migrations/v3/client_usage.go (13 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, windows-latest)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
🔇 Additional comments (8)
cmd/internal/migrations/v3/client_usage.go (8)

52-53: Regex patterns for future conflict detection look correct.

The use of \b word boundaries in futureErrConflictPattern and futureErrsConflictPattern properly constrains matching to exact err and errs identifiers, avoiding false positives with similar names like errMsg.


72-75: Constants are well-defined.

callTypeString and defaultErrName provide clear named constants that improve readability throughout the file.


254-266: Skipping var err and var errs during preserved-line collection is correct.

This prevents these declarations from being duplicated or misplaced in the output, as they'll be handled by the error-naming logic.


309-315: Body handling with SetRawBody looks correct.

The logic correctly wraps string body expressions with []byte() when bodyIsString is true, ensuring type compatibility with SetRawBody.


461-471: Parse-only AcquireAgent migration path is well-implemented.

This default case correctly handles AcquireAgent blocks that only call Parse() without subsequent Bytes/String/Struct calls. The response is discarded with _, and error handling is properly injected using the chosen error name.


507-529: chooseErrName logic is sound.

The function correctly:

  1. Reuses err if already declared in scope
  2. Uses err if no future conflicts exist
  3. Falls back to candidate names (clientErr, agentErr, etc.) when conflicts are detected

This addresses the previously flagged concern about err redeclaration.


874-878: buildSimpleAgentReplacement correctly uses := for new response declarations.

The response variable shadows the original agent variable with a different type (*client.Response vs *fiber.Agent), so using := is correct here since it's a new declaration in the output.


1120-1135: Conditional error handling rewrite is well-designed.

The hasLegacyErrs gate correctly limits the errserr transformation to files with actual legacy Fiber multi-error patterns (if len(errs) > 0, "errs": errs, etc.), preserving unrelated []error slices.

@ReneWerner87
Copy link
Member Author

/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 significantly improves the client usage migrator by adding support for 'parse-only' agent blocks and making the error handling more robust by avoiding variable name collisions. The changes are extensive and well-tested, covering many edge cases. I've identified a couple of areas for improvement to prevent potential data loss during migration and to make the legacy pattern detection even more comprehensive. Overall, this is a very solid contribution.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46205df and d04112f.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (13 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/internal/migrations/v3/client_usage_test.go (1)
cmd/internal/migrations/v3/client_usage.go (1)
  • MigrateClientUsage (77-115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, windows-latest)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
🔇 Additional comments (6)
cmd/internal/migrations/v3/client_usage.go (3)

173-501: AcquireAgent rewrite + parse-only path and body handling look consistent and well-scoped.

The extended rewriteAcquireAgentBlocksWithAlias logic correctly:

  • Tracks bodyExpr / bodyIsString via requestBodyPattern and emits SetRawBody([]byte(...)) when needed.
  • Preserves comments and non-err/errs var declarations between Parse() and the terminal Struct/Bytes/String call, then re-inserts them while marking original lines as skipped.
  • Reconstructs the flow for Struct/Bytes/String cases by:
    • Choosing an error identifier with chooseErrName.
    • Using errAssignmentOperator to pick := vs = safely when errName or resp are already in scope.
    • Preventing nil dereferences by declaring status/body vars and populating them only under if errName == nil { ... }.
    • Re-emitting the original error branches with replaceErrIdentifier so they key off the new errName instead of the old parse/errs variables.
  • Handles the parse‑only branch in the default case by emitting _, <errName> <op> req.Send() followed by the original handler body guarded under if <errName> != nil { ... }, which aligns with the new tests for AcquireAgentOnlyParse*.

This restructuring aligns with the new tests (e.g., parse‑only, with existing err, and collision‑avoidance cases) and avoids double‑emitting old agent/parse lines thanks to the updated i = ... jumps and skipLines usage.


800-977: Simple-agent rewrite now uses explicit errName and always short-declares the response/err pair.

The changes in rewriteSimpleAgentBlocksWithAlias and buildSimpleAgentReplacement look good:

  • errName := chooseErrName(out, lines, i) mirrors the AcquireAgent path, so simple-agent rewrites benefit from the same collision avoidance and future-conflict logic.
  • Passing errAssign := ":=" explicitly into buildSimpleAgentReplacement guarantees varName, errName are short-declared (no attempt to reuse an existing agent variable with =), which matches the original agent := fiber.Get(...) shape and addresses the prior concern about over‑smart assignment-operator selection.
  • buildSimpleAgentReplacement correctly parameterizes:
    • The call type (bytes vs string vs struct) via callType and callTypeString.
    • The error variable via errName in both the if errName == nil block and the JSON decode path for struct calls.

Given this is a one-shot migration tool, the small cost of recalculating config and generating these patterns is acceptable, and the behavior now aligns with the updated tests.


1186-1199: Gated rewriteClientErrorHandling avoids clobbering arbitrary errs slices.

The hasLegacyErrs guard ensures you only rewrite to single-error semantics when the classic multi-error patterns are present (if len(errs) > 0, len(errs) usage, "errs": errs), which fixes the earlier issue where unrelated []error accumulators were being renamed and broken.

This gating is especially important now that AcquireAgent-only-parse flows can legitimately use an errs []error accumulator (e.g., AcquireAgentOnlyParseRespectsErrsSlice), and the implementation here matches that intent.

cmd/internal/migrations/v3/client_usage_test.go (3)

349-436: Good coverage for struct flow with vars between Parse and the call, including future err collisions.

Test_MigrateClientUsage_RewritesAcquireAgentStructWithVarsBetweenParseAndCall nicely exercises:

  • Local vars declared between a.Parse() and a.Struct(...) (status/body/errs/target), ensuring the migrator preserves their declarations and moves them to the right place.
  • A later var err error in the same function, verifying chooseErrName/futureErrConflictExists pick clientErr and that the rewritten flow uses clientErr consistently in both the direct return clientErr path and the JSON/response error branch.

This directly validates the more complex scoping and collision-avoidance logic added in rewriteAcquireAgentBlocksWithAlias.


634-711: Parse-bytes-with-body test validates request-body capture and raw-body emission.

Test_MigrateClientUsage_RewritesParseBytesFlowWithBody correctly asserts that:

  • A POST + SetBodyString + SetRequestURI + Parse() + Bytes() flow is rewritten to:
    • client.New() / a.R() with SetMethod("POST"), SetURL(...), and SetHeader("Content-Type", "application/json").
    • SetRawBody([]byte("{\"demo\":true}")) carrying over the string body.
    • A single resp, err := req.Send() plus the standard status/body extraction and error handling.

This test gives solid coverage for the new requestBodyPattern and bodyExpr/bodyIsString handling in the AcquireAgent path.


1112-1442: AcquireAgent-only-parse test matrix comprehensively exercises err naming and slice preservation.

The new tests around parse-only AcquireAgent usage are well-chosen:

  • AcquireAgentOnlyParse checks the basic transformation from a.Parse() with logging into req.Send() with err and preserved log call.
  • AcquireAgentOnlyParseWithExistingErr verifies that an existing var err error leads to _ , err = req.Send() (assignment, not declaration).
  • AcquireAgentOnlyParseAvoidsErrCollisions confirms that a later var err error forces an alternate name (clientErr), and that all uses in the log branch are rewritten to clientErr.
  • AcquireAgentOnlyParseIgnoresErrLikeNames ensures identifiers like errMsg do not influence the chosen error name or assignment operator.
  • AcquireAgentOnlyParseRespectsErrsSlice ensures a user-managed var errs []error accumulator plus append(errs, err) and fmt.Println(errs) is preserved, with the migrator only injecting _ , err := req.Send() and if err != nil { errs = append(errs, err) }.

Together these tests provide strong regression coverage for the new chooseErrName, futureErrConflictExists, and rewriteClientErrorHandling gating behavior in the parse-only path.

@ReneWerner87 ReneWerner87 merged commit 09c9abb into master Dec 7, 2025
14 of 15 checks passed
@ReneWerner87 ReneWerner87 deleted the codex/2025-12-06-08-00-08 branch December 7, 2025 15:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
cmd/internal/migrations/v3/client_usage.go (1)

1203-1216: Redundant condition check.

Lines 1213-1216 are redundant since baseLegacy is already checked at line 1208. If !baseLegacy, the function returns at line 1210, so hasLegacyErrs will always be true when reaching line 1214.

Consider simplifying:

 func rewriteClientErrorHandling(content string) string {
 	// Only rewrite when we see the legacy multi-error usage patterns. This avoids
 	// mutating unrelated identifiers such as custom "errs" slices.
 	baseLegacy := clientErrIfPattern.MatchString(content) || clientErrLenPattern.MatchString(content) || clientErrComparePattern.MatchString(content) || clientErrMapPattern.MatchString(content)
-	declaredErrs := clientErrsDeclPattern.MatchString(content)
 	if !baseLegacy {
 		// Declaration-only cases keep errs slices intact.
 		return content
 	}
-
-	hasLegacyErrs := baseLegacy || declaredErrs
-	if !hasLegacyErrs {
-		return content
-	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d04112f and bf9f607.

📒 Files selected for processing (2)
  • cmd/internal/migrations/v3/client_usage.go (13 hunks)
  • cmd/internal/migrations/v3/client_usage_test.go (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/internal/migrations/v3/client_usage_test.go (1)
cmd/internal/migrations/v3/client_usage.go (1)
  • MigrateClientUsage (76-114)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build (1.25.x, windows-latest)
  • GitHub Check: Build (1.25.x, macos-13)
  • GitHub Check: Build (1.25.x, macos-latest)
  • GitHub Check: Build (1.25.x, ubuntu-latest)
🔇 Additional comments (32)
cmd/internal/migrations/v3/client_usage.go (20)

71-74: LGTM!

Constants are well-defined and provide good maintainability for the error name handling logic.


176-201: LGTM!

Body handling logic correctly distinguishes between SetBody and SetBodyString, capturing the expression for proper translation to SetRawBody in the migrated code.


235-311: LGTM!

The preserved lines handling correctly addresses the previous concerns about code deletion. Parse-only blocks are now properly detected and handled, with comments and variable declarations being preserved appropriately.


313-348: LGTM!

Error name selection and client setup logic properly handles collision detection and method literal conversion. The body expression wrapping for string bodies ([]byte(bodyExpr)) is correct.


349-417: LGTM!

The struct case handling correctly propagates error names, handles variable declarations, and includes backward compatibility for errs slices when needed.


418-459: LGTM!

Bytes case handling follows the same consistent pattern as the struct case with proper error propagation.


460-501: LGTM!

String case handling correctly uses string type for the body variable and follows the same consistent pattern.


502-519: LGTM!

The default case properly handles parse-only AcquireAgent blocks as described in the PR objectives. The conditional placement of addPreserved ensures preserved lines appear in the correct location.


530-552: LGTM!

The errAssignmentOperator function correctly determines whether to use := or = based on whether the error variable is already in scope and whether new variables are being introduced.


554-576: LGTM!

The chooseErrName function properly handles error variable name selection, avoiding collisions with both existing declarations and future declarations in the code.


609-625: LGTM!

The replaceErrIdentifier function correctly uses word boundaries to replace error identifiers without affecting similarly-named variables like errMsg.


627-662: LGTM!

Helper functions for detecting blank assignments and identifier usage are well-implemented with proper word boundary matching.


664-676: LGTM!

Simple and effective block boundary detection using brace depth tracking.


678-729: LGTM!

The identifier declaration detection correctly handles control-statement scoped declarations by skipping if/for/switch/else if lines for short declaration patterns while still checking var-block style declarations. This addresses the previous review concerns about false positives from if err := ... patterns.


731-747: LGTM!

The declaredInVarBlockLine function now uses token-based matching (fields[0] != name) instead of prefix-based matching, which correctly addresses the previous review concerns about false positives with similarly-named variables like errMsg.


749-767: LGTM!

The methodLiteral function correctly converts Fiber method constants to quoted string literals for the new client API.


839-839: LGTM!

Error name selection is properly integrated into the simple agent block rewrite path.


957-993: LGTM!

The buildSimpleAgentReplacement function correctly uses the chosen error name throughout the generated code.


1222-1237: LGTM!

The line-by-line replacement correctly preserves var errs declaration lines while replacing other uses of errs with err. This aligns with the gated approach to avoid breaking legitimate error slice accumulators.


578-607: Control-flow scoped declarations are correctly handled.

The function properly detects function-scoped var err and var errs declarations while correctly skipping block-scoped declarations in control statements (if, for, switch). The regex patterns use word boundaries (\b) to precisely match var err, err :=, var errs, and errs := without false positives. Test coverage via Test_MigrateClientUsage_AcquireAgentOnlyParseAvoidsErrCollisions validates that the collision detection works correctly, preserving block-scoped errors in if statements while detecting function-scoped declarations that would conflict with the injected error variable.

cmd/internal/migrations/v3/client_usage_test.go (12)

317-346: LGTM!

The test correctly verifies that errs []error declarations in var blocks are preserved while the error handling is migrated to the new single err pattern.


604-632: LGTM!

The test correctly verifies the parse bytes flow migration with the new client API.


634-711: LGTM!

New test correctly verifies that SetBodyString is properly migrated to SetRawBody([]byte(...)).


1086-1110: LGTM!

The test correctly verifies the AcquireAgent block migration with the exact expected output format.


1112-1176: LGTM!

This test verifies the core PR feature: migrating AcquireAgent blocks that only parse requests. The response is correctly discarded with _ since only the error is needed.


1178-1242: LGTM!

The test correctly verifies that when err is already declared, the migration uses assignment (=) instead of short declaration (:=) to avoid redeclaration errors.


1244-1312: LGTM!

The test correctly verifies that collision avoidance works when var err error is declared after the AcquireAgent block. The migration chooses clientErr to avoid conflicts.


1314-1370: LGTM!

The test correctly verifies that comments and code following parse-only AcquireAgent blocks are preserved in the migration.


1372-1426: LGTM!

The test verifies that the token-based matching in declaredInVarBlockLine correctly ignores variables like errMsg that start with "err" but are not the err identifier.


1428-1496: LGTM!

The test verifies that var errMsg string declarations (with err-like prefix) don't incorrectly trigger collision avoidance for future declarations.


1498-1556: LGTM!

This test correctly verifies that legitimate errs []error accumulators are preserved while using a separate err variable for the Send() call. This addresses the previous critical review concern about type errors with append.


349-436: Test expectation for map key naming needs verification against actual output.

The test Test_MigrateClientUsage_RewritesAcquireAgentStructWithVarsBetweenParseAndCall expects the JSON map key to be renamed from "errs" to "clientErr" when the error variable is renamed to clientErr due to collision avoidance. However, the replaceErrIdentifier function uses word boundary patterns (\berrs\b) that only match identifiers, not string literals. The map key "errs" in fiber.Map{"errs": errs} is a string literal and should not be transformed by the standard identifier replacement logic.

The rewriteClientErrorHandling function's clientErrMapPattern ("errs"\s*:\s*errs) also won't match "errs": clientErr after the main migration runs, so it cannot rename the key either.

While the test currently passes, clarify whether:

  • The JSON key should remain as "err" (semantic API contract) regardless of the internal variable name, or
  • Both key and value should be renamed consistently when collision avoidance renames the error variable

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants