Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ infra/node_modules/
infra/dist/
infra/cdk.out/
infra/coverage
infra/constants/event-statuses.ts


# DeepEval
Expand Down
23 changes: 0 additions & 23 deletions infra/constants/event-statuses.ts

This file was deleted.

3 changes: 2 additions & 1 deletion infra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
"name": "infra",
"private": true,
"scripts": {
"prebuild": "npm run package-agent && npm run prepare-lambda",
"prebuild": "npm run generate-event-statuses && npm run package-agent && npm run prepare-lambda",
"build": "tsc -p tsconfig.json",
"watch": "tsc -w",
"clean": "rm -rf cdk.out dist",
"generate-event-statuses": "python3 ../scripts/generate-event-statuses.py constants/event-statuses.ts",
"prepare-lambda": "rm -rf dist/build-lambda && mkdir -p dist/build-lambda/src && cp ../infra/lambda/*.py dist/build-lambda/ && cp ../src/__init__.py dist/build-lambda/src/ && cp -r ../src/shared dist/build-lambda/src/",
"package-agent": "rm -rf dist/build-agent && bash ../scripts/build-deployment-package.sh",
"synth": "npm run build && cdk synth",
Expand Down
43 changes: 43 additions & 0 deletions scripts/generate-event-statuses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""Generate infra/constants/event-statuses.ts from src/shared/event_statuses.py.

Usage: generate-event-statuses.py <output-path>

src/shared/event_statuses.py is the single source of truth for event status
strings. This script mirrors it into a TypeScript module so the Step
Functions workflow (infra/lib/workflow.ts) can't drift from the Python
values that actually get written to DynamoDB.
"""

import sys
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT))

from src.shared.event_statuses import EventStatus # noqa: E402

HEADER = """// GENERATED FILE — do not edit by hand.
// Source of truth: src/shared/event_statuses.py
// Regenerated automatically by `npm run generate-event-statuses` (part of `npm run build`).
"""


def render(statuses: dict[str, str]) -> str:
entries = "\n".join(f" {name}: '{value}'," for name, value in statuses.items())
return (
f"{HEADER}\n"
f"export const EventStatus = {{\n{entries}\n}} as const;\n\n"
f"export type EventStatusType = (typeof EventStatus)[keyof typeof EventStatus];\n"
)


def main() -> None:
output_path = Path(sys.argv[1])
statuses = {name: value for name, value in vars(EventStatus).items() if not name.startswith("_")}
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(render(statuses))


if __name__ == "__main__":
main()
44 changes: 44 additions & 0 deletions tests/test_generate_event_statuses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Unit tests for scripts/generate-event-statuses.py."""

import importlib.util
from pathlib import Path

REPO_ROOT = Path(__file__).resolve().parents[1]
SCRIPT_PATH = REPO_ROOT / "scripts" / "generate-event-statuses.py"

_spec = importlib.util.spec_from_file_location("generate_event_statuses", SCRIPT_PATH)
generate_event_statuses = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(generate_event_statuses)


def test_render_mirrors_provided_statuses():
output = generate_event_statuses.render({"FOO": "FOO", "BAR": "BAR_VALUE"})

assert "FOO: 'FOO'," in output
assert "BAR: 'BAR_VALUE'," in output
assert "export const EventStatus" in output
assert "as const" in output
assert "export type EventStatusType" in output


def test_render_preserves_insertion_order():
output = generate_event_statuses.render({"A": "1", "B": "2", "C": "3"})

assert output.index("A: '1'") < output.index("B: '2'") < output.index("C: '3'")


def test_main_mirrors_every_real_event_status(tmp_path, monkeypatch):
from src.shared.event_statuses import EventStatus

output_path = tmp_path / "event-statuses.ts"
monkeypatch.setattr("sys.argv", ["generate-event-statuses.py", str(output_path)])

generate_event_statuses.main()

content = output_path.read_text()
expected = {name: value for name, value in vars(EventStatus).items() if not name.startswith("_")}

assert expected, "EventStatus should not be empty"
for name, value in expected.items():
assert f"{name}: '{value}'," in content
assert "GENERATED FILE" in content
Loading