Skip to content

Replace container name in command output#63

Open
gtsiolis wants to merge 1 commit intomainfrom
george/replace-container-name
Open

Replace container name in command output#63
gtsiolis wants to merge 1 commit intomainfrom
george/replace-container-name

Conversation

@gtsiolis
Copy link
Member

@gtsiolis gtsiolis commented Mar 3, 2026

See DES-152 for more context.

BEFORE AFTER
Screenshot 2026-03-04 at 00 28 43 Screenshot 2026-03-04 at 00 27 52

@gtsiolis gtsiolis self-assigned this Mar 3, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

Standardizes user-facing messages to consistently reference "LocalStack" instead of dynamic container names across start/stop flows and plain-text status formatting; tests updated to match the new strings. (≤50 words)

Changes

Cohort / File(s) Summary
Container Start
internal/container/start.go
Replaced per-container names with the static "LocalStack" label in start progress, readiness checks, and error messages.
Container Stop
internal/container/stop.go
Unified stop progress and error messages to reference "LocalStack" while preserving use of the container name for the actual stop call.
Output Formatting
internal/output/plain_format.go
Replaced dynamic container-name substitutions in ContainerStatusEvent messages with fixed "LocalStack" phrasing for pulling/starting/waiting/ready and default cases.
Tests
internal/output/plain_format_test.go, internal/output/plain_sink_test.go
Updated test fixtures and expected strings to reflect "LocalStack" wording and adjusted test container image identifiers where applicable.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • silv-io
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: replacing container name references with standardized 'LocalStack' messaging throughout the command output.
Description check ✅ Passed The description is related to the changeset, providing visual before-and-after context for the output message changes referenced in DES-152.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch george/replace-container-name

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.

Caution

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

⚠️ Outside diff range comments (1)
internal/container/stop.go (1)

12-27: 🛠️ Refactor suggestion | 🟠 Major

Route stop progress through output.Sink, not onProgress callbacks.

This path still emits user-visible progress via raw callback strings, which breaks parity with the typed output event pipeline used in internal/ workflows.

Proposed direction
 package container

 import (
 	"context"
 	"fmt"

 	"github.com/containerd/errdefs"
 	"github.com/localstack/lstk/internal/config"
+	"github.com/localstack/lstk/internal/output"
 	"github.com/localstack/lstk/internal/runtime"
 )

