Fix: Incorrect property access causing indexing failures #267
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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" |