Skip to content

Commit df64bc7

Browse files
only print up stacks unless --all
1 parent ac98f34 commit df64bc7

3 files changed

Lines changed: 85 additions & 30 deletions

File tree

src/cmd/cli/command/commands_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ type MockFabricControllerClient struct {
208208
defangv1connect.FabricControllerClient
209209
canIUseResponse defangv1.CanIUseResponse
210210
savedProvider map[string]defangv1.Provider
211+
stacksToList []*defangv1.Stack
211212
}
212213

213214
func (m *MockFabricControllerClient) CanIUse(context.Context, *connect.Request[defangv1.CanIUseRequest]) (*connect.Response[defangv1.CanIUseResponse], error) {
@@ -240,7 +241,7 @@ func (m *MockFabricControllerClient) ListDeployments(ctx context.Context, req *c
240241

241242
func (m *MockFabricControllerClient) ListStacks(ctx context.Context, req *connect.Request[defangv1.ListStacksRequest]) (*connect.Response[defangv1.ListStacksResponse], error) {
242243
return connect.NewResponse(&defangv1.ListStacksResponse{
243-
Stacks: []*defangv1.Stack{},
244+
Stacks: m.stacksToList,
244245
}), nil
245246
}
246247

src/cmd/cli/command/stack.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,24 +137,30 @@ func makeStackListCmd() *cobra.Command {
137137
return err
138138
}
139139

140-
filteredStacks := make([]stacks.ListItem, 0, len(stackList))
141-
for _, stack := range stackList {
142-
if stack.Status == defangv1.StackStatus_STACK_STATUS_DOWN {
143-
continue
140+
all, _ := cmd.Flags().GetBool("all")
141+
if !all {
142+
filteredStacks := make([]stacks.ListItem, 0, len(stackList))
143+
for _, stack := range stackList {
144+
if stack.Status == defangv1.StackStatus_STACK_STATUS_DOWN {
145+
continue
146+
}
147+
filteredStacks = append(filteredStacks, stack)
144148
}
145-
filteredStacks = append(filteredStacks, stack)
146-
}
147149

148-
if len(filteredStacks) == 0 {
149-
_, err = term.Infof("All stacks in the current directory are down.\n")
150-
return err
150+
if len(filteredStacks) == 0 {
151+
_, err = term.Infof("All stacks in the current directory are down.\n")
152+
return err
153+
}
154+
155+
stackList = filteredStacks
151156
}
152157

153158
columns := []string{"Name", "Default", "Provider", "Region", "Account", "Mode", "DeployedAt"}
154-
return term.Table(filteredStacks, columns...)
159+
return term.Table(stackList, columns...)
155160
},
156161
}
157162
stackListCmd.Flags().Bool("json", false, "Output in JSON format")
163+
stackListCmd.Flags().BoolP("all", "a", false, "Include stacks that are down")
158164
return stackListCmd
159165
}
160166

src/cmd/cli/command/stack_test.go

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -64,40 +64,35 @@ func TestStackListCmd(t *testing.T) {
6464
global.Client = origClient
6565
})
6666

67-
// Set up a mock client
67+
// Set up a mock client (shared, but stacksToList is updated per subtest)
6868
mockClient := client.GrpcClient{}
6969
mockCtrl := &MockFabricControllerClient{
7070
canIUseResponse: defangv1.CanIUseResponse{},
7171
}
7272
mockClient.SetFabricClient(mockCtrl)
7373
global.Client = &mockClient
7474

75-
// Set up a fake RootCmd with required flags
76-
RootCmd = &cobra.Command{Use: "defang"}
77-
RootCmd.PersistentFlags().StringVarP(&global.Stack.Name, "stack", "s", global.Stack.Name, "stack name")
78-
RootCmd.PersistentFlags().VarP(&global.Stack.Provider, "provider", "P", "provider")
79-
RootCmd.PersistentFlags().StringP("project-name", "p", "", "project name")
80-
RootCmd.PersistentFlags().StringArrayP("file", "f", []string{}, "compose file path(s)")
81-
82-
// Create stackListCmd with manual RunE to avoid configureLoader call during test
83-
var stackListCmd = makeStackListCmd()
84-
85-
// Add stackListCmd as a child of RootCmd
86-
RootCmd.AddCommand(stackListCmd)
75+
downStackFile := []byte("DEFANG_PROVIDER=aws\nAWS_REGION=us-test-1\nDEFANG_MODE=affordable")
76+
upStackFile := []byte("DEFANG_PROVIDER=gcp\nGOOGLE_REGION=us-central1\nDEFANG_MODE=balanced")
8777

