Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for world cardinal build #113

Merged
merged 7 commits into from
Mar 19, 2025
Merged

Conversation

ezavada
Copy link
Contributor

@ezavada ezavada commented Mar 14, 2025

  • new command just builds the cardinal docker image, doesn't run anything

Closes: PLAT-202

Summary by CodeRabbit

  • New Features
    • Introduced a new command-line option to build the Cardinal game image with customizable parameters, enhanced error reporting, and support for concurrent processing.
    • Improved Docker workflows by streamlining image building and enabling optional image pushing with real-time progress feedback.
    • Enhanced the interactive terminal experience during project setup for smoother region selection.
  • Chores
    • Upgraded the underlying build environment dependencies for improved reliability.

- just builds the cardinal docker image, doesn't run anything
@ezavada ezavada requested a review from zulkhair March 14, 2025 22:16
Copy link

graphite-app bot commented Mar 14, 2025

How to use the Graphite Merge Queue

Add the label graphite/merge to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

Copy link

coderabbitai bot commented Mar 14, 2025

Walkthrough

This update introduces a new CLI command in the Cardinal package for building a game image using the Cobra library. The changes integrate configuration management, concurrent processing for Docker image building, and optional image pushing. Additionally, the Docker client gains new methods to manage build and push operations, and the Cardinal service’s Docker dependency version is upgraded. A custom function for creating BubbleTea programs is added and integrated into the region selector flow within forge test and project logic, with updated error handling and improved test assertions.

Changes

File(s) Change Summary
cmd/.../cardinal/build.go
cmd/.../cardinal/cardinal.go
Added the new buildCmd command for building the Cardinal game image. The command uses Cobra for CLI, registers flags, integrates configuration overrides, error handling, and concurrency. Also introduced getCardinalServices to isolate Cardinal-specific service retrieval.
common/docker/client.go
common/docker/client_image.go
Introduced a new Build method in the Docker client to handle volume processing, image pulling, and building of services. Additionally, added pushImages to push Docker images to a registry with progress tracking and error grouping. Minor comment updates and error handling adjustments were made in the image pull workflow.
common/docker/service/cardinal.go Updated the Docker dependency for the Cardinal service by upgrading the Go image from "golang:1.22-bookworm" to "golang:1.24-bookworm" in both dependency and configuration fields.
cmd/.../forge/common.go
cmd/.../forge/forge_test.go
cmd/.../forge/project.go
Added NewTeaProgram, a custom BubbleTea program creator that checks for TTY status and adjusts input settings accordingly. Existing code in tests and project methods has been updated to use NewTeaProgram instead of tea.NewProgram, along with improved error handling and enhanced test assertions.

Sequence Diagram(s)

Loading
sequenceDiagram
    participant User as User CLI
    participant CMD as buildCmd
    participant Client as Docker Client
    participant Proc as Build Process
    User->>CMD: Invoke "build" command
    CMD->>CMD: Retrieve configuration & flags
    CMD->>Client: Call Build(ctx, pushTo, pushAuth, serviceBuilders...)
    Client->>Client: Process volume creation
    Client->>Proc: Pull images for services
    Proc-->>Client: Images pulled
    Client->>Proc: Build images concurrently
    Proc-->>Client: Build complete
    alt Push option enabled
      Client->>Client: Execute pushImages
    else
      Client->>Client: Skip push step
    end
    Client-->>CMD: Return success or error
    CMD-->>User: Output build status
Loading
sequenceDiagram
    participant Caller as Forge Code/Test
    participant NTP as NewTeaProgram
    participant BTea as BubbleTea Program
    Caller->>NTP: Instantiate region selector
    NTP->>NTP: Check if stderr is a TTY
    NTP->>BTea: Configure program options (use std input if not TTY)
    BTea-->>Caller: Return program instance

Possibly related PRs

  • feat: parameterize nakama image #84: Introduces modifications to the Docker client's image build methods (buildImages and pullImages), which directly relate to the new build and push functionality established in this update.

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

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 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.

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 (2)
common/docker/client.go (1)

