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}"
276 changes: 276 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
# go-sqlcmd Development Container

This folder contains the configuration for a VS Code Dev Container / GitHub Codespaces development environment for go-sqlcmd.

## What's Included

- **Go 1.24** development environment with all necessary tools
- **SQL Server 2025** (Developer Edition) running in a sidecar container
- **Pre-configured VS Code extensions**:
- Go (official extension)
- MS SQL (for database management)
- Docker
- GitHub Copilot
- GitLens
- **Go quality tools**: golangci-lint, gopls, delve debugger, staticcheck
- **Locally built sqlcmd** added to PATH automatically

## Quick Start

### Using VS Code (Recommended)

1. Install the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
2. Open this repository in VS Code
3. When prompted, click **"Reopen in Container"**, or:
- Press `F1` and select **"Dev Containers: Reopen in Container"**
4. Wait for the container to build (first time takes ~5 minutes)
5. Start developing!

### Using GitHub Codespaces

1. Click the green **"Code"** button on the repository
2. Select **"Codespaces"** tab
3. Click **"Create codespace on main"** (or your preferred branch)
4. Wait for the environment to start

## Running Tests

Environment variables are pre-configured for running tests:

```bash
# Run all tests
go test ./...

# Run short tests
go test -short ./...

# Run tests with verbose output
go test -v ./...
```

### Helpful Aliases

After the container starts, these aliases are available:

| Alias | Command |
|-------|---------|
| `gtest` | Run all tests |
| `gtest-short` | Run short tests |
| `gtest-v` | Run tests with verbose output |
| `gbuild` | Build sqlcmd locally |
| `ginstall` | Build and install sqlcmd to ~/bin |
| `gfmt` | Format code |
| `gvet` | Run go vet |
| `glint` | Run golangci-lint |
| `ggen` | Run go generate (for translations) |
| `test-db` | Test database connection |
| `sql` | Connect to SQL Server (go-sqlcmd) |
| `sql-legacy` | Connect using legacy ODBC sqlcmd |
| `rebuild` | Rebuild sqlcmd |

## SQL Server Connection

The SQL Server instance is accessible at:

- **Server**: `localhost,1433`
- **Username**: `sa`
- **Password**: Available via `$SQLCMDPASSWORD` environment variable
- **Database**: `master` (default) or `SqlCmdTest` (created for testing)

> **Note**: The SQL Server password for this devcontainer is provided via the `$SQLCMDPASSWORD` environment variable and is a non-production, development-only default.
> For the default devcontainer setup, the password value (`SqlCmd@2025!`) is checked into this repository for convenience; override it via environment variables or Codespaces/CI secrets for non-local use.
> When using VS Code's MSSQL extension, copy the value from `$SQLCMDPASSWORD` when prompted.

### Using the Built-in sqlcmd

The container has **two versions** of sqlcmd available:

1. **go-sqlcmd** (this project) - the modern Go-based sqlcmd, built from source at `~/bin/sqlcmd`
2. **Legacy ODBC sqlcmd** - the classic version from mssql-tools18 at `/opt/mssql-tools18/bin/sqlcmd`

Since go-sqlcmd is first in PATH, the `sqlcmd` command runs the modern version. Use the aliases or full paths to choose which version:

```bash
# go-sqlcmd (this project) - default in PATH
sql # alias for go-sqlcmd with connection args
sqlcmd -S localhost -U sa -P "$SQLCMDPASSWORD" -C

# Legacy ODBC sqlcmd (for compatibility testing)
sql-legacy # alias for legacy sqlcmd with connection args
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SQLCMDPASSWORD" -C

# Run a query with go-sqlcmd
sql -Q "SELECT @@VERSION"

# Compare behavior between versions
sql -Q "SELECT 1 AS test"
sql-legacy -Q "SELECT 1 AS test"
```

### VS Code SQL Extension

The MSSQL extension is pre-configured with a connection profile named **"sqlcmd-container (use SQLCMDPASSWORD env var)"**. Click the SQL Server icon in the Activity Bar to connect.

### Connecting from Host Machine Tools

The SQL Server port (1433) is forwarded to your host machine, so you can connect using tools installed locally:

#### Azure Data Studio

