Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
94e8d63
feat(open): add sqlcmd open vscode and sqlcmd open ssms commands
dlevy-msft-sql Feb 6, 2026
3b31493
fix: handle JSONC in VS Code settings.json and use atomic write
dlevy-msft-sql Apr 17, 2026
2d66bd7
fix: prevent TestVSCode from writing to real settings.json
dlevy-msft-sql Apr 17, 2026
328f223
fix: suppress errcheck lint for best-effort os.Remove on cleanup paths
dlevy-msft-sql Apr 18, 2026
de6bd33
fix: RunWithOutput stdout conflict and clipboard security warning
dlevy-msft-sql Apr 20, 2026
6471a22
i18n: localize Linux clipboard fallback error
dlevy-msft-sql May 27, 2026
e6edcc2
feat: remove sqlcmd open ads (Azure Data Studio retired)
dlevy-msft-sql May 27, 2026
581a975
feat(open): launch SSMS via ssms:// URL handler with registry-based d…
dlevy-msft-sql May 28, 2026
b5fdd02
revert: launch SSMS via ssms:// URL handler
dlevy-msft-sql May 28, 2026
1081169
feat(open): discover SSMS via vswhere and add --version flag
dlevy-msft-sql May 28, 2026
5268f50
feat(open): add --build flag and build-aware VS Code discovery
dlevy-msft-sql May 28, 2026
2843507
fix(tools): include exe name as argv[0] on Windows so first flag is n…
dlevy-msft-sql May 28, 2026
8a576d2
fix(tools): launch tools detached so sqlcmd returns immediately
dlevy-msft-sql May 28, 2026
168b08b
fix(open): connect via mssql --open-url instead of opening empty window
dlevy-msft-sql May 28, 2026
0798901
fix(tools): redirect gui child stdio to null device so sqlcmd exits
dlevy-msft-sql May 28, 2026
12c4753
feat(open): finalize vscode launch for mssql extension
dlevy-msft-sql May 28, 2026
68cba80
fix(open): satisfy golangci-lint (errcheck, QF1007)
dlevy-msft-sql May 28, 2026
c7ea7a0
fix(open): return empty string when container inspect fails
dlevy-msft-sql May 28, 2026
419e1cf
fix(open): use Mandatory encrypt enum and honor VSCODE_EXTENSIONS
dlevy-msft-sql May 28, 2026
13d80a9
refactor(open): drop ai-slop comments and tautological clipboard tests
dlevy-msft-sql May 28, 2026
e102968
fix(tools): launch macOS vscode via in-bundle binary not the .app dir…
dlevy-msft-sql May 29, 2026
d094eee
fix(open): pass ssms username argv raw without bogus shell-escape
dlevy-msft-sql May 29, 2026
1d6044c
fix(open): back up settings.json when vscode comments would be lost
dlevy-msft-sql May 29, 2026
9720559
refactor(open): drop dead vscode RunWithOutput and tautological tests
dlevy-msft-sql May 29, 2026
eb9a63a
revert: keep macOS vscode searchLocations on the .app bundle
dlevy-msft-sql May 29, 2026
496849d
fix(open): don't claim mssql extension install succeeded when we only…
dlevy-msft-sql May 29, 2026
b790eea
fix(tools): detach stdio when /dev/null open fails to avoid pipe-drai…
dlevy-msft-sql May 29, 2026
e7925b0
test(open): assert full settings.json path tail per OS not just Code
dlevy-msft-sql May 29, 2026
db49928
refactor(open): drop --install-extension; vscode:// URL already prompts
dlevy-msft-sql May 29, 2026
960bb98
docs: address PR feedback on open vscode/ssms
dlevy-msft-sql May 29, 2026
51baca8
refactor(tools): drop unused RunWithOutput and stale --install-extens…
dlevy-msft-sql May 29, 2026
95e916e
fix(i18n): restore translation catalog after rebase
dlevy-msft-sql May 29, 2026
fcaf561
fix(open): drop tcp: prefix and base64-encode test password
dlevy-msft-sql May 29, 2026
1c87f52
feat(open): platform-conditional vscode/ssms hints in help
dlevy-msft-sql May 29, 2026
f07ddab
test(ssms): cover partial-install case; drop trivial Name() test
dlevy-msft-sql May 29, 2026
a37266e
refactor(open): preserve vscode settings.json comments via hujson
dlevy-msft-sql May 29, 2026
1675185
feat(open): enable 'sqlcmd open' on linux
dlevy-msft-sql May 29, 2026
9604050
refactor(root): drop tautological GOOS gate on open subcommand
dlevy-msft-sql May 29, 2026
2d60ac6
fix(open): resolve vscode settings path for snap, XDG, and missing HOME
dlevy-msft-sql May 29, 2026
1876351
fix(open): scope persisted credentials and clipboard copy to the inst…
dlevy-msft-sql May 30, 2026
d769749
fix: address copilot review on PR #688
dlevy-msft-sql May 30, 2026
1e8f29a
chore: remove accidentally committed scratch files
dlevy-msft-sql May 30, 2026
4a513f5
fix(container): return empty string when ContainerName called with em…
dlevy-msft-sql May 30, 2026
54fe8a7
fix(open): use platform-appropriate home-dir hint
dlevy-msft-sql May 30, 2026
e0e7bad
fix: address copilot review on basic auth guard and ssms help text
dlevy-msft-sql May 30, 2026
c2b2e37
fix: localize home directory error and ssms_unix fatal message
dlevy-msft-sql May 30, 2026
22e1955
fix: address copilot review on argv normalization, home dir nil err, …
dlevy-msft-sql May 30, 2026
7c69a69
refactor: hoist ssms struct and DefineCommand to untagged file
dlevy-msft-sql May 30, 2026
1118c5b
fix: verify vscode install before writing settings; harden code shim …
dlevy-msft-sql May 30, 2026
3a16f29
refactor: rename Ssms type to SSMS for acronym consistency
dlevy-msft-sql May 30, 2026
e414939
fix: detect early-exit failures in tool.Run and show SSMS install help
dlevy-msft-sql May 30, 2026
b8bc282
fix: guard copyPasswordToClipboard against nil output
dlevy-msft-sql May 30, 2026
94ff696
test: gate COMSPEC-based tool tests to Windows
dlevy-msft-sql May 30, 2026
16d19cf
docs: update tool.Run stdio comment to match Wait goroutine
dlevy-msft-sql May 30, 2026
8bb6015
fix: restrict isLocalEndpoint to container-backed endpoints
dlevy-msft-sql May 30, 2026
b06382f
fix: drop redundant port field from vscode mssql profile
dlevy-msft-sql May 30, 2026
dcb21bf
fix: resolve clip.exe via SystemRoot to avoid PATH hijack
dlevy-msft-sql May 30, 2026
8f5c674
fix: clean up vscode connection profile when sqlcmd delete runs
dlevy-msft-sql Jun 1, 2026
dd4434c
fix: harden Windows path fallbacks for clip.exe and VS Code probing
dlevy-msft-sql Jun 1, 2026
c3c6089
fix(open): fail fast on 'open vscode' and 'open ssms' with no current…
dlevy-msft-sql Jun 1, 2026
da7acdb
fix(open): guard linux/darwin VS Code probes against empty HOME
dlevy-msft-sql Jun 1, 2026
268315e
refactor: drop restate-the-code comments from open/clipboard files
dlevy-msft-sql Jun 1, 2026
5505434
feat: stage password to clipboard for VS Code remote SQL auth
dlevy-msft-sql Jun 1, 2026
af144b3
test: reset shared config between open tests to make them order-indep…
dlevy-msft-sql Jun 1, 2026
6e6ae83
fix: harden vscode settings dir perms, pin pbcopy path, isolate more …
dlevy-msft-sql Jun 1, 2026
05be752
fix: pin linux clipboard helper to LookPath result to prevent PATH races
dlevy-msft-sql Jun 1, 2026
3701550
fix: suggest install options when linux clipboard helper is missing
dlevy-msft-sql Jun 1, 2026
432486c
fix: list per-WM install commands in linux clipboard error
dlevy-msft-sql Jun 1, 2026
e600213
fix(open vscode): launch via in-bundle code CLI on macOS
dlevy-msft-sql Jun 2, 2026
bc405e4
fix(config add-endpoint): don't apply locale thousands separator to port
dlevy-msft-sql Jun 2, 2026
a3aae09
refactor(open): trim restate-the-code and dramatic comments
dlevy-msft-sql Jun 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ First build takes ~5 minutes.
- **Password**: `$SQLCMDPASSWORD` env var (`SqlCmd@2025!` for local dev)
- **Database**: `master` or `SqlCmdTest`