72-107: Good implementation of the Build method.

The method correctly implements the functionality to build the Cardinal Docker image without starting containers. It properly handles volume creation, service instantiation, image pulling, and conditional building.

There are commented out lines related to network creation (76-79) that could be removed since they're not needed for the build functionality.

 func (c *Client) Build(ctx context.Context,
 	serviceBuilders ...service.Builder) error {

 	namespace := c.cfg.DockerEnv["CARDINAL_NAMESPACE"]
-	//err := c.createNetworkIfNotExists(ctx, namespace)
-	//if err != nil {
-	//	return eris.Wrap(err, "Failed to create network")
-	//}

 	err := c.processVolume(ctx, CREATE, namespace)
cmd/world/cardinal/build.go (1)

41-65: Consider consolidating log level validation.

The code has multiple blocks handling log level validation and defaults. Consider refactoring this into a helper function to improve readability and maintainability.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 76ede61 and d3c41ad.

📒 Files selected for processing (4)
  • cmd/world/cardinal/build.go (1 hunks)
  • cmd/world/cardinal/cardinal.go (2 hunks)
  • common/docker/client.go (1 hunks)
  • common/docker/service/cardinal.go (1 hunks)
🔇 Additional comments (6)
cmd/world/cardinal/cardinal.go (2)

54-57: Good implementation of the Cardinal-specific service retriever.

This helper function properly isolates the Cardinal service from other services, which aligns well with the PR objective of building only the Cardinal Docker image.


39-40: LGTM - Command registration looks good.

The build command is properly integrated into the existing command structure and flag registration system.

common/docker/service/cardinal.go (1)

114-117: Good update to Go 1.24.

Upgrading from Go 1.22 to Go 1.24 is a positive change as it includes performance improvements, security enhancements, and bug fixes that will benefit the Cardinal service.

cmd/world/cardinal/build.go (3)

22-103: Well-structured command implementation.

The build command is well-implemented with appropriate error handling, configuration management, and user feedback. It follows the established pattern for Cobra commands in this codebase.


89-94: Verify error handling for successful build.

On line 94, you're returning a wrapped error ErrGracefulExit when the build completes successfully. This seems unusual since this is the success path. Consider returning nil instead of an error on successful completion.

 group.Go(func() error {
 	if err := dockerClient.Build(ctx, services...); err != nil {
 		return eris.Wrap(err, "Encountered an error with Docker")
 	}
-	return eris.Wrap(ErrGracefulExit, "Stack terminated")
+	return nil
 })

1-15:

✅ Verification successful

Ensure all used variables are defined.

The code uses several variables that aren't defined in this file:

  • DockerCardinalEnvLogLevel
  • flagLogLevel
  • validLogLevels
  • CardinalPort
  • ErrGracefulExit

These are likely defined in another file in the package but should be verified.


🏁 Script executed:

#!/bin/bash
# Description: Verify the existence of undefined variables used in build.go

echo "Checking for variable definitions in the cardinal package..."
rg -A 1 "DockerCardinalEnvLogLevel|flagLogLevel|validLogLevels|CardinalPort|ErrGracefulExit" --type go cmd/world/cardinal/

Length of output: 5301


Confirmed Definitions in the Cardinal Package

All the variables referenced in build.go have been verified to be defined within the package:

  • DockerCardinalEnvLogLevel, flagLogLevel, and validLogLevels are defined in cmd/world/cardinal/start.go.
  • CardinalPort is defined in cmd/world/cardinal/dev.go.
  • ErrGracefulExit is defined in cmd/world/cardinal/start.go.

No further action is required regarding variable definitions.

Copy link

codecov bot commented Mar 14, 2025

Codecov Report

Attention: Patch coverage is 5.11628% with 204 lines in your changes missing coverage. Please review.

Project coverage is 48.15%. Comparing base (855fac3) to head (d2cf796).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
common/docker/client_image.go 0.00% 91 Missing ⚠️
cmd/world/cardinal/build.go 8.43% 76 Missing ⚠️
common/docker/client.go 0.00% 26 Missing ⚠️
cmd/world/forge/common.go 0.00% 6 Missing ⚠️
cmd/world/cardinal/cardinal.go 40.00% 3 Missing ⚠️
cmd/world/forge/project.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #113      +/-   ##
==========================================
- Coverage   49.81%   48.15%   -1.66%     
==========================================
  Files          64       65       +1     
  Lines        5785     6030     +245     
==========================================
+ Hits         2882     2904      +22     
- Misses       2495     2714     +219     
- Partials      408      412       +4     

☔ 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.

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)
common/docker/client.go (1)

