Skip to content
This repository was archived by the owner on Aug 12, 2026. It is now read-only.
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
77 changes: 77 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Version control
.git
.gitignore
.gitattributes

# Python artifacts
__pycache__
*.pyc
*.pyo
*.pyd
.Python
.venv
.venv/
.python-version
pip-log.txt
pip-delete-this-directory.txt

# Development and testing
tests/
.pytest_cache/
.coverage
.coverage.*
coverage.xml
htmlcov/
.tox/
.nox/
.cache
.mypy_cache/
.ruff_cache/
.pyright/
.pre-commit-config.yaml
.env.example

# IDE and editor files
.vscode/
.idea/
*.swp
*.swo
*~

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Documentation (optional, remove if needed in image)
README.md
docs/README.md

# CI/CD
.github/

# Build artifacts
build/
dist/
*.egg-info/

# Logs
*.log
logs/

# Temporary files
.tmp/
temp/
*.tmp

# Node modules (if any)
node_modules/

# Docker
Dockerfile*
docker-compose*.yml
.dockerignore
117 changes: 117 additions & 0 deletions .github/workflows/create-prod-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: "Production CI/CD - Create Release Image"

on:
push:
tags:
# Run on every tag matching this pattern (e.g. v1.4.0)
- v[0-9]*.[0-9]*.[0-9]*
- "!v[0-9]*.[0-9]*.[0-9]*-rc.[0-9]*"

permissions:
contents: read

jobs:
quality_checks:
uses: ./.github/workflows/ci.yaml

prepare_metadata:
runs-on: ubuntu-latest
needs: quality_checks
outputs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

