Skip to content

Commit 38bb217

Browse files
authored
Merge pull request #205 from microsoft/stuartpa/attach-db
Round out the sqlcmd install scenario
2 parents e3e6e71 + a90efc2 commit 38bb217

File tree

109 files changed

+2620
-785
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+2620
-785
lines changed

cmd/modern/main.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ func main() {
4141
ErrorHandler: checkErr,
4242
HintHandler: displayHints})}
4343
rootCmd = cmdparser.New[*Root](dependencies)
44-
4544
if isFirstArgModernCliSubCommand() {
4645
cmdparser.Initialize(initializeCallback)
4746
rootCmd.Execute()
@@ -75,11 +74,6 @@ func initializeCallback() {
7574
OutputType: rootCmd.outputType,
7675
LoggingLevel: verbosity.Level(rootCmd.loggingLevel),
7776
})
78-
rootCmd.SetCrossCuttingConcerns(
79-
dependency.Options{
80-
EndOfLine: sqlcmd.SqlcmdEol,
81-
Output: outputter,
82-
})
8377
internal.Initialize(
8478
internal.InitializeOptions{
8579
ErrorHandler: checkErr,
@@ -95,7 +89,7 @@ func initializeCallback() {
9589
// nil. Pass (inject) checkErr into all dependencies (internal helpers etc.) as an
9690
// errorHandler.
9791
//
98-
// To aid debugging issues, if the logging level is > 2 (e.g. -v 3 or -v 4), we
92+
// To aid debugging issues, if the logging level is > 2 (e.g. --verbosity 3 or --verbosity 4), we
9993
// panic which outputs a stacktrace.
10094
func checkErr(err error) {
10195
if rootCmd.loggingLevel > 2 {
@@ -115,5 +109,6 @@ func displayHints(hints []string) {
115109
for i, hint := range hints {
116110
outputter.Infof(" %d. %v", i+1, hint)
117111
}
112+
outputter.Infof("")
118113
}
119114
}

cmd/modern/main_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@ func TestInitializeCallback(t *testing.T) {
2727

2828
func TestDisplayHints(t *testing.T) {
2929
buf := test.NewMemoryBuffer()
30-
defer buf.Close()
30+
defer checkErr(buf.Close())
3131
outputter = output.New(output.Options{StandardWriter: buf})
3232
displayHints([]string{"This is a hint"})
3333
assert.Equal(t, pal.LineBreak()+
3434
"HINT:"+
3535
pal.LineBreak()+
36-
" 1. This is a hint"+pal.LineBreak(), buf.String())
36+
" 1. This is a hint"+pal.LineBreak()+pal.LineBreak(), buf.String())
3737
}
3838

3939
func TestCheckErr(t *testing.T) {
40-
defer func() { test.CatchExpectedError(recover(), t) }()
41-
42-
rootCmd = cmdparser.New[*Root](dependency.Options{})
43-
rootCmd.loggingLevel = 4
44-
checkErr(nil)
45-
checkErr(errors.New("test error"))
40+
assert.Panics(t, func() {
41+
rootCmd = cmdparser.New[*Root](dependency.Options{})
42+
rootCmd.loggingLevel = 4
43+
checkErr(nil)
44+
checkErr(errors.New("test error"))
45+
})
4646
}

cmd/modern/root.go

+29-32
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/microsoft/go-sqlcmd/cmd/modern/root"
88
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
99
"github.com/microsoft/go-sqlcmd/internal/config"
10+
"runtime"
1011
)
1112

1213
// Root type implements the very top-level command for sqlcmd (which contains
@@ -23,17 +24,23 @@ type Root struct {
2324
// It sets the cli name, description, and subcommands, and adds global flags.
2425
// It also provides usage examples for sqlcmd.
2526
func (c *Root) DefineCommand(...cmdparser.CommandOptions) {
26-
examples := []cmdparser.ExampleOptions{
27-
{
28-
Description: "Install, Query, Uninstall SQL Server",
29-
Steps: []string{
30-
"sqlcmd install mssql",
31-
`sqlcmd query "SELECT @@version"`,
32-
"sqlcmd uninstall"}}}
27+
// Example usage steps
28+
steps := []string{"sqlcmd create mssql --using https://aka.ms/AdventureWorksLT.bak"}
29+
30+
if runtime.GOOS == "windows" {
31+
steps = append(steps, "sqlcmd open ads")
32+
}
33+
34+
steps = append(steps, `sqlcmd query "SELECT @version"`)
35+
steps = append(steps, "sqlcmd delete")
36+
37+
examples := []cmdparser.ExampleOptions{{
38+
Description: "Install/Create, Query, Uninstall SQL Server",
39+
Steps: steps}}
3340

3441
commandOptions := cmdparser.CommandOptions{
3542
Use: "sqlcmd",
36-
Short: "sqlcmd: command-line interface for the #SQLFamily",
43+
Short: "sqlcmd: Install/Create/Query SQL Server, Azure SQL, and Tools",
3744
SubCommands: c.SubCommands(),
3845
Examples: examples,
3946
}
@@ -47,12 +54,21 @@ func (c *Root) DefineCommand(...cmdparser.CommandOptions) {
4754
func (c *Root) SubCommands() []cmdparser.Command {
4855
dependencies := c.Dependencies()
4956

50-
return []cmdparser.Command{
57+
subCommands := []cmdparser.Command{
5158
cmdparser.New[*root.Config](dependencies),
5259
cmdparser.New[*root.Install](dependencies),
5360
cmdparser.New[*root.Query](dependencies),
61+
cmdparser.New[*root.Start](dependencies),
62+
cmdparser.New[*root.Stop](dependencies),
5463
cmdparser.New[*root.Uninstall](dependencies),
5564
}
65+
66+
// BUG:(stuartpa) - Add Mac / Linux support
67+
if runtime.GOOS == "windows" {
68+
subCommands = append(subCommands, cmdparser.New[*root.Open](dependencies))
69+
}
70+
71+
return subCommands
5672
}
5773

5874
// Execute runs the application based on the command-line
@@ -70,47 +86,28 @@ func (c *Root) IsValidSubCommand(command string) bool {
7086
}
7187

7288
func (c *Root) addGlobalFlags() {
73-
c.AddFlag(cmdparser.FlagOptions{
74-
Bool: &globalOptions.TrustServerCertificate,
75-
Name: "trust-server-certificate",
76-
Shorthand: "C",
77-
Usage: "Whether to trust the certificate presented by the endpoint for encryption",
78-
})
79-
80-
c.AddFlag(cmdparser.FlagOptions{
81-
String: &globalOptions.DatabaseName,
82-
Name: "database-name",
83-
Shorthand: "d",
84-
Usage: "The initial database for the connection",
85-
})
86-
87-
c.AddFlag(cmdparser.FlagOptions{
88-
Bool: &globalOptions.UseTrustedConnection,
89-
Name: "use-trusted-connection",
90-
Shorthand: "E",
91-
Usage: "Whether to use integrated security",
92-
})
93-
9489
c.AddFlag(cmdparser.FlagOptions{
9590
String: &c.configFilename,
9691
DefaultString: config.DefaultFileName(),
9792
Name: "sqlconfig",
9893
Usage: "Configuration file",
9994
})
10095

96+
/* BUG:(stuartpa) - At the moment this is a top level flag, but it doesn't
97+
work with all sub-commands (e.g. query), so removing for now.
10198
c.AddFlag(cmdparser.FlagOptions{
10299
String: &c.outputType,
103-
DefaultString: "yaml",
100+
DefaultString: "json",
104101
Name: "output",
105102
Shorthand: "o",
106103
Usage: "output type (yaml, json or xml)",
107104
})
105+
*/
108106

109107
c.AddFlag(cmdparser.FlagOptions{
110108
Int: (*int)(&c.loggingLevel),
111109
DefaultInt: 2,
112110
Name: "verbosity",
113-
Shorthand: "v",
114111
Usage: "Log level, error=0, warn=1, info=2, debug=3, trace=4",
115112
})
116113
}

cmd/modern/root/config.go

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func (c *Config) DefineCommand(...cmdparser.CommandOptions) {
2121
Short: `Modify sqlconfig files using subcommands like "sqlcmd config use-context mssql"`,
2222
SubCommands: c.SubCommands(),
2323
}
24+
2425
c.Cmd.DefineCommand(options)
2526
}
2627

cmd/modern/root/config/add-context.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package config
55

66
import (
77
"fmt"
8+
89
"github.com/microsoft/go-sqlcmd/cmd/modern/sqlconfig"
910
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
1011
"github.com/microsoft/go-sqlcmd/internal/config"
@@ -67,7 +68,7 @@ func (c *AddContext) run() {
6768
if c.endpointName == "" || !config.EndpointExists(c.endpointName) {
6869
output.FatalfWithHintExamples([][]string{
6970
{"View existing endpoints to choose from", "sqlcmd config get-endpoints"},
70-
{"Add a new local endpoint", "sqlcmd install"},
71+
{"Add a new local endpoint", "sqlcmd create"},
7172
{"Add an already existing endpoint", "sqlcmd config add-endpoint --address localhost --port 1433"}},
7273
"Endpoint required to add context. Endpoint '%v' does not exist. Use --endpoint flag", c.endpointName)
7374
}
@@ -77,14 +78,15 @@ func (c *AddContext) run() {
7778
output.FatalfWithHintExamples([][]string{
7879
{"View list of users", "sqlcmd config get-users"},
7980
{"Add the user", fmt.Sprintf("sqlcmd config add-user --name %v", c.userName)},
80-
{"Add an endpoint", "sqlcmd install"}},
81+
{"Add an endpoint", "sqlcmd create"}},
8182
"User '%v' does not exist", c.userName)
8283
}
8384
}
8485

85-
config.AddContext(context)
86+
context.Name = config.AddContext(context)
8687
config.SetCurrentContextName(context.Name)
8788
output.InfofWithHintExamples([][]string{
89+
{"Open in Azure Data Studio", "sqlcmd open ads"},
8890
{"To start interactive query session", "sqlcmd query"},
8991
{"To run a query", "sqlcmd query \"SELECT @@version\""},
9092
}, "Current Context '%v'", context.Name)

cmd/modern/root/config/add-context_test.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package config
55

66
import (
77
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
8-
"github.com/microsoft/go-sqlcmd/internal/test"
8+
"github.com/stretchr/testify/assert"
99
"testing"
1010
)
1111

@@ -16,16 +16,16 @@ func TestAddContext(t *testing.T) {
1616
}
1717

1818
func TestNegAddContext(t *testing.T) {
19-
defer func() { test.CatchExpectedError(recover(), t) }()
20-
21-
cmdparser.TestSetup(t)
22-
cmdparser.TestCmd[*AddContext]("--endpoint does-not-exist")
19+
assert.Panics(t, func() {
20+
cmdparser.TestSetup(t)
21+
cmdparser.TestCmd[*AddContext]("--endpoint does-not-exist")
22+
})
2323
}
2424

2525
func TestNegAddContext2(t *testing.T) {
26-
defer func() { test.CatchExpectedError(recover(), t) }()
27-
28-
cmdparser.TestSetup(t)
29-
cmdparser.TestCmd[*AddEndpoint]()
30-
cmdparser.TestCmd[*AddContext]("--endpoint endpoint --user does-not-exist")
26+
assert.Panics(t, func() {
27+
cmdparser.TestSetup(t)
28+
cmdparser.TestCmd[*AddEndpoint]()
29+
cmdparser.TestCmd[*AddContext]("--endpoint endpoint --user does-not-exist")
30+
})
3131
}

cmd/modern/root/config/add-user_test.go

+19-17
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package config
55

66
import (
77
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
8-
"github.com/microsoft/go-sqlcmd/internal/test"
8+
"github.com/stretchr/testify/assert"
99
"os"
1010
"testing"
1111
)
@@ -17,33 +17,35 @@ func TestAddUser(t *testing.T) {
1717
}
1818

1919
func TestNegAddUser(t *testing.T) {
20-
defer func() { test.CatchExpectedError(recover(), t) }()
21-
22-
cmdparser.TestSetup(t)
23-
cmdparser.TestCmd[*AddUser]("--username user1 --auth-type bad-bad")
20+
assert.Panics(t, func() {
21+
cmdparser.TestSetup(t)
22+
cmdparser.TestCmd[*AddUser]("--username user1 --auth-type bad-bad")
23+
})
2424
}
2525

2626
func TestNegAddUser2(t *testing.T) {
27-
defer func() { test.CatchExpectedError(recover(), t) }()
28-
29-
cmdparser.TestSetup(t)
30-
cmdparser.TestCmd[*AddUser]("--username user1 --auth-type other --encrypt-password")
27+
assert.Panics(t, func() {
28+
cmdparser.TestSetup(t)
29+
cmdparser.TestCmd[*AddUser]("--username user1 --auth-type other --encrypt-password")
30+
})
3131
}
3232

3333
func TestNegAddUser3(t *testing.T) {
34-
defer func() { test.CatchExpectedError(recover(), t) }()
34+
assert.Panics(t, func() {
3535

36-
os.Setenv("SQLCMD_PASSWORD", "")
36+
os.Setenv("SQLCMD_PASSWORD", "")
3737

38-
cmdparser.TestSetup(t)
39-
cmdparser.TestCmd[*AddUser]("--username user1")
38+
cmdparser.TestSetup(t)
39+
cmdparser.TestCmd[*AddUser]("--username user1")
40+
})
4041
}
4142

4243
func TestNegAddUser4(t *testing.T) {
43-
defer func() { test.CatchExpectedError(recover(), t) }()
44+
assert.Panics(t, func() {
4445

45-
os.Setenv("SQLCMD_PASSWORD", "whatever")
46+
os.Setenv("SQLCMD_PASSWORD", "whatever")
4647

47-
cmdparser.TestSetup(t)
48-
cmdparser.TestCmd[*AddUser]()
48+
cmdparser.TestSetup(t)
49+
cmdparser.TestCmd[*AddUser]()
50+
})
4951
}

cmd/modern/root/config/delete-context_test.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package config
55

66
import (
77
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
8-
"github.com/microsoft/go-sqlcmd/internal/test"
8+
"github.com/stretchr/testify/assert"
99
"testing"
1010
)
1111

@@ -18,15 +18,17 @@ func TestDeleteContext(t *testing.T) {
1818
}
1919

2020
func TestNegDeleteContext(t *testing.T) {
21-
defer func() { test.CatchExpectedError(recover(), t) }()
21+
assert.Panics(t, func() {
2222

23-
cmdparser.TestSetup(t)
24-
cmdparser.TestCmd[*DeleteContext]()
23+
cmdparser.TestSetup(t)
24+
cmdparser.TestCmd[*DeleteContext]()
25+
})
2526
}
2627

2728
func TestNegDeleteContext2(t *testing.T) {
28-
defer func() { test.CatchExpectedError(recover(), t) }()
29+
assert.Panics(t, func() {
2930

30-
cmdparser.TestSetup(t)
31-
cmdparser.TestCmd[*DeleteContext]("--name does-not-exist")
31+
cmdparser.TestSetup(t)
32+
cmdparser.TestCmd[*DeleteContext]("--name does-not-exist")
33+
})
3234
}

cmd/modern/root/config/delete-endpoint_test.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package config
55

66
import (
77
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
8-
"github.com/microsoft/go-sqlcmd/internal/test"
8+
"github.com/stretchr/testify/assert"
99
"testing"
1010
)
1111

@@ -16,15 +16,17 @@ func TestDeleteEndpoint(t *testing.T) {
1616
}
1717

1818
func TestNegDeleteEndpoint(t *testing.T) {
19-
defer func() { test.CatchExpectedError(recover(), t) }()
19+
assert.Panics(t, func() {
2020

21-
cmdparser.TestSetup(t)
22-
cmdparser.TestCmd[*DeleteEndpoint]()
21+
cmdparser.TestSetup(t)
22+
cmdparser.TestCmd[*DeleteEndpoint]()
23+
})
2324
}
2425

2526
func TestNegDeleteEndpoint2(t *testing.T) {
26-
defer func() { test.CatchExpectedError(recover(), t) }()
27+
assert.Panics(t, func() {
2728

28-
cmdparser.TestSetup(t)
29-
cmdparser.TestCmd[*DeleteEndpoint]("--name does-not-exist")
29+
cmdparser.TestSetup(t)
30+
cmdparser.TestCmd[*DeleteEndpoint]("--name does-not-exist")
31+
})
3032
}

0 commit comments

Comments
 (0)