orchestra-cli 0.3.5__tar.gz → 0.5.0__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.5 → orchestra_cli-0.5.0}/PKG-INFO +58 -3
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/README.md +57 -2
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/build_pipeline.py +20 -16
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/cli.py +8 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/create_pipeline.py +7 -7
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/delete_pipeline.py +7 -7
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/fetch_pipelines.py +7 -8
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/get_pipeline.py +7 -7
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/import_pipeline.py +7 -7
- orchestra_cli-0.5.0/orchestra_cli/src/list_accounts.py +16 -0
- orchestra_cli-0.5.0/orchestra_cli/src/login.py +208 -0
- orchestra_cli-0.5.0/orchestra_cli/src/login_page.html +42 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/migrate_pipeline.py +19 -11
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/run_pipeline.py +31 -30
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/task_logs.py +24 -18
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/update_pipeline.py +8 -8
- orchestra_cli-0.5.0/orchestra_cli/src/use_account.py +61 -0
- orchestra_cli-0.5.0/orchestra_cli/tests/conftest.py +41 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_delete_pipeline.py +4 -15
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_fetch_pipelines.py +41 -0
- orchestra_cli-0.5.0/orchestra_cli/tests/test_list_accounts.py +84 -0
- orchestra_cli-0.5.0/orchestra_cli/tests/test_login.py +316 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_run_pipeline.py +126 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_task_logs.py +34 -0
- orchestra_cli-0.5.0/orchestra_cli/tests/test_use_account.py +214 -0
- orchestra_cli-0.5.0/orchestra_cli/tests/utils/test_api.py +229 -0
- orchestra_cli-0.5.0/orchestra_cli/tests/utils/test_picker.py +45 -0
- orchestra_cli-0.5.0/orchestra_cli/utils/accounts.py +44 -0
- orchestra_cli-0.5.0/orchestra_cli/utils/api.py +199 -0
- orchestra_cli-0.5.0/orchestra_cli/utils/credentials.py +49 -0
- orchestra_cli-0.5.0/orchestra_cli/utils/picker.py +58 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/pipeline_lookup.py +3 -5
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli.egg-info/PKG-INFO +58 -3
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli.egg-info/SOURCES.txt +12 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/pyproject.toml +4 -1
- orchestra_cli-0.3.5/orchestra_cli/tests/conftest.py +0 -14
- orchestra_cli-0.3.5/orchestra_cli/utils/api.py +0 -65
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/__init__.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/pipeline_upsert.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/src/validate_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/__init__.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_build_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_cli.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_create_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_get_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_import_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_migrate_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_pipeline_selector.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_update_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/test_validate_pipeline.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/utils/__init__.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/tests/utils/test_git.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/constants.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/git.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/pipeline_selector.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/pipeline_update.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/styling.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli/utils/yaml_loader.py +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli.egg-info/dependency_links.txt +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli.egg-info/entry_points.txt +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli.egg-info/requires.txt +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/orchestra_cli.egg-info/top_level.txt +0 -0
- {orchestra_cli-0.3.5 → orchestra_cli-0.5.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: orchestra-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
@@ -34,15 +34,17 @@ pipx install orchestra-cli
|
|
|
34
34
|
|
|
35
35
|
## Environment variables
|
|
36
36
|
|
|
37
|
-
- `ORCHESTRA_API_KEY`:
|
|
37
|
+
- `ORCHESTRA_API_KEY`: Credential for actions that call the API (`pipeline import`, `pipeline new`, `pipeline update`, `pipeline migrate`, `pipeline get`, `pipeline list`, `pipeline delete`, `pipeline run`, `pipeline build`, `accounts list`). Not needed once you have run `orchestra login`: a login takes precedence, and the key is used only when you are not logged in or your login has expired.
|
|
38
|
+
- `ORCHESTRA_ACCOUNT_ID`: Optional. The workspace to act in when your `orchestra login` covers several. Every `pipeline` and `task` command that calls the API also takes `--account-id`, which wins over the variable, and both win over the default saved by `orchestra accounts use`. API keys belong to one account and don't need it.
|
|
38
39
|
- `BASE_URL`: Optional. Override the default Orchestra host (`https://app.getorchestra.io`) for non‑production/testing.
|
|
39
40
|
|
|
40
41
|
## Command structure
|
|
41
42
|
|
|
42
|
-
Commands follow a `noun verb` shape. The current nouns are `pipeline` and `
|
|
43
|
+
Commands follow a `noun verb` shape. The current nouns are `pipeline`, `task` and `accounts`:
|
|
43
44
|
|
|
44
45
|
| Command | Description |
|
|
45
46
|
| ------------------------------------ | ------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `orchestra login` | Log in through your browser so later commands need no API key. |
|
|
46
48
|
| `orchestra pipeline validate <file>` | Validate a pipeline YAML locally against the Orchestra API schema. |
|
|
47
49
|
| `orchestra pipeline import` | Register a pipeline YAML (from a git repo) with Orchestra under an alias. |
|
|
48
50
|
| `orchestra pipeline get` | Fetch one pipeline by path, alias, or pipeline ID. |
|
|
@@ -54,6 +56,8 @@ Commands follow a `noun verb` shape. The current nouns are `pipeline` and `task`
|
|
|
54
56
|
| `orchestra pipeline run` | Start a pipeline run by selector, optionally pinning branch/commit and waiting. |
|
|
55
57
|
| `orchestra pipeline build` | Validate local YAML, create or update a draft pipeline, and start that draft version. |
|
|
56
58
|
| `orchestra task logs` | Fetch or follow logs for a single task run. |
|
|
59
|
+
| `orchestra accounts list` | List the workspaces your login or API key covers, with their ids, as JSON. |
|
|
60
|
+
| `orchestra accounts use [id\|name]` | Save the workspace later commands act in when no `--account-id` is given. |
|
|
57
61
|
|
|
58
62
|
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
63
|
|
|
@@ -112,6 +116,20 @@ pipeline:
|
|
|
112
116
|
|
|
113
117
|
---
|
|
114
118
|
|
|
119
|
+
## login
|
|
120
|
+
|
|
121
|
+
Log in through your browser instead of pasting an API key. The token is cached in `~/.orchestra/credentials.json` (readable only by you) and refreshed automatically, so later commands need no `ORCHESTRA_API_KEY`.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
orchestra login
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Logins are per host: a login made with `BASE_URL` pointing at another environment is only used against that environment. CI and scripts, where nobody is logged in, keep using `ORCHESTRA_API_KEY`.
|
|
128
|
+
|
|
129
|
+
After logging in it saves a default workspace, as `accounts use` does: the only one if your login covers one, or the one you pick from a list if it covers several. Esc skips the default, and without a terminal it prints a hint to run `orchestra accounts use` instead. If the accounts can't be listed, the login still succeeds with no default set.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
115
133
|
## pipeline import
|
|
116
134
|
|
|
117
135
|
Create (import) a pipeline in Orchestra by referencing a YAML file inside a git repository. The command infers your repository host/provider, default branch, and YAML path relative to the repo root.
|
|
@@ -400,6 +418,43 @@ Behavior
|
|
|
400
418
|
|
|
401
419
|
---
|
|
402
420
|
|
|
421
|
+
## accounts list
|
|
422
|
+
|
|
423
|
+
List the workspaces the current credential covers. An `orchestra login` token can cover several workspaces; an API key lists just its own.
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
orchestra accounts list
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Behavior
|
|
430
|
+
|
|
431
|
+
- Sends `GET /public/v1/accounts`, with no account header.
|
|
432
|
+
- Prints the `[{id, name}]` response as pretty JSON, adding `default: true` to the account saved by `accounts use` and `false` to the rest.
|
|
433
|
+
- Exit codes: `0` on success, `1` on failure.
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## accounts use
|
|
438
|
+
|
|
439
|
+
Save a default workspace for an `orchestra login` that covers several, so commands no longer need `--account-id`.
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
orchestra accounts use 'some great account'
|
|
443
|
+
orchestra accounts use 00000000-0000-0000-0000-000000000000
|
|
444
|
+
orchestra accounts use # pick from a list
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Behavior
|
|
448
|
+
|
|
449
|
+
- Fetches the accounts as `accounts list` does, then matches an exact id first and a case-insensitive exact name second.
|
|
450
|
+
- Exits `1`, listing the valid names, when nothing matches, and asks for the id when several workspaces share the name.
|
|
451
|
+
- With no argument, lists the workspaces with the cursor on the current default: ↑/↓ moves, Enter saves, and Esc, Ctrl+C or Ctrl+D exits `1` leaving the default unchanged. Without a terminal (CI, piped input) it exits `1` and asks for an id or name instead.
|
|
452
|
+
- Saves the account into the login's entry in `~/.orchestra/credentials.json`. It survives token refreshes; running `orchestra login` again resets it.
|
|
453
|
+
- `--account-id` and `ORCHESTRA_ACCOUNT_ID` still override the default. It is never sent with an API key.
|
|
454
|
+
- Exits `1` when you are using an API key rather than a login, since a key covers one account.
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
403
458
|
## task logs
|
|
404
459
|
|
|
405
460
|
Fetch or follow logs for a single task run.
|
|
@@ -20,15 +20,17 @@ pipx install orchestra-cli
|
|
|
20
20
|
|
|
21
21
|
## Environment variables
|
|
22
22
|
|
|
23
|
-
- `ORCHESTRA_API_KEY`:
|
|
23
|
+
- `ORCHESTRA_API_KEY`: Credential for actions that call the API (`pipeline import`, `pipeline new`, `pipeline update`, `pipeline migrate`, `pipeline get`, `pipeline list`, `pipeline delete`, `pipeline run`, `pipeline build`, `accounts list`). Not needed once you have run `orchestra login`: a login takes precedence, and the key is used only when you are not logged in or your login has expired.
|
|
24
|
+
- `ORCHESTRA_ACCOUNT_ID`: Optional. The workspace to act in when your `orchestra login` covers several. Every `pipeline` and `task` command that calls the API also takes `--account-id`, which wins over the variable, and both win over the default saved by `orchestra accounts use`. API keys belong to one account and don't need it.
|
|
24
25
|
- `BASE_URL`: Optional. Override the default Orchestra host (`https://app.getorchestra.io`) for non‑production/testing.
|
|
25
26
|
|
|
26
27
|
## Command structure
|
|
27
28
|
|
|
28
|
-
Commands follow a `noun verb` shape. The current nouns are `pipeline` and `
|
|
29
|
+
Commands follow a `noun verb` shape. The current nouns are `pipeline`, `task` and `accounts`:
|
|
29
30
|
|
|
30
31
|
| Command | Description |
|
|
31
32
|
| ------------------------------------ | ------------------------------------------------------------------------------------------- |
|
|
33
|
+
| `orchestra login` | Log in through your browser so later commands need no API key. |
|
|
32
34
|
| `orchestra pipeline validate <file>` | Validate a pipeline YAML locally against the Orchestra API schema. |
|
|
33
35
|
| `orchestra pipeline import` | Register a pipeline YAML (from a git repo) with Orchestra under an alias. |
|
|
34
36
|
| `orchestra pipeline get` | Fetch one pipeline by path, alias, or pipeline ID. |
|
|
@@ -40,6 +42,8 @@ Commands follow a `noun verb` shape. The current nouns are `pipeline` and `task`
|
|
|
40
42
|
| `orchestra pipeline run` | Start a pipeline run by selector, optionally pinning branch/commit and waiting. |
|
|
41
43
|
| `orchestra pipeline build` | Validate local YAML, create or update a draft pipeline, and start that draft version. |
|
|
42
44
|
| `orchestra task logs` | Fetch or follow logs for a single task run. |
|
|
45
|
+
| `orchestra accounts list` | List the workspaces your login or API key covers, with their ids, as JSON. |
|
|
46
|
+
| `orchestra accounts use [id\|name]` | Save the workspace later commands act in when no `--account-id` is given. |
|
|
43
47
|
|
|
44
48
|
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
49
|
|
|
@@ -98,6 +102,20 @@ pipeline:
|
|
|
98
102
|
|
|
99
103
|
---
|
|
100
104
|
|
|
105
|
+
## login
|
|
106
|
+
|
|
107
|
+
Log in through your browser instead of pasting an API key. The token is cached in `~/.orchestra/credentials.json` (readable only by you) and refreshed automatically, so later commands need no `ORCHESTRA_API_KEY`.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
orchestra login
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Logins are per host: a login made with `BASE_URL` pointing at another environment is only used against that environment. CI and scripts, where nobody is logged in, keep using `ORCHESTRA_API_KEY`.
|
|
114
|
+
|
|
115
|
+
After logging in it saves a default workspace, as `accounts use` does: the only one if your login covers one, or the one you pick from a list if it covers several. Esc skips the default, and without a terminal it prints a hint to run `orchestra accounts use` instead. If the accounts can't be listed, the login still succeeds with no default set.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
101
119
|
## pipeline import
|
|
102
120
|
|
|
103
121
|
Create (import) a pipeline in Orchestra by referencing a YAML file inside a git repository. The command infers your repository host/provider, default branch, and YAML path relative to the repo root.
|
|
@@ -386,6 +404,43 @@ Behavior
|
|
|
386
404
|
|
|
387
405
|
---
|
|
388
406
|
|
|
407
|
+
## accounts list
|
|
408
|
+
|
|
409
|
+
List the workspaces the current credential covers. An `orchestra login` token can cover several workspaces; an API key lists just its own.
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
orchestra accounts list
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Behavior
|
|
416
|
+
|
|
417
|
+
- Sends `GET /public/v1/accounts`, with no account header.
|
|
418
|
+
- Prints the `[{id, name}]` response as pretty JSON, adding `default: true` to the account saved by `accounts use` and `false` to the rest.
|
|
419
|
+
- Exit codes: `0` on success, `1` on failure.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## accounts use
|
|
424
|
+
|
|
425
|
+
Save a default workspace for an `orchestra login` that covers several, so commands no longer need `--account-id`.
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
orchestra accounts use 'some great account'
|
|
429
|
+
orchestra accounts use 00000000-0000-0000-0000-000000000000
|
|
430
|
+
orchestra accounts use # pick from a list
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Behavior
|
|
434
|
+
|
|
435
|
+
- Fetches the accounts as `accounts list` does, then matches an exact id first and a case-insensitive exact name second.
|
|
436
|
+
- Exits `1`, listing the valid names, when nothing matches, and asks for the id when several workspaces share the name.
|
|
437
|
+
- With no argument, lists the workspaces with the cursor on the current default: ↑/↓ moves, Enter saves, and Esc, Ctrl+C or Ctrl+D exits `1` leaving the default unchanged. Without a terminal (CI, piped input) it exits `1` and asks for an id or name instead.
|
|
438
|
+
- Saves the account into the login's entry in `~/.orchestra/credentials.json`. It survives token refreshes; running `orchestra login` again resets it.
|
|
439
|
+
- `--account-id` and `ORCHESTRA_ACCOUNT_ID` still override the default. It is never sent with an API key.
|
|
440
|
+
- Exits `1` when you are using an API key rather than a login, since a key covers one account.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
389
444
|
## task logs
|
|
390
445
|
|
|
391
446
|
Fetch or follow logs for a single task run.
|
|
@@ -3,7 +3,13 @@ from pathlib import Path
|
|
|
3
3
|
import httpx
|
|
4
4
|
import typer
|
|
5
5
|
|
|
6
|
-
from ..utils.api import
|
|
6
|
+
from ..utils.api import (
|
|
7
|
+
account_id_option,
|
|
8
|
+
api_client,
|
|
9
|
+
fail_with_response,
|
|
10
|
+
request_or_exit,
|
|
11
|
+
require_credential,
|
|
12
|
+
)
|
|
7
13
|
from ..utils.constants import get_create_pipeline_url, get_update_pipeline_url
|
|
8
14
|
from ..utils.git import confirm_git_warnings_or_exit, prepare_git_backed_run_target
|
|
9
15
|
from ..utils.pipeline_lookup import lookup_existing_pipeline
|
|
@@ -64,22 +70,20 @@ def _build_create_selector(
|
|
|
64
70
|
|
|
65
71
|
|
|
66
72
|
def _create_draft_pipeline(
|
|
73
|
+
client: httpx.Client,
|
|
67
74
|
path: Path,
|
|
68
75
|
lookup_selector: PipelineSelector,
|
|
69
76
|
pipeline_data: dict[str, object],
|
|
70
77
|
force: bool,
|
|
71
|
-
api_key: str,
|
|
72
78
|
) -> tuple[PipelineSelector, int]:
|
|
73
79
|
create_selector = _build_create_selector(path, lookup_selector, force)
|
|
74
80
|
payload = build_upsert_payload(pipeline_data, publish=False, selector=create_selector)
|
|
75
81
|
|
|
76
82
|
typer.echo(f"Creating draft pipeline ({create_selector.display()})")
|
|
77
83
|
create_response = request_or_exit(
|
|
78
|
-
|
|
84
|
+
client.post,
|
|
79
85
|
get_create_pipeline_url(),
|
|
80
86
|
json=payload,
|
|
81
|
-
timeout=30,
|
|
82
|
-
headers=auth_headers(api_key),
|
|
83
87
|
)
|
|
84
88
|
|
|
85
89
|
if create_response.status_code == 201:
|
|
@@ -96,20 +100,18 @@ def _create_draft_pipeline(
|
|
|
96
100
|
|
|
97
101
|
|
|
98
102
|
def _update_draft_pipeline(
|
|
103
|
+
client: httpx.Client,
|
|
99
104
|
existing_pipeline: dict[str, object],
|
|
100
105
|
pipeline_data: dict[str, object],
|
|
101
|
-
api_key: str,
|
|
102
106
|
) -> tuple[PipelineSelector, int]:
|
|
103
107
|
update_selector = build_update_selector(existing_pipeline, "Build")
|
|
104
108
|
payload = build_upsert_payload(pipeline_data, publish=False, selector=update_selector)
|
|
105
109
|
|
|
106
110
|
typer.echo(f"Updating draft pipeline ({update_selector.display()})")
|
|
107
111
|
update_response = request_or_exit(
|
|
108
|
-
|
|
112
|
+
client.put,
|
|
109
113
|
get_update_pipeline_url(),
|
|
110
114
|
json=payload,
|
|
111
|
-
timeout=30,
|
|
112
|
-
headers=auth_headers(api_key),
|
|
113
115
|
)
|
|
114
116
|
|
|
115
117
|
if update_response.status_code == 200:
|
|
@@ -141,11 +143,13 @@ def build_pipeline(
|
|
|
141
143
|
"--force/--no-force",
|
|
142
144
|
help="Ignore any warnings and run the pipeline anyway",
|
|
143
145
|
),
|
|
146
|
+
account_id: str | None = account_id_option(),
|
|
144
147
|
) -> None:
|
|
145
148
|
"""
|
|
146
149
|
Validate local YAML, create or update a draft pipeline, and start the draft version.
|
|
147
150
|
"""
|
|
148
|
-
|
|
151
|
+
require_credential()
|
|
152
|
+
client = api_client(account_id)
|
|
149
153
|
if path is None:
|
|
150
154
|
typer.echo(
|
|
151
155
|
red("A pipeline YAML file path is required (use -p or --path with your YAML file)"),
|
|
@@ -155,19 +159,19 @@ def build_pipeline(
|
|
|
155
159
|
|
|
156
160
|
confirm_git_warnings_or_exit(force, path)
|
|
157
161
|
pipeline_data = load_validated_pipeline_data(path)
|
|
158
|
-
existing_pipeline = lookup_existing_pipeline(
|
|
162
|
+
existing_pipeline = lookup_existing_pipeline(client, lookup_selector, "Build", allow_404=True)
|
|
159
163
|
|
|
160
164
|
if existing_pipeline is None:
|
|
161
165
|
run_selector, version_number = _create_draft_pipeline(
|
|
166
|
+
client=client,
|
|
162
167
|
path=path,
|
|
163
168
|
lookup_selector=lookup_selector,
|
|
164
169
|
pipeline_data=pipeline_data,
|
|
165
170
|
force=force,
|
|
166
|
-
api_key=api_key,
|
|
167
171
|
)
|
|
168
172
|
start_pipeline_run(
|
|
173
|
+
client=client,
|
|
169
174
|
selector=run_selector,
|
|
170
|
-
api_key=api_key,
|
|
171
175
|
payload=build_run_payload(
|
|
172
176
|
branch=branch,
|
|
173
177
|
commit=commit,
|
|
@@ -181,14 +185,14 @@ def build_pipeline(
|
|
|
181
185
|
pipeline_storage_provider = storage_provider(existing_pipeline)
|
|
182
186
|
if pipeline_storage_provider is None or pipeline_storage_provider == "ORCHESTRA":
|
|
183
187
|
run_selector, version_number = _update_draft_pipeline(
|
|
188
|
+
client=client,
|
|
184
189
|
existing_pipeline=existing_pipeline,
|
|
185
190
|
pipeline_data=pipeline_data,
|
|
186
|
-
api_key=api_key,
|
|
187
191
|
)
|
|
188
192
|
|
|
189
193
|
start_pipeline_run(
|
|
194
|
+
client=client,
|
|
190
195
|
selector=run_selector,
|
|
191
|
-
api_key=api_key,
|
|
192
196
|
payload=build_run_payload(
|
|
193
197
|
branch=branch,
|
|
194
198
|
commit=commit,
|
|
@@ -221,8 +225,8 @@ def build_pipeline(
|
|
|
221
225
|
)
|
|
222
226
|
|
|
223
227
|
start_pipeline_run(
|
|
228
|
+
client=client,
|
|
224
229
|
selector=run_selector,
|
|
225
|
-
api_key=api_key,
|
|
226
230
|
payload=build_run_payload(
|
|
227
231
|
branch=git_branch,
|
|
228
232
|
commit=git_commit,
|
|
@@ -6,10 +6,13 @@ from .delete_pipeline import delete_pipeline
|
|
|
6
6
|
from .fetch_pipelines import fetch_pipelines
|
|
7
7
|
from .get_pipeline import get_pipeline
|
|
8
8
|
from .import_pipeline import import_pipeline
|
|
9
|
+
from .list_accounts import list_accounts
|
|
10
|
+
from .login import login
|
|
9
11
|
from .migrate_pipeline import migrate_pipeline
|
|
10
12
|
from .run_pipeline import run_pipeline
|
|
11
13
|
from .task_logs import task_logs
|
|
12
14
|
from .update_pipeline import update_pipeline
|
|
15
|
+
from .use_account import use_account
|
|
13
16
|
from .validate_pipeline import validate
|
|
14
17
|
|
|
15
18
|
app = typer.Typer(help="Orchestra CLI – perform operations with Orchestra locally.")
|
|
@@ -18,6 +21,9 @@ pipeline_app = typer.Typer(help="Manage Orchestra pipelines (validate, import, r
|
|
|
18
21
|
app.add_typer(pipeline_app, name="pipeline")
|
|
19
22
|
task_app = typer.Typer(help="Inspect Orchestra task runs.")
|
|
20
23
|
app.add_typer(task_app, name="task")
|
|
24
|
+
app.command(name="login")(login)
|
|
25
|
+
accounts_app = typer.Typer(help="List and choose the workspaces your credential covers.")
|
|
26
|
+
app.add_typer(accounts_app, name="accounts")
|
|
21
27
|
|
|
22
28
|
pipeline_app.command(name="validate")(validate)
|
|
23
29
|
pipeline_app.command(name="import")(import_pipeline)
|
|
@@ -30,6 +36,8 @@ pipeline_app.command(name="build")(build_pipeline)
|
|
|
30
36
|
pipeline_app.command(name="delete")(delete_pipeline)
|
|
31
37
|
pipeline_app.command(name="migrate")(migrate_pipeline)
|
|
32
38
|
task_app.command(name="logs")(task_logs)
|
|
39
|
+
accounts_app.command(name="list")(list_accounts)
|
|
40
|
+
accounts_app.command(name="use")(use_account)
|
|
33
41
|
|
|
34
42
|
# Legacy top-level aliases (hidden) - keep the old `orchestra <command>` syntax working
|
|
35
43
|
# so existing scripts and CI pipelines do not break. Hidden from `--help` to keep the
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
import httpx
|
|
4
3
|
import typer
|
|
5
4
|
|
|
6
5
|
from ..utils.api import (
|
|
7
|
-
|
|
6
|
+
account_id_option,
|
|
7
|
+
api_client,
|
|
8
8
|
fail_with_response,
|
|
9
9
|
request_or_exit,
|
|
10
|
-
|
|
10
|
+
require_credential,
|
|
11
11
|
)
|
|
12
12
|
from ..utils.constants import get_create_pipeline_url
|
|
13
13
|
from ..utils.pipeline_selector import (
|
|
@@ -32,11 +32,13 @@ def create_pipeline(
|
|
|
32
32
|
"--publish/--no-publish",
|
|
33
33
|
help="Whether the pipeline is published and can be triggered",
|
|
34
34
|
),
|
|
35
|
+
account_id: str | None = account_id_option(),
|
|
35
36
|
):
|
|
36
37
|
"""
|
|
37
38
|
Create an Orchestra-backed pipeline from a local YAML file.
|
|
38
39
|
"""
|
|
39
|
-
|
|
40
|
+
require_credential()
|
|
41
|
+
client = api_client(account_id)
|
|
40
42
|
if path is None:
|
|
41
43
|
typer.echo(red("Provide --path to create a pipeline from YAML"))
|
|
42
44
|
raise typer.Exit(code=1)
|
|
@@ -50,11 +52,9 @@ def create_pipeline(
|
|
|
50
52
|
payload = build_upsert_payload(data, publish, selector)
|
|
51
53
|
|
|
52
54
|
response = request_or_exit(
|
|
53
|
-
|
|
55
|
+
client.post,
|
|
54
56
|
get_create_pipeline_url(),
|
|
55
57
|
json=payload,
|
|
56
|
-
timeout=30,
|
|
57
|
-
headers=auth_headers(api_key),
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
if response.status_code == 201:
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
import httpx
|
|
4
3
|
import typer
|
|
5
4
|
|
|
6
5
|
from ..utils.api import (
|
|
7
|
-
|
|
6
|
+
account_id_option,
|
|
7
|
+
api_client,
|
|
8
8
|
fail_with_response,
|
|
9
9
|
request_or_exit,
|
|
10
|
-
|
|
10
|
+
require_credential,
|
|
11
11
|
)
|
|
12
12
|
from ..utils.constants import get_delete_pipeline_url
|
|
13
13
|
from ..utils.pipeline_selector import (
|
|
@@ -23,11 +23,13 @@ def delete_pipeline(
|
|
|
23
23
|
path: Path | None = pipeline_path_option(),
|
|
24
24
|
alias: str | None = pipeline_alias_option(),
|
|
25
25
|
pipeline_id: str | None = pipeline_id_option(),
|
|
26
|
+
account_id: str | None = account_id_option(),
|
|
26
27
|
):
|
|
27
28
|
"""
|
|
28
29
|
Delete a pipeline by selector.
|
|
29
30
|
"""
|
|
30
|
-
|
|
31
|
+
require_credential()
|
|
32
|
+
client = api_client(account_id)
|
|
31
33
|
selector = resolve_pipeline_selector(alias, pipeline_id, path)
|
|
32
34
|
|
|
33
35
|
if not typer.confirm(f"Delete pipeline ({selector.display()})?"):
|
|
@@ -35,11 +37,9 @@ def delete_pipeline(
|
|
|
35
37
|
raise typer.Exit(code=1)
|
|
36
38
|
|
|
37
39
|
response = request_or_exit(
|
|
38
|
-
|
|
40
|
+
client.delete,
|
|
39
41
|
get_delete_pipeline_url(),
|
|
40
42
|
params=selector.to_payload(),
|
|
41
|
-
timeout=30,
|
|
42
|
-
headers=auth_headers(api_key),
|
|
43
43
|
)
|
|
44
44
|
|
|
45
45
|
if response.status_code == 204:
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
|
-
import httpx
|
|
4
3
|
import typer
|
|
5
4
|
|
|
6
5
|
from ..utils.api import (
|
|
7
|
-
|
|
6
|
+
account_id_option,
|
|
7
|
+
api_client,
|
|
8
8
|
fail_with_response,
|
|
9
9
|
request_or_exit,
|
|
10
|
-
|
|
10
|
+
require_credential,
|
|
11
11
|
)
|
|
12
12
|
from ..utils.constants import get_api_url
|
|
13
13
|
from ..utils.styling import indent_message, red, yellow
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def fetch_pipelines():
|
|
16
|
+
def fetch_pipelines(account_id: str | None = account_id_option()):
|
|
17
17
|
"""
|
|
18
18
|
Fetch pipelines available to the current Orchestra API key.
|
|
19
19
|
|
|
20
20
|
The API always includes each pipeline's latest run metadata.
|
|
21
21
|
"""
|
|
22
|
-
|
|
22
|
+
require_credential()
|
|
23
|
+
client = api_client(account_id)
|
|
23
24
|
|
|
24
25
|
response = request_or_exit(
|
|
25
|
-
|
|
26
|
+
client.get,
|
|
26
27
|
get_api_url("pipelines"),
|
|
27
|
-
timeout=30,
|
|
28
|
-
headers=auth_headers(api_key),
|
|
29
28
|
)
|
|
30
29
|
|
|
31
30
|
if response.status_code == 200:
|
|
@@ -3,14 +3,14 @@ import re
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import cast
|
|
5
5
|
|
|
6
|
-
import httpx
|
|
7
6
|
import typer
|
|
8
7
|
|
|
9
8
|
from ..utils.api import (
|
|
10
|
-
|
|
9
|
+
account_id_option,
|
|
10
|
+
api_client,
|
|
11
11
|
fail_with_response,
|
|
12
12
|
request_or_exit,
|
|
13
|
-
|
|
13
|
+
require_credential,
|
|
14
14
|
)
|
|
15
15
|
from ..utils.constants import get_pipeline_url
|
|
16
16
|
from ..utils.pipeline_selector import (
|
|
@@ -46,19 +46,19 @@ def get_pipeline(
|
|
|
46
46
|
path: Path | None = pipeline_path_option(),
|
|
47
47
|
alias: str | None = pipeline_alias_option(),
|
|
48
48
|
pipeline_id: str | None = pipeline_id_option(),
|
|
49
|
+
account_id: str | None = account_id_option(),
|
|
49
50
|
):
|
|
50
51
|
"""
|
|
51
52
|
Fetch one pipeline using the shared selector model.
|
|
52
53
|
"""
|
|
53
|
-
|
|
54
|
+
require_credential()
|
|
55
|
+
client = api_client(account_id)
|
|
54
56
|
selector = resolve_pipeline_selector(alias, pipeline_id, path)
|
|
55
57
|
|
|
56
58
|
response = request_or_exit(
|
|
57
|
-
|
|
59
|
+
client.get,
|
|
58
60
|
get_pipeline_url(),
|
|
59
61
|
params=selector.to_payload(),
|
|
60
|
-
timeout=30,
|
|
61
|
-
headers=auth_headers(api_key),
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
if response.status_code == 200:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
-
import httpx
|
|
5
4
|
import typer
|
|
6
5
|
|
|
7
6
|
from ..utils.api import (
|
|
8
|
-
|
|
7
|
+
account_id_option,
|
|
8
|
+
api_client,
|
|
9
9
|
fail_with_response,
|
|
10
10
|
request_or_exit,
|
|
11
|
-
|
|
11
|
+
require_credential,
|
|
12
12
|
)
|
|
13
13
|
from ..utils.constants import get_api_url
|
|
14
14
|
from ..utils.git import (
|
|
@@ -39,11 +39,13 @@ def import_pipeline(
|
|
|
39
39
|
"-w",
|
|
40
40
|
help="Git branch to use for the imported pipeline (defaults to current local branch)",
|
|
41
41
|
),
|
|
42
|
+
account_id: str | None = account_id_option(),
|
|
42
43
|
):
|
|
43
44
|
"""
|
|
44
45
|
Create a pipeline in Orchestra by referencing a YAML file in your git repository.
|
|
45
46
|
"""
|
|
46
|
-
|
|
47
|
+
require_credential()
|
|
48
|
+
client = api_client(account_id)
|
|
47
49
|
if path is None:
|
|
48
50
|
typer.echo(red("Provide --path to import a pipeline from git"))
|
|
49
51
|
raise typer.Exit(code=1)
|
|
@@ -98,11 +100,9 @@ def import_pipeline(
|
|
|
98
100
|
payload["alias"] = alias
|
|
99
101
|
|
|
100
102
|
response = request_or_exit(
|
|
101
|
-
|
|
103
|
+
client.post,
|
|
102
104
|
get_api_url("pipelines/import"),
|
|
103
105
|
json=payload,
|
|
104
|
-
timeout=30,
|
|
105
|
-
headers=auth_headers(api_key),
|
|
106
106
|
)
|
|
107
107
|
|
|
108
108
|
if response.status_code == 201:
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from ..utils.accounts import fetch_accounts
|
|
6
|
+
from ..utils.api import api_client
|
|
7
|
+
from ..utils.credentials import load_credentials
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def list_accounts():
|
|
11
|
+
"""List the Orchestra workspaces the current login or API key covers."""
|
|
12
|
+
accounts = fetch_accounts(api_client(scoped=False))
|
|
13
|
+
# Read after fetching, which forgets a dead login whose default no longer applies.
|
|
14
|
+
default_id = (load_credentials() or {}).get("account_id")
|
|
15
|
+
accounts = [{**account, "default": account["id"] == default_id} for account in accounts]
|
|
16
|
+
typer.echo(json.dumps(accounts, indent=2))
|