1. Open Azure Data Studio on your host machine
2. Create a new connection:
- Server: `localhost,1433`
- Authentication: SQL Login
- User: `sa`
- Password: `SqlCmd@2025!`
- Trust server certificate: Yes

#### SQL Server Management Studio (Windows)

1. Open SSMS on your Windows host
2. Connect to Server:
- Server name: `localhost,1433`
- Authentication: SQL Server Authentication
- Login: `sa`
- Password: `SqlCmd@2025!`
- Check "Trust server certificate"

## Environment Variables

The following environment variables are set automatically:

| Variable | Value |
|----------|-------|
| `SQLCMDSERVER` | `localhost` |
| `SQLCMDUSER` | `sa` |
| `SQLCMDPASSWORD` | `SqlCmd@2025!` |
| `SQLCMDDATABASE` | `master` |
| `SQLCMDDBNAME` | `master` |

These use the same environment variable names as the CI pipeline to ensure local tests behave similarly, although the actual password and SQL Server version in CI may differ.

## Working with sqlcmd

### Build and Test Workflow

```bash
# Build sqlcmd from source
ginstall

# Test the build
~/bin/sqlcmd --version

# Run a query against the local SQL Server
sql -Q "SELECT name FROM sys.databases"

# Run the test suite
gtest
```

### Rebuilding After Changes

```bash
# Quick rebuild
rebuild

# Or full rebuild with install
ginstall
```

## Customization

### Adding SQL Setup Scripts

The `setup.sql` script in `.devcontainer/mssql/` is executed automatically when the container starts. To run additional SQL scripts, either add them to `setup.sql` or update `post-create.sh` to execute them explicitly.

### Modifying the SA Password

To change the SQL Server password:

1. Update both `SA_PASSWORD` and `MSSQL_SA_PASSWORD` in `docker-compose.yml` (these must match)
2. Update `SQLCMDPASSWORD` in `devcontainer.json` (both `remoteEnv` and `go.testEnvVars` sections)
3. Update the password in the `mssql.connections` settings in `devcontainer.json`

### Using a Different SQL Server Version

Edit `docker-compose.yml` and change the image tag:

```yaml
db:
image: mcr.microsoft.com/mssql/server:2022-latest # or 2019-latest
```

> **Note:** SQL Server 2025 is the default as it includes the latest features.

## Troubleshooting

### ARM64 (Apple Silicon) Users

SQL Server container images may have issues on ARM64 architecture. If you encounter problems:

1. Edit `docker-compose.yml` to use SQL Server 2022:
```yaml
db:
image: mcr.microsoft.com/mssql/server:2022-latest
```
2. Ensure Rosetta is enabled in Docker Desktop: **Settings > General > "Use Rosetta for x86_64/amd64 emulation on Apple Silicon"**

### SQL Server not starting

Check the Docker logs:
```bash
docker logs $(docker ps -qf "name=db")
```

Common issues:
- Insufficient memory (SQL Server requires at least 2GB RAM)
- Port 1433 already in use
- ARM64 architecture issues (see above)

### Connection refused

Wait a few seconds after the container starts. SQL Server takes ~30 seconds to become ready. The health check should handle this automatically.

### Tests failing with connection errors

Ensure the environment variables are set:
```bash
echo $SQLCMDSERVER
echo $SQLCMDPASSWORD
```

If empty, try restarting the terminal or running:
```bash
source ~/.bashrc
```

### sqlcmd not found

Run the install command:
```bash
ginstall
```

Or manually:
```bash
go build -o ~/bin/sqlcmd ./cmd/modern
```

## Files Reference

| File | Purpose |
|------|---------|
| `devcontainer.json` | Main configuration file |
| `docker-compose.yml` | Container orchestration (Go + SQL Server) |
| `Dockerfile` | Go development container image |
| `post-create.sh` | Setup script (runs after container creation) |
| `mssql/setup.sql` | Initial database setup script |

## Contributing

When modifying the devcontainer:

1. Test locally with `Dev Containers: Rebuild Container`
2. Ensure all tests pass: `go test ./...`
3. Verify SQL connection works: `test-db`
4. Verify sqlcmd builds: `ginstall && ~/bin/sqlcmd --version`
Loading
Loading