name: Index Management
on:
push:
branches: [ main ]
paths:
- '**/*.py'
- '**/*.js'
- '**/*.ts'
- '**/*.md'
- '**/*.java'
- '**/*.go'
- '**/*.rs'
- '**/*.c'
- '**/*.cpp'
- '**/*.h'
- '**/*.hpp'
- '**/*.cs'
- '**/*.swift'
- '**/*.kt'
- '**/*.dart'
- '**/*.html'
- '**/*.css'
pull_request:
branches: [ main ]
paths:
- '**/*.py'
- '**/*.js'
- '**/*.ts'
- '**/*.md'
- '**/*.java'
- '**/*.go'
- '**/*.rs'
- '**/*.c'
- '**/*.cpp'
- '**/*.h'
- '**/*.hpp'
- '**/*.cs'
- '**/*.swift'
- '**/*.kt'
- '**/*.dart'
- '**/*.html'
- '**/*.css'
workflow_dispatch:
inputs:
force_rebuild:
description: 'Force rebuild all indexes'
required: false
default: 'false'
type: boolean
env:
PYTHON_VERSION: '3.11'
jobs:
check-index-compatibility:
name: Check Index Compatibility
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
outputs:
compatible: ${{ steps.check.outputs.compatible }}
needs_rebuild: ${{ steps.check.outputs.needs_rebuild }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Check index compatibility
id: check
run: |
python -c "
from mcp_server.utils.semantic_indexer import SemanticIndexer
import os
import json
indexer = SemanticIndexer()
compatible = indexer.check_compatibility()
print(f'Index compatibility: {compatible}')
# Check if significant source changes occurred
import subprocess
result = subprocess.run(['git', 'diff', '--name-only', 'origin/main...HEAD'],
capture_output=True, text=True)
changed_files = result.stdout.strip().split('\n') if result.stdout.strip() else []
source_files = [f for f in changed_files if f.endswith(('.py', '.js', '.ts', '.md', '.java', '.go', '.rs', '.c', '.cpp', '.h', '.hpp', '.cs', '.swift', '.kt', '.dart', '.html', '.css'))]
needs_rebuild = len(source_files) > 0 or not compatible
print(f'Changed source files: {len(source_files)}')
print(f'Needs rebuild: {needs_rebuild}')
# Set outputs
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write(f'compatible={str(compatible).lower()}\n')
f.write(f'needs_rebuild={str(needs_rebuild).lower()}\n')
"
- name: Comment on PR if incompatible
if: steps.check.outputs.compatible == 'false'
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `⚠️ **Index Compatibility Warning**
The current index artifacts use a different embedding model or configuration than your changes.
**Options:**
1. The index will be automatically rebuilt after merge
2. You can manually rebuild by commenting \`/rebuild-index\` on this PR
This ensures optimal search performance with your changes.`
})
validate-and-promote-indexes:
name: Validate and Promote Indexes
runs-on: ubuntu-latest
needs:
- check-index-compatibility
# Allow job to run even if check-index-compatibility was skipped (e.g., on push events)
if: |
always() &&
!cancelled() &&
(needs.check-index-compatibility.result == 'success' || needs.check-index-compatibility.result == 'skipped') &&
(
(github.event_name == 'push' && github.ref == 'refs/heads/main') ||
(github.event_name == 'workflow_dispatch' && inputs.force_rebuild == 'true') ||
(github.event_name == 'pull_request' && needs.check-index-compatibility.outputs.needs_rebuild == 'true')
)
environment: production
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Check for uploaded artifacts
id: check_artifacts
run: |
# Look for recently uploaded index artifacts
echo "Checking for developer-uploaded index artifacts..."
# This would use the artifact management workflow
# For now, check if indexes exist in the repository
if [ -f "code_index.db" ] && [ -f ".index_metadata.json" ]; then
echo "found=true" >> $GITHUB_OUTPUT
echo "✅ Found index artifacts to validate"
else
echo "found=false" >> $GITHUB_OUTPUT
echo "❌ No index artifacts found"
fi
- name: Validate index artifacts
if: steps.check_artifacts.outputs.found == 'true'
run: |
python -c "
import os
import json
from pathlib import Path
from mcp_server.storage.sqlite_store import SQLiteStore
print('🔍 Validating index artifacts...')
# Validate SQLite index
if Path('code_index.db').exists():
try:
store = SQLiteStore('code_index.db')
with store._get_connection() as conn:
cursor = conn.execute('SELECT COUNT(*) FROM files')
file_count = cursor.fetchone()[0]
cursor = conn.execute('SELECT COUNT(*) FROM symbols')
symbol_count = cursor.fetchone()[0]
print(f'✅ SQLite index valid: {file_count} files, {symbol_count} symbols')
except Exception as e:
print(f'❌ SQLite validation failed: {e}')
exit(1)
else:
print('❌ SQLite index missing')
exit(1)
# Validate metadata
if Path('.index_metadata.json').exists():
with open('.index_metadata.json', 'r') as f:
metadata = json.load(f)
print(f'✅ Index metadata valid: {metadata.get(\"embedding_model\", \"unknown\")} model')
else:
print('⚠️ Index metadata missing')
# Validate vector index (if exists)
if Path('vector_index.qdrant').exists():
print('✅ Vector index found')
else:
print('ℹ️ Vector index not included (optional)')
print('\\n✅ All validations passed!')
"
- name: Upload indexes as artifacts
if: steps.check_artifacts.outputs.found == 'true' && github.event_name == 'push'
run: |
# Trigger artifact upload workflow
echo "📤 Uploading validated indexes as artifacts..."
# Use the artifact management script
python scripts/index-artifact-upload.py --method direct
- name: Fallback - Build minimal index
if: steps.check_artifacts.outputs.found == 'false'
run: |
echo "⚠️ No developer-provided indexes found"
echo "ℹ️ In production, indexes should be built locally and pushed"
echo "ℹ️ Use: mcp_cli.py artifact push"
# Create minimal index for compatibility
python -c "
from mcp_server.storage.sqlite_store import SQLiteStore
store = SQLiteStore('code_index.db')
print('Created minimal SQLite index')
"
# Create minimal metadata
echo '{"version": "minimal", "note": "Rebuild locally with full indexing"}' > .index_metadata.json
- name: Summary
if: always()
run: |
echo "### 📊 Index Management Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.check_artifacts.outputs.found }}" == "true" ]; then
echo "✅ Developer-provided indexes validated successfully" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Developers should build indexes locally to avoid GitHub compute usage:" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo 'python mcp_cli.py index rebuild' >> $GITHUB_STEP_SUMMARY
echo 'python mcp_cli.py artifact push' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ No developer indexes found - created minimal index" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "To provide indexes with your PR:" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo '# Build indexes locally' >> $GITHUB_STEP_SUMMARY
echo 'python mcp_cli.py index rebuild' >> $GITHUB_STEP_SUMMARY
echo '# Include in commit' >> $GITHUB_STEP_SUMMARY
echo 'git add code_index.db .index_metadata.json' >> $GITHUB_STEP_SUMMARY
echo 'git commit -m "chore: update indexes"' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
fi
validate-pr-indexes:
name: Validate PR Index Changes
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
needs: [check-index-compatibility]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Test index functionality
run: |
python -c "
import os
from mcp_server.storage.sqlite_store import SQLiteStore
if os.path.exists('code_index.db'):
store = SQLiteStore('code_index.db')
print('✓ Can load existing SQLite index')
# Test basic functionality
with store._get_connection() as conn:
cursor = conn.execute('SELECT COUNT(*) FROM symbols')
symbol_count = cursor.fetchone()[0]
print(f'✓ Found {symbol_count} symbols in index')
else:
print('ℹ No existing SQLite index found')
# Test semantic indexer compatibility
from mcp_server.utils.semantic_indexer import SemanticIndexer
indexer = SemanticIndexer()
compatible = indexer.check_compatibility()
print(f'✓ Index compatibility check: {compatible}')
"
- name: Comment validation results
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `✅ **Index Validation Complete**
Your changes have been validated against the existing index artifacts.
- SQLite index: Functional
- Vector index compatibility: Checked
- Ready for merge without reindexing delays
After merge, indexes will be automatically updated if needed.`
})