Skip to content

Conversation

gfyrag
Copy link
Collaborator

@gfyrag gfyrag commented May 2, 2025

No description provided.

@gfyrag gfyrag requested a review from a team as a code owner May 2, 2025 12:17
Copy link

coderabbitai bot commented May 2, 2025

Walkthrough

This set of changes introduces a new rolling upgrades CLI tool under test/rolling-upgrades, implemented in Go and JavaScript. The tool leverages Pulumi's automation API to facilitate controlled upgrades of a ledger deployment, supporting configuration overlays and targeted resource replacements. The Justfile is updated to include linting and tidying for the new directory. The Pulumi deployment configuration system is enhanced with a new Duration type for improved (un)marshaling of durations in JSON and YAML, and several struct tags are updated for optional serialization. Minor formatting adjustments are also made to existing code.

Changes

File(s) Change Summary
test/rolling-upgrades/cmd/root.go, test/rolling-upgrades/main.go, test/rolling-upgrades/cmd/script.js Introduced a new CLI tool for rolling upgrades, with a Go-based command-line interface and supporting JavaScript script. Implements config merging, Pulumi stack automation, resource replacement, and cleanup logic.
Justfile Extended lint and tidy targets to include the test/rolling-upgrades directory.
deployments/pulumi/pkg/config/config.go Added a custom Duration type for better duration handling in config (un)marshaling. Updated several struct fields to use the new type, improved error wrapping, and added omitempty tags for optional serialization. Embedded Common struct inline in Config.
deployments/pulumi/main.go Removed an extraneous blank line inside the main function's anonymous function, with no effect on logic or behavior.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI (rolling-upgrades)
    participant Pulumi Automation API
    participant Pulumi Stack

    User->>CLI (rolling-upgrades): Execute with flags (init, target, stack, etc.)
    CLI (rolling-upgrades)->>CLI (rolling-upgrades): Load and merge configs
    CLI (rolling-upgrades)->>Pulumi Automation API: Create/Select Stack
    CLI (rolling-upgrades)->>Pulumi Stack: Destroy generator resource (if exists)
    CLI (rolling-upgrades)->>Pulumi Stack: Up stack with initial config
    CLI (rolling-upgrades)->>Pulumi Stack: Up stack with target config (replace resource)
    CLI (rolling-upgrades)->>Pulumi Stack: Optionally destroy all resources (cleanup)
    Pulumi Stack-->>CLI (rolling-upgrades): Operation results
    CLI (rolling-upgrades)-->>User: Output results
Loading

Possibly related PRs

  • fix: benchmarks #716: Extends Justfile's lint and tidy targets to include test/performance, similar to this PR's inclusion of test/rolling-upgrades.
  • feat: Use Nix & Justfile #619: Introduces the initial Justfile with lint and tidy commands; this PR builds upon those commands by adding new directories.

Suggested labels

benchmarks

Suggested reviewers

  • Dav-14
  • paul-nicolas

Poem

In a warren of code, a new path unfurls,
With rolling upgrades, the ledger twirls.
Durations now dance in stringy delight,
As configs grow nimble, tags feather-light.
Lint and tidy hop to new ground,
While Pulumi stacks spin round and round.
🐇 Cheers to upgrades that leap with glee—
More robust, more clever, as code should be!

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gfyrag gfyrag force-pushed the test/rolling-upgrades branch from 4961558 to fc715e0 Compare May 2, 2025 12:19
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: 6

🧹 Nitpick comments (4)
test/rolling-upgrades/cmd/script.js (1)

6-15: Consider exporting next to improve re-usability

If this script is ever required/imported as a module (e.g. by k6 or a node runner) the next function will be out of scope.
Adding an explicit export future-proofs the file without changing current behaviour when it’s only embedded as plain text.

 function next() {
     return [{
         action: 'CREATE_TRANSACTION',
         data: {
             script: {
                 plain
             }
         }
     }]
 }