steps:
- name: Checkout code
uses: actions/checkout@v5.0.0
with:
ref: ${{ github.ref }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5.8.0
with:
images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
tags: |
type=ref,event=tag,enable=true

flavor: |
latest=true

labels: |
org.opencontainers.image.title=${{ github.event.repository.name }}
org.opencontainers.image.description=${{ github.event.repository.description }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.source=${{ github.event.repository.clone_url }}
org.opencontainers.image.version=${{ github.ref_name }}
org.opencontainers.image.revision=${{ github.sha }}

build_image:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read

environment: production
needs: [quality_checks, prepare_metadata]
outputs:
image-url: ghcr.io/${{ github.repository_owner}}/${{ github.repository }}:${{ github.ref_name }}
image-id: ${{ steps.build.outputs.imageid }}
digest: ${{ steps.build.outputs.digest }}

steps:
- name: Checkout code
uses: actions/checkout@v5.0.0
with:
ref: ${{ github.ref }}

- name: Generate env file
run: |
echo "BASE_URL=${{ vars.BASE_URL }}" >> .env

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
with:
platforms: linux/amd64

- name: Restore Docker cache
uses: actions/cache@v4.2.4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

- name: Login to GHCR
uses: docker/login-action@v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
id: build
uses: docker/build-push-action@v6.18.0
with:
context: .
push: true
tags: ${{ needs.prepare_metadata.outputs.tags }}
labels: ${{ needs.prepare_metadata.outputs.labels }}
platforms: linux/amd64
provenance: false
sbom: false
cache-from: |
type=gha
type=local,src=/tmp/.buildx-cache

cache-to: |
type=gha,mode=max
type=local,dest=/tmp/.buildx-cache-updated,mode=max

build-args: |
BUILDKIT_INLINE_CACHE=1

- name: Update cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-updated /tmp/.buildx-cache
117 changes: 117 additions & 0 deletions .github/workflows/create-staging-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: "Staging CI/CD - Create Release Candidate Image"

on:
push:
tags:
# Run on every tag matching this pattern (e.g. v1.4.0-rc.1)
- "v[0-9]*.[0-9]*.[0-9]*-rc.[0-9]*"

permissions:
contents: read

jobs:
quality_checks:
uses: ./.github/workflows/ci.yaml

prepare_metadata:
runs-on: ubuntu-latest
needs: quality_checks
outputs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

steps:
- name: Checkout code
uses: actions/checkout@v5.0.0
with:
ref: ${{ github.ref }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5.8.0
with:
images: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}
tags: |
type=ref,event=tag,enable=true
type=raw,value=staging-latest

flavor: |
latest=false

labels: |
org.opencontainers.image.title=${{ github.event.repository.name }}
org.opencontainers.image.description=${{ github.event.repository.description }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.source=${{ github.event.repository.clone_url }}
org.opencontainers.image.version=${{ github.ref_name }}
org.opencontainers.image.revision=${{ github.sha }}

build_image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

environment: staging
needs: [quality_checks, prepare_metadata]
outputs:
image-url: ghcr.io/${{ github.repository_owner}}/${{ github.repository }}:${{ github.ref_name }}
image-id: ${{ steps.build.outputs.imageid }}
digest: ${{ steps.build.outputs.digest }}

steps:
- name: Checkout code
uses: actions/checkout@v5.0.0
with:
ref: ${{ github.ref }}

- name: Generate env file
run: |
echo "BASE_URL=${{ vars.BASE_URL }}" >> .env

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.11.1
with:
platforms: linux/amd64

- name: Restore Docker cache
uses: actions/cache@v4.2.4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

- name: Login to GHCR
uses: docker/login-action@v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
id: build
uses: docker/build-push-action@v6.18.0
with:
context: .
push: true
tags: ${{ needs.prepare_metadata.outputs.tags }}
labels: ${{ needs.prepare_metadata.outputs.labels }}
platforms: linux/amd64
provenance: false
sbom: false
cache-from: |
type=gha
type=local,src=/tmp/.buildx-cache

cache-to: |
type=gha,mode=max
type=local,dest=/tmp/.buildx-cache-updated,mode=max

build-args: |
BUILDKIT_INLINE_CACHE=1

- name: Update cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-updated /tmp/.buildx-cache
33 changes: 33 additions & 0 deletions Dockerfile
Comment thread
RepoRover marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Multi-stage build for database schema spec generator
# Stage 1: Build the schemas
FROM ghcr.io/astral-sh/uv:0.8.13-alpine3.22 AS builder

# Set working directory
WORKDIR /app

# Copy dependency files first for better caching
COPY pyproject.toml uv.lock ./

# Install dependencies
RUN uv sync --frozen --no-install-project --no-dev

# Copy source code and input files
COPY main.py ./
COPY database_schema_spec/ ./database_schema_spec/
COPY docs/ ./docs/
COPY .env ./

# Generate the schemas
RUN uv run python main.py

# Stage 2: Final lightweight image with only the output
FROM alpine:3.22 AS final

# Create output directory
RUN mkdir -p /output

# Copy generated schemas from builder stage
COPY --from=builder /app/output/ /output/

# Optional: Set a default command to list contents (for debugging)
CMD ["ls", "-la", "/output"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,5 @@ output/
├── vmap.json
└── postgresql/
└── 15.0/
└── unified_schema.json
└── spec.json
```
28 changes: 28 additions & 0 deletions database_schema_spec/cli/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,34 @@ def generate_variant(self, variant: DatabaseVariantSpec) -> Path:
base_schema, variant
)

# Inject dynamic $id derived from BASE_URL for the final output
id_field = config.json_schema_fields.id_field
schema_field = config.json_schema_fields.schema_field
spec_url = self.output_manager._get_spec_url(
variant.engine, variant.version, config.base_url
)
# Set/override $id
unified_schema[id_field] = spec_url

# Reorder top-level keys to ensure `$id` appears immediately after `$schema` when present
if isinstance(unified_schema, dict):
reordered: dict[str, object] = {}
# If $schema exists, place it first
if schema_field in unified_schema:
reordered[schema_field] = unified_schema[schema_field]
reordered[id_field] = unified_schema[id_field]
for k, v in unified_schema.items():
if k not in (schema_field, id_field):
reordered[k] = v
unified_schema = reordered # type: ignore[assignment]
else:
# If no $schema, put $id first then the rest in original order
reordered[id_field] = unified_schema[id_field]
for k, v in unified_schema.items():
if k != id_field:
reordered[k] = v
unified_schema = reordered # type: ignore[assignment]

# Validate the resulting schema
validation_result = self.validator.validate_schema(unified_schema)
if not validation_result.is_valid:
Expand Down
Loading