orchestra-cli 0.3.3__tar.gz → 0.3.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/PKG-INFO +5 -3
  2. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/README.md +4 -2
  3. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/validate_pipeline.py +8 -4
  4. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_create_pipeline.py +12 -0
  5. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_validate_pipeline.py +41 -0
  6. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/yaml_loader.py +27 -1
  7. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/PKG-INFO +5 -3
  8. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/pyproject.toml +6 -1
  9. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/__init__.py +0 -0
  10. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/build_pipeline.py +0 -0
  11. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/cli.py +0 -0
  12. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/create_pipeline.py +0 -0
  13. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/delete_pipeline.py +0 -0
  14. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/fetch_pipelines.py +0 -0
  15. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/get_pipeline.py +0 -0
  16. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/import_pipeline.py +0 -0
  17. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/migrate_pipeline.py +0 -0
  18. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/pipeline_upsert.py +0 -0
  19. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/run_pipeline.py +0 -0
  20. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/task_logs.py +0 -0
  21. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/update_pipeline.py +0 -0
  22. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/__init__.py +0 -0
  23. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/conftest.py +0 -0
  24. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_build_pipeline.py +0 -0
  25. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_cli.py +0 -0
  26. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_delete_pipeline.py +0 -0
  27. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_fetch_pipelines.py +0 -0
  28. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_get_pipeline.py +0 -0
  29. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_import_pipeline.py +0 -0
  30. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_migrate_pipeline.py +0 -0
  31. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_pipeline_selector.py +0 -0
  32. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_run_pipeline.py +0 -0
  33. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_task_logs.py +0 -0
  34. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_update_pipeline.py +0 -0
  35. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/utils/__init__.py +0 -0
  36. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/utils/test_git.py +0 -0
  37. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/api.py +0 -0
  38. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/constants.py +0 -0
  39. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/git.py +0 -0
  40. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/pipeline_lookup.py +0 -0
  41. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/pipeline_selector.py +0 -0
  42. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/pipeline_update.py +0 -0
  43. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/styling.py +0 -0
  44. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/SOURCES.txt +0 -0
  45. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/dependency_links.txt +0 -0
  46. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/entry_points.txt +0 -0
  47. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/requires.txt +0 -0
  48. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/top_level.txt +0 -0
  49. {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orchestra-cli
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: Orchestra CLI. Perform operations with Orchestra locally.
5
5
  Author-email: Orchestra Technologies <support@getorchestra.io>
6
6
  Requires-Python: >=3.10
@@ -55,6 +55,8 @@ Commands follow a `noun verb` shape. The current nouns are `pipeline` and `task`
55
55
  | `orchestra pipeline build` | Validate local YAML, create or update a draft pipeline, and start that draft version. |
56
56
  | `orchestra task logs` | Fetch or follow logs for a single task run. |
57
57
 
58
+ Commands that read a local pipeline file (`pipeline validate`, `import`, `new`, `update`, `build`, and `run --path` with `--task`) accept `.yaml`, `.yml` and `.oml` files; any other extension is rejected. `.oml` files are read as YAML, so only OML written in YAML or JSON syntax is supported. OML block terminators (`.`) and embeds (`%sql ... %%`) fail with an `Invalid YAML` error.
59
+
58
60
  Use `orchestra --help`, `orchestra <noun> --help`, or `orchestra <noun> <verb> --help` for built-in help.
59
61
 
60
62
  ### Legacy command names
@@ -77,7 +79,7 @@ New code and documentation should prefer the noun/verb form.
77
79
 
78
80
  ## pipeline validate
79
81
 
80
- Validate a YAML file against the Orchestra API schema.
82
+ Validate a pipeline file against the Orchestra API schema.
81
83
 
82
84
  ```bash
83
85
  orchestra pipeline validate path/to/pipeline.yaml
@@ -87,7 +89,7 @@ orchestra-cli pipeline validate path/to/pipeline.yaml
87
89
 
88
90
  Options
89
91
 
90
- - `file` (positional): Path to the YAML file to validate.
92
+ - `file` (positional): Path to the `.yaml`, `.yml` or `.oml` file to validate.
91
93
 
92
94
  Behavior
93
95
 
@@ -41,6 +41,8 @@ Commands follow a `noun verb` shape. The current nouns are `pipeline` and `task`
41
41
  | `orchestra pipeline build` | Validate local YAML, create or update a draft pipeline, and start that draft version. |
42
42
  | `orchestra task logs` | Fetch or follow logs for a single task run. |
43
43
 
44
+ Commands that read a local pipeline file (`pipeline validate`, `import`, `new`, `update`, `build`, and `run --path` with `--task`) accept `.yaml`, `.yml` and `.oml` files; any other extension is rejected. `.oml` files are read as YAML, so only OML written in YAML or JSON syntax is supported. OML block terminators (`.`) and embeds (`%sql ... %%`) fail with an `Invalid YAML` error.
45
+
44
46
  Use `orchestra --help`, `orchestra <noun> --help`, or `orchestra <noun> <verb> --help` for built-in help.
45
47
 
46
48
  ### Legacy command names
@@ -63,7 +65,7 @@ New code and documentation should prefer the noun/verb form.
63
65
 
64
66
  ## pipeline validate
65
67
 
66
- Validate a YAML file against the Orchestra API schema.
68
+ Validate a pipeline file against the Orchestra API schema.
67
69
 
68
70
  ```bash
69
71
  orchestra pipeline validate path/to/pipeline.yaml
@@ -73,7 +75,7 @@ orchestra-cli pipeline validate path/to/pipeline.yaml
73
75
 
74
76
  Options
75
77
 
76
- - `file` (positional): Path to the YAML file to validate.
78
+ - `file` (positional): Path to the `.yaml`, `.yml` or `.oml` file to validate.
77
79
 
78
80
  Behavior
79
81
 
@@ -9,7 +9,7 @@ import yaml
9
9
  from ..utils.api import request_or_exit
10
10
  from ..utils.constants import get_api_url
11
11
  from ..utils.styling import bold, green, indent_message, red, yellow
12
- from ..utils.yaml_loader import load_yaml
12
+ from ..utils.yaml_loader import echo_invalid_yaml, exit_if_unsupported_extension, load_yaml
13
13
 
14
14
 
15
15
  def get_yaml_snippet(data: Any, loc: list[Any]) -> dict[str, Any] | None:
@@ -39,14 +39,18 @@ def _render_validation_details(details: list[dict[str, Any]], data: Any) -> None
39
39
  typer.echo(yellow("(Could not locate this path in your YAML)"))
40
40
 
41
41
 
42
- def validate(file: Path = typer.Argument(..., help="YAML file to validate")):
42
+ def validate(
43
+ file: Path = typer.Argument(..., help="Pipeline file to validate (.yaml, .yml or .oml)"),
44
+ ):
43
45
  """
44
- Validate a YAML file against the API.
46
+ Validate a pipeline file (.yaml, .yml or .oml) against the API.
45
47
  """
46
48
  if not file.exists():
47
49
  typer.echo(red(f"File not found: {file}"))
48
50
  raise typer.Exit(code=1)
49
51
 
52
+ exit_if_unsupported_extension(file)
53
+
50
54
  data, err = load_yaml(file)
51
55
  if err is not None:
52
56
  try:
@@ -60,7 +64,7 @@ def validate(file: Path = typer.Argument(..., help="YAML file to validate")):
60
64
  _render_validation_details(details, data)
61
65
  raise typer.Exit(code=1)
62
66
 
63
- typer.echo(red(f"Invalid YAML: {err}"))
67
+ echo_invalid_yaml(file, err)
64
68
  raise typer.Exit(code=1)
65
69
 
66
70
  response = request_or_exit(httpx.post, get_api_url("pipelines/schema"), json=data, timeout=10)
@@ -249,3 +249,15 @@ def test_create_success_with_invalid_json_fails(tmp_path: Path, httpx_mock: HTTP
249
249
  result = runner.invoke(app, ["pipeline", "new", "--alias", "demo", "--path", str(yaml_file)])
250
250
  assert result.exit_code == 1
251
251
  assert "success response was not valid JSON" in result.output
252
+
253
+
254
+ def test_create_rejects_unsupported_extension(tmp_path: Path):
255
+ pipeline_file = tmp_path / "pipe.json"
256
+ pipeline_file.write_text('{"name": "demo"}')
257
+
258
+ result = runner.invoke(
259
+ app,
260
+ ["pipeline", "new", "--alias", "demo", "--path", str(pipeline_file)],
261
+ )
262
+ assert result.exit_code == 1
263
+ assert "Unsupported file extension '.json'" in result.output
@@ -89,3 +89,44 @@ def test_validate_fails_on_duplicate_yaml_keys(tmp_path):
89
89
  assert "YAML snippet:" in result.output
90
90
  assert "connection: first" in result.output
91
91
  assert "team: data" in result.output
92
+
93
+
94
+ def test_validate_oml_file_posts_expected_json(tmp_path, httpx_mock: HTTPXMock):
95
+ pipeline_file = tmp_path / "pipeline.oml"
96
+ pipeline_file.write_text('{"version": "v1", "name": "anomalies"}')
97
+ httpx_mock.add_response(
98
+ method="POST",
99
+ url="https://app.getorchestra.io/api/engine/public/pipelines/schema",
100
+ json={"ok": True},
101
+ status_code=200,
102
+ )
103
+
104
+ result = runner.invoke(app, ["pipeline", "validate", str(pipeline_file)])
105
+
106
+ assert result.exit_code == 0
107
+ assert "Validation passed" in result.output
108
+ requests = httpx_mock.get_requests()
109
+ assert len(requests) == 1
110
+ assert json.loads(requests[0].content) == {"version": "v1", "name": "anomalies"}
111
+
112
+
113
+ def test_validate_oml_only_syntax_explains_limitation(tmp_path):
114
+ pipeline_file = tmp_path / "pipeline.oml"
115
+ pipeline_file.write_text("task:\n sql: %sql select 1 %%\n")
116
+
117
+ result = runner.invoke(app, ["pipeline", "validate", str(pipeline_file)])
118
+
119
+ assert result.exit_code == 1
120
+ assert "Invalid YAML" in result.output
121
+ assert "embeds (`%sql ... %%`), those are not supported yet" in result.output
122
+
123
+
124
+ def test_validate_rejects_unsupported_extension(tmp_path):
125
+ pipeline_file = tmp_path / "pipeline.json"
126
+ pipeline_file.write_text('{"version": "v1"}')
127
+
128
+ result = runner.invoke(app, ["pipeline", "validate", str(pipeline_file)])
129
+
130
+ assert result.exit_code == 1
131
+ assert "Unsupported file extension '.json'" in result.output
132
+ assert ".yaml, .yml, .oml" in result.output
@@ -16,6 +16,8 @@ import yaml
16
16
  from .constants import get_api_url
17
17
  from .styling import indent_message, red, yellow
18
18
 
19
+ SUPPORTED_EXTENSIONS = (".yaml", ".yml", ".oml")
20
+
19
21
 
20
22
  class DuplicateKeyYAMLError(Exception):
21
23
  def __init__(self, details: list[dict[str, Any]], parsed_data: dict[str, Any] | None = None):
@@ -67,6 +69,28 @@ class DuplicateKeySafeLoader(yaml.SafeLoader):
67
69
  return mapping
68
70
 
69
71
 
72
+ def exit_if_unsupported_extension(path: Path) -> None:
73
+ if path.suffix.lower() not in SUPPORTED_EXTENSIONS:
74
+ typer.echo(
75
+ red(
76
+ f"Unsupported file extension '{path.suffix}': "
77
+ f"expected one of {', '.join(SUPPORTED_EXTENSIONS)}",
78
+ ),
79
+ )
80
+ raise typer.Exit(code=1)
81
+
82
+
83
+ def echo_invalid_yaml(path: Path, err: str) -> None:
84
+ typer.echo(red(f"Invalid YAML: {err}"))
85
+ if path.suffix.lower() == ".oml":
86
+ typer.echo(
87
+ yellow(
88
+ ".oml files are read as YAML. If this file uses OML block terminators (`.`) "
89
+ "or embeds (`%sql ... %%`), those are not supported yet.",
90
+ ),
91
+ )
92
+
93
+
70
94
  def load_yaml(file: Path) -> tuple[dict | None, str | None]:
71
95
  """Read a YAML file and return ``(data, None)`` or ``(None, error_message)``."""
72
96
  try:
@@ -109,9 +133,11 @@ def load_validated_pipeline_data(path: Path) -> dict:
109
133
  typer.echo(red(f"File not found: {path}"))
110
134
  raise typer.Exit(code=1)
111
135
 
136
+ exit_if_unsupported_extension(path)
137
+
112
138
  data, err = load_yaml(path)
113
139
  if err is not None:
114
- typer.echo(red(f"Invalid YAML: {err}"))
140
+ echo_invalid_yaml(path, err)
115
141
  raise typer.Exit(code=1)
116
142
 
117
143
  ok, err_msg = validate_yaml_with_api(data or {})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orchestra-cli
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: Orchestra CLI. Perform operations with Orchestra locally.
5
5
  Author-email: Orchestra Technologies <support@getorchestra.io>
6
6
  Requires-Python: >=3.10
@@ -55,6 +55,8 @@ Commands follow a `noun verb` shape. The current nouns are `pipeline` and `task`
55
55
  | `orchestra pipeline build` | Validate local YAML, create or update a draft pipeline, and start that draft version. |
56
56
  | `orchestra task logs` | Fetch or follow logs for a single task run. |
57
57
 
58
+ Commands that read a local pipeline file (`pipeline validate`, `import`, `new`, `update`, `build`, and `run --path` with `--task`) accept `.yaml`, `.yml` and `.oml` files; any other extension is rejected. `.oml` files are read as YAML, so only OML written in YAML or JSON syntax is supported. OML block terminators (`.`) and embeds (`%sql ... %%`) fail with an `Invalid YAML` error.
59
+
58
60
  Use `orchestra --help`, `orchestra <noun> --help`, or `orchestra <noun> <verb> --help` for built-in help.
59
61
 
60
62
  ### Legacy command names
@@ -77,7 +79,7 @@ New code and documentation should prefer the noun/verb form.
77
79
 
78
80
  ## pipeline validate
79
81
 
80
- Validate a YAML file against the Orchestra API schema.
82
+ Validate a pipeline file against the Orchestra API schema.
81
83
 
82
84
  ```bash
83
85
  orchestra pipeline validate path/to/pipeline.yaml
@@ -87,7 +89,7 @@ orchestra-cli pipeline validate path/to/pipeline.yaml
87
89
 
88
90
  Options
89
91
 
90
- - `file` (positional): Path to the YAML file to validate.
92
+ - `file` (positional): Path to the `.yaml`, `.yml` or `.oml` file to validate.
91
93
 
92
94
  Behavior
93
95
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "orchestra-cli"
3
- version = "0.3.3"
3
+ version = "0.3.5"
4
4
  description = "Orchestra CLI. Perform operations with Orchestra locally."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -48,6 +48,11 @@ line-length = 100
48
48
  # N = pep8-naming
49
49
  select = ["E", "F", "W", "I", "N", "UP", "ARG", "COM"]
50
50
 
51
+ [tool.ruff.lint.isort]
52
+ # `requires-python = ">=3.10"` makes ruff classify tomllib as third-party, but
53
+ # the dev scripts that import it run on 3.12.
54
+ extra-standard-library = ["tomllib"]
55
+
51
56
  [tool.black]
52
57
  line-length = 100
53
58
  exclude = '''
File without changes