Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
push:
branches:
- master
- cli-v2
pull_request:
branches:
- master
- cli-v2

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
test:
name: Unit tests (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: "${{ matrix.python-version }}"
allow-prereleases: true
- name: Install dependencies
run: |
pip install --upgrade pip
pip install ".[dev]"
# Python 3.9 needs tomli for pyproject.toml parsing in tests
if python -c "import sys; sys.exit(0 if sys.version_info < (3, 11) else 1)"; then
pip install "tomli>=1.0"
fi
- name: Run unit tests and microbenchmarks (correctness only)
run: pytest tests/unit/ tests/microbenchmarks/ --benchmark-disable -v --reruns 2 --reruns-delay 5
34 changes: 24 additions & 10 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,35 @@ on:
tags:
- "[0-9]+.[0-9]+.[0-9]+"

permissions:
contents: read

jobs:
test:
name: Run unit tests
name: Unit tests (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version: "${{ matrix.python-version }}"
allow-prereleases: true
- name: Install dependencies
run: pip install ".[dev]"
run: |
pip install --upgrade pip
pip install ".[dev]"
# Python 3.9 needs tomli for pyproject.toml parsing in tests
if python -c "import sys; sys.exit(0 if sys.version_info < (3, 11) else 1)"; then
pip install "tomli>=1.0"
fi
- name: Run unit tests and microbenchmarks (correctness only)
run: pytest tests/unit/ tests/microbenchmarks/ --benchmark-disable -v --reruns 2 --reruns-delay 5

Expand All @@ -28,20 +42,20 @@ jobs:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install build
run: pip install build
- name: Build sdist and wheel
run: python -m build
- name: Upload distributions
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: python-package-distributions
path: dist/
Expand All @@ -59,7 +73,7 @@ jobs:
contents: read
steps:
- name: Download distributions
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: python-package-distributions
path: dist/
Expand Down
1 change: 1 addition & 0 deletions limacharlie/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def _config_no_warnings() -> bool:
"case": ("case_cmd", "group"),
"cloud-adapter": ("cloud_sensor", "group"),
"completion": ("completion", "cmd"),
"config": ("config_cmd", "group"),
"detection": ("detection", "group"),
"download": ("download", "group"),
"dr": ("dr", "group"),
Expand Down
9 changes: 8 additions & 1 deletion tests/microbenchmarks/test_cli_startup_microbenchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,21 @@ def test_cli_import_does_not_load_output(self):
to avoid ~14ms of jmespath/tabulate/yaml/csv import overhead on
fast paths like --help, --version, and --ai-help.
"""
# Track which third-party deps are already loaded by other tests
# in the same process so we only assert on *newly* imported ones.
third_party_deps = ("jmespath", "tabulate", "yaml")
already_loaded = {dep for dep in third_party_deps if dep in sys.modules}

to_remove = [k for k in sys.modules if k.startswith("limacharlie")]
saved = {k: sys.modules.pop(k) for k in to_remove}
try:
importlib.import_module("limacharlie.cli")
assert "limacharlie.output" not in sys.modules, (
"limacharlie.output imported at module level"
)
for dep in ("jmespath", "tabulate", "yaml"):
for dep in third_party_deps:
if dep in already_loaded:
continue
assert dep not in sys.modules, (
f"{dep} imported at module level via limacharlie.output"
)
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/test_cli_lazy_loading_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
# Every top-level command/group that must be registered on cli.
EXPECTED_TOP_LEVEL_COMMANDS = frozenset({
"ai", "api", "api-key", "arl", "artifact", "audit", "auth", "billing",
"case", "cloud-adapter", "completion", "detection", "download", "dr",
"case", "cloud-adapter", "completion", "config", "detection", "download", "dr",
"endpoint-policy", "event", "exfil", "extension", "external-adapter",
"fp", "group", "help", "hive", "ingestion-key", "installation-key",
"integrity", "ioc", "job", "logging", "lookup", "note", "org", "output",
Expand All @@ -70,6 +70,7 @@
"case_cmd": ("group", "case"),
"cloud_sensor": ("group", "cloud-adapter"),
"completion": ("cmd", "completion"),
"config_cmd": ("group", "config"),
"detection": ("group", "detection"),
"download": ("group", "download"),
"dr": ("group", "dr"),
Expand Down Expand Up @@ -124,6 +125,7 @@
"get-token", "list-envs", "list-orgs", "login", "logout",
"signup", "test", "use-env", "use-org", "whoami",
}),
"config": frozenset({"migrate", "show-paths"}),
"billing": frozenset({"details", "invoice", "plans", "status"}),
"case": frozenset({
"add-note", "artifact", "assignees", "bulk-update",
Expand Down