Port 1433 is forwarded — connect from host tools (ADS, SSMS) using same credentials.
Port 1433 is forwarded — connect from host tools (VS Code, SSMS) using same credentials.

## Two sqlcmd Versions

Expand Down
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,43 @@ The Homebrew package manager may be used on Linux and Windows Subsystem for Linu

Use `sqlcmd` to create SQL Server instances using a local container runtime (e.g. [Docker][] or [Podman][])

### Create SQL Server instance using local container runtime and connect using Azure Data Studio
### Create SQL Server instance using local container runtime

To create a local SQL Server instance with the AdventureWorksLT database restored, query it, and connect to it using Azure Data Studio, run:
To create a local SQL Server instance with the AdventureWorksLT database restored, run:

```
sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak
sqlcmd query "SELECT DB_NAME()"
sqlcmd open ads
```

Use `sqlcmd --help` to view all the available sub-commands. Use `sqlcmd -?` to view the original ODBC `sqlcmd` flags.

### Connect using Visual Studio Code

Use `sqlcmd open vscode` to open Visual Studio Code with a connection profile configured for the current context:

```
sqlcmd open vscode
```

This command will:
1. **Create a connection profile** in VS Code's user settings with the current context name
2. **Launch VS Code** via the `vscode://` URL handler, which opens the MSSQL extension on the new profile

