Skip to content

Prevent creating stack with name of existing stack#1969

Open
jordanstephens wants to merge 9 commits intomainfrom
jordan/warn-existing-stack
Open

Prevent creating stack with name of existing stack#1969
jordanstephens wants to merge 9 commits intomainfrom
jordan/warn-existing-stack

Conversation

@jordanstephens
Copy link
Member

@jordanstephens jordanstephens commented Mar 6, 2026

Description

Fail to create a stack if the name is invalid. Check if passed by arg or by interactive survey

Linked Issues

Checklist

  • I have performed a self-review of my code
  • I have added appropriate tests
  • I have updated the Defang CLI docs and/or README to reflect my changes, if necessary

Summary by CodeRabbit

  • New Features

    • Stack creation now validates names consistently and prevents creating duplicate stacks within the current project.
  • Bug Fixes

    • Validation and existence checks run reliably in both interactive and non-interactive flows; error messages for invalid or duplicate names are clearer and consistent.
  • Tests

    • Added tests covering name validation, existence checks, prompting flows, and error propagation.

@jordanstephens jordanstephens requested a review from lionello as a code owner March 6, 2026 22:34
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds centralized stack-name validation and backend existence checks to stack creation: exports StackNamePattern and ValidateStackName, adds stackExists() using a new GetStack Fabric RPC, validates names earlier, and prevents duplicate stack creation in interactive and non-interactive CLI flows; tests and mocks added.

Changes

Cohort / File(s) Summary
CLI stack creation & tests
src/cmd/cli/command/stack.go, src/cmd/cli/command/stack_test.go
Validate stack name earlier, resolve project context earlier, add stackExists() that calls Fabric client's GetStack, and block duplicate stack creation in both non-interactive and interactive flows; add tests and a mock client to cover existence and error cases.
Client interface & gRPC client
src/pkg/cli/client/client.go, src/pkg/cli/client/grpc.go
Added GetStack(ctx context.Context, *defangv1.GetStackRequest) (*defangv1.GetStackResponse, error) to FabricClient and implemented it in GrpcClient as an RPC wrapper.
Stack name validation utils & callers
src/pkg/stacks/stacks.go, src/pkg/stacks/wizard.go, src/pkg/stacks/stacks_test.go
Exported StackNamePattern, added ValidateStackName(string) error, replaced inline regex checks with centralized validation in CreateInDirectory/RemoveInDirectory and wizard validator; updated tests to use new validation and error checks.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as "CLI Command"
    participant Validator as "ValidateStackName"
    participant Fabric as "Fabric Client (GetStack)"
    participant Backend as "Backend / Project Store"

    User->>CLI: invoke "stack new" (with name or prompt)
    CLI->>Validator: ValidateStackName(name)
    Validator-->>CLI: valid / invalid

    alt invalid
        CLI-->>User: error "invalid stack name"
    else valid
        CLI->>Fabric: GetStack(project, name)
        Fabric->>Backend: RPC GetStack query
        Backend-->>Fabric: stack found / not found / error
        Fabric-->>CLI: GetStackResponse / error

        alt stack found
            CLI-->>User: error "stack already exists"
        else not found
            CLI->>Backend: create stack
            Backend-->>CLI: created
            CLI-->>User: success
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • lionello

Poem

🐰
I sniff the name beneath the moon,
I check the list and hum a tune,
"No twin stacks here," I softly cry—
I hop, I guard, your stack can fly. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Prevent creating stack with name of existing stack' directly matches the main objective of the PR: preventing duplicate stack names by failing creation attempts.
Linked Issues check ✅ Passed The PR implements all requirements from issue #594: validates stack names, checks for existing stacks, and prevents creation of stacks with duplicate names in both interactive and non-interactive paths.
Out of Scope Changes check ✅ Passed All changes are scoped to stack name validation and duplicate detection. Changes include stack existence checks, validation helpers, and necessary test coverage with no unrelated modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jordan/warn-existing-stack
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

Migrating from UI to YAML configuration.

Use the @coderabbitai configuration command in a PR comment to get a dump of all your UI settings in YAML format. You can then edit this YAML file and upload it to the root of your repository to configure CodeRabbit programmatically.

@jordanstephens jordanstephens changed the title Jordan/warn existing stack Prevent creating stack with name of existing stack Mar 6, 2026
Copy link
Contributor

@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: 3

Caution

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

⚠️ Outside diff range comments (1)
src/cmd/cli/command/stack_test.go (1)

165-184: ⚠️ Potential issue | 🟡 Minor

