Skip to content
Merged
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
13 changes: 13 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Local state that must not reach the build: secrets, dependencies the image
# installs itself, and build output it rebuilds.
.git
.claude
.mcp.json
**/.env
backend/_data
backend/public
backend/bin
backend/coverage.out
frontend/node_modules
frontend/dist
frontend/coverage
94 changes: 94 additions & 0 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: Backend

on:
push:
branches:
- main
paths:
- 'backend/**'
- 'scripts/coverage.sh'
- '.github/workflows/backend.yml'
pull_request:
paths:
- 'backend/**'
- 'scripts/coverage.sh'
- '.github/workflows/backend.yml'
workflow_dispatch:

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
# The total may not drop below this. Raise it as coverage grows; new lines
# are held to 100% on pull requests regardless.
COVER_MIN: '95'

jobs:
test:
name: Test and build
runs-on: ubuntu-latest
permissions:
contents: read

# The Postgres driver's tests are skipped without a database; CI runs them.
services:
postgres:
image: postgres:18
env:
POSTGRES_PASSWORD: secret
POSTGRES_DB: shop
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10

steps:
- name: Checkout
uses: actions/checkout@v4
with:
# The base branch's history, to find the lines a pull request adds.
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
with:
# Tracks the toolchain the module declares rather than a second copy
# of the version that would quietly drift from it.
go-version-file: backend/go.mod
cache-dependency-path: backend/go.sum

- name: Seed the test database
# The driver's tests count the rows this fixture inserts.
run: psql "$SQLMCP_TEST_PG_DSN" -v ON_ERROR_STOP=1 -q -f internal/service/dbdriver/testdata/shop.sql
env:
SQLMCP_TEST_PG_DSN: postgres://postgres:secret@localhost:5432/shop?sslmode=disable
working-directory: backend

- name: Vet
run: go vet ./...
working-directory: backend

- name: Build
# As the Dockerfile builds it: Postgres is parsed by WASM, not cgo.
run: CGO_ENABLED=0 go build ./...
working-directory: backend

- name: Test with coverage
# -coverpkg credits a handler with the lines the app's HTTP tests run
# through it. testutil is test support and cmd/server only wires main.
env:
SQLMCP_TEST_PG_DSN: postgres://postgres:secret@localhost:5432/shop?sslmode=disable
run: |
pkgs=$(go list ./... | grep -v -e /testutil -e /cmd/ | paste -sd, -)
go test -race -coverpkg="$pkgs" -coverprofile=coverage.out ./...
working-directory: backend

- name: Enforce coverage
run: |
base=
if [ "${{ github.event_name }}" = pull_request ]; then
base=origin/${{ github.base_ref }}
fi
./scripts/coverage.sh backend/coverage.out "$COVER_MIN" $base
echo "Backend coverage: $(cd backend && go tool cover -func=coverage.out | tail -1 | awk '{ print $NF }')" >> "$GITHUB_STEP_SUMMARY"
26 changes: 26 additions & 0 deletions .github/workflows/case.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Case collisions

# Deliberately not filtered by path: any added file can collide with another.
on:
push:
branches:
- main
pull_request:
workflow_dispatch:

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
check:
name: No two paths differ only by case
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Check paths
run: ./scripts/check-case.sh
51 changes: 51 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build and Push Docker Image

on:
push:
branches:
- main

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/sql-mcp
tags: |
type=raw,value=latest
type=sha,prefix=,format=short

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
51 changes: 51 additions & 0 deletions .github/workflows/docker-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Release Docker Image on Tag

on:
push:
tags:
- 'v*'

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/sql-mcp
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
40 changes: 40 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Docker

# Builds the image on pull requests without pushing it, so a change that
# breaks the Dockerfile fails here rather than on main.
on:
pull_request:
paths:
- 'Dockerfile'
- '.dockerignore'
- 'backend/**'
- 'frontend/**'
- '.github/workflows/docker.yml'
workflow_dispatch:

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
build:
name: Build the image
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build
# One platform: the Dockerfile is the same for both, and QEMU would
# make every pull request several minutes slower.
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: false
cache-from: type=gha
49 changes: 49 additions & 0 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Frontend

on:
push:
branches:
- main
paths:
- 'frontend/**'
- '.github/workflows/frontend.yml'
pull_request:
paths:
- 'frontend/**'
- '.github/workflows/frontend.yml'
workflow_dispatch:

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

defaults:
run:
working-directory: frontend

jobs:
test:
name: Test and build
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '26'
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci

- name: Test with coverage
# The thresholds live in vitest.config.js and fail the run.
run: npm run test:coverage

- name: Build
run: npm run build
Loading
Loading