If the MSSQL extension is not installed, VS Code prompts to install it the first time the URL is opened.

Once VS Code opens, use the MSSQL extension's Object Explorer to connect using the profile. When you connect to the container, VS Code will automatically detect it as a Docker container and provide additional container management features (start/stop/delete) directly from the Object Explorer.

### Connect using SQL Server Management Studio (Windows)

On Windows, use `sqlcmd open ssms` to open SQL Server Management Studio pre-configured to connect to the current context:

```
sqlcmd open ssms
```

This command launches SSMS with the server and username pre-filled. When the current context uses SQL authentication, sqlcmd also copies the password to the clipboard so you can paste it (Ctrl+V) into the SSMS login dialog. Contexts using integrated (Windows) authentication skip the clipboard step and connect without a password prompt.

### The ~/.sqlcmd/sqlconfig file

Each time `sqlcmd create` completes, a new context is created (e.g. mssql, mssql2, mssql3 etc.). A context contains the endpoint and user configuration detail. To switch between contexts, run `sqlcmd config use <context-name>`, to view name of the current context, run `sqlcmd config current-context`, to list all contexts, run `sqlcmd config get-contexts`.
Expand Down
15 changes: 7 additions & 8 deletions cmd/modern/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ type Root struct {
// It also provides usage examples for sqlcmd.
func (c *Root) DefineCommand(...cmdparser.CommandOptions) {
// Example usage steps
steps := []string{"sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak"}
steps := []string{
"sqlcmd create mssql --accept-eula --using https://aka.ms/AdventureWorksLT.bak",
"sqlcmd open vscode",
}

if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
steps = append(steps, "sqlcmd open ads")
if runtime.GOOS == "windows" {
Comment thread
dlevy-msft-sql marked this conversation as resolved.
steps = append(steps, "sqlcmd open ssms")
}

steps = append(steps, `sqlcmd query "SELECT @@version"`)
Expand Down Expand Up @@ -67,17 +70,13 @@ func (c *Root) SubCommands() []cmdparser.Command {
subCommands := []cmdparser.Command{
cmdparser.New[*root.Config](dependencies),
cmdparser.New[*root.Install](dependencies),
cmdparser.New[*root.Open](dependencies),
cmdparser.New[*root.Query](dependencies),
cmdparser.New[*root.Start](dependencies),
cmdparser.New[*root.Stop](dependencies),
cmdparser.New[*root.Uninstall](dependencies),
}

// BUG(stuartpa): - Add Linux support
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
subCommands = append(subCommands, cmdparser.New[*root.Open](dependencies))
}

return subCommands
}

Expand Down
16 changes: 11 additions & 5 deletions cmd/modern/root/config/add-context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package config

import (
"fmt"
"runtime"

"github.com/microsoft/go-sqlcmd/cmd/modern/sqlconfig"
"github.com/microsoft/go-sqlcmd/internal/cmdparser"
Expand Down Expand Up @@ -88,9 +89,14 @@ func (c *AddContext) run() {

context.Name = config.AddContext(context)
config.SetCurrentContextName(context.Name)
output.InfoWithHintExamples([][]string{
{localizer.Sprintf("Open in Azure Data Studio"), "sqlcmd open ads"},
{localizer.Sprintf("To start interactive query session"), "sqlcmd query"},
{localizer.Sprintf("To run a query"), "sqlcmd query \"SELECT @@version\""},
}, localizer.Sprintf("Current Context '%v'", context.Name))
hints := [][]string{}
if runtime.GOOS == "windows" {
hints = append(hints, []string{localizer.Sprintf("Open in SQL Server Management Studio"), "sqlcmd open ssms"})
}
hints = append(hints,
[]string{localizer.Sprintf("Open in Visual Studio Code"), "sqlcmd open vscode"},
[]string{localizer.Sprintf("To start interactive query session"), "sqlcmd query"},
[]string{localizer.Sprintf("To run a query"), "sqlcmd query \"SELECT @@version\""},
)
output.InfoWithHintExamples(hints, localizer.Sprintf("Current Context '%v'", context.Name))
}
2 changes: 1 addition & 1 deletion cmd/modern/root/config/add-endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,5 @@ func (c *AddEndpoint) run() {
{localizer.Sprintf("View all endpoints details"), "sqlcmd config get-endpoints --detailed"},
{localizer.Sprintf("Delete this endpoint"), fmt.Sprintf("sqlcmd config delete-endpoint %v", uniqueEndpointName)},
},
localizer.Sprintf("Endpoint '%v' added (address: '%v', port: '%v')", uniqueEndpointName, c.address, c.port))
localizer.Sprintf("Endpoint '%v' added (address: '%v', port: '%v')", uniqueEndpointName, c.address, fmt.Sprintf("%d", c.port)))
}
6 changes: 3 additions & 3 deletions cmd/modern/root/install/mssql-base.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,10 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {

hints := [][]string{}

// TODO: sqlcmd open ads only support on Windows right now, add Mac support
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
hints = append(hints, []string{localizer.Sprintf("Open in Azure Data Studio"), "sqlcmd open ads"})
if runtime.GOOS == "windows" {
hints = append(hints, []string{localizer.Sprintf("Open in SQL Server Management Studio"), "sqlcmd open ssms"})
}
hints = append(hints, []string{localizer.Sprintf("Open in Visual Studio Code"), "sqlcmd open vscode"})

hints = append(hints, []string{localizer.Sprintf("Run a query"), "sqlcmd query \"SELECT @@version\""})
hints = append(hints, []string{localizer.Sprintf("Start interactive session"), "sqlcmd query"})
Expand Down
7 changes: 4 additions & 3 deletions cmd/modern/root/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ type Open struct {
func (c *Open) DefineCommand(...cmdparser.CommandOptions) {
options := cmdparser.CommandOptions{
Use: "open",
Short: localizer.Sprintf("Open tools (e.g Azure Data Studio) for current context"),
Short: localizer.Sprintf("Open tools (e.g., Visual Studio Code, SSMS) for current context"),
SubCommands: c.SubCommands(),
}

c.Cmd.DefineCommand(options)
}

// SubCommands sets up the sub-commands for `sqlcmd open` such as
// `sqlcmd open ads`
// `sqlcmd open vscode` and `sqlcmd open ssms`
func (c *Open) SubCommands() []cmdparser.Command {
dependencies := c.Dependencies()

return []cmdparser.Command{
cmdparser.New[*open.Ads](dependencies),
cmdparser.New[*open.VSCode](dependencies),
cmdparser.New[*open.SSMS](dependencies),
}
Comment thread
dlevy-msft-sql marked this conversation as resolved.
Comment thread
dlevy-msft-sql marked this conversation as resolved.
}
100 changes: 0 additions & 100 deletions cmd/modern/root/open/ads.go

This file was deleted.

37 changes: 0 additions & 37 deletions cmd/modern/root/open/ads_darwin.go

This file was deleted.

24 changes: 0 additions & 24 deletions cmd/modern/root/open/ads_linux.go

This file was deleted.

Loading
Loading