Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
46 changes: 46 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# go-sqlcmd Development Container
FROM mcr.microsoft.com/devcontainers/go:1.24-bookworm

# Install additional OS packages
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get install -y curl libkrb5-dev gnupg2 \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*

# Install Microsoft ODBC driver and mssql-tools18 (legacy ODBC sqlcmd/bcp for compatibility testing)
RUN curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg \
&& curl -fsSL https://packages.microsoft.com/config/debian/12/prod.list | tee /etc/apt/sources.list.d/mssql-release.list \
&& apt-get update \
&& ACCEPT_EULA=Y apt-get install -y msodbcsql18 mssql-tools18 unixodbc-dev \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
ENV PATH="/opt/mssql-tools18/bin:${PATH}"

# Install golangci-lint for code quality
# Download pre-built binary with SHA256 checksum verification (supply chain security)
# Supports both amd64 and arm64 architectures
ARG GOLANGCI_LINT_VERSION=1.64.8
ARG GOLANGCI_LINT_SHA256_AMD64=b6270687afb143d019f387c791cd2a6f1cb383be9b3124d241ca11bd3ce2e54e
ARG GOLANGCI_LINT_SHA256_ARM64=a6ab58ebcb1c48572622146cdaec2956f56871038a54ed1149f1386e287789a5
RUN ARCH=$(dpkg --print-architecture) \
&& if [ "$ARCH" = "amd64" ]; then \
CHECKSUM="${GOLANGCI_LINT_SHA256_AMD64}"; \
elif [ "$ARCH" = "arm64" ]; then \
CHECKSUM="${GOLANGCI_LINT_SHA256_ARM64}"; \
else \
echo "Unsupported architecture: $ARCH" && exit 1; \
fi \
&& curl -fsSLO "https://github.com/golangci/golangci-lint/releases/download/v${GOLANGCI_LINT_VERSION}/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${ARCH}.tar.gz" \
&& echo "${CHECKSUM} golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${ARCH}.tar.gz" | sha256sum -c - \
&& tar -xzf "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${ARCH}.tar.gz" \
&& mv "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${ARCH}/golangci-lint" /usr/local/bin/ \
&& rm -rf "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${ARCH}" "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${ARCH}.tar.gz" \
&& golangci-lint --version

# Install additional Go tools (pinned versions for reproducibility)
RUN go install golang.org/x/tools/gopls@v0.18.1 \
&& go install github.com/go-delve/delve/cmd/dlv@v1.24.1 \
&& go install honnef.co/go/tools/cmd/staticcheck@v0.6.1 \
&& go install golang.org/x/text/cmd/gotext@v0.22.0

# Create bin directory for local sqlcmd builds
RUN mkdir -p /home/vscode/bin && chown vscode:vscode /home/vscode/bin
ENV PATH="/home/vscode/bin:${PATH}"
51 changes: 51 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# go-sqlcmd Development Container

Dev Container / Codespaces environment with Go 1.24 and SQL Server 2025.

## Quick Start

**VS Code**: Open repo → click "Reopen in Container" when prompted.

**Codespaces**: Click "Code" → "Codespaces" → "Create codespace".

First build takes ~5 minutes.

## Commands

| Alias | What it does |
|-------|--------------|
| `gtest` | Run tests |
| `ginstall` | Build and install sqlcmd to ~/bin |
| `glint` | Run golangci-lint |
| `sql` | Connect to SQL Server (go-sqlcmd) |
| `sql-legacy` | Connect with legacy ODBC sqlcmd |
| `test-db` | Test database connection |

## SQL Server Connection

- **Server**: `localhost,1433`
- **User**: `sa`
- **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.

## Two sqlcmd Versions

- **go-sqlcmd**: `~/bin/sqlcmd` (default in PATH, use `sql` alias)
- **Legacy ODBC**: `/opt/mssql-tools18/bin/sqlcmd` (use `sql-legacy` alias)

## Customization

**Change SQL version**: Edit `docker-compose.yml` image tag.

**Add setup scripts**: Edit `.devcontainer/mssql/setup.sql`.

**Change password**: Update `docker-compose.yml` and `devcontainer.json`.

## Troubleshooting

- **ARM64 (Apple Silicon)**: Use GitHub Codespaces instead - SQL Server has no native ARM64 images
- **SQL Server not starting**: Check `docker logs $(docker ps -qf "name=db")`. Needs 2GB+ RAM
- **Connection refused**: Wait ~30s for SQL Server to start
- **sqlcmd not found**: Run `ginstall`
91 changes: 91 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"name": "go-sqlcmd Development",
"dockerComposeFile": "docker-compose.yml",
"service": "devcontainer",
"workspaceFolder": "/workspaces/go-sqlcmd",
"shutdownAction": "stopCompose",

