diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2975329 --- /dev/null +++ b/.dockerignore @@ -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 \ No newline at end of file diff --git a/.github/workflows/create-prod-image.yaml b/.github/workflows/create-prod-image.yaml new file mode 100644 index 0000000..8c56c90 --- /dev/null +++ b/.github/workflows/create-prod-image.yaml @@ -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 diff --git a/.github/workflows/create-staging-image.yaml b/.github/workflows/create-staging-image.yaml new file mode 100644 index 0000000..7f9be0e --- /dev/null +++ b/.github/workflows/create-staging-image.yaml @@ -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 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8112059 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +# Multi-stage build for database schema spec generator +# Stage 1: Build the schemas +FROM alpine:3.22.1 AS builder + +# Install Python, uv, and git (needed for some dependencies) +RUN apk add --no-cache python3 py3-pip git + +# Install uv package manager +RUN pip3 install --break-system-packages uv + +# 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.1 + +# 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"]