8878
tests := []struct {
8979
name string
90-
stacks []stacks.Parameters
80+
localStacks []stacks.Parameters
81+
remoteStacks []*defangv1.Stack
82+
cmdArgs []string
9183
expectOutput string
84+
containsAll []string
85+
containsNone []string
9286
}{
9387
{
9488
name: "no stacks present",
95-
stacks: []stacks.Parameters{},
89+
localStacks: []stacks.Parameters{},
90+
cmdArgs: []string{"list"},
9691
expectOutput: " * No Defang stacks found in the current directory.\n",
9792
},
9893
{
9994
name: "multiple stacks present",
100-
stacks: []stacks.Parameters{
95+
localStacks: []stacks.Parameters{
10196
{
10297
Name: "teststack1",
10398
Provider: client.ProviderAWS,
@@ -111,13 +106,57 @@ func TestStackListCmd(t *testing.T) {
111106
Mode: modes.ModeBalanced,
112107
},
113108
},
109+
cmdArgs: []string{"list"},
114110
expectOutput: "NAME DEFAULT PROVIDER REGION ACCOUNT MODE DEPLOYEDAT\n" +
115111
"teststack1 aws us-test-2 AFFORDABLE \n" +
116112
"teststack2 gcp us-central1 BALANCED \n",
117113
},
114+
{
115+
name: "down stack hidden by default",
116+
remoteStacks: []*defangv1.Stack{
117+
{Name: "downstack", Status: defangv1.StackStatus_STACK_STATUS_DOWN, StackFile: downStackFile},
118+
},
119+
cmdArgs: []string{"list"},
120+
expectOutput: " * All stacks in the current directory are down.\n",
121+
},
122+
{
123+
name: "down stack shown with --all",
124+
remoteStacks: []*defangv1.Stack{
125+
{Name: "downstack", Status: defangv1.StackStatus_STACK_STATUS_DOWN, StackFile: downStackFile},
126+
},
127+
cmdArgs: []string{"list", "--all"},
128+
containsAll: []string{"downstack"},
129+
},
130+
{
131+
name: "mixed stacks, down hidden without --all",
132+
remoteStacks: []*defangv1.Stack{
133+
{Name: "upstack", Status: defangv1.StackStatus_STACK_STATUS_UP, StackFile: upStackFile},
134+
{Name: "downstack", Status: defangv1.StackStatus_STACK_STATUS_DOWN, StackFile: downStackFile},
135+
},
136+
cmdArgs: []string{"list"},
137+
containsAll: []string{"upstack"},
138+
containsNone: []string{"downstack"},
139+
},
140+
{
141+
name: "mixed stacks, all shown with --all",
142+
remoteStacks: []*defangv1.Stack{
143+
{Name: "upstack", Status: defangv1.StackStatus_STACK_STATUS_UP, StackFile: upStackFile},
144+
{Name: "downstack", Status: defangv1.StackStatus_STACK_STATUS_DOWN, StackFile: downStackFile},
145+
},
146+
cmdArgs: []string{"list", "--all"},
147+
containsAll: []string{"upstack", "downstack"},
148+
},
118149
}
119150
for _, tt := range tests {
120151
t.Run(tt.name, func(t *testing.T) {
152+
// Recreate RootCmd and stackListCmd per subtest so flag state is fresh
153+
RootCmd = &cobra.Command{Use: "defang"}
154+
RootCmd.PersistentFlags().StringVarP(&global.Stack.Name, "stack", "s", global.Stack.Name, "stack name")
155+
RootCmd.PersistentFlags().VarP(&global.Stack.Provider, "provider", "P", "provider")
156+
RootCmd.PersistentFlags().StringP("project-name", "p", "", "project name")
157+
RootCmd.PersistentFlags().StringArrayP("file", "f", []string{}, "compose file path(s)")
158+
RootCmd.AddCommand(makeStackListCmd())
159+
121160
// Setup stacks
122161
t.Chdir(t.TempDir())
123162
// create a compose file so stackListCmd doesn't error out
@@ -128,18 +167,27 @@ func TestStackListCmd(t *testing.T) {
128167
image: nginx`),
129168
os.FileMode(0644),
130169
)
131-
for _, stack := range tt.stacks {
170+
for _, stack := range tt.localStacks {
132171
stacks.CreateInDirectory(".", stack)
133172
}
173+
mockCtrl.stacksToList = tt.remoteStacks
134174

135175
buffer := new(bytes.Buffer)
136176
mockStdin := bytes.NewReader([]byte{})
137177
MockTerm(t, buffer, mockStdin)
138178

139-
RootCmd.SetArgs([]string{"list"})
179+
RootCmd.SetArgs(tt.cmdArgs)
140180
err := RootCmd.Execute()
141181
assert.NoError(t, err)
142-
assert.Equal(t, tt.expectOutput, buffer.String())
182+
if tt.expectOutput != "" {
183+
assert.Equal(t, tt.expectOutput, buffer.String())
184+
}
185+
for _, s := range tt.containsAll {
186+
assert.Contains(t, buffer.String(), s)
187+
}
188+
for _, s := range tt.containsNone {
189+
assert.NotContains(t, buffer.String(), s)
190+
}
143191
})
144192
}
145193
}

0 commit comments

Comments
 (0)