Adopt shared CI workflow for aiservice (#2609)

## Summary

- Add `aiservice-ci.yml` using the shared reusable workflow from
`codeflash-ai/github-workflows`
- Remove old `django-unit-tests.yaml` and `mypy_aiservice.yml` (both
replaced by the new unified workflow)
- **Typecheck job**: uses the shared workflow
(`codeflash-ai/github-workflows/.github/workflows/uv-mypy.yml`)
- **Test job**: defined locally in `aiservice-ci.yml` (needs repository
secrets that can't be passed to reusable workflows in other repos)

## What changed

| Before | After |
|---|---|
| `django-unit-tests.yaml` (standalone) | `aiservice-ci.yml` — test job
|
| `mypy_aiservice.yml` (standalone) | `aiservice-ci.yml` — typecheck job
(shared workflow) |
This commit is contained in:
Kevin Turcios 2026-04-15 02:32:22 -05:00 committed by GitHub
parent 4c9cdff1b0
commit 0cbd8e0b6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 52 additions and 311 deletions

52
.github/workflows/aiservice-ci.yml vendored Normal file
View file

@ -0,0 +1,52 @@
name: AI Service CI
on:
push:
branches: [main]
paths:
- "django/aiservice/**"
- ".github/workflows/aiservice-ci.yml"
pull_request:
paths:
- "django/aiservice/**"
- ".github/workflows/aiservice-ci.yml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Typecheck via shared workflow (mypy doesn't need secrets).
typecheck:
uses: codeflash-ai/github-workflows/.github/workflows/ci-python-uv.yml@main
with:
working-directory: "django/aiservice"
sync-command: "uv sync"
typecheck-command: "uv run mypy --non-interactive --config-file pyproject.toml @mypy_allowlist.txt"
# Test locally (pytest needs secrets as env vars).
test:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: django/aiservice
env:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
OPENAI_API_VERSION: ${{ secrets.OPENAI_API_VERSION }}
ANTHROPIC_FOUNDRY_API_KEY: ${{ secrets.ANTHROPIC_FOUNDRY_API_KEY }}
ANTHROPIC_FOUNDRY_BASE_URL: ${{ secrets.ANTHROPIC_FOUNDRY_BASE_URL }}
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v8.0.0
with:
python-version: "3.12"
enable-cache: true
- run: uv sync
- name: Test
run: uv run pytest

View file

@ -1,98 +0,0 @@
name: django-unit-tests
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
defaults:
run:
working-directory: django/aiservice
permissions:
contents: read
pull-requests: read
checks: read
jobs:
# This job checks if the workflow should run based on file changes
check-changes:
runs-on: ubuntu-latest
outputs:
should-run: ${{ steps.filter.outputs.aiservice == 'true' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
aiservice:
- 'django/aiservice/**'
- '.github/workflows/django-unit-tests.yaml'
# This job always runs and succeeds, allowing PRs to be merged when paths don't match
no-aiservice-changes:
name: No aiservice changes detected
needs: check-changes
if: needs.check-changes.outputs.should-run != 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: .
steps:
- name: Skip tests
run: echo "Skipping django unit tests - no changes in django/aiservice/"
unit-tests:
needs: [check-changes]
if: needs.check-changes.outputs.should-run == 'true'
runs-on: ubuntu-latest
env:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
OPENAI_API_VERSION: ${{ secrets.OPENAI_API_VERSION }}
ANTHROPIC_FOUNDRY_API_KEY: ${{ secrets.ANTHROPIC_FOUNDRY_API_KEY }}
ANTHROPIC_FOUNDRY_BASE_URL: ${{ secrets.ANTHROPIC_FOUNDRY_BASE_URL }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
- name: Install project dependencies
working-directory: ./django/aiservice
run: uv sync
- name: Django Unit tests
working-directory: ./django/aiservice
run: uv run pytest
django-unit-tests-status:
runs-on: ubuntu-latest
needs: [check-changes, no-aiservice-changes, unit-tests]
if: always()
defaults:
run:
working-directory: .
steps:
- name: Check all job statuses
run: |
if [[ "${{ needs.unit-tests.result }}" == "success" ]] || \
[[ "${{ needs.no-aiservice-changes.result }}" == "success" ]]; then
echo "✓ Django unit tests workflow completed successfully"
exit 0
else
echo "✗ Django unit tests workflow failed"
exit 1
fi

View file

@ -1,119 +0,0 @@
name: Duplicate Code Detector
on:
workflow_dispatch:
pull_request:
types: [opened, synchronize]
jobs:
detect-duplicates:
if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref || github.ref }}
- name: Start Serena MCP server
run: |
docker pull ghcr.io/github/serena-mcp-server:latest
docker run -d --name serena \
--network host \
-v "${{ github.workspace }}:${{ github.workspace }}:rw" \
ghcr.io/github/serena-mcp-server:latest \
serena start-mcp-server --context codex --project "${{ github.workspace }}"
mkdir -p /tmp/mcp-config
cat > /tmp/mcp-config/mcp-servers.json << 'EOF'
{
"mcpServers": {
"serena": {
"command": "docker",
"args": ["exec", "-i", "serena", "serena", "start-mcp-server", "--context", "codex", "--project", "${{ github.workspace }}"]
}
}
}
EOF
- name: Configure AWS Credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: us-east-1
- name: Run Claude Code
uses: anthropics/claude-code-action@v1.0.89
with:
use_bedrock: "true"
use_sticky_comment: true
allowed_bots: "claude[bot],codeflash-ai[bot]"
claude_args: '--model us.anthropic.claude-sonnet-4-6 --mcp-config /tmp/mcp-config/mcp-servers.json --allowedTools "Read,Glob,Grep,Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(wc *),Bash(find *),mcp__serena__*"'
prompt: |
You are a duplicate code detector with access to Serena semantic code analysis.
## Setup
First activate the project in Serena:
- Use `mcp__serena__activate_project` with the workspace path `${{ github.workspace }}`
## Steps
1. Get the list of changed source files (excluding tests):
`git diff --name-only origin/main...HEAD -- '*.py' '*.ts' '*.tsx' '*.js' '*.jsx' | grep -v -E '(test_|_test\.|\.test\.|\.spec\.|/tests/|/test/|/__tests__/)'`
2. Use Serena's semantic analysis on changed files:
- `mcp__serena__get_symbols_overview` to understand file structure
- `mcp__serena__find_symbol` to search for similarly named symbols across the codebase
- `mcp__serena__find_referencing_symbols` to understand usage patterns
- `mcp__serena__search_for_pattern` to find similar code patterns
3. For each changed file, look for:
- **Exact Duplication**: Identical code blocks (>10 lines) in multiple locations
- **Structural Duplication**: Same logic with minor variations (different variable names)
- **Functional Duplication**: Different implementations of the same functionality
- **Copy-Paste Programming**: Similar blocks that could be extracted into shared utilities
4. Cross-reference against the rest of the codebase using Serena:
- Search for similar function signatures and logic patterns
- Check if new code duplicates existing utilities or helpers
- Look for repeated patterns across modules
- Check across service boundaries (django/aiservice, js/cf-api, js/cf-webapp, js/common)
## What to Report
- Identical or nearly identical functions in different files
- Repeated code blocks that could be extracted to utilities
- Similar classes or modules with overlapping functionality
- Copy-pasted code with minor modifications
- Duplicated business logic across components or services
## What to Skip
- Standard boilerplate (imports, __init__, exports, etc.)
- Test setup/teardown code
- Configuration with similar structure
- Language-specific patterns (constructors, getters/setters)
- Small snippets (<5 lines) unless highly repetitive
- Workflow files under .github/
- Prisma schema and migration files
- node_modules, .venv, build artifacts
## Output
Post a single PR comment with your findings. For each pattern found:
- Severity (High/Medium/Low)
- File locations with line numbers
- Code samples showing the duplication
- Concrete refactoring suggestion
If no significant duplication is found, say so briefly. Do not create issues — just comment on the PR.
- name: Stop Serena
if: always()
run: docker stop serena && docker rm serena || true

View file

@ -1,94 +0,0 @@
name: Mypy Type Checking for Aiservice
on:
push:
branches:
- main
pull_request:
defaults:
run:
working-directory: django/aiservice
permissions:
contents: read
pull-requests: read
jobs:
check-changes:
runs-on: ubuntu-latest
outputs:
should-run: ${{ steps.filter.outputs.aiservice == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'push' }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
aiservice:
- 'django/aiservice/**'
- '.github/workflows/mypy_aiservice.yml'
skip-type-check:
needs: check-changes
if: needs.check-changes.outputs.should-run != 'true'
runs-on: ubuntu-latest
defaults:
run:
working-directory: .
steps:
- name: Skip type check
run: echo "Skipping mypy - no changes in django/aiservice/"
type-check-aiservice:
needs: check-changes
if: needs.check-changes.outputs.should-run == 'true'
runs-on: ubuntu-latest
env:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }}
OPENAI_API_VERSION: ${{ secrets.OPENAI_API_VERSION }}
ANTHROPIC_FOUNDRY_API_KEY: ${{ secrets.ANTHROPIC_FOUNDRY_API_KEY }}
ANTHROPIC_FOUNDRY_BASE_URL: ${{ secrets.ANTHROPIC_FOUNDRY_BASE_URL }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
- name: ensure pip is available for mypy
run: uv venv --seed
- name: Install project dependencies
run: uv sync
- name: Run mypy on allowlist
run: uv run mypy --non-interactive --config-file pyproject.toml @mypy_allowlist.txt
mypy-aiservice-status:
runs-on: ubuntu-latest
needs: [check-changes, skip-type-check, type-check-aiservice]
if: always()
defaults:
run:
working-directory: .
steps:
- name: Check all job statuses
run: |
if [[ "${{ needs.type-check-aiservice.result }}" == "success" ]] || \
[[ "${{ needs.skip-type-check.result }}" == "success" ]]; then
echo "✓ Mypy type check workflow completed successfully"
exit 0
else
echo "✗ Mypy type check workflow failed"
exit 1
fi