EVOKORE// WORKFLOWS / ci.yml
Agent-33workflow · 244 lines
.github/workflows/ci.yml
CI / automation
View on GitHub →# Node.js 24 migration: COMPLETE (all actions Node 24 ready)
# - actions/checkout: v6
# - actions/github-script: v8
# - actions/setup-python: v6
# - actions/upload-artifact: v7
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
merge-sequencing-guard:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- name: Enforce sequence label ordering
uses: actions/github-script@v9
with:
script: |
const labels = (context.payload.pull_request.labels || []).map((label) => label.name);
const sequenceLabels = labels.filter((name) => /^sequence:[1-3]$/.test(name));
if (sequenceLabels.length === 0) {
core.notice("No sequence label found on PR. Skipping merge sequencing guard.");
return;
}
if (sequenceLabels.length > 1) {
core.setFailed(`Expected a single sequence label, found: ${sequenceLabels.join(", ")}`);
return;
}
const currentLabel = sequenceLabels[0];
const currentSequence = Number(currentLabel.split(":")[1]);
if (currentSequence === 1) {
core.info("PR is sequence:1. No predecessor required.");
return;
}
const predecessorLabel = `sequence:${currentSequence - 1}`;
const baseBranch = context.payload.pull_request.base.ref;
const owner = context.repo.owner;
const repo = context.repo.repo;
const closedPulls = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "closed",
base: baseBranch,
per_page: 100,
});
const predecessor = closedPulls.find((pr) => {
const prLabels = (pr.labels || []).map((label) => label.name);
return pr.merged_at && prLabels.includes(predecessorLabel);
});
if (!predecessor) {
core.setFailed(
`Missing merged predecessor on base branch '${baseBranch}'. ` +
`PRs labeled '${currentLabel}' require a merged '${predecessorLabel}'.`
);
return;
}
core.info(
`Merge sequencing check passed. Found predecessor #${predecessor.number} ` +
`(${predecessorLabel}) merged into '${baseBranch}'.`
);
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: engine
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
env:
AGENT33_SKIP_FRONTEND_BUILD: "1"
run: pip install -e ".[dev]"
- name: Runtime import boundaries
run: python scripts/check_import_boundaries.py
- name: Runtime compatibility lock
run: python scripts/check_runtime_compatibility.py
- name: Ruff check
run: ruff check src/ tests/
- name: Ruff format check
run: ruff format --check src/ tests/
- name: Mypy strict type check
run: mypy src/
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: engine
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
env:
AGENT33_SKIP_FRONTEND_BUILD: "1"
run: pip install -e ".[dev]"
- name: Run tests
run: pytest --cov=agent33 --cov-report=term-missing -x -q
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: engine
steps:
- uses: actions/checkout@v6
- name: Build Docker images
run: docker compose build
pip-smoke:
runs-on: ubuntu-latest
needs: [lint]
defaults:
run:
working-directory: engine
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Build wheel (skip frontend)
env:
AGENT33_SKIP_FRONTEND_BUILD: "1"
run: |
pip install hatchling
python -m hatchling build --target wheel
- name: Install wheel and smoke test
run: |
pip install dist/*.whl
agent33 --help
python -c "import agent33; print('agent33 importable OK')"
python -c "from agent33.static import ui_path; print('static module importable OK')"
benchmark-smoke:
runs-on: ubuntu-latest
continue-on-error: true
defaults:
run:
working-directory: engine
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
env:
AGENT33_SKIP_FRONTEND_BUILD: "1"
run: pip install -e ".[dev]"
- name: Fetch baseline from benchmarks branch
working-directory: ${{ github.workspace }}
run: |
git fetch origin benchmarks:refs/remotes/origin/benchmarks || true
mkdir -p engine/test-results
if git show origin/benchmarks:baselines/ctrf-baseline-latest.json > engine/test-results/ctrf-baseline.json 2>/dev/null; then
echo "Baseline fetched from benchmarks branch"
else
echo "No baseline found on benchmarks branch — running without comparison"
rm -f engine/test-results/ctrf-baseline.json
fi
- name: Run smoke benchmarks
env:
AGENT33_SKIP_FRONTEND_BUILD: "1"
run: |
if [ -f "test-results/ctrf-baseline.json" ]; then
agent33 bench smoke \
--baseline test-results/ctrf-baseline.json \
--output test-results/ctrf-smoke-report.json
else
agent33 bench smoke \
--output test-results/ctrf-smoke-report.json
fi
- name: Summarize benchmark regressions
if: always()
env:
AGENT33_SKIP_FRONTEND_BUILD: "1"
run: |
if [ -f "test-results/ctrf-smoke-report.json" ]; then
if [ -f "test-results/ctrf-baseline.json" ]; then
agent33 bench report \
test-results/ctrf-smoke-report.json \
--baseline test-results/ctrf-baseline.json \
--github-step-summary
else
agent33 bench report \
test-results/ctrf-smoke-report.json \
--github-step-summary
fi
else
{
echo "## SkillsBench benchmark report"
echo
echo "- Smoke CTRF report was not generated."
} >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload benchmark artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: benchmark-smoke-results
path: engine/test-results/
retention-days: 30