Two table cases aren’t exercising the paths they’re named after.

"missing stack name" calls RunE with one empty arg, which the CLI can’t actually produce, and "stack already exists" uses existing-stack, which fails name validation before stackExists() runs. That leaves both the zero-arg path and the duplicate-name path untested.

💡 Suggested change
 		{
 			name: "missing stack name",
 			parameters: stacks.Parameters{
 				Name:     "",
@@
 		{
 			name: "stack already exists",
 			parameters: stacks.Parameters{
-				Name:     "existing-stack",
+				Name:     "existingstack",
 				Provider: client.ProviderAWS,
 				Region:   "us-test-2",
 				Mode:     modes.ModeAffordable,
 			},
-			existingStacks: []*defangv1.Stack{{Name: "existing-stack", Project: ""}},
+			existingStacks: []*defangv1.Stack{{Name: "existingstack", Project: ""}},
 			expectErr:      true,
 		},
@@
-			err := stackCreateCmd.RunE(stackCreateCmd, []string{tt.parameters.Name})
+			var args []string
+			if tt.parameters.Name != "" {
+				args = []string{tt.parameters.Name}
+			}
+			err := stackCreateCmd.RunE(stackCreateCmd, args)

Also applies to: 191-200

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

In `@src/cmd/cli/command/stack_test.go` around lines 165 - 184, The two test cases
in stack_test.go are not exercising the intended paths: change the "missing
stack name" case to call the command's RunE with zero args (simulate CLI
invocation with no arguments) so the name-validation path for empty input is
hit, and change the "stack already exists" case to use a valid, non-empty stack
name that passes name validation (e.g., "existing-stack" kept but ensure the
test supplies it as a proper argument) so that stackExists() is reached and
triggers the duplicate-name error; update the test invocations around
RunE/Execute/command creation in the same file to reflect zero-arg invocation
for the first case and valid-arg invocation for the second so the code paths for
name missing and duplicate name are both covered.
🧹 Nitpick comments (1)
src/pkg/stacks/stacks_test.go (1)

30-31: Use ValidateStackName() here instead of the raw regexp.

This test is checking whether MakeDefaultName() produces a name the package accepts. Matching StackNamePattern directly couples the assertion to the current implementation and will miss any extra rules added in ValidateStackName().

💡 Suggested change
-			if !StackNamePattern.MatchString(result) {
-				t.Errorf("MakeDefaultName() produced invalid stack name: %q", result)
-			}
+			if err := ValidateStackName(result); err != nil {
+				t.Errorf("MakeDefaultName() produced invalid stack name %q: %v", result, err)
+			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pkg/stacks/stacks_test.go` around lines 30 - 31, The test currently
asserts MakeDefaultName() by matching against StackNamePattern directly; change
it to call ValidateStackName(result) and assert that it returns nil (or no
error) so the test verifies the full validation logic. Replace the direct
StackNamePattern.MatchString(result) check with a call to
ValidateStackName(result) and update the failure message to include the returned
error (e.g., "MakeDefaultName() produced invalid stack name: %q: %v") so the
test fails with the validator's reason.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cmd/cli/command/stack_test.go`:
- Around line 25-29: The mock ListStacks implementation
(mockFabricClientWithStacks.ListStacks) ignores ListStacksRequest.Project, so
tests like TestStackExists won't catch code that fails to scope by project;
modify ListStacks to check the incoming request.Project against an expected
project value stored on the mock (e.g., add a field like expectedProject or use
m.project) and return an error (or empty result) when they differ, while still
returning m.listStacksErr when set and returning the stacked response when the
project matches.

In `@src/cmd/cli/command/stack.go`:
- Around line 47-49: The validation call to stacks.ValidateStackName should only
run when the user actually supplied the positional STACK_NAME; currently it runs
unconditionally and rejects the zero-arg interactive flow when stackName == "".
Update the branch around ValidateStackName (the code referencing stackName and
stacks.ValidateStackName) to first check that stackName is non-empty (or that
the positional arg count > 0) and only then call stacks.ValidateStackName,
leaving the empty stackName path to proceed to the interactive survey.

In `@src/pkg/stacks/stacks_test.go`:
- Around line 202-205: The test asserts a platform-specific error string after
calling RemoveInDirectory(".", "nonexistingstack"); instead, check for the
standard not-found sentinel: replace assert.ErrorContains(t, err, "...no such
file...") with a portability-safe assertion like assert.ErrorIs(t, err,
os.ErrNotExist) (or assert.True(t, errors.Is(err, os.ErrNotExist)) if ErrorIs
isn't available) and add the necessary import for os (and errors if used); keep
the existing assert.Error(t, err) or remove it since ErrorIs covers presence.

---

Outside diff comments:
In `@src/cmd/cli/command/stack_test.go`:
- Around line 165-184: The two test cases in stack_test.go are not exercising
the intended paths: change the "missing stack name" case to call the command's
RunE with zero args (simulate CLI invocation with no arguments) so the
name-validation path for empty input is hit, and change the "stack already
exists" case to use a valid, non-empty stack name that passes name validation
(e.g., "existing-stack" kept but ensure the test supplies it as a proper
argument) so that stackExists() is reached and triggers the duplicate-name
error; update the test invocations around RunE/Execute/command creation in the
same file to reflect zero-arg invocation for the first case and valid-arg
invocation for the second so the code paths for name missing and duplicate name
are both covered.

---

Nitpick comments:
In `@src/pkg/stacks/stacks_test.go`:
- Around line 30-31: The test currently asserts MakeDefaultName() by matching
against StackNamePattern directly; change it to call ValidateStackName(result)
and assert that it returns nil (or no error) so the test verifies the full
validation logic. Replace the direct StackNamePattern.MatchString(result) check
with a call to ValidateStackName(result) and update the failure message to
include the returned error (e.g., "MakeDefaultName() produced invalid stack
name: %q: %v") so the test fails with the validator's reason.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 61061d17-cd8e-4771-b5cd-0416519ff04b

📥 Commits

Reviewing files that changed from the base of the PR and between 70f85a4 and 3aa15be.

📒 Files selected for processing (5)
  • src/cmd/cli/command/stack.go
  • src/cmd/cli/command/stack_test.go
  • src/pkg/stacks/stacks.go
  • src/pkg/stacks/stacks_test.go
  • src/pkg/stacks/wizard.go

Copy link
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cmd/cli/command/stack_test.go`:
- Around line 184-194: The test case "stack already exists" uses an invalid Name
"existing-stack" (hyphen) which fails ValidateStackName; change the
Parameters.Name and the existingStacks[*].Name to a valid name that matches
^[a-z][a-z0-9]*$ (e.g., "existingstack" or "existingstack1") so validation
passes and the test exercise the existence-check path in the code that handles
stacks.Parameters and the existingStacks slice.

In `@src/cmd/cli/command/stack.go`:
- Around line 220-232: The stackExists helper should treat a "not found"
response from GetStack as a non-error: modify stackExists (the function calling
global.Client.GetStack) to detect a CodeNotFound/NotFound error (use grpc/status
to get the error code or check the server's CodeNotFound sentinel) and return
(false, nil) when that occurs; for any other error, return (false, err), and
otherwise keep the existing logic that returns resp.GetStack() != nil.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 10df2ee6-1a67-43aa-92a4-44bb4e55e376

📥 Commits

Reviewing files that changed from the base of the PR and between 3aa15be and 8e49f07.

📒 Files selected for processing (5)
  • src/cmd/cli/command/stack.go
  • src/cmd/cli/command/stack_test.go
  • src/pkg/cli/client/client.go
  • src/pkg/cli/client/grpc.go
  • src/pkg/stacks/stacks_test.go

Copy link
Contributor

@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)
src/cmd/cli/command/stack_test.go (2)

26-39: Mock doesn't simulate CodeNotFound error for non-existent stacks.

The real GetStack server returns a CodeNotFound error when a stack doesn't exist, but this mock returns an empty response. This means tests exercise the resp.GetStack() != nil path but don't verify the CodeNotFound handling in stackExists.

Consider returning a connect error to match server behavior:

♻️ Suggested improvement
+import "connectrpc.com/connect"

 func (m mockFabricClientWithStacks) GetStack(_ context.Context, req *defangv1.GetStackRequest) (*defangv1.GetStackResponse, error) {
 	if m.listStacksErr != nil {
 		return nil, m.listStacksErr
 	}
 	if m.expectedProject != "" && req.Project != m.expectedProject {
-		return &defangv1.GetStackResponse{}, nil
+		return nil, connect.NewError(connect.CodeNotFound, nil)
 	}
 	for _, s := range m.existingStacks {
 		if s.Name == req.Stack {
 			return &defangv1.GetStackResponse{Stack: s}, nil
 		}
 	}
-	return &defangv1.GetStackResponse{}, nil
+	return nil, connect.NewError(connect.CodeNotFound, nil)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cmd/cli/command/stack_test.go` around lines 26 - 39, The mock GetStack
implementation in mockFabricClientWithStacks should simulate the server's
NotFound behavior instead of returning an empty response; update
mockFabricClientWithStacks.GetStack to return a connect error with CodeNotFound
(matching the connect/grpc error used by the real server) when the requested
stack is not present or project mismatch so tests exercise the stackExists error
path and the code that handles the not-found error.

173-183: Clarify test intent: empty name bypasses validation, error comes later.

When Name is "" and passed as args[0], the validation at lines 45-47 in stack.go is skipped (guarded by stackName != ""). The error occurs downstream in CreateInDirectory. Consider adding a comment or asserting the specific error message to clarify what's being tested.

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

In `@src/cmd/cli/command/stack_test.go` around lines 173 - 183, The test case
"missing stack name" is ambiguous because an empty Parameters.Name bypasses the
validation guarded by stackName != "" in stack.go and the actual error
originates from CreateInDirectory; update the test by either adding a clarifying
comment explaining that an empty name skips the early validation and triggers an
error later in CreateInDirectory, or change the assertion to check for the
specific error message returned by CreateInDirectory (referencing
CreateInDirectory and the test case name "missing stack name") so the intent and
failure source are explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cmd/cli/command/stack.go`:
- Around line 228-232: The build fails because the connect package is referenced
(connect.CodeOf and connect.CodeNotFound) but not imported; open the imports
block in the file containing stack.go and add the appropriate connect package
import (the package that defines CodeOf/CodeNotFound) so the references to
connect.CodeOf and connect.CodeNotFound resolve and the file compiles.

---

Nitpick comments:
In `@src/cmd/cli/command/stack_test.go`:
- Around line 26-39: The mock GetStack implementation in
mockFabricClientWithStacks should simulate the server's NotFound behavior
instead of returning an empty response; update
mockFabricClientWithStacks.GetStack to return a connect error with CodeNotFound
(matching the connect/grpc error used by the real server) when the requested
stack is not present or project mismatch so tests exercise the stackExists error
path and the code that handles the not-found error.
- Around line 173-183: The test case "missing stack name" is ambiguous because
an empty Parameters.Name bypasses the validation guarded by stackName != "" in
stack.go and the actual error originates from CreateInDirectory; update the test
by either adding a clarifying comment explaining that an empty name skips the
early validation and triggers an error later in CreateInDirectory, or change the
assertion to check for the specific error message returned by CreateInDirectory
(referencing CreateInDirectory and the test case name "missing stack name") so
the intent and failure source are explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec698264-9515-4472-b4be-39260561ac18

📥 Commits

Reviewing files that changed from the base of the PR and between 8e49f07 and 61e03af.

📒 Files selected for processing (2)
  • src/cmd/cli/command/stack.go
  • src/cmd/cli/command/stack_test.go

@jordanstephens jordanstephens requested a review from lionello March 10, 2026 17:12
Copy link
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cmd/cli/command/stack.go`:
- Around line 220-243: The function stackExists currently contains a duplicated
import block inside its body and lacks proper handling for not-found errors;
remove the duplicated import block from inside stackExists, add the missing
import "connectrpc.com/connect" to the file's top-level imports, and update the
error handling after calling global.Client.GetStack (in stackExists with
defangv1.GetStackRequest) to detect and treat a CodeNotFound response as "stack
does not exist" (e.g. check connect.CodeOf(err) == connect.CodeNotFound and
return (false, nil) in that case), otherwise return the error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2e737c72-2bc2-42f6-beb2-60a8b6536392

📥 Commits

Reviewing files that changed from the base of the PR and between 61e03af and 87c6c66.

📒 Files selected for processing (1)
  • src/cmd/cli/command/stack.go

@jordanstephens jordanstephens force-pushed the jordan/warn-existing-stack branch from 87c6c66 to 4e0dcfb Compare March 11, 2026 18:38
Copy link
Contributor

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

♻️ Duplicate comments (1)
src/cmd/cli/command/stack.go (1)

3-14: ⚠️ Potential issue | 🔴 Critical

Missing import for connect package causes build failure.

The connect package is referenced at line 229 but not imported. Add the missing import to fix the pipeline failure.

🐛 Proposed fix
 import (
 	"context"
 	"encoding/json"
 	"fmt"

+	"connectrpc.com/connect"
 	"github.com/DefangLabs/defang/src/pkg/cli"
 	"github.com/DefangLabs/defang/src/pkg/modes"
 	"github.com/DefangLabs/defang/src/pkg/stacks"
 	"github.com/DefangLabs/defang/src/pkg/term"
 	defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1"
 	"github.com/spf13/cobra"
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cmd/cli/command/stack.go` around lines 3 - 14, The build fails because
the connect package (used as connect.NewRequest in this file) is not imported;
add the missing import for the connect package (e.g.,
"github.com/bufbuild/connect-go") to the import block in stack.go so references
like connect.NewRequest (around the stack command handler) resolve and the file
compiles.
🧹 Nitpick comments (1)
src/cmd/cli/command/stack_test.go (1)

26-39: Mock may not accurately simulate real GetStack behavior for non-existent stacks.

The mock returns an empty GetStackResponse{} when a stack isn't found, but the real gRPC implementation likely returns a connect.CodeNotFound error. Since stackExists (in stack.go) handles CodeNotFound as the "not found" signal, these tests may pass while masking issues with the actual error handling path.

Consider updating the mock to return connect.NewError(connect.CodeNotFound, ...) when the stack isn't found to better simulate production behavior.

♻️ Suggested improvement
+import "connectrpc.com/connect"
+
 func (m mockFabricClientWithStacks) GetStack(_ context.Context, req *defangv1.GetStackRequest) (*defangv1.GetStackResponse, error) {
 	if m.listStacksErr != nil {
 		return nil, m.listStacksErr
 	}
 	if m.expectedProject != "" && req.Project != m.expectedProject {
-		return &defangv1.GetStackResponse{}, nil
+		return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("stack not found"))
 	}
 	for _, s := range m.existingStacks {
 		if s.Name == req.Stack {
 			return &defangv1.GetStackResponse{Stack: s}, nil
 		}
 	}
-	return &defangv1.GetStackResponse{}, nil
+	return nil, connect.NewError(connect.CodeNotFound, fmt.Errorf("stack %q not found", req.Stack))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cmd/cli/command/stack_test.go` around lines 26 - 39, The mock GetStack
implementation in mockFabricClientWithStacks should simulate the real gRPC
behavior for missing stacks by returning a connect.CodeNotFound error instead of
an empty GetStackResponse; update the GetStack method
(mockFabricClientWithStacks.GetStack) so that when no matching stack is found it
returns connect.NewError(connect.CodeNotFound, fmt.Errorf("stack %s not found",
req.Stack)) (and add the necessary connect import) so tests exercising
stackExists will follow the same error path as production.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/cmd/cli/command/stack.go`:
- Around line 3-14: The build fails because the connect package (used as
connect.NewRequest in this file) is not imported; add the missing import for the
connect package (e.g., "github.com/bufbuild/connect-go") to the import block in
stack.go so references like connect.NewRequest (around the stack command
handler) resolve and the file compiles.

---

Nitpick comments:
In `@src/cmd/cli/command/stack_test.go`:
- Around line 26-39: The mock GetStack implementation in
mockFabricClientWithStacks should simulate the real gRPC behavior for missing
stacks by returning a connect.CodeNotFound error instead of an empty
GetStackResponse; update the GetStack method
(mockFabricClientWithStacks.GetStack) so that when no matching stack is found it
returns connect.NewError(connect.CodeNotFound, fmt.Errorf("stack %s not found",
req.Stack)) (and add the necessary connect import) so tests exercising
stackExists will follow the same error path as production.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8996a33-4fbd-4e78-9dae-e3a413e8723a

📥 Commits

Reviewing files that changed from the base of the PR and between 87c6c66 and 4e0dcfb.

📒 Files selected for processing (7)
  • src/cmd/cli/command/stack.go
  • src/cmd/cli/command/stack_test.go
  • src/pkg/cli/client/client.go
  • src/pkg/cli/client/grpc.go
  • src/pkg/stacks/stacks.go
  • src/pkg/stacks/stacks_test.go
  • src/pkg/stacks/wizard.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/pkg/stacks/stacks_test.go
  • src/pkg/cli/client/grpc.go

Copy link
Contributor

@edwardrf edwardrf left a comment

Choose a reason for hiding this comment

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

LGTM

jordanstephens and others added 9 commits March 18, 2026 11:05
Replace platform-specific error string check with a portable sentinel
check so the test passes on all operating systems (e.g. Windows).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tests

stackExists switched from ListStacks to GetStack but lost the empty-stack
early-return guard; restore it. Replace the unused ListStacks mock with a
GetStack implementation that validates project scope via expectedProject,
and add a test case covering wrong-project returns false.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@jordanstephens jordanstephens force-pushed the jordan/warn-existing-stack branch from 8b6356c to 73cfbe1 Compare March 18, 2026 18:10
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