// Configure tool-specific properties
"customizations": {
"vscode": {
"extensions": [
"golang.go",
"ms-mssql.mssql",
"ms-azuretools.vscode-docker",
"GitHub.copilot",
"GitHub.copilot-chat",
"eamodio.gitlens",
"EditorConfig.EditorConfig",
"streetsidesoftware.code-spell-checker"
],
"settings": {
"go.toolsManagement.autoUpdate": false,
"go.useLanguageServer": true,
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast"],
"go.testEnvVars": {
"SQLCMDSERVER": "localhost",
"SQLCMDUSER": "sa",
"SQLCMDPASSWORD": "${env:SQLCMDPASSWORD}",
"SQLCMDDATABASE": "master"
},
"mssql.connections": [
{
"server": "localhost,1433",
"database": "master",
"authenticationType": "SqlLogin",
"user": "sa",
"password": "",
"savePassword": false,
"profileName": "sqlcmd-container (use SQLCMDPASSWORD env var)",
"encrypt": "Optional",
"trustServerCertificate": true
}
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "golang.go",
"[go]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"terminal.integrated.defaultProfile.linux": "bash"
}
}
},

// Forward the SQL Server port
"forwardPorts": [1433],
"portsAttributes": {
"1433": {
"label": "SQL Server",
"onAutoForward": "silent"
}
},

// Use 'postCreateCommand' to run commands after the container is created
"postCreateCommand": "bash .devcontainer/post-create.sh",

// Environment variables for tests - password must match docker-compose.yml
// This is a development-only container credential, not a production secret.
// For GitHub Codespaces, you can override SQLCMDPASSWORD via Codespaces Secrets.
"remoteEnv": {
"SQLCMDSERVER": "localhost",
"SQLCMDUSER": "sa",
"SQLCMDPASSWORD": "${localEnv:SQLCMDPASSWORD:SqlCmd@2025!}",
"SQLCMDDATABASE": "master",
"SQLCMDDBNAME": "master"
},

// Features to add to the dev container
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"moby": true
},
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "latest"
}
}
}
37 changes: 37 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
version: '3.8'

services:
devcontainer:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspaces/go-sqlcmd:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: service:db
depends_on:
db:
condition: service_healthy

db:
image: mcr.microsoft.com/mssql/server:2025-latest
restart: unless-stopped
environment:
ACCEPT_EULA: "Y"
# Password can be overridden via SQLCMDPASSWORD environment variable
SA_PASSWORD: "${SQLCMDPASSWORD:-SqlCmd@2025!}"
MSSQL_SA_PASSWORD: "${SQLCMDPASSWORD:-SqlCmd@2025!}"
MSSQL_PID: "Developer"
volumes:
- mssql-data:/var/opt/mssql
healthcheck:
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P \"$$MSSQL_SA_PASSWORD\" -C -Q \"SELECT 1\" || exit 1"]
interval: 10s
timeout: 5s
retries: 15
start_period: 45s

volumes:
mssql-data:
69 changes: 69 additions & 0 deletions .devcontainer/mssql/setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
-- go-sqlcmd Development Database Setup
-- This script runs automatically when the devcontainer starts

USE master;
GO

-- Create a test database for development
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'SqlCmdTest')
BEGIN
CREATE DATABASE SqlCmdTest;
PRINT 'Created database: SqlCmdTest';
END
GO

-- Enable contained database authentication for testing
-- Use TRY/CATCH in case this fails on certain SQL Server configurations
BEGIN TRY
EXEC sp_configure 'contained database authentication', 1;
RECONFIGURE;
END TRY
BEGIN CATCH
PRINT 'Note: Could not enable contained database authentication (may already be enabled or not supported)';
END CATCH;
GO

-- Make SqlCmdTest a contained database for testing
BEGIN TRY
ALTER DATABASE SqlCmdTest SET CONTAINMENT = PARTIAL;
END TRY
BEGIN CATCH
PRINT 'Note: Could not set database containment (may not be supported)';
END CATCH;
GO

USE SqlCmdTest;
GO

-- Create a sample table for quick testing
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'TestTable')
BEGIN
CREATE TABLE TestTable (
ID INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Value NVARCHAR(MAX),
CreatedAt DATETIME2 DEFAULT GETUTCDATE()
);

INSERT INTO TestTable (Name, Value) VALUES
('Test1', 'Sample value 1'),
('Test2', 'Sample value 2'),
('Test3', 'Sample value 3');

PRINT 'Created table: TestTable with sample data';
END
GO

-- Create a view for testing
IF NOT EXISTS (SELECT * FROM sys.views WHERE name = 'TestView')
BEGIN
EXEC('CREATE VIEW TestView AS SELECT ID, Name, CreatedAt FROM TestTable');
PRINT 'Created view: TestView';
END
GO

PRINT 'go-sqlcmd development database setup complete!';
PRINT 'Test database: SqlCmdTest';
PRINT 'Sample table: TestTable (3 rows)';
PRINT 'Sample view: TestView';
GO
Loading
Loading