+
+module.exports = { next };
deployments/pulumi/pkg/config/config.go (1)

256-262: Interface conformity checks are great – tiny tweak

The “dummy value” assertions are valuable, but using a pointer for the interfaces that require a pointer receiver (Unmarshal) is clearer:

-var _ json.Unmarshaler = (*Duration)(nil)
+var _ json.Unmarshaler = (*Duration)(nil) // already ok

Nothing blocking, just a minor style note.

test/rolling-upgrades/cmd/root.go (2)

99-107: Unnecessary file handle opened and never used.

os.Create(tmpConfigFileName) is invoked here, yet the file is reopened inside updateConfigFile().
The first handle is kept open until the end of runE, wasting an FD and risking platform-specific file-locking issues.

You can safely remove lines 100-106 and rely on updateConfigFile() to create/truncate the file.


72-73: --toggle/-t flag appears to be a leftover sample flag.

It is not read anywhere in the codebase and may confuse users of the CLI.
Consider deleting it.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d7cdb4 and fc715e0.

⛔ Files ignored due to path filters (4)
  • .github/workflows/rolling-upgrades.yml is excluded by !**/*.yml
  • deployments/pulumi/go.mod is excluded by !**/*.mod
  • test/rolling-upgrades/go.mod is excluded by !**/*.mod
  • test/rolling-upgrades/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (6)
  • Justfile (2 hunks)
  • deployments/pulumi/main.go (0 hunks)
  • deployments/pulumi/pkg/config/config.go (14 hunks)
  • test/rolling-upgrades/cmd/root.go (1 hunks)
  • test/rolling-upgrades/cmd/script.js (1 hunks)
  • test/rolling-upgrades/main.go (1 hunks)
💤 Files with no reviewable changes (1)
  • deployments/pulumi/main.go
🧰 Additional context used
🧬 Code Graph Analysis (2)
test/rolling-upgrades/main.go (1)
test/rolling-upgrades/cmd/root.go (1)
  • Execute (57-62)
test/rolling-upgrades/cmd/root.go (2)
deployments/pulumi/pkg/config/config.go (8)
  • Common (500-515)
  • Storage (233-244)
  • API (299-326)
  • Worker (342-342)
  • Config (611-637)
  • Generator (592-598)
  • GeneratorLedgerConfiguration (561-579)
  • Duration (256-256)
pkg/client/internal/utils/utils.go (1)
  • Contains (62-69)
🔇 Additional comments (3)
Justfile (2)

17-18: Nice addition – keeps new code covered by linting

Including the new directory in the lint pass is spot-on and consistent with the existing pattern.
No issues spotted here.


28-29: Tidy target update looks good

Ensures module dependencies of the new package stay clean.
Thanks for keeping the workflow consistent.

deployments/pulumi/pkg/config/config.go (1)

304-305: Zero vs omitted: consider using a pointer

API.GracePeriod is now a value (zero default).
Callers cannot distinguish “not provided” from “explicit 0”.
If 0 is a meaningful value, keep as-is; otherwise a *Duration with omitempty would allow intent to be preserved.

No action required if 0 is indeed the intended default.

Comment on lines +3 to +6
import "github.com/formance/ledger/tests/rolling-upgrades/cmd"

func main() {
cmd.Execute()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Incorrect module path will break compilation

The import path lacks the hq segment used everywhere else in the repo and points to tests/rolling-upgrades, while the actual directory is test/rolling-upgrades.
This will cause go vet, go build, and golangci-lint to fail.

-import "github.com/formance/ledger/tests/rolling-upgrades/cmd"
+import "github.com/formancehq/ledger/test/rolling-upgrades/cmd"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import "github.com/formance/ledger/tests/rolling-upgrades/cmd"
func main() {
cmd.Execute()
import "github.com/formancehq/ledger/test/rolling-upgrades/cmd"
func main() {
cmd.Execute()
🤖 Prompt for AI Agents (early access)
In test/rolling-upgrades/main.go around lines 3 to 6, the import path is incorrect; it should include the 'hq' segment and use 'test/rolling-upgrades' instead of 'tests/rolling-upgrades'. Update the import statement to the correct module path reflecting the actual directory structure and consistent with the rest of the repo to fix compilation and linting errors.

Comment on lines +263 to +266
func (d *Duration) UnmarshalJSON(data []byte) error {

fmt.Println(string(data))

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove stray debug fmt.Println

Leaving unconditional prints in a library function will spam stdout for every config load, including in production CI/CD runs.

-	fmt.Println(string(data))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (d *Duration) UnmarshalJSON(data []byte) error {
fmt.Println(string(data))
func (d *Duration) UnmarshalJSON(data []byte) error {
🤖 Prompt for AI Agents (early access)
In deployments/pulumi/pkg/config/config.go around lines 263 to 266, remove the stray debug fmt.Println statement that prints the JSON data during unmarshalling. This print causes unnecessary output in production and CI/CD environments. Simply delete or comment out the fmt.Println line to prevent spamming stdout on every config load.

Comment on lines +274 to +288
overlays, err := cmd.Flags().GetStringArray(overlayFlag)
if err != nil {
return nil, err
}
for _, overlay := range overlays {
oCfg := &PartialConfig{}
if err := json.Unmarshal([]byte(overlay), oCfg); err != nil {
return nil, fmt.Errorf("failed to unmarshal overlay (%s): %w", overlay, err)
}

err := mergo.Merge(cfg, oCfg)
if err != nil {
return nil, fmt.Errorf("failed to merge overlay (%s): %w", overlay, err)
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Overlay values never override base config – pass mergo.WithOverride (and preserve ordering).

mergo.Merge(dst, src) only populates empty fields by default, so later overlays cannot replace previously set values.
This effectively disables the whole “overlay” concept for non-zero fields and makes the result order-dependent in an unintuitive way.

-       err := mergo.Merge(cfg, oCfg)
+       // Allow overlay values to override existing ones.
+       err := mergo.Merge(cfg, oCfg, mergo.WithOverride)

You may also want to sort / apply the overlays in the order they were supplied so --overlay A --overlay B gives B the highest priority.
Without this fix, users will get silently-ignored overrides.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
overlays, err := cmd.Flags().GetStringArray(overlayFlag)
if err != nil {
return nil, err
}
for _, overlay := range overlays {
oCfg := &PartialConfig{}
if err := json.Unmarshal([]byte(overlay), oCfg); err != nil {
return nil, fmt.Errorf("failed to unmarshal overlay (%s): %w", overlay, err)
}
err := mergo.Merge(cfg, oCfg)
if err != nil {
return nil, fmt.Errorf("failed to merge overlay (%s): %w", overlay, err)
}
}
overlays, err := cmd.Flags().GetStringArray(overlayFlag)
if err != nil {
return nil, err
}
for _, overlay := range overlays {
oCfg := &PartialConfig{}
if err := json.Unmarshal([]byte(overlay), oCfg); err != nil {
return nil, fmt.Errorf("failed to unmarshal overlay (%s): %w", overlay, err)
}
// Allow overlay values to override existing ones.
err := mergo.Merge(cfg, oCfg, mergo.WithOverride)
if err != nil {
return nil, fmt.Errorf("failed to merge overlay (%s): %w", overlay, err)
}
}
🤖 Prompt for AI Agents (early access)
In test/rolling-upgrades/cmd/root.go around lines 274 to 288, the current use of mergo.Merge does not allow overlay values to override existing fields because it lacks the mergo.WithOverride option. To fix this, update the mergo.Merge call to include mergo.WithOverride so that overlay fields replace existing values. Also, ensure overlays are applied in the order they are supplied so that later overlays have higher priority, preserving the intended override behavior.

Comment on lines +151 to +153
if err := upStack(cmd, stack, tmpConfigFileName,
optup.Replace([]string{"urn:pulumi:tests-rolling-upgrades::ledger::Formance:Ledger$Formance:Ledger:API$kubernetes:apps/v1:Deployment::ledger-api"}),
); err != nil {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

optup.Replace URN also hard-codes the stack name.

Same issue as above – if the user passes --stack-name foo, the replacement will silently do nothing.

-       optup.Replace([]string{"urn:pulumi:tests-rolling-upgrades::ledger::Formance:Ledger$Formance:Ledger:API$kubernetes:apps/v1:Deployment::ledger-api"}),
+       optup.Replace([]string{
+               fmt.Sprintf("urn:pulumi:%s::ledger::Formance:Ledger$Formance:Ledger:API$kubernetes:apps/v1:Deployment::ledger-api", stack.Name()),
+       }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if err := upStack(cmd, stack, tmpConfigFileName,
optup.Replace([]string{"urn:pulumi:tests-rolling-upgrades::ledger::Formance:Ledger$Formance:Ledger:API$kubernetes:apps/v1:Deployment::ledger-api"}),
); err != nil {
if err := upStack(cmd, stack, tmpConfigFileName,
optup.Replace([]string{
fmt.Sprintf("urn:pulumi:%s::ledger::Formance:Ledger$Formance:Ledger:API$kubernetes:apps/v1:Deployment::ledger-api", stack.Name()),
}),
); err != nil {
🤖 Prompt for AI Agents (early access)
In test/rolling-upgrades/cmd/root.go around lines 151 to 153, the optup.Replace call hard-codes the stack name in the URN, causing it to ignore any user-supplied --stack-name argument. Modify the URN string construction to dynamically include the actual stack name variable instead of the fixed "tests-rolling-upgrades" value, ensuring the replacement works correctly for any stack name provided by the user.

Comment on lines +248 to +256
_, err = stack.Destroy(cmd.Context(), destroyOptions...)
// Ugly check...
if err != nil && !strings.Contains(err.Error(), "no resource named") {
return err
}
if strings.Contains(err.Error(), "no resource named") {
pterm.Info.Println("No generator to destroy.")
} else {
pterm.Info.Println("Generator destroyed.")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Possible nil-pointer panic when err is nil.

err.Error() is called even when the previous Destroy succeeded (err == nil).
A successful destroy will therefore panic the CLI.

-       if err != nil && !strings.Contains(err.Error(), "no resource named") {
-               return err
-       }
-       if strings.Contains(err.Error(), "no resource named") {
+       if err != nil {
+               if !strings.Contains(err.Error(), "no resource named") {
+                       return err
+               }
+               // err is non-nil and indicates “no resource named”
+               pterm.Info.Println("No generator to destroy.")
+       } else {
                pterm.Info.Println("Generator destroyed.")
-       }
+       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_, err = stack.Destroy(cmd.Context(), destroyOptions...)
// Ugly check...
if err != nil && !strings.Contains(err.Error(), "no resource named") {
return err
}
if strings.Contains(err.Error(), "no resource named") {
pterm.Info.Println("No generator to destroy.")
} else {
pterm.Info.Println("Generator destroyed.")
_, err = stack.Destroy(cmd.Context(), destroyOptions...)
// Ugly check...
if err != nil {
if !strings.Contains(err.Error(), "no resource named") {
return err
}
// err is non-nil and indicates “no resource named”
pterm.Info.Println("No generator to destroy.")
} else {
pterm.Info.Println("Generator destroyed.")
}
🤖 Prompt for AI Agents (early access)
In test/rolling-upgrades/cmd/root.go around lines 248 to 256, the code calls err.Error() without checking if err is nil, which can cause a nil-pointer panic when Destroy succeeds. Fix this by first checking if err is not nil before calling err.Error(), and restructure the conditional logic to avoid calling err.Error() when err is nil.

Comment on lines +236 to +240
optdestroy.Target([]string{
"urn:pulumi:ledger-tests-rolling-upgrades::ledger::Formance:Ledger$Formance:Ledger:Tools:Generator::generator",
}),
optdestroy.TargetDependents(),
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Hard-coded URN contains a different stack name (“ledger-tests-rolling-upgrades”).

The CLI lets users change --stack-name, but this URN is fixed and even differs from the default tests-rolling-upgrades.
Targets will never match, making the generator impossible to delete.

Consider building the URN dynamically, e.g.:

stackURN := fmt.Sprintf("urn:pulumi:%s::ledger::Formance:Ledger$Formance:Ledger:Tools:Generator::generator", stack.Name())
optdestroy.Target([]string{stackURN}),

🏁 Script executed:

#!/bin/bash
set -e

echo "Listing test/rolling-upgrades directory structure"
fd . test/rolling-upgrades

echo
echo "Locating root.go"
find test/rolling-upgrades -type f -name root.go

echo
echo "Showing code lines 1-150 of root.go"
sed -n '1,150p' test/rolling-upgrades/cmd/root.go || true

echo
echo "Showing lines 200-260 of root.go"
sed -n '200,260p' test/rolling-upgrades/cmd/root.go || true

echo
echo "Searching for 'stack.Name' usage"
rg -n "stack.Name" test/rolling-upgrades/cmd/root.go || true

echo
echo "Searching for stack variable declaration"
rg -n "stack *:=" test/rolling-upgrades/cmd/root.go || true

Length of output: 6383


Fix hard-coded URN to use the selected stack name

The destroyGeneratorIfExists function always tries to destroy a resource in the "ledger-tests-rolling-upgrades" stack, but the CLI flag defaults to "tests-rolling-upgrades" (or whatever is passed via --stack-name). This mismatch means the destroy target never matches and the generator will never be removed.

• File: test/rolling-upgrades/cmd/root.go
• Function: destroyGeneratorIfExists (around line 236)

Replace the hard-coded target:

optdestroy.Target([]string{
    "urn:pulumi:ledger-tests-rolling-upgrades::ledger::Formance:Ledger$Formance:Ledger:Tools:Generator::generator",
}),

With a dynamically built URN:

stackURN := fmt.Sprintf(
    "urn:pulumi:%s::ledger::Formance:Ledger$Formance:Ledger:Tools:Generator::generator",
    stack.Name(),
)
optdestroy.Target([]string{stackURN}),

This ensures the destroy operation always uses the actual stack name provided at runtime.

🤖 Prompt for AI Agents (early access)
In test/rolling-upgrades/cmd/root.go around lines 236 to 240, the destroyGeneratorIfExists function uses a hard-coded URN with a fixed stack name "ledger-tests-rolling-upgrades" which does not match the dynamic stack name passed via CLI. Replace the hard-coded URN string with a dynamically constructed one using fmt.Sprintf and stack.Name() to build the URN, then pass this dynamic URN to optdestroy.Target. This ensures the destroy target matches the actual stack name at runtime.

Copy link

codecov bot commented May 2, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 82.00%. Comparing base (3b718a3) to head (fc715e0).
Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #895      +/-   ##
==========================================
- Coverage   82.18%   82.00%   -0.19%     
==========================================
  Files         141      141              
  Lines        7613     7746     +133     
==========================================
+ Hits         6257     6352      +95     
- Misses       1039     1068      +29     
- Partials      317      326       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gfyrag gfyrag added this pull request to the merge queue May 2, 2025
Merged via the queue into main with commit 881f7f2 May 2, 2025
9 of 10 checks passed
@gfyrag gfyrag deleted the test/rolling-upgrades branch May 2, 2025 13:44
@coderabbitai coderabbitai bot mentioned this pull request May 6, 2025
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.

2 participants