72-100: New Build method looks good, with a suggestion for code reuse

The implementation of the new Build method is well-structured and follows the project's existing patterns for Docker operations. It properly creates volumes, pulls images, and builds Docker images without starting containers.

I noticed that the code for creating service instances from builders (lines 82-86) is duplicated across several methods in this file (Build, Start, Stop, Purge). Consider extracting this common functionality into a helper method to reduce duplication and improve maintainability.

+func (c *Client) createServices(serviceBuilders ...service.Builder) []service.Service {
+	dockerServices := make([]service.Service, 0)
+	for _, sb := range serviceBuilders {
+		ds := sb(c.cfg)
+		dockerServices = append(dockerServices, ds)
+	}
+	return dockerServices
+}

 func (c *Client) Build(ctx context.Context,
 	serviceBuilders ...service.Builder) error {
 	namespace := c.cfg.DockerEnv["CARDINAL_NAMESPACE"]
 
 	err := c.processVolume(ctx, CREATE, namespace)
 	if err != nil {
 		return eris.Wrap(err, "Failed to create volume")
 	}
 
-	// get all services
-	dockerServices := make([]service.Service, 0)
-	for _, sb := range serviceBuilders {
-		ds := sb(c.cfg)
-		dockerServices = append(dockerServices, ds)
-	}
+	// get all services
+	dockerServices := c.createServices(serviceBuilders...)

The method correctly implements the PR objective to add support for building the Cardinal Docker image without executing additional processes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between d3c41ad and ca7deea.

📒 Files selected for processing (2)
  • cmd/world/cardinal/cardinal.go (2 hunks)
  • common/docker/client.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/world/cardinal/cardinal.go

Copy link
Collaborator

@zulkhair zulkhair left a comment

Choose a reason for hiding this comment

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

Tested on my local and worked

image.png

image.png

- new flag push to indicate a push should be done
- new flags used by push: auth, user, pass, and regtoken; all used for authentication
- added NewTeaProgram() to work without TTY under debugger
- workaround for bug in tests were region selector was sometimes nil
- switch to direct tea program
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 (7)
cmd/world/root/create.go (1)

209-209: Confirm consistency of forge.NewTeaProgram.
This change aligns with the shift from tea.NewProgram to the custom forge implementation. Ensure that other references to the Bubble Tea program in this package are consistently updated.

cmd/world/forge/forge_test.go (3)

1590-1590: Consider splitting this test to avoid high cognitive complexity.
The //nolint:gocognit annotation suppresses complexity warnings. Overly large or deeply nested tests can be brittle and harder to maintain.


1741-1749: Handle nil region selector with explicit test failure.
Instead of only printing the message "failed to create region selector", consider failing the test (e.g., using s.Require().NotNil(regionSelector)) to avoid masking potential errors.


1758-1764: Use assertions to handle a nil region selector in tests.
Relying only on print("region selector is nil") can make it harder to detect errors in CI. Switching to an assertion (e.g., s.Require().NotNil) or returning early ensures quick feedback.

common/docker/client.go (1)

72-109: Well implemented Docker image build functionality.

The new Build method provides a streamlined approach to building Cardinal Docker images without starting containers. The implementation follows similar patterns to other client methods with proper error handling and a clear workflow.

Consider adding a parallel function to the existing Start method's deferred cleanup. While volumes are created, there's no cleanup mechanism if the build succeeds but subsequent operations fail. This would be especially helpful in CI/CD environments where cleanup is important.

common/docker/client_image.go (2)

487-602: Well-structured image push implementation.

The new pushImages method is well-implemented with proper progress tracking, error handling, and concurrent operations. It follows patterns established in the pullImages method for consistency.

Consider enhancing error handling in the image inspection section (lines 505-508). Currently, it returns early on the first error. A more robust approach might be to collect these errors and continue with valid images, especially if pushing multiple images:

-		_, _, err := c.client.ImageInspectWithRaw(ctx, imageName)
-		if err != nil {
-			return eris.New(fmt.Sprintf("Error inspecting image %s for service %s: %v\n",
-				imageName, service.Name, err))
-		}
+		_, _, err := c.client.ImageInspectWithRaw(ctx, imageName)
+		if err != nil {
+			errChan <- eris.New(fmt.Sprintf("Error inspecting image %s for service %s: %v\n",
+				imageName, service.Name, err))
+			wg.Done() // Reduce wait counter for this image
+			continue  // Skip this image but continue with others
+		}

424-424: Minor: Code duplication in decoder loop.

The comment //nolint:dupl // different commands addresses the duplication between this loop and the similar one in pushImages, but consider refactoring this into a shared helper function to improve maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between ca7deea and c60d938.

📒 Files selected for processing (11)
  • cmd/world/cardinal/build.go (1 hunks)
  • cmd/world/forge/common.go (2 hunks)
  • cmd/world/forge/forge_test.go (3 hunks)
  • cmd/world/forge/project.go (1 hunks)
  • cmd/world/root/create.go (2 hunks)
  • cmd/world/root/doctor.go (2 hunks)
  • common/docker/client.go (1 hunks)
  • common/docker/client_container.go (2 hunks)
  • common/docker/client_image.go (4 hunks)
  • common/docker/client_network.go (1 hunks)
  • common/docker/client_volume.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • cmd/world/forge/project.go
🧰 Additional context used
🧬 Code Definitions (5)
common/docker/client_volume.go (5)
common/docker/client_container.go (8) (8)
  • c (26-113)
  • c (115-135)
  • c (137-147)
  • c (149-165)
  • c (167-187)
  • c (189-214)
  • c (216-282)
  • processType (24-24)
common/docker/client_network.go (1) (1)
  • c (14-89)
common/docker/client_image.go (1) (1)
  • c (31-123)
cmd/world/forge/common.go (1) (1)
  • NewTeaProgram (251-257)
tea/component/multispinner/multispinner.go (1) (1)
  • CreateSpinner (38-62)
common/docker/client.go (2)
common/docker/client_volume.go (1) (1)
  • c (15-100)
common/docker/client_image.go (8) (8)
  • c (31-123)
  • c (125-167)
  • c (172-220)
  • c (231-284)
  • c (286-316)
  • c (318-337)
  • c (343-369)
  • err (241-241)
common/docker/client_image.go (2)
cmd/world/forge/common.go (2) (2)
  • NewTeaProgram (251-257)
  • err (40-40)
tea/component/multispinner/multispinner.go (1) (1)
  • CreateSpinner (38-62)
common/docker/client_container.go (2)
cmd/world/forge/common.go (1) (1)
  • NewTeaProgram (251-257)
tea/component/multispinner/multispinner.go (1) (1)
  • CreateSpinner (38-62)
cmd/world/forge/forge_test.go (2)
cmd/world/forge/project.go (1) (1)
  • regionSelector (21-21)
cmd/world/forge/common.go (1) (1)
  • NewTeaProgram (251-257)
🔇 Additional comments (15)
cmd/world/forge/common.go (1)

249-257: Good implementation of the NewTeaProgram utility function.

This function provides a consistent way to handle TTY detection when creating BubbleTea programs. It's a useful abstraction that ensures programs work correctly both in terminal and non-terminal environments (like debuggers).

The commented-out line suggests you considered removing the renderer altogether, but decided to keep it. This maintains visual output while still fixing input handling for non-TTY environments.

common/docker/client_network.go (2)

9-9: Updated import to use the forge package.

The change correctly imports the forge package containing the new NewTeaProgram utility function.


17-17: Consistent use of the new NewTeaProgram utility.

This change ensures that the network creation process properly handles both TTY and non-TTY environments, aligning with the standardization approach across the codebase.

cmd/world/root/doctor.go (2)

9-9: Added forge package import.

The change correctly imports the forge package containing the NewTeaProgram utility function.


87-87: Standardized creation of BubbleTea programs.

The change from direct tea.NewProgram to forge.NewTeaProgram ensures consistent handling of terminal environments across the codebase, particularly important for debugging scenarios.

common/docker/client_volume.go (2)

10-10: Updated import to use the forge package.

The change correctly imports the forge package containing the NewTeaProgram utility function.


18-18: Standardized creation of BubbleTea programs.

The change from direct tea.NewProgram to forge.NewTeaProgram ensures consistent handling of terminal environments across the codebase. This is particularly important for volume operations that need to work reliably in both interactive and automated contexts.

cmd/world/root/create.go (1)

11-11: Importing the forge package looks consistent.
No issues detected with the added import statement.

cmd/world/cardinal/build.go (5)

1-15: Package and imports are well-structured.
The chosen imports for Docker registry, error handling, logging, and concurrency appear consistent with the file’s functionality.


17-23: Flag constants named clearly.
The constants for push and authentication are self-explanatory, improving the command’s clarity.


29-31: Command usage description is concise.
The short and long descriptions accurately convey the purpose of the build command.


32-127: Ensure correct build flag usage for Docker.
From earlier feedback, the Docker build operation may require cfg.Build = true. Revisit whether this is still necessary here.

+ // Ensure Build flag is enabled before building
+ cfg.Build = true

130-137: Flag registrations look appropriate.
Registering build-related flags for log level, debugging, telemetry, and image pushing is coherent with the command’s functionality.

common/docker/client_container.go (1)

18-18: Good refactoring to use forge.NewTeaProgram.

This change improves terminal handling by using the custom wrapper function that properly handles non-terminal environments. This ensures better compatibility across different runtime environments.

Also applies to: 41-41

common/docker/client_image.go (1)

25-25: Good refactoring to use forge.NewTeaProgram.

Consistent with changes in other files, this refactoring improves terminal handling by using the custom wrapper that handles non-terminal environments properly.

Also applies to: 53-53

ezavada added 2 commits March 19, 2025 16:59
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/world/forge/forge_test.go (1)

1590-1590: Consider refactoring this complex test function.

The //nolint:gocognit comment is suppressing cognitive complexity warnings, which indicates the function might be too complex. While test functions often have higher complexity due to test case setup and assertions, consider breaking this test down into smaller, more focused tests for better maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 3a4ee5b and d1182bf.

📒 Files selected for processing (1)
  • cmd/world/forge/forge_test.go (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
cmd/world/forge/forge_test.go (1)
cmd/world/forge/project.go (3) (3)
  • regionSelector (21-21)
  • err (549-549)
  • createProject (216-296)
🔇 Additional comments (3)
cmd/world/forge/forge_test.go (3)

1748-1750: Good defensive coding with nil check.

Adding a nil check for regionSelector before operating on it is a great improvement that prevents potential nil pointer dereferences and provides informative feedback when initialization fails.


1759-1766: Improved error handling for region selector.

This conditional block adds a proper nil check before sending actions to the region selector, making the test more robust against failures. The additional debug message helps identify when the region selector is not properly initialized.


1773-1775: Enhanced test reliability with require assertions.

Replacing s.NoError(err) and explicit nil checks with s.Require().NoError(err) and s.Require().NotNil(prj) is an improvement that ensures the test fails immediately if these critical checks don't pass, preventing subsequent code from running with invalid values.

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 (2)
common/docker/client_image.go (2)

499-507: Consider tagging images with the destination registry before pushing.

The current implementation checks if images exist locally but doesn't tag them with the destination registry. This could cause issues if pushTo is different from the original image name.

Consider adding image tagging before pushing:

 		// check if the image exists
 		_, _, err := c.client.ImageInspectWithRaw(ctx, imageName)
 		if err != nil {
 			return eris.New(fmt.Sprintf("Error inspecting image %s for service %s: %v\n",
 				imageName, service.Name, err))
 		}
+
+		// Tag the image with the destination registry if needed
+		destinationImage := fmt.Sprintf("%s/%s", pushTo, strings.Split(imageName, "/")[len(strings.Split(imageName, "/"))-1])
+		if err := c.client.ImageTag(ctx, imageName, destinationImage); err != nil {
+			return eris.Wrap(err, fmt.Sprintf("Failed to tag image %s as %s", imageName, destinationImage))
+		}

536-576: Consider extracting common Docker event handling logic.

There's significant code duplication between this event handling logic and the one in pullImages. Consider refactoring to extract the common pattern into a utility function.

Create a shared function to handle Docker operation progress:

+// processDockerStreamEvents handles events from Docker stream operations like pull, push, etc.
+// It updates the progress bar based on the events and collects errors.
+func processDockerStreamEvents(
+   ctx context.Context, 
+   decoder *json.Decoder, 
+   bar *mpb.Bar, 
+   imageName string, 
+   operation string,
+   errChan chan<- error) {
+   var current int
+   var event map[string]interface{}
+   for decoder.More() {
+      select {
+      case <-ctx.Done():
+         fmt.Printf("%s of image %s was canceled\n", operation, imageName)
+         bar.Abort(false)
+         return
+      default:
+         if err := decoder.Decode(&event); err != nil {
+            errChan <- eris.New(fmt.Sprintf("Error decoding event for %s: %v\n", imageName, err))
+            continue
+         }
+
+         // Check for errorDetail and error fields
+         if errorDetail, ok := event["errorDetail"]; ok {
+            if errorMessage, ok := errorDetail.(map[string]interface{})["message"]; ok {
+               errChan <- eris.New(errorMessage.(string))
+               continue
+            }
+         } else if errorMsg, ok := event["error"]; ok {
+            errChan <- eris.New(errorMsg.(string))
+            continue
+         }
+
+         // Handle progress updates
+         if progressDetail, ok := event["progressDetail"].(map[string]interface{}); ok {
+            if total, ok := progressDetail["total"].(float64); ok && total > 0 {
+               calculatedCurrent := int(progressDetail["current"].(float64) * 100 / total)
+               if calculatedCurrent > current {
+                  bar.SetCurrent(int64(calculatedCurrent))
+                  current = calculatedCurrent
+               }
+            }
+         }
+      }
+   }
+   bar.SetCurrent(100)
+}

Then use this function in both pullImages and pushImages:

- decoder := json.NewDecoder(responseBody)
- var current int
- var event map[string]interface{}
- for decoder.More() { //nolint:dupl // different commands
-    // ... existing event handling logic
- }
- 
- // Finish the progress bar
- bar.SetCurrent(100) //nolint:gomnd
+ processDockerStreamEvents(ctx, json.NewDecoder(responseBody), bar, imageName, "Pushing", errChan)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between d1182bf and d2cf796.

📒 Files selected for processing (1)
  • common/docker/client_image.go (2 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
common/docker/client_image.go (2)
common/docker/client.go (8) (8)
  • c (68-70)
  • c (72-109)
  • c (111-166)
  • c (168-183)
  • c (185-205)
  • c (207-216)
  • c (218-268)
  • Client (48-51)
common/docker/service/service.go (1) (1)
  • Service (25-38)
🔇 Additional comments (2)
common/docker/client_image.go (2)

423-423: Appropriate linting suppression.

The linting suppression for the duplicate code is well-documented, explaining that although similar patterns exist, they serve different commands.


486-601: Well-structured implementation of the pushImages method.

The implementation properly handles concurrent image pushing with progress tracking, error collection, and provides a clean interface that integrates well with the existing Build method.

@ezavada ezavada merged commit c4c6dfb into main Mar 19, 2025
9 of 11 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 27, 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.

None yet

2 participants