4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
469 lines
15 KiB
YAML
469 lines
15 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- "surfaces/**"
|
|
- "config/**"
|
|
- "core/**"
|
|
- "platform/deployment/**"
|
|
- "integrations/**"
|
|
- "platform/**"
|
|
- "tools/**"
|
|
- "tests/**"
|
|
- "pyproject.toml"
|
|
- "uv.lock"
|
|
- "pytest.ini"
|
|
- "ruff.toml"
|
|
- "mypy.ini"
|
|
- "Makefile"
|
|
- ".importlinter"
|
|
- ".importlinter.strict"
|
|
- ".github/ci/**"
|
|
- ".github/workflows/ci.yml"
|
|
|
|
pull_request:
|
|
branches: [main]
|
|
paths:
|
|
- "surfaces/**"
|
|
- "config/**"
|
|
- "core/**"
|
|
- "platform/deployment/**"
|
|
- "integrations/**"
|
|
- "platform/**"
|
|
- "tools/**"
|
|
- "tests/**"
|
|
- "pyproject.toml"
|
|
- "uv.lock"
|
|
- "pytest.ini"
|
|
- "ruff.toml"
|
|
- "mypy.ini"
|
|
- "Makefile"
|
|
- ".importlinter"
|
|
- ".importlinter.strict"
|
|
- ".github/ci/**"
|
|
- ".github/workflows/ci.yml"
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
PYTHON_SOURCE_PATHS: "config core integrations platform surfaces tools"
|
|
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
quality:
|
|
name: quality (${{ matrix.os }})
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest]
|
|
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 15
|
|
continue-on-error: ${{ matrix.os == 'windows-latest' }}
|
|
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v8.1.0
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: |
|
|
pyproject.toml
|
|
uv.lock
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install dependencies
|
|
run: uv sync --frozen --extra dev
|
|
|
|
- name: Lint
|
|
run: uv run python -m ruff check $PYTHON_SOURCE_PATHS tests/
|
|
|
|
- name: Format check
|
|
run: uv run python -m ruff format --check $PYTHON_SOURCE_PATHS tests/
|
|
|
|
- name: Typecheck
|
|
run: uv run python -m mypy $PYTHON_SOURCE_PATHS
|
|
|
|
- name: Import graph
|
|
run: uv run python .github/ci/check_imports.py --strict
|
|
|
|
# Full layered contracts (.importlinter.strict), not the minimal default
|
|
# .importlinter config used by ``make check-imports``.
|
|
- name: Import boundaries
|
|
run: uv run lint-imports --config .importlinter.strict
|
|
|
|
test:
|
|
name: test (${{ matrix.shard }})
|
|
strategy:
|
|
fail-fast: false
|
|
max-parallel: 5
|
|
matrix:
|
|
include:
|
|
- os: ubuntu-latest
|
|
shard: tools-runtime
|
|
# ``tests/core/agent`` is excluded here; it runs in cli-runtime,
|
|
# which pins openai for its live action-planning oracles.
|
|
extra_pytest_args: >-
|
|
--ignore=tests/core/agent
|
|
pytest_paths: >-
|
|
tests/tools
|
|
tests/core
|
|
tests/platform
|
|
tests/utils
|
|
tests/masking
|
|
tests/watch_dog
|
|
- os: ubuntu-latest
|
|
shard: cli-runtime
|
|
# Live shell action-agent contracts are validated on openai,
|
|
# matching interactive-shell-live.yml. The
|
|
# default anthropic tool-call model (haiku) cannot reliably perform
|
|
# compound action planning, so pin this shard to openai.
|
|
# ``tests/core/agent`` runs here because it contains the live
|
|
# action-planning oracles (``test_live_action_planning`` and
|
|
# ``test_live_turn_execution_oracle``) that need the openai pin —
|
|
# plus the static ``test_import_boundaries`` guard the surfaces
|
|
# restructure (#3299) added.
|
|
llm_provider: openai
|
|
pytest_paths: >-
|
|
tests/cli
|
|
tests/interactive_shell
|
|
tests/agent
|
|
tests/core/agent
|
|
tests/fleet_monitoring
|
|
tests/analytics
|
|
tests/tools/investigation
|
|
tests/delivery
|
|
tests/sandbox
|
|
tests/hermes
|
|
- os: ubuntu-latest
|
|
shard: integrations-and-misc
|
|
pytest_paths: >-
|
|
tests/integrations
|
|
tests/deployment
|
|
tests/benchmarks
|
|
tests/chaos_engineering
|
|
tests/shared
|
|
tests/config
|
|
tests/github_ci
|
|
tests/packaging
|
|
tests/scheduler
|
|
gateway/tests
|
|
- os: ubuntu-latest
|
|
shard: e2e-general
|
|
pytest_paths: >-
|
|
tests/e2e
|
|
extra_pytest_args: >-
|
|
--ignore=tests/e2e/kubernetes
|
|
--ignore=tests/e2e/openclaw
|
|
--ignore=tests/e2e/upstream_lambda
|
|
--ignore=tests/e2e/upstream_prefect_ecs_fargate
|
|
--ignore=tests/e2e/upstream_apache_flink_ecs
|
|
- os: ubuntu-latest
|
|
shard: e2e-provider-and-openclaw
|
|
pytest_paths: >-
|
|
tests/e2e/openclaw
|
|
tests/e2e/upstream_lambda
|
|
tests/e2e/upstream_prefect_ecs_fargate
|
|
tests/e2e/upstream_apache_flink_ecs
|
|
tests/e2e/kubernetes
|
|
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 30
|
|
|
|
env:
|
|
# Per-shard LLM provider for live_llm contracts; defaults to anthropic.
|
|
LLM_PROVIDER: ${{ matrix.llm_provider || 'anthropic' }}
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
JWT_TOKEN: ${{ secrets.JWT_TOKEN }}
|
|
GRAFANA_READ_TOKEN: ${{ secrets.GRAFANA_READ_TOKEN }}
|
|
GCLOUD_HOSTED_METRICS_ID: ${{ secrets.GCLOUD_HOSTED_METRICS_ID }}
|
|
GCLOUD_HOSTED_METRICS_URL: ${{ secrets.GCLOUD_HOSTED_METRICS_URL }}
|
|
GCLOUD_HOSTED_LOGS_ID: ${{ secrets.GCLOUD_HOSTED_LOGS_ID }}
|
|
GCLOUD_HOSTED_LOGS_URL: ${{ secrets.GCLOUD_HOSTED_LOGS_URL }}
|
|
GCLOUD_RW_API_KEY: ${{ secrets.GCLOUD_RW_API_KEY }}
|
|
GCLOUD_OTLP_ENDPOINT: ${{ secrets.GCLOUD_OTLP_ENDPOINT }}
|
|
GCLOUD_OTLP_AUTH_HEADER: ${{ secrets.GCLOUD_OTLP_AUTH_HEADER }}
|
|
PYTHONUTF8: "1"
|
|
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v8.1.0
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: |
|
|
pyproject.toml
|
|
uv.lock
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install dependencies
|
|
run: uv sync --frozen --extra dev
|
|
|
|
- name: Validate pytest marker
|
|
env:
|
|
# Fork PRs do not receive repository secrets; skip live_llm contracts
|
|
# (see interactive-shell-live.yml). Index a JSON string array so the
|
|
# value is always a marker string — never a bare boolean from
|
|
# ``a && 'x' || 'y'`` (boolean false → ``-m false`` → xdist
|
|
# ``N workers [0 items]``, which can still exit 0).
|
|
PYTEST_MARKER_EXPR: ${{ fromJSON('["not synthetic", "not (synthetic or live_llm)"]')[github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true] }}
|
|
run: |
|
|
echo "PYTEST_MARKER_EXPR=${PYTEST_MARKER_EXPR}"
|
|
case "${PYTEST_MARKER_EXPR}" in
|
|
"not synthetic"|"not (synthetic or live_llm)") ;;
|
|
*)
|
|
echo "Refusing unexpected PYTEST_MARKER_EXPR: '${PYTEST_MARKER_EXPR}'" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
- name: Run tests
|
|
env:
|
|
COVERAGE_FILE: .coverage.${{ matrix.shard }}
|
|
PYTEST_MARKER_EXPR: ${{ fromJSON('["not synthetic", "not (synthetic or live_llm)"]')[github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true] }}
|
|
# Keep ``run: >`` (folded) so ``matrix.pytest_paths`` stays one argv list.
|
|
# A ``run: |`` + ``\`` rewrite can drop/split those paths and yield
|
|
# ``N workers [0 items]`` even when the marker is correct.
|
|
run: >
|
|
uv run python -m pytest -n auto -v
|
|
${{ matrix.pytest_paths }}
|
|
--cov=config
|
|
--cov=core
|
|
--cov=platform.deployment.aws --cov=platform.deployment
|
|
--cov=integrations
|
|
--cov=platform
|
|
--cov=surfaces
|
|
--cov=tools
|
|
--cov-report=
|
|
--ignore=tests/e2e/kubernetes_local_alert_simulation
|
|
--ignore=tests/synthetic
|
|
${{ matrix.extra_pytest_args }}
|
|
-m "${PYTEST_MARKER_EXPR}"
|
|
|
|
- name: Upload shard coverage data
|
|
if: >-
|
|
always() &&
|
|
github.event_name == 'push' &&
|
|
github.ref == 'refs/heads/main'
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: coverage-data-${{ matrix.shard }}
|
|
path: .coverage.${{ matrix.shard }}*
|
|
if-no-files-found: error
|
|
include-hidden-files: true
|
|
retention-days: 7
|
|
|
|
coverage-report:
|
|
name: coverage-report
|
|
runs-on: ubuntu-latest
|
|
needs: [test]
|
|
if: >-
|
|
always() &&
|
|
github.event_name == 'push' &&
|
|
github.ref == 'refs/heads/main'
|
|
timeout-minutes: 15
|
|
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v8.1.0
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: |
|
|
pyproject.toml
|
|
uv.lock
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install dependencies
|
|
run: uv sync --frozen --extra dev
|
|
|
|
- name: Download shard coverage artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
pattern: coverage-data-*
|
|
path: ./
|
|
merge-multiple: true
|
|
|
|
- name: Combine coverage and build report
|
|
run: |
|
|
uv run python -m coverage combine .
|
|
uv run python -m coverage html
|
|
|
|
- name: Upload combined coverage
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: coverage-report-ubuntu-latest
|
|
path: |
|
|
htmlcov/
|
|
.coverage
|
|
retention-days: 7
|
|
|
|
test-kubernetes:
|
|
runs-on: ubuntu-latest
|
|
continue-on-error: true
|
|
timeout-minutes: 15
|
|
|
|
if: >-
|
|
github.repository == 'Tracer-Cloud/opensre' &&
|
|
(github.event_name == 'push' ||
|
|
(
|
|
github.event_name == 'pull_request' &&
|
|
(
|
|
contains(github.event.pull_request.title, 'k8s') ||
|
|
contains(github.event.pull_request.title, 'kubernetes')
|
|
)
|
|
))
|
|
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v8.1.0
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: |
|
|
pyproject.toml
|
|
uv.lock
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install dependencies
|
|
run: uv sync --frozen --extra dev
|
|
|
|
- name: Run Kubernetes tests
|
|
env:
|
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
AWS_DEFAULT_REGION: us-east-1
|
|
run: uv run python -m tests.e2e.kubernetes.test_local
|
|
|
|
should-run-thorough:
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'Tracer-Cloud/opensre'
|
|
outputs:
|
|
thorough: ${{ steps.filter.outputs.thorough }}
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
- uses: dorny/paths-filter@v4
|
|
id: filter
|
|
with:
|
|
filters: |
|
|
thorough:
|
|
- ".github/workflows/ci.yml"
|
|
- "pyproject.toml"
|
|
- "uv.lock"
|
|
- "platform/deployment/**"
|
|
- "integrations/**"
|
|
- "tools/investigation/**"
|
|
- "tools/**"
|
|
- "tests/e2e/cloudwatch_demo/**"
|
|
- "tests/e2e/upstream_lambda/**"
|
|
- "tests/e2e/upstream_prefect_ecs_fargate/**"
|
|
- "tests/e2e/upstream_apache_flink_ecs/**"
|
|
|
|
test-thorough:
|
|
runs-on: ubuntu-latest
|
|
needs: [test, should-run-thorough]
|
|
if: >-
|
|
github.event_name == 'push' &&
|
|
github.ref == 'refs/heads/main' &&
|
|
github.repository == 'Tracer-Cloud/opensre' &&
|
|
needs.should-run-thorough.outputs.thorough == 'true'
|
|
timeout-minutes: 30
|
|
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- name: cloudwatch-demo
|
|
command: python3 -m tests.e2e.cloudwatch_demo.test_aws
|
|
- name: upstream-lambda
|
|
command: python3 -m tests.e2e.upstream_lambda.test_agent_e2e
|
|
- name: prefect-ecs-fargate
|
|
command: python3 -m tests.e2e.upstream_prefect_ecs_fargate.test_agent_e2e
|
|
- name: flink-ecs
|
|
command: python3 -m tests.e2e.upstream_apache_flink_ecs.test_agent_e2e
|
|
|
|
name: test-thorough (${{ matrix.name }})
|
|
|
|
env:
|
|
# Thorough e2e suites make live LLM calls; run them on openai because the
|
|
# default anthropic account is credit-exhausted. Requires a valid, funded
|
|
# OPENAI_API_KEY secret.
|
|
LLM_PROVIDER: openai
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
JWT_TOKEN: ${{ secrets.JWT_TOKEN }}
|
|
TRACER_API_URL: ${{ secrets.TRACER_API_URL }}
|
|
TRACER_INGEST_TOKEN: ${{ secrets.TRACER_INGEST_TOKEN }}
|
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
AWS_REGION: us-east-1
|
|
AWS_DEFAULT_REGION: us-east-1
|
|
GRAFANA_READ_TOKEN: ${{ secrets.GRAFANA_READ_TOKEN }}
|
|
GCLOUD_HOSTED_METRICS_ID: ${{ secrets.GCLOUD_HOSTED_METRICS_ID }}
|
|
GCLOUD_HOSTED_METRICS_URL: ${{ secrets.GCLOUD_HOSTED_METRICS_URL }}
|
|
GCLOUD_HOSTED_LOGS_ID: ${{ secrets.GCLOUD_HOSTED_LOGS_ID }}
|
|
GCLOUD_HOSTED_LOGS_URL: ${{ secrets.GCLOUD_HOSTED_LOGS_URL }}
|
|
GCLOUD_RW_API_KEY: ${{ secrets.GCLOUD_RW_API_KEY }}
|
|
CLOUDWATCH_VERIFY_LOGS: ${{ matrix.name == 'cloudwatch-demo' && '0' || '1' }}
|
|
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
|
|
- name: Install uv
|
|
uses: astral-sh/setup-uv@v8.1.0
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: |
|
|
pyproject.toml
|
|
uv.lock
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install dependencies
|
|
run: uv sync --frozen --extra dev
|
|
|
|
- name: Install tracer CLI
|
|
run: |
|
|
curl -sSL https://install.tracer.cloud | sh -s user_36fbN6K6FwEgJFHsQv1pUByo8K6
|
|
|
|
- name: Initialize tracer (optional)
|
|
run: |
|
|
sudo tracer init --token ${{ secrets.JWT_TOKEN }}
|
|
continue-on-error: true
|
|
timeout-minutes: 2
|
|
|
|
- name: Run test
|
|
run: uv run ${{ matrix.command }}
|
|
timeout-minutes: 30
|