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