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.
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/PKG-INFO +5 -3
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/README.md +4 -2
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/validate_pipeline.py +8 -4
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_create_pipeline.py +12 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_validate_pipeline.py +41 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/yaml_loader.py +27 -1
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/PKG-INFO +5 -3
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/pyproject.toml +6 -1
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/__init__.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/build_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/cli.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/create_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/delete_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/fetch_pipelines.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/get_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/import_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/migrate_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/pipeline_upsert.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/run_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/task_logs.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/src/update_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/__init__.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/conftest.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_build_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_cli.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_delete_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_fetch_pipelines.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_get_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_import_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_migrate_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_pipeline_selector.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_run_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_task_logs.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/test_update_pipeline.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/utils/__init__.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/tests/utils/test_git.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/api.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/constants.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/git.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/pipeline_lookup.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/pipeline_selector.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/pipeline_update.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli/utils/styling.py +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/SOURCES.txt +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/dependency_links.txt +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/entry_points.txt +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/requires.txt +0 -0
- {orchestra_cli-0.3.3 → orchestra_cli-0.3.5}/orchestra_cli.egg-info/top_level.txt +0 -0
- {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
|
+
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
42
|
+
def validate(
|
|
43
|
+
file: Path = typer.Argument(..., help="Pipeline file to validate (.yaml, .yml or .oml)"),
|
|
44
|
+
):
|
|
43
45
|
"""
|
|
44
|
-
Validate a
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
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
|
|
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
|
|
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
|
+
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|