Skip to content

Commit 9bb8187

Browse files
authored
fix: restore output for add and remove subcommands, add tests (#348)
In our upgrade to bubbletea v2, we didn't catch that we lost the output for dbc add and remove. Whereas dbc 0.2.0 prints like this, ```sh $ dbc add mysql added mysql to driver list use `dbc sync` to install the drivers in the list ``` git main prints like this (nothing): ```sh $ dbc add mysql ``` This patch restores the output and adds regression tests for both subcommands.
1 parent 47d886c commit 9bb8187

4 files changed

Lines changed: 159 additions & 4 deletions

File tree

cmd/dbc/add.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ type addModel struct {
7575
Path string
7676
Pre bool
7777
list DriversList
78+
result string
7879
}
7980

8081
func (m addModel) Init() tea.Cmd {
@@ -212,7 +213,8 @@ func (m addModel) Init() tea.Cmd {
212213
func (m addModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
213214
switch msg := msg.(type) {
214215
case string:
215-
return m, tea.Sequence(tea.Println(msg), tea.Quit)
216+
m.result = msg
217+
return m, tea.Quit
216218
default:
217219
bm, cmd := m.baseModel.Update(msg)
218220
m.baseModel = bm.(baseModel)
@@ -221,4 +223,11 @@ func (m addModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
221223
}
222224
}
223225

226+
func (m addModel) FinalOutput() string {
227+
if m.status != 0 {
228+
return ""
229+
}
230+
return m.result
231+
}
232+
224233
func (m addModel) View() tea.View { return tea.NewView("") }

cmd/dbc/add_test.go

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ func TestAddRepeatedNewWithConstraint(t *testing.T) {
142142
m, err = p.Run()
143143
require.NoError(t, err)
144144
assert.Equal(t, 0, m.(HasStatus).Status())
145-
assert.Contains(t, out.String(), "old constraint: any; new constraint: >=1.0.0")
145+
if fo, ok := m.(HasFinalOutput); ok {
146+
assert.Contains(t, fo.FinalOutput(), "old constraint: any; new constraint: >=1.0.0")
147+
}
146148

147149
data, err := os.ReadFile(filepath.Join(dir, "dbc.toml"))
148150
require.NoError(t, err)
@@ -409,3 +411,60 @@ func (suite *SubcommandTestSuite) TestAddCompleteRegistryFailure() {
409411
suite.Contains(out, "error getting driver list")
410412
suite.Contains(out, "network unreachable")
411413
}
414+
415+
func (suite *SubcommandTestSuite) TestAddOutput() {
416+
m := InitCmd{Path: filepath.Join(suite.tempdir, "dbc.toml")}.GetModel()
417+
suite.runCmd(m)
418+
419+
m = AddCmd{
420+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
421+
Driver: []string{"test-driver-1"},
422+
}.GetModelCustom(
423+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
424+
425+
out := suite.runCmd(m)
426+
suite.Contains(out, "added test-driver-1 to driver list")
427+
suite.Contains(out, "use `dbc sync` to install the drivers in the list")
428+
}
429+
430+
func (suite *SubcommandTestSuite) TestAddMultipleOutput() {
431+
m := InitCmd{Path: filepath.Join(suite.tempdir, "dbc.toml")}.GetModel()
432+
suite.runCmd(m)
433+
434+
m = AddCmd{
435+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
436+
Driver: []string{"test-driver-1", "test-driver-2"},
437+
}.GetModelCustom(
438+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
439+
440+
out := suite.runCmd(m)
441+
suite.Contains(out, "added test-driver-1 to driver list")
442+
suite.Contains(out, "added test-driver-2 to driver list")
443+
suite.Contains(out, "use `dbc sync` to install the drivers in the list")
444+
}
445+
446+
func (suite *SubcommandTestSuite) TestAddReplacingDriverOutput() {
447+
m := InitCmd{Path: filepath.Join(suite.tempdir, "dbc.toml")}.GetModel()
448+
suite.runCmd(m)
449+
450+
// Add driver without constraint
451+
m = AddCmd{
452+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
453+
Driver: []string{"test-driver-1"},
454+
}.GetModelCustom(
455+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
456+
suite.runCmd(m)
457+
458+
// Add same driver with constraint and verify replacement message
459+
m = AddCmd{
460+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
461+
Driver: []string{"test-driver-1>=1.0.0"},
462+
}.GetModelCustom(
463+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
464+
465+
out := suite.runCmd(m)
466+
suite.Contains(out, "replacing existing driver test-driver-1")
467+
suite.Contains(out, "old constraint: any; new constraint: >=1.0.0")
468+
suite.Contains(out, "added test-driver-1 to driver list")
469+
suite.Contains(out, "with constraint >=1.0.0")
470+
}

cmd/dbc/remove.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ type removeModel struct {
5454
Driver string
5555
Path string
5656

57-
list DriversList
57+
list DriversList
58+
result string
5859
}
5960

6061
func (m removeModel) Init() tea.Cmd {
@@ -107,7 +108,8 @@ func (m removeModel) Init() tea.Cmd {
107108
func (m removeModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
108109
switch msg := msg.(type) {
109110
case string:
110-
return m, tea.Sequence(tea.Println(msg), tea.Quit)
111+
m.result = msg
112+
return m, tea.Quit
111113
default:
112114
bm, cmd := m.baseModel.Update(msg)
113115
m.baseModel = bm.(baseModel)
@@ -116,4 +118,11 @@ func (m removeModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
116118
}
117119
}
118120

121+
func (m removeModel) FinalOutput() string {
122+
if m.status != 0 {
123+
return ""
124+
}
125+
return m.result
126+
}
127+
119128
func (m removeModel) View() tea.View { return tea.NewView("") }

cmd/dbc/remove_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2026 Columnar Technologies Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"path/filepath"
19+
)
20+
21+
func (suite *SubcommandTestSuite) TestRemoveOutput() {
22+
m := InitCmd{Path: filepath.Join(suite.tempdir, "dbc.toml")}.GetModel()
23+
suite.runCmd(m)
24+
25+
// Add a driver first
26+
m = AddCmd{
27+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
28+
Driver: []string{"test-driver-1"},
29+
}.GetModelCustom(
30+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
31+
suite.runCmd(m)
32+
33+
// Remove the driver and verify output
34+
m = RemoveCmd{
35+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
36+
Driver: "test-driver-1",
37+
}.GetModelCustom(
38+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
39+
40+
out := suite.runCmd(m)
41+
suite.Contains(out, "removed 'test-driver-1' from driver list")
42+
}
43+
44+
func (suite *SubcommandTestSuite) TestRemoveNonexistentDriverError() {
45+
m := InitCmd{Path: filepath.Join(suite.tempdir, "dbc.toml")}.GetModel()
46+
suite.runCmd(m)
47+
48+
// Add a driver first so the list isn't empty
49+
m = AddCmd{
50+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
51+
Driver: []string{"test-driver-1"},
52+
}.GetModelCustom(
53+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
54+
suite.runCmd(m)
55+
56+
// Try to remove a driver that doesn't exist
57+
m = RemoveCmd{
58+
Path: filepath.Join(suite.tempdir, "dbc.toml"),
59+
Driver: "nonexistent-driver",
60+
}.GetModelCustom(
61+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
62+
63+
out := suite.runCmdErr(m)
64+
suite.Contains(out, "driver 'nonexistent-driver' not found")
65+
}
66+
67+
func (suite *SubcommandTestSuite) TestRemoveFromNonexistentFile() {
68+
// Try to remove from a file that doesn't exist
69+
m := RemoveCmd{
70+
Path: filepath.Join(suite.tempdir, "nonexistent-dbc.toml"),
71+
Driver: "test-driver-1",
72+
}.GetModelCustom(
73+
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
74+
75+
out := suite.runCmdErr(m)
76+
suite.Contains(out, "doesn't exist")
77+
suite.Contains(out, "Did you run `dbc init`?")
78+
}

0 commit comments

Comments
 (0)