Skip to content

Comments

Disambiguate stacks in interactive selector#1910

Merged
jordanstephens merged 2 commits intomainfrom
jordan/stack-labels
Feb 9, 2026
Merged

Disambiguate stacks in interactive selector#1910
jordanstephens merged 2 commits intomainfrom
jordan/stack-labels

Conversation

@jordanstephens
Copy link
Member

@jordanstephens jordanstephens commented Feb 5, 2026

Description

I have a lot of stacks, and though I try to name them descriptively, sometimes, I forget which is which. This PR aims to add some extra info to the interactive stack selection list by printing stack provider, region and last deployed time after the name. If all of the providers or regions are the same, they won't be printed.

With many providers and regions, everything is printed

defang deploy
This project was deployed with an implicit Stack called 'beta' before Stacks were introduced.
   To learn more about Stacks, visit: https://s.defang.io/stacks
To skip this prompt, run this command with --stack=<stack_name>
Select a stack
? stack  [Use arrows to move, type to filter]
> jordan (Google Cloud Platform, us-central1, last deployed Jan 19 2026)
  jordanaws (AWS, us-west-2, last deployed Jan 19 2026)
  oneclick (AWS, us-west-2)
  production (AWS, us-west-2)
  staging (AWS, us-west-2, last deployed Jan 24 2026)
  beta (Defang Playground)
  Create new stack

With the same provider, only region is printed

defang deploy
This project was deployed with an implicit Stack called 'beta' before Stacks were introduced.
   To learn more about Stacks, visit: https://s.defang.io/stacks
To skip this prompt, run this command with --stack=<stack_name>
Select a stack
? stack  [Use arrows to move, type to filter]
> prod (us-east-1, last deployed Feb 3 2026)
  staging (us-west-2, last deployed Feb 5 2026)
  Create new stack

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

Release Notes

  • New Features

    • Stack selection options now display provider and region information (e.g., "production (us-west-2)"), making it easier to distinguish between multiple stacks.
  • Tests

    • Updated test expectations to validate enhanced stack selection labeling across various scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

The PR refactors stack selection label generation to display provider-region information alongside stack names. A new public function MakeStackSelectorLabels precomputes a map of display labels from stack lists, replacing inline construction. Tests are updated to reflect the new label format.

Changes

Cohort / File(s) Summary
Label Generation Refactoring
src/pkg/stacks/selector.go
Introduces MakeStackSelectorLabels function to precompute display labels for stacks. Adds helper functions (stackLabelParts, reduceStackLabelParts, formatStackLabelParts) that generate compact labels by deduplicating common attributes across stacks, then replaces inline label construction with labelMap lookups. Imports strings package for formatting.
Test Updates
src/pkg/stacks/manager_test.go, src/pkg/stacks/selector_test.go
Updates all test expectations to include provider-region information in stack selection labels (e.g., "existingstack (gcp)" vs "existingstack"). Adds new test function TestMakeStackSelectorLabels to validate label generation across empty, single, and multi-stack scenarios with deduplication rules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Lio/stacks #1860 — Modifies src/pkg/stacks/selector.go with related changes to SelectStackOptions naming and structure, creating potential overlap or integration points with this label refactoring.

Suggested reviewers

  • lionello

Poem

🐰 Labels bloom with regions bright,
Stacks now dressed in provider light,
Precomputed maps cut through the maze,
Cleaner selections, clearer ways!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding disambiguating information (provider, region metadata) to the interactive stack selector to help users distinguish between stacks.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jordan/stack-labels

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

level=warning msg="[linters_context] running gomodguard failed: unable to read module file go.mod: current working directory must have a go.mod file: if you are not using go modules it is suggested to disable this linter"
level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

@jordanstephens jordanstephens changed the title Adding disambiguating info to interactive stack selector Disambiguate stacks in interactive selector Feb 5, 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: 1

🤖 Fix all issues with AI agents
In `@src/pkg/stacks/selector.go`:
- Around line 128-138: MakeStackSelectorLabels can drop a stack when two
different stacks produce the same formatted label; update
MakeStackSelectorLabels to detect label collisions from
formatStackLabelParts(parts) and handle them instead of overwriting: check if
labelMap already has the label, and on collision either (A) append a
disambiguating suffix using a unique field from the corresponding ListItem
(e.g., stacks[i].Name or an ID) or index, or (B) change the map value to a slice
and push both stacks' identifiers so multiple stacks are selectable; ensure you
use stackLabelParts, reduceStackLabelParts, formatStackLabelParts unchanged and
only modify labelMap population logic in MakeStackSelectorLabels to preserve
uniqueness or collect collisions.
🧹 Nitpick comments (2)
src/pkg/stacks/selector.go (1)

59-67: Inefficient O(n²) lookup to preserve stack ordering.

The nested loop iterating over labelMap for each stack results in O(n²) complexity. Since maps in Go have non-deterministic iteration order, this approach is needed to preserve the original stack ordering, but it's inefficient.

Consider building the labels in order directly:

♻️ Proposed refactor to build labels in order
-	labelMap := MakeStackSelectorLabels(stackList)
-	stackLabels := make([]string, 0, len(stackList)+1)
-	stackNames := make([]string, 0, len(stackList))
-	for _, stack := range stackList {
-		for label, name := range labelMap {
-			if name == stack.Name {
-				stackLabels = append(stackLabels, label)
-				stackNames = append(stackNames, name)
-				break
-			}
-		}
-	}
+	labelMap := MakeStackSelectorLabels(stackList)
+	stackLabels := make([]string, 0, len(stackList)+1)
+	stackNames := make([]string, 0, len(stackList))
+	// Build a reverse map for O(1) lookup
+	nameToLabel := make(map[string]string, len(labelMap))
+	for label, name := range labelMap {
+		nameToLabel[name] = label
+	}
+	for _, stack := range stackList {
+		if label, ok := nameToLabel[stack.Name]; ok {
+			stackLabels = append(stackLabels, label)
+			stackNames = append(stackNames, stack.Name)
+		}
+	}

Alternatively, consider changing MakeStackSelectorLabels to return both the label slice (in order) and the map, avoiding the need for reverse lookup.

src/pkg/stacks/selector_test.go (1)

472-539: Good test coverage, consider adding edge cases.

The test cases cover the main label reduction scenarios well. Consider adding tests for:

  1. DeployedAt formatting: Verify that DeployedAt is included in labels when set
  2. Label collision: Test behavior when stacks could produce identical labels
📝 Suggested additional test cases
{
	name: "includes deployed date",
	stacks: []ListItem{
		{
			Parameters: Parameters{Name: "production", Provider: "aws", Region: "us-west-2"},
			DeployedAt: time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC),
		},
	},
	wantLabels: []string{"production (aws, us-west-2, last deployed Jan 15 2026)"},
},
{
	name: "hides redundant deployed date when all same",
	stacks: []ListItem{
		{
			Parameters: Parameters{Name: "prod", Provider: "aws", Region: "us-west-2"},
			DeployedAt: time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC),
		},
		{
			Parameters: Parameters{Name: "dev", Provider: "aws", Region: "us-east-1"},
			DeployedAt: time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC),
		},
	},
	wantLabels: []string{"prod (us-west-2)", "dev (us-east-1)"},
},

@jordanstephens jordanstephens enabled auto-merge (squash) February 9, 2026 23:03
@jordanstephens jordanstephens merged commit 16f3a0d into main Feb 9, 2026
14 checks passed
@jordanstephens jordanstephens deleted the jordan/stack-labels branch February 9, 2026 23:56
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