mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
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:
parent
4c9cdff1b0
commit
0cbd8e0b6c
4 changed files with 52 additions and 311 deletions
52
.github/workflows/aiservice-ci.yml
vendored
Normal file
52
.github/workflows/aiservice-ci.yml
vendored
Normal 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
|
||||||
98
.github/workflows/django-unit-tests.yaml
vendored
98
.github/workflows/django-unit-tests.yaml
vendored
|
|
@ -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
|
|
||||||
119
.github/workflows/duplicate-code-detector.yml
vendored
119
.github/workflows/duplicate-code-detector.yml
vendored
|
|
@ -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
|
|
||||||
94
.github/workflows/mypy_aiservice.yml
vendored
94
.github/workflows/mypy_aiservice.yml
vendored
|
|
@ -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
|
|
||||||
Loading…
Reference in a new issue