-func Stop(ctx context.Context, rt runtime.Runtime, onProgress func(string)) error {
+func Stop(ctx context.Context, rt runtime.Runtime, sink output.Sink) error {
 	cfg, err := config.Get()
 	if err != nil {
 		return fmt.Errorf("failed to get config: %w", err)
 	}

 	for _, c := range cfg.Containers {
-		onProgress("Stopping LocalStack...")
+		output.EmitInfo(sink, "Stopping LocalStack...")
 		if err := rt.Stop(ctx, c.Name()); err != nil {
 			if errdefs.IsNotFound(err) {
 				return fmt.Errorf("LocalStack is not running")
 			}
 			return fmt.Errorf("failed to stop LocalStack: %w", err)
 		}
-		onProgress("LocalStack stopped")
+		output.EmitInfo(sink, "LocalStack stopped")
 	}

As per coding guidelines internal/**/*.go: “Any feature/workflow package that produces user-visible progress should accept an output.Sink dependency and emit events through internal/output.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/container/stop.go` around lines 12 - 27, The Stop function currently
uses an onProgress callback to emit raw strings; change its signature to accept
an output.Sink (instead of onProgress) and emit typed progress events via the
internal/output API (e.g., create and write a progress event for "Stopping
LocalStack..." and "LocalStack stopped") when iterating cfg.Containers and
calling rt.Stop(ctx, c.Name()). Update all references to Stop to pass an
output.Sink, remove onProgress usage, and ensure error branches still return the
same errors while emitting any final/failure events via the sink.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/container/stop.go`:
- Around line 12-27: The Stop function currently uses an onProgress callback to
emit raw strings; change its signature to accept an output.Sink (instead of
onProgress) and emit typed progress events via the internal/output API (e.g.,
create and write a progress event for "Stopping LocalStack..." and "LocalStack
stopped") when iterating cfg.Containers and calling rt.Stop(ctx, c.Name()).
Update all references to Stop to pass an output.Sink, remove onProgress usage,
and ensure error branches still return the same errors while emitting any
final/failure events via the sink.

ℹ️ Review info

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ac17a7 and 719deba.

📒 Files selected for processing (5)
  • internal/container/start.go
  • internal/container/stop.go
  • internal/output/plain_format.go
  • internal/output/plain_format_test.go
  • internal/output/plain_sink_test.go

@gtsiolis gtsiolis force-pushed the george/replace-container-name branch from 719deba to 6eb594e Compare March 3, 2026 22:28
@gtsiolis gtsiolis requested a review from anisaoshafi as a code owner March 3, 2026 22:28
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.

🧹 Nitpick comments (1)
internal/output/plain_format_test.go (1)

51-60: Add table cases for all newly customized status branches.

The updated expectations are correct, but only two of the modified formatStatusLine branches are asserted here. Please add cases for starting, waiting, ready (without detail), and default fallback paths to lock in the full behavior change.

Suggested test additions
 		{
 			name:   "status pulling",
 			event:  ContainerStatusEvent{Phase: "pulling", Container: "localstack/localstack-pro:latest"},
 			want:   "Preparing LocalStack...",
 			wantOK: true,
 		},
+		{
+			name:   "status starting",
+			event:  ContainerStatusEvent{Phase: "starting", Container: "localstack-aws"},
+			want:   "Starting LocalStack...",
+			wantOK: true,
+		},
+		{
+			name:   "status waiting",
+			event:  ContainerStatusEvent{Phase: "waiting", Container: "localstack-aws"},
+			want:   "Waiting for LocalStack to be ready...",
+			wantOK: true,
+		},
 		{
 			name:   "status ready with detail",
 			event:  ContainerStatusEvent{Phase: "ready", Container: "localstack-aws", Detail: "abc123"},
 			want:   "LocalStack ready (abc123)",
 			wantOK: true,
 		},
+		{
+			name:   "status ready without detail",
+			event:  ContainerStatusEvent{Phase: "ready", Container: "localstack-aws"},
+			want:   "LocalStack ready",
+			wantOK: true,
+		},
+		{
+			name:   "status default with detail",
+			event:  ContainerStatusEvent{Phase: "restarting", Container: "localstack-aws", Detail: "attempt 1"},
+			want:   "LocalStack: restarting (attempt 1)",
+			wantOK: true,
+		},
+		{
+			name:   "status default without detail",
+			event:  ContainerStatusEvent{Phase: "restarting", Container: "localstack-aws"},
+			want:   "LocalStack: restarting",
+			wantOK: true,
+		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/output/plain_format_test.go` around lines 51 - 60, The tests only
cover two branches of formatStatusLine; add table-driven cases asserting the
other new branches by adding entries to the test cases slice that construct
ContainerStatusEvent values for Phase "starting", "waiting", "ready" with no
Detail, and a generic unknown phase to exercise the default fallback, and set
the expected want strings and wantOK booleans to match the new formatStatusLine
behavior so all branches are asserted in the same Test function that iterates
over the cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/output/plain_format_test.go`:
- Around line 51-60: The tests only cover two branches of formatStatusLine; add
table-driven cases asserting the other new branches by adding entries to the
test cases slice that construct ContainerStatusEvent values for Phase
"starting", "waiting", "ready" with no Detail, and a generic unknown phase to
exercise the default fallback, and set the expected want strings and wantOK
booleans to match the new formatStatusLine behavior so all branches are asserted
in the same Test function that iterates over the cases.

ℹ️ Review info

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 719deba and 6eb594e.

📒 Files selected for processing (5)
  • internal/container/start.go
  • internal/container/stop.go
  • internal/output/plain_format.go
  • internal/output/plain_format_test.go
  • internal/output/plain_sink_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/output/plain_sink_test.go
  • internal/container/start.go
  • internal/container/stop.go

containerID, err := rt.Start(ctx, c)
if err != nil {
return fmt.Errorf("failed to start %s: %w", c.Name, err)
return fmt.Errorf("failed to start LocalStack: %w", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: This code loops over all containers specified in the config. I know that we only support one container for launch, but the moment we want to support more the output will be confusing.
If someone adds a Snowflake or Azure container, all status messages will still say "LocalStack".
We could also use ProductName() which would read "localstack-pro" instead of "localstack-aws".
I am fine with ignoring this problem for now, just wanted to make you aware of it 🙂

Copy link
Member

Choose a reason for hiding this comment

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

We also have the Emulator Display name that we're using in the header. Could do that instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good insight. ⚾

I'd keep it as is.

  1. The output here can stay consistent with the platform vision and avoid limiting the CLI in SKU-specific messaging, see relevant discussion for more context.
  2. The emulation-specific information can still live as metadata or sub-information, regardless if one would start AWS, or SNO, both emulators, or side containers with tools (see DRG-364), etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

Jsut refreshed and saw your comment above in #63 (comment) after posting, @silv-io.

We also have the Emulator Display name that we're using in the header. Could do that instead?

Do you mean something like this?

diff --git a/internal/container/start.go b/internal/container/start.go
index 8e55be3..85b587d 100644
--- a/internal/container/start.go
+++ b/internal/container/start.go
@@ -122,12 +122,12 @@ func startContainers(ctx context.Context, rt runtime.Runtime, sink output.Sink,
                output.EmitStatus(sink, "starting", c.Name, "")
                containerID, err := rt.Start(ctx, c)
                if err != nil {
-                       return fmt.Errorf("failed to start LocalStack: %w", err)
+                       return fmt.Errorf("failed to start %s: %w", c.ProductName, err)
                }

                output.EmitStatus(sink, "waiting", c.Name, "")
                healthURL := fmt.Sprintf("http://localhost:%s%s", c.Port, c.HealthPath)
-               if err := awaitStartup(ctx, rt, sink, containerID, "LocalStack", healthURL); err != nil {
+               if err := awaitStartup(ctx, rt, sink, containerID, c.ProductName, healthURL); err != nil {
                        return err
                }

@@ -144,7 +144,7 @@ func selectContainersToStart(ctx context.Context, rt runtime.Runtime, sink outpu
                        return nil, fmt.Errorf("failed to check container status: %w", err)
                }
                if running {
-                       output.EmitInfo(sink, "LocalStack is already running")
+                       output.EmitInfo(sink, fmt.Sprintf("%s is already running", c.ProductName))
                        continue
                }
                if err := ports.CheckAvailable(c.Port); err != nil {
diff --git a/internal/container/stop.go b/internal/container/stop.go
index 0e7af84..11a59dd 100644
--- a/internal/container/stop.go
+++ b/internal/container/stop.go
@@ -16,14 +16,18 @@ func Stop(ctx context.Context, rt runtime.Runtime, onProgress func(string)) erro
        }

        for _, c := range cfg.Containers {
-               onProgress("Stopping LocalStack...")
+               productName, err := c.ProductName()
+               if err != nil {
+                       productName = "LocalStack"
+               }
+               onProgress(fmt.Sprintf("Stopping %s...", productName))
                if err := rt.Stop(ctx, c.Name()); err != nil {
                        if errdefs.IsNotFound(err) {
-                               return fmt.Errorf("LocalStack is not running")
+                               return fmt.Errorf("%s is not running", productName)
                        }
-                       return fmt.Errorf("failed to stop LocalStack: %w", err)
+                       return fmt.Errorf("failed to stop %s: %w", productName, err)
                }
-               onProgress("LocalStack stopped")
+               onProgress(fmt.Sprintf("%s stopped", productName))
        }

        return nil

Copy link
Member

Choose a reason for hiding this comment

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

yes!

Copy link
Collaborator

@carole-lavillonniere carole-lavillonniere left a comment

Choose a reason for hiding this comment

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

Added one small concern, but it's good to go for me if you think we can ignore it!

@gtsiolis gtsiolis force-pushed the george/replace-container-name branch from 6eb594e to 42746a2 Compare March 4, 2026 10:34
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.

Caution

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

⚠️ Outside diff range comments (1)
internal/container/stop.go (1)

12-12: 🛠️ Refactor suggestion | 🟠 Major

Decouple Stop from UI callbacks and emit typed output events instead.

Line 12 keeps a UI callback in the container domain, and Lines 19-26 emit pre-rendered strings. This couples domain logic to presentation and conflicts with the output event model.

As per coding guidelines: "internal/{auth,config,container,runtime}//*.go: Do not pass UI callbacks like onProgress func(...) through domain layers; prefer typed output events" and "{cmd,internal}//*.go: Emit typed events through internal/output (EmitInfo, EmitSuccess, EmitNote, EmitWarning, EmitStatus, EmitProgress, etc.) instead of printing from domain/command handlers".

Also applies to: 19-26

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/container/stop.go` at line 12, The Stop function currently accepts a
UI callback (onProgress) and emits pre-rendered strings (lines ~19-26); remove
the onProgress parameter from Stop(ctx context.Context, rt runtime.Runtime,
onProgress func(string)) and instead emit typed output events via the
internal/output package (e.g., output.EmitStatus, output.EmitProgress,
EmitInfo/EmitSuccess as appropriate) from within Stop and any helper functions;
update callers to stop passing UI callbacks and rely on the output event system,
and replace all direct string callbacks/usages in the Stop implementation with
the corresponding typed output.EmitX calls so domain logic is decoupled from
presentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@internal/container/stop.go`:
- Line 12: The Stop function currently accepts a UI callback (onProgress) and
emits pre-rendered strings (lines ~19-26); remove the onProgress parameter from
Stop(ctx context.Context, rt runtime.Runtime, onProgress func(string)) and
instead emit typed output events via the internal/output package (e.g.,
output.EmitStatus, output.EmitProgress, EmitInfo/EmitSuccess as appropriate)
from within Stop and any helper functions; update callers to stop passing UI
callbacks and rely on the output event system, and replace all direct string
callbacks/usages in the Stop implementation with the corresponding typed
output.EmitX calls so domain logic is decoupled from presentation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 484e6858-945c-4fc5-a231-260617f1d716

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb594e and 42746a2.

📒 Files selected for processing (5)
  • internal/container/start.go
  • internal/container/stop.go
  • internal/output/plain_format.go
  • internal/output/plain_format_test.go
  • internal/output/plain_sink_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/container/start.go

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.

3 participants