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
9e8487c
feat(open): add sqlcmd open vscode and sqlcmd open ssms commands
dlevy-msft-sql Feb 6, 2026
3ea2ba1
fix: handle JSONC in VS Code settings.json and use atomic write
dlevy-msft-sql Apr 17, 2026
6059b67
fix: prevent TestVSCode from writing to real settings.json
dlevy-msft-sql Apr 17, 2026
b8e573e
fix: suppress errcheck lint for best-effort os.Remove on cleanup paths
dlevy-msft-sql Apr 18, 2026
4dbd118
fix: RunWithOutput stdout conflict and clipboard security warning
dlevy-msft-sql Apr 20, 2026
3ff298e
i18n: localize Linux clipboard fallback error
dlevy-msft-sql May 27, 2026
67c9187
feat: remove sqlcmd open ads (Azure Data Studio retired)
dlevy-msft-sql May 27, 2026
d1cdf75
feat(open): launch SSMS via ssms:// URL handler with registry-based d…
dlevy-msft-sql May 28, 2026
0cee938
revert: launch SSMS via ssms:// URL handler
dlevy-msft-sql May 28, 2026
05adaff
feat(open): discover SSMS via vswhere and add --version flag
dlevy-msft-sql May 28, 2026
b2a8c19
feat(open): add --build flag and build-aware VS Code discovery
dlevy-msft-sql May 28, 2026
d7797bc
fix(tools): include exe name as argv[0] on Windows so first flag is n…
dlevy-msft-sql May 28, 2026
5c30915
fix(tools): launch tools detached so sqlcmd returns immediately
dlevy-msft-sql May 28, 2026
cd52563
fix(open): connect via mssql --open-url instead of opening empty window
dlevy-msft-sql May 28, 2026
ba793b0
fix(tools): redirect gui child stdio to null device so sqlcmd exits
dlevy-msft-sql May 28, 2026
4c600aa
feat(open): finalize vscode launch for mssql extension
dlevy-msft-sql May 28, 2026
f67fe35
fix(open): satisfy golangci-lint (errcheck, QF1007)
dlevy-msft-sql May 28, 2026
37a308b
fix(open): return empty string when container inspect fails
dlevy-msft-sql May 28, 2026
860c168
fix(open): use Mandatory encrypt enum and honor VSCODE_EXTENSIONS
dlevy-msft-sql May 28, 2026
948874f
refactor(open): drop ai-slop comments and tautological clipboard tests
dlevy-msft-sql May 28, 2026
8227754
fix(tools): launch macOS vscode via in-bundle binary not the .app dir…
dlevy-msft-sql May 29, 2026
db302a8
fix(open): pass ssms username argv raw without bogus shell-escape
dlevy-msft-sql May 29, 2026
f68cc0d
fix(open): back up settings.json when vscode comments would be lost
dlevy-msft-sql May 29, 2026
6b52dae
refactor(open): drop dead vscode RunWithOutput and tautological tests
dlevy-msft-sql May 29, 2026
1c6c48f
revert: keep macOS vscode searchLocations on the .app bundle
dlevy-msft-sql May 29, 2026
fc6db75
fix(open): don't claim mssql extension install succeeded when we only…
dlevy-msft-sql May 29, 2026
4ce2b06
fix(tools): detach stdio when /dev/null open fails to avoid pipe-drai…
dlevy-msft-sql May 29, 2026
faa516e
test(open): assert full settings.json path tail per OS not just Code
dlevy-msft-sql May 29, 2026
1dae245
refactor(open): drop --install-extension; vscode:// URL already prompts
dlevy-msft-sql May 29, 2026
6408d01
docs: address PR feedback on open vscode/ssms
dlevy-msft-sql May 29, 2026
92d5c8c
refactor(tools): drop unused RunWithOutput and stale --install-extens…
dlevy-msft-sql May 29, 2026
bf3720a
fix(i18n): restore translation catalog after rebase
dlevy-msft-sql May 29, 2026
229f6e4
fix(open): drop tcp: prefix and base64-encode test password
dlevy-msft-sql May 29, 2026
1b00afa
feat(open): platform-conditional vscode/ssms hints in help
dlevy-msft-sql May 29, 2026
2af58cd
test(ssms): cover partial-install case; drop trivial Name() test
dlevy-msft-sql May 29, 2026
0ecabb9
refactor(open): preserve vscode settings.json comments via hujson
dlevy-msft-sql May 29, 2026
31ea8e5
feat(open): enable 'sqlcmd open' on linux
dlevy-msft-sql May 29, 2026
f8bbf23
refactor(root): drop tautological GOOS gate on open subcommand
dlevy-msft-sql May 29, 2026
01fbc91
fix(open): resolve vscode settings path for snap, XDG, and missing HOME
dlevy-msft-sql May 29, 2026
9ea4273
fix(open): scope persisted credentials and clipboard copy to the inst…
dlevy-msft-sql May 30, 2026
f9eb449
fix: address copilot review on PR #688
dlevy-msft-sql May 30, 2026
745769d
chore: remove accidentally committed scratch files
dlevy-msft-sql May 30, 2026
3dab1f9
fix(container): return empty string when ContainerName called with em…
dlevy-msft-sql May 30, 2026
a8c0b0a
fix(open): use platform-appropriate home-dir hint
dlevy-msft-sql May 30, 2026
79ba062
fix: address copilot review on basic auth guard and ssms help text
dlevy-msft-sql May 30, 2026
d66954e
fix: localize home directory error and ssms_unix fatal message
dlevy-msft-sql May 30, 2026
9520827
fix: address copilot review on argv normalization, home dir nil err, …
dlevy-msft-sql May 30, 2026
ea35c7a
refactor: hoist ssms struct and DefineCommand to untagged file
dlevy-msft-sql May 30, 2026
4848426
fix: verify vscode install before writing settings; harden code shim …
dlevy-msft-sql May 30, 2026
6f7b2c2
refactor: rename Ssms type to SSMS for acronym consistency
dlevy-msft-sql May 30, 2026
b876d8d
fix: detect early-exit failures in tool.Run and show SSMS install help
dlevy-msft-sql May 30, 2026
425acbb
fix: guard copyPasswordToClipboard against nil output
dlevy-msft-sql May 30, 2026
7787b35
test: gate COMSPEC-based tool tests to Windows
dlevy-msft-sql May 30, 2026
afae351
docs: update tool.Run stdio comment to match Wait goroutine
dlevy-msft-sql May 30, 2026
7740e75
fix: restrict isLocalEndpoint to container-backed endpoints
dlevy-msft-sql May 30, 2026
cf60098
fix: drop redundant port field from vscode mssql profile
dlevy-msft-sql May 30, 2026
81c200c
fix: resolve clip.exe via SystemRoot to avoid PATH hijack
dlevy-msft-sql May 30, 2026
e82dfad
fix: clean up vscode connection profile when sqlcmd delete runs
dlevy-msft-sql Jun 1, 2026
ff278ac
fix: harden Windows path fallbacks for clip.exe and VS Code probing
dlevy-msft-sql Jun 1, 2026
9467346
fix(open): fail fast on 'open vscode' and 'open ssms' with no current…
dlevy-msft-sql Jun 1, 2026
dcecce0
fix(open): guard linux/darwin VS Code probes against empty HOME
dlevy-msft-sql Jun 1, 2026
83ceefb
refactor: drop restate-the-code comments from open/clipboard files
dlevy-msft-sql Jun 1, 2026
337881f
feat: stage password to clipboard for VS Code remote SQL auth
dlevy-msft-sql Jun 1, 2026
2538c8f
test: reset shared config between open tests to make them order-indep…
dlevy-msft-sql Jun 1, 2026
8fb81b9
fix: harden vscode settings dir perms, pin pbcopy path, isolate more …
dlevy-msft-sql Jun 1, 2026
610feff
fix: pin linux clipboard helper to LookPath result to prevent PATH races
dlevy-msft-sql Jun 1, 2026
7d10cd2
fix: suggest install options when linux clipboard helper is missing
dlevy-msft-sql Jun 1, 2026
5e73234
fix: list per-WM install commands in linux clipboard error
dlevy-msft-sql Jun 1, 2026
af1fcf2
fix(open vscode): launch via in-bundle code CLI on macOS
dlevy-msft-sql Jun 2, 2026
a73f0a8
fix(config add-endpoint): don't apply locale thousands separator to port
dlevy-msft-sql Jun 2, 2026
74504d7
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