ci: aggregate all PR testing behind a single required CI Gate workflow (#5476)
This commit is contained in:
@@ -0,0 +1,171 @@
|
|||||||
|
name: CI Gate
|
||||||
|
|
||||||
|
# Single required status check for all PRs.
|
||||||
|
#
|
||||||
|
# Path-filtered CI workflows can't be marked as required in branch
|
||||||
|
# protection: on a PR that doesn't touch their paths they never report, and
|
||||||
|
# the required check hangs at "Expected" forever. This gate solves that. It
|
||||||
|
# runs on every PR, detects which packages changed, calls only the relevant
|
||||||
|
# package CI workflows (as reusable workflows), and the final "CI Gate" job
|
||||||
|
# reports the aggregate result — success when every invoked pipeline passed
|
||||||
|
# (skipped pipelines are fine), failure when any failed.
|
||||||
|
#
|
||||||
|
# Branch protection should require exactly one status check: "CI Gate".
|
||||||
|
#
|
||||||
|
# Package CI workflows keep their own push-to-main and workflow_dispatch
|
||||||
|
# triggers; only their pull_request triggers moved here. To wire in a new
|
||||||
|
# package: add a filter under the `changes` job, a call job that `uses:` the
|
||||||
|
# package workflow, and list the call job in the gate's `needs`.
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ci-gate-${{ github.event.pull_request.number }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
changes:
|
||||||
|
name: Detect changed packages
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
python_sdk: ${{ steps.filter.outputs.python_sdk }}
|
||||||
|
ts_sdk: ${{ steps.filter.outputs.ts_sdk }}
|
||||||
|
cli_python: ${{ steps.filter.outputs.cli_python }}
|
||||||
|
cli_node: ${{ steps.filter.outputs.cli_node }}
|
||||||
|
openclaw: ${{ steps.filter.outputs.openclaw }}
|
||||||
|
opencode_plugin: ${{ steps.filter.outputs.opencode_plugin }}
|
||||||
|
pi_agent_plugin: ${{ steps.filter.outputs.pi_agent_plugin }}
|
||||||
|
docs_llms_txt: ${{ steps.filter.outputs.docs_llms_txt }}
|
||||||
|
steps:
|
||||||
|
- uses: dorny/paths-filter@v3
|
||||||
|
id: filter
|
||||||
|
with:
|
||||||
|
# Each filter mirrors the package workflow's old pull_request
|
||||||
|
# paths, plus the package workflow file itself and this gate file
|
||||||
|
# (changing either must re-exercise the pipeline).
|
||||||
|
filters: |
|
||||||
|
python_sdk:
|
||||||
|
- 'mem0/**'
|
||||||
|
- 'tests/**'
|
||||||
|
- 'pyproject.toml'
|
||||||
|
- '.github/workflows/ci.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
ts_sdk:
|
||||||
|
- 'mem0-ts/**'
|
||||||
|
- '.github/workflows/ts-sdk-ci.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
cli_python:
|
||||||
|
- 'cli/python/**'
|
||||||
|
- '.github/workflows/cli-python-ci.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
cli_node:
|
||||||
|
- 'cli/node/**'
|
||||||
|
- '.github/workflows/cli-node-ci.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
openclaw:
|
||||||
|
- 'openclaw/**'
|
||||||
|
- '.github/workflows/openclaw-checks.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
opencode_plugin:
|
||||||
|
- 'mem0-plugin/.opencode-plugin/**'
|
||||||
|
- '.github/workflows/opencode-plugin-checks.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
pi_agent_plugin:
|
||||||
|
- 'pi-agent-plugin/**'
|
||||||
|
- '.github/workflows/pi-agent-plugin-checks.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
docs_llms_txt:
|
||||||
|
- 'docs/**/*.mdx'
|
||||||
|
- 'docs/llms.txt'
|
||||||
|
- 'scripts/check-llms-txt-coverage.py'
|
||||||
|
- 'scripts/llms-txt-ignore.txt'
|
||||||
|
- '.github/workflows/docs-llms-txt-check.yml'
|
||||||
|
- '.github/workflows/ci-gate.yml'
|
||||||
|
|
||||||
|
python-sdk:
|
||||||
|
name: Python SDK
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.python_sdk == 'true'
|
||||||
|
uses: ./.github/workflows/ci.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
ts-sdk:
|
||||||
|
name: TypeScript SDK
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.ts_sdk == 'true'
|
||||||
|
uses: ./.github/workflows/ts-sdk-ci.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
cli-python:
|
||||||
|
name: Python CLI
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.cli_python == 'true'
|
||||||
|
uses: ./.github/workflows/cli-python-ci.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
cli-node:
|
||||||
|
name: Node CLI
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.cli_node == 'true'
|
||||||
|
uses: ./.github/workflows/cli-node-ci.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
openclaw:
|
||||||
|
name: OpenClaw
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.openclaw == 'true'
|
||||||
|
uses: ./.github/workflows/openclaw-checks.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
opencode-plugin:
|
||||||
|
name: OpenCode Plugin
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.opencode_plugin == 'true'
|
||||||
|
uses: ./.github/workflows/opencode-plugin-checks.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
pi-agent-plugin:
|
||||||
|
name: Pi Agent Plugin
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.pi_agent_plugin == 'true'
|
||||||
|
uses: ./.github/workflows/pi-agent-plugin-checks.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
docs-llms-txt:
|
||||||
|
name: docs llms.txt
|
||||||
|
needs: changes
|
||||||
|
if: needs.changes.outputs.docs_llms_txt == 'true'
|
||||||
|
uses: ./.github/workflows/docs-llms-txt-check.yml
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
gate:
|
||||||
|
name: CI Gate
|
||||||
|
needs:
|
||||||
|
- changes
|
||||||
|
- python-sdk
|
||||||
|
- ts-sdk
|
||||||
|
- cli-python
|
||||||
|
- cli-node
|
||||||
|
- openclaw
|
||||||
|
- opencode-plugin
|
||||||
|
- pi-agent-plugin
|
||||||
|
- docs-llms-txt
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Evaluate pipeline results
|
||||||
|
env:
|
||||||
|
NEEDS: ${{ toJSON(needs) }}
|
||||||
|
run: |
|
||||||
|
echo "$NEEDS" | jq -r 'to_entries[] | "\(.key): \(.value.result)"'
|
||||||
|
failed=$(echo "$NEEDS" | jq -r '[to_entries[] | select(.value.result == "failure" or .value.result == "cancelled") | .key] | join(", ")')
|
||||||
|
if [ -n "$failed" ]; then
|
||||||
|
echo "::error::Failing pipelines: $failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "All pipelines relevant to this change passed."
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
name: ci
|
name: ci
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main runs remain standalone.
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
workflow_call:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
changelog_check:
|
changelog_check:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: CLI Node CI
|
name: CLI Node CI
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main and manual runs remain standalone.
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -7,10 +9,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'cli/node/**'
|
- 'cli/node/**'
|
||||||
- '.github/workflows/cli-node-ci.yml'
|
- '.github/workflows/cli-node-ci.yml'
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'cli/node/**'
|
|
||||||
- '.github/workflows/cli-node-ci.yml'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: CLI Python CI
|
name: CLI Python CI
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main and manual runs remain standalone.
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -7,10 +9,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'cli/python/**'
|
- 'cli/python/**'
|
||||||
- '.github/workflows/cli-python-ci.yml'
|
- '.github/workflows/cli-python-ci.yml'
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'cli/python/**'
|
|
||||||
- '.github/workflows/cli-python-ci.yml'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
|||||||
@@ -6,13 +6,10 @@ name: docs - llms.txt check
|
|||||||
# python scripts/check-llms-txt-coverage.py # read-only
|
# python scripts/check-llms-txt-coverage.py # read-only
|
||||||
# python scripts/check-llms-txt-coverage.py --write # scaffold placeholders
|
# python scripts/check-llms-txt-coverage.py --write # scaffold placeholders
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# manual runs remain standalone.
|
||||||
on:
|
on:
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'docs/**/*.mdx'
|
|
||||||
- 'docs/llms.txt'
|
|
||||||
- 'scripts/check-llms-txt-coverage.py'
|
|
||||||
- 'scripts/llms-txt-ignore.txt'
|
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: openclaw checks
|
name: openclaw checks
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main and manual runs remain standalone.
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -7,10 +9,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'openclaw/**'
|
- 'openclaw/**'
|
||||||
- '.github/workflows/openclaw-checks.yml'
|
- '.github/workflows/openclaw-checks.yml'
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'openclaw/**'
|
|
||||||
- '.github/workflows/openclaw-checks.yml'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: opencode-plugin checks
|
name: opencode-plugin checks
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main and manual runs remain standalone.
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -7,10 +9,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'mem0-plugin/.opencode-plugin/**'
|
- 'mem0-plugin/.opencode-plugin/**'
|
||||||
- '.github/workflows/opencode-plugin-checks.yml'
|
- '.github/workflows/opencode-plugin-checks.yml'
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'mem0-plugin/.opencode-plugin/**'
|
|
||||||
- '.github/workflows/opencode-plugin-checks.yml'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: pi-agent-plugin checks
|
name: pi-agent-plugin checks
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main and manual runs remain standalone.
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
@@ -7,10 +9,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'pi-agent-plugin/**'
|
- 'pi-agent-plugin/**'
|
||||||
- '.github/workflows/pi-agent-plugin-checks.yml'
|
- '.github/workflows/pi-agent-plugin-checks.yml'
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'pi-agent-plugin/**'
|
|
||||||
- '.github/workflows/pi-agent-plugin-checks.yml'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
name: TypeScript SDK CI
|
name: TypeScript SDK CI
|
||||||
|
|
||||||
|
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||||
|
# push-to-main runs remain standalone.
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
paths:
|
paths:
|
||||||
- 'mem0-ts/**'
|
- 'mem0-ts/**'
|
||||||
- '.github/workflows/ts-sdk-ci.yml'
|
- '.github/workflows/ts-sdk-ci.yml'
|
||||||
pull_request:
|
workflow_call:
|
||||||
paths:
|
|
||||||
- 'mem0-ts/**'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check_changes:
|
check_changes:
|
||||||
|
|||||||
@@ -406,15 +406,21 @@ To add a new LLM, embedding, vector store, or reranker provider:
|
|||||||
|
|
||||||
### CI Workflows (automated testing)
|
### CI Workflows (automated testing)
|
||||||
|
|
||||||
| Workflow | File | Triggers | Tests |
|
PR testing is orchestrated by a single entry point: **`ci-gate.yml` (CI Gate)** runs on every PR, detects which packages changed, and invokes only the relevant package workflows below as reusable workflows (`workflow_call`). Its final **`CI Gate`** job aggregates the results (skipped pipelines pass; failed or cancelled ones fail) and is the **only status check that needs to be required** in branch protection. Package workflows keep their own push-to-main and manual triggers; their `pull_request` triggers moved into the gate's path filters.
|
||||||
|----------|------|----------|-------|
|
|
||||||
| Python SDK | `ci.yml` | Push to main, PRs on `mem0/`, `tests/`, `pyproject.toml` | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
|
| Workflow | File | Standalone Triggers | Tests |
|
||||||
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main, PRs on `mem0-ts/` | Prettier + build + jest on Node 20, 22 |
|
|----------|------|---------------------|-------|
|
||||||
| Python CLI | `cli-python-ci.yml` | Push to `cli/python/`, PRs, manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
| CI Gate | `ci-gate.yml` | All PRs | Routes to and aggregates the workflows below |
|
||||||
| Node CLI | `cli-node-ci.yml` | Push to `cli/node/`, PRs, manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
|
| Python SDK | `ci.yml` | Push to main | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
|
||||||
| OpenClaw | `openclaw-checks.yml` | Push to `openclaw/`, PRs, manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
|
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main (on `mem0-ts/`) | Prettier + build + jest on Node 20, 22 |
|
||||||
| OpenCode Plugin | `opencode-plugin-checks.yml` | Push to `mem0-plugin/.opencode-plugin/`, PRs, manual | Bun: tsc type-check + build + dist artifact check |
|
| Python CLI | `cli-python-ci.yml` | Push to main (on `cli/python/`), manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
||||||
| Pi Agent Plugin | `pi-agent-plugin-checks.yml` | Push to `pi-agent-plugin/`, PRs, manual | tsc + vitest + tsup build (dist artifact check) on Node 20, 22 |
|
| Node CLI | `cli-node-ci.yml` | Push to main (on `cli/node/`), manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
|
||||||
|
| OpenClaw | `openclaw-checks.yml` | Push to main (on `openclaw/`), manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
|
||||||
|
| OpenCode Plugin | `opencode-plugin-checks.yml` | Push to main (on `mem0-plugin/.opencode-plugin/`), manual | Bun: tsc type-check + build + dist artifact check |
|
||||||
|
| Pi Agent Plugin | `pi-agent-plugin-checks.yml` | Push to main (on `pi-agent-plugin/`), manual | tsc + vitest + tsup build (dist artifact check) on Node 20, 22 |
|
||||||
|
| docs llms.txt | `docs-llms-txt-check.yml` | Manual | `docs/llms.txt` coverage check |
|
||||||
|
|
||||||
|
When adding a new package CI workflow: give it `workflow_call` (plus `push`/`workflow_dispatch` as needed, but no `pull_request` trigger), then register it in `ci-gate.yml` — a path filter under the `changes` job, a call job, and an entry in the gate job's `needs` list.
|
||||||
|
|
||||||
### CD Workflows (automated publishing)
|
### CD Workflows (automated publishing)
|
||||||
|
|
||||||
|
|||||||
@@ -8,4 +8,10 @@ export default defineConfig({
|
|||||||
define: {
|
define: {
|
||||||
__CLI_VERSION__: JSON.stringify(pkg.version),
|
__CLI_VERSION__: JSON.stringify(pkg.version),
|
||||||
},
|
},
|
||||||
|
test: {
|
||||||
|
// Integration tests spawn the CLI via `npx tsx` (15s subprocess
|
||||||
|
// timeout); the first spawn in a file pays a cold-start cost that can
|
||||||
|
// exceed vitest's 5s default on CI runners.
|
||||||
|
testTimeout: 30_000,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ from io import StringIO
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from click.exceptions import Exit as ClickExit
|
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
from typer import Exit as TyperExit
|
||||||
|
|
||||||
from mem0_cli.commands.config_cmd import (
|
from mem0_cli.commands.config_cmd import (
|
||||||
cmd_config_get,
|
cmd_config_get,
|
||||||
@@ -181,7 +181,7 @@ class TestAddCommand:
|
|||||||
patch("mem0_cli.commands.memory.console", console),
|
patch("mem0_cli.commands.memory.console", console),
|
||||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||||
patch("mem0_cli.commands.memory._stdin_is_piped", return_value=False),
|
patch("mem0_cli.commands.memory._stdin_is_piped", return_value=False),
|
||||||
pytest.raises((SystemExit, ClickExit)),
|
pytest.raises((SystemExit, TyperExit)),
|
||||||
):
|
):
|
||||||
cmd_add(
|
cmd_add(
|
||||||
mock_backend,
|
mock_backend,
|
||||||
@@ -206,7 +206,7 @@ class TestAddCommand:
|
|||||||
with (
|
with (
|
||||||
patch("mem0_cli.commands.memory.console", console),
|
patch("mem0_cli.commands.memory.console", console),
|
||||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||||
pytest.raises((SystemExit, ClickExit)),
|
pytest.raises((SystemExit, TyperExit)),
|
||||||
):
|
):
|
||||||
cmd_add(
|
cmd_add(
|
||||||
mock_backend,
|
mock_backend,
|
||||||
@@ -764,7 +764,7 @@ class TestImportCommand:
|
|||||||
with (
|
with (
|
||||||
patch("mem0_cli.commands.utils.console", console),
|
patch("mem0_cli.commands.utils.console", console),
|
||||||
patch("mem0_cli.commands.utils.err_console", err_console),
|
patch("mem0_cli.commands.utils.err_console", err_console),
|
||||||
pytest.raises((SystemExit, ClickExit)),
|
pytest.raises((SystemExit, TyperExit)),
|
||||||
):
|
):
|
||||||
cmd_import(mock_backend, "/nonexistent/file.json", user_id=None, agent_id=None)
|
cmd_import(mock_backend, "/nonexistent/file.json", user_id=None, agent_id=None)
|
||||||
|
|
||||||
@@ -801,7 +801,7 @@ class TestEntitiesListCommand:
|
|||||||
with (
|
with (
|
||||||
patch("mem0_cli.commands.entities.console", console),
|
patch("mem0_cli.commands.entities.console", console),
|
||||||
patch("mem0_cli.commands.entities.err_console", err_console),
|
patch("mem0_cli.commands.entities.err_console", err_console),
|
||||||
pytest.raises((SystemExit, ClickExit)),
|
pytest.raises((SystemExit, TyperExit)),
|
||||||
):
|
):
|
||||||
cmd_entities_list(mock_backend, "invalid", output="table")
|
cmd_entities_list(mock_backend, "invalid", output="table")
|
||||||
|
|
||||||
@@ -944,7 +944,7 @@ class TestEntitiesDeleteCommand:
|
|||||||
with (
|
with (
|
||||||
patch("mem0_cli.commands.entities.console", console),
|
patch("mem0_cli.commands.entities.console", console),
|
||||||
patch("mem0_cli.commands.entities.err_console", err_console),
|
patch("mem0_cli.commands.entities.err_console", err_console),
|
||||||
pytest.raises((SystemExit, ClickExit)),
|
pytest.raises((SystemExit, TyperExit)),
|
||||||
):
|
):
|
||||||
cmd_entities_delete(
|
cmd_entities_delete(
|
||||||
mock_backend,
|
mock_backend,
|
||||||
@@ -1308,7 +1308,7 @@ class TestAgentMode:
|
|||||||
patch("mem0_cli.commands.memory.console", console),
|
patch("mem0_cli.commands.memory.console", console),
|
||||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||||
patch("sys.stdout", captured_stdout),
|
patch("sys.stdout", captured_stdout),
|
||||||
pytest.raises((SystemExit, ClickExit)),
|
pytest.raises((SystemExit, TyperExit)),
|
||||||
):
|
):
|
||||||
cmd_get(mock_backend, "bad-id", output="text")
|
cmd_get(mock_backend, "bad-id", output="text")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user