Skip to content

Fix: Incorrect property access causing indexing failures #267

Fix: Incorrect property access causing indexing failures

Fix: Incorrect property access causing indexing failures #267

Workflow file for this run

# SPDX-FileCopyrightText: 2025 Knitli Inc.
# SPDX-FileContributor: Adam Poulemanos <[email protected]>
#
# SPDX-License-Identifier: MIT OR Apache-2.0
name: Docker Build and Publish
on:
push:
branches:
- main
- staging
tags:
- v*.*.*
paths:
- src/**
- Dockerfile
- docker-compose.yml
- .dockerignore
- pyproject.toml
- .github/workflows/docker.yml
- uv.lock
pull_request:
branches:
- main
- staging
paths:
- src/**
- Dockerfile
- docker-compose.yml
- .dockerignore
- pyproject.toml
- .github/workflows/docker.yml
- uv.lock
workflow_dispatch:
inputs:
update_description_only:
description: Only update Docker Hub description (no build)
required: false
type: boolean
default: false
env:
REGISTRY: docker.io
IMAGE_NAME: knitli/codeweaver
permissions:
contents: read
jobs:
# Update Docker Hub description only (manual trigger)
update-description:
name: Update Docker Hub Description
runs-on: ubuntu-latest
if: github.event.inputs.update_description_only == 'true'
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@b3498302c5c423fa896b97a26bb183df735d08f8
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ env.IMAGE_NAME }}
readme-filepath: ./DOCKER.md
short-description: The missing abstraction layer between AI and your code - deep, structural understanding for better AI results
- name: Confirmation
run: echo "✅ Docker Hub description updated successfully!"
# Build and test Docker image
build:
name: Build Docker Image
runs-on: ubuntu-latest
if: github.event.inputs.update_description_only != 'true'
permissions:
contents: read
packages: write
# Continue even if tests fail (SSL issues in CI are known)
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@b3498302c5c423fa896b97a26bb183df735d08f8
with:
fetch-depth: 0 # Full history for versioning
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db
with:
install: true
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# Branch-based tags
type=ref,event=branch
# PR tags
type=ref,event=pr
# Semantic versioning tags from git tags
# Note: PEP 440 versions (e.g., 0.1.0a1) may not parse correctly with semver
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# Raw version extraction for PEP 440 pre-release versions (e.g., v0.1.0a1)
type=match,pattern=v(.*),group=1
# Latest tag for main branch (only for stable releases, not pre-releases)
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
# SHA for traceability (only on branch/tag builds, not PRs)
type=sha,prefix=sha-
- name: Build Docker image
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
with:
context: .
file: ./Dockerfile
push: false
load: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.ref_name }}
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}
- name: Test Docker image
run: |
echo "Testing Docker image build..."
# Get the first tag from the metadata output
IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1)
echo "Testing image: $IMAGE_TAG"
# Test that image was built
docker images "$IMAGE_TAG"
# Test that image can start (basic smoke test)
# Note: This will fail without proper config, but we're just checking it starts
docker run --rm --entrypoint /bin/sh "$IMAGE_TAG" -c "codeweaver --version" || true
- name: Save Docker image for testing
if: github.event_name == 'pull_request'
run: |
IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1)
docker save "$IMAGE_TAG" -o /tmp/codeweaver-image.tar
- name: Upload Docker image artifact
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: docker-image
path: /tmp/codeweaver-image.tar
retention-days: 7
# Integration test with docker-compose
test-compose:
name: Test Docker Compose
runs-on: ubuntu-latest
needs: build
if: github.event.inputs.update_description_only != 'true'
permissions:
contents: read
# Note: This job rebuilds the image independently with 'docker compose build'
# The 'needs: build' dependency is for logical ordering, not artifact reuse
# Mark as non-blocking since build may fail in CI due to SSL issues
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@b3498302c5c423fa896b97a26bb183df735d08f8
with:
fetch-depth: 0
- name: Verify .git directory exists
run: |
if [ ! -d ".git" ]; then
echo "Error: .git directory not found!"
exit 1
fi
# .github/workflows/docker.yml
- name: Create test environment file
run: |
cat > .env << EOF
PROJECT_PATH=.
CODEWEAVER_PORT=9328
QDRANT_PORT=6333
QDRANT_GRPC_PORT=6334
CODEWEAVER_PROFILE=quickstart # ← Add this
COLLECTION_NAME=codeweaver-test
ENABLE_TELEMETRY=false
LOG_LEVEL=INFO
EOF
- name: Build and start services
run: |
docker compose build
docker compose up -d
# .github/workflows/docker.yml
- name: Wait for services to be healthy
env:
# Health check endpoints - /healthz for Qdrant (v1.5.0+), /health/ for CodeWeaver
QDRANT_HEALTH_URL: http://localhost:6333/healthz
CODEWEAVER_HEALTH_URL: http://localhost:9328/health/
run: |
echo "Waiting for Qdrant to be ready..."
# Use /healthz endpoint (Qdrant v1.5.0+), /health returns 404
max_attempts=30
attempt=0
until curl -sf "$QDRANT_HEALTH_URL" >/dev/null 2>&1; do
attempt=$((attempt + 1))
if [ $attempt -ge $max_attempts ]; then
echo "Qdrant failed to become healthy after $max_attempts attempts"
docker compose logs qdrant
exit 1
fi
echo "Waiting for Qdrant... (attempt $attempt/$max_attempts)"
sleep 2
done
echo "Qdrant is healthy!"
echo "Waiting for CodeWeaver to be ready..."
# Increase timeout to 5 minutes for initial model downloads
timeout 300 bash -c 'until curl -sf http://localhost:9328/health/ 2>/dev/null; do echo "Waiting for CodeWeaver (may download models on first run)..."; sleep 10; done'
- name: Test Qdrant accessibility
env:
QDRANT_HEALTH_URL: http://localhost:6333/healthz
run: |
echo "Testing Qdrant health endpoint..."
curl -sf "$QDRANT_HEALTH_URL" || (echo "Qdrant health check failed" && docker compose logs qdrant && exit 1)
echo "Qdrant health check passed!"
- name: Test CodeWeaver accessibility
env:
CODEWEAVER_HEALTH_URL: http://localhost:9328/health/
run: |
echo "Testing CodeWeaver health endpoint..."
curl -f http://localhost:9328/health/ || (docker compose logs codeweaver && exit 1)
curl -f http://localhost:9328/health/ || (docker compose logs codeweaver && exit 1)
- name: Check logs for errors
if: always()
run: |
echo "=== Qdrant Logs ==="
docker compose logs qdrant
echo "=== CodeWeaver Logs ==="
docker compose logs codeweaver
- name: Stop services
if: always()
run: docker compose down -v
# Publish to Docker Hub (only on main branch or tags)
publish:
name: Publish to Docker Hub
runs-on: ubuntu-latest
needs:
- build
- test-compose
# Only publish if build succeeded; test-compose can fail due to SSL issues
if: |
github.event.inputs.update_description_only != 'true' &&
github.event_name != 'pull_request' &&
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) &&
needs.build.result == 'success'
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@b3498302c5c423fa896b97a26bb183df735d08f8
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db
- name: Log in to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
# Semantic versioning tags from git tags
# Note: PEP 440 versions (e.g., 0.1.0a1) may not parse correctly with semver
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# Raw version extraction for PEP 440 pre-release versions (e.g., v0.1.0a1)
type=match,pattern=v(.*),group=1
# Latest tag for main branch (only for stable releases, not pre-releases)
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
# SHA for traceability
type=sha,prefix=sha-
- name: Build and push Docker image
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ github.ref_name }}
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ env.IMAGE_NAME }}
readme-filepath: ./DOCKER.md
short-description: The missing abstraction layer between AI and your code - deep, structural understanding for better AI results
- name: Generate image summary
run: |
{
echo "## Docker Image Published"
echo ""
echo "**Repository:** ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
echo "**Tags:**"
echo '```'
echo "${{ steps.meta.outputs.tags }}"
echo '```'
echo ""
echo "**Pull command:**"
echo '```bash'
echo "docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"