Skip to content

Commit 7d7ee2f

Browse files
Add stale command exit-code option
1 parent d4cb1c3 commit 7d7ee2f

3 files changed

Lines changed: 44 additions & 1 deletion

File tree

docs/CATALOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ or on the command line, where stdout is exactly the pipeable source-URI list:
178178
hflow stale --catalog data/catalog --pipeline pipeline.py | xargs hflow ingest
179179
```
180180

181+
Pass `--exit-code` to make the command exit with status 1 when it finds any
182+
stale episodes, which lets CI gate on stale data without changing the default
183+
pipe-friendly behavior:
184+
185+
```bash
186+
hflow stale --catalog data/catalog --pipeline pipeline.py --exit-code
187+
```
188+
181189
`--pipeline` imports your pipeline file and compares against its current
182190
`pipeline_version` plus the current episode format version; pass
183191
`--pipeline-version <hash>` instead to compare against a known hash without

src/hflow/cli.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ def _build_parser() -> argparse.ArgumentParser:
7272
default="./data/catalog",
7373
help="catalog directory or object-store prefix (default: ./data/catalog)",
7474
)
75+
stale_parser.add_argument(
76+
"--exit-code",
77+
action="store_true",
78+
help="exit 1 when any stale episode is found",
79+
)
7580
stale_group = stale_parser.add_mutually_exclusive_group(required=True)
7681
stale_group.add_argument(
7782
"--pipeline",
@@ -315,7 +320,7 @@ def _command_stale(arguments: argparse.Namespace) -> int:
315320
+ (f" / schema_version {schema_version}" if schema_version is not None else ""),
316321
file=sys.stderr,
317322
)
318-
return 0
323+
return 1 if arguments.exit_code and stale else 0
319324

320325

321326
def _command_up(arguments: argparse.Namespace) -> int:

tests/test_catalog_curation.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,36 @@ def test_cli_stale_prints_source_uris_for_ingest(
366366
assert "1 episode(s)" in captured.err
367367

368368

369+
@pytest.mark.parametrize(
370+
("pipeline_version", "expected_exit_code"),
371+
[("somethingnewer", 1), (FAKE_STAMPS.pipeline_version, 0)],
372+
)
373+
def test_cli_stale_exit_code_gates_on_stale_episodes(
374+
tmp_path: Path,
375+
pipeline_version: str,
376+
expected_exit_code: int,
377+
) -> None:
378+
catalog = Catalog(tmp_path / "catalog")
379+
catalog.append_episode(
380+
canonical_path=_fake_canonical(tmp_path),
381+
stamps=FAKE_STAMPS,
382+
episode_metadata={},
383+
check_rows=[],
384+
source_uri="episodes-in/run_0001.mcap",
385+
)
386+
exit_code = cli_main(
387+
[
388+
"stale",
389+
"--catalog",
390+
str(tmp_path / "catalog"),
391+
"--pipeline-version",
392+
pipeline_version,
393+
"--exit-code",
394+
]
395+
)
396+
assert exit_code == expected_exit_code
397+
398+
369399
def test_cli_stale_reports_a_broken_pipeline_file_instead_of_crashing(
370400
tmp_path: Path, capsys: pytest.CaptureFixture[str]
371401
) -> None:

0 commit comments

Comments
 (0)