pltr-cli 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- pltr/cli.py +10 -0
- pltr/commands/dataset.py +309 -0
- pltr/commands/folder.py +338 -0
- pltr/commands/mediasets.py +422 -0
- pltr/commands/orchestration.py +642 -0
- pltr/services/dataset.py +368 -10
- pltr/services/folder.py +167 -0
- pltr/services/mediasets.py +293 -0
- pltr/services/orchestration.py +457 -0
- pltr/utils/formatting.py +638 -0
- {pltr_cli-0.3.0.dist-info → pltr_cli-0.5.0.dist-info}/METADATA +139 -5
- {pltr_cli-0.3.0.dist-info → pltr_cli-0.5.0.dist-info}/RECORD +15 -11
- pltr/services/dataset_full.py +0 -302
- pltr/services/dataset_v2.py +0 -128
- {pltr_cli-0.3.0.dist-info → pltr_cli-0.5.0.dist-info}/WHEEL +0 -0
- {pltr_cli-0.3.0.dist-info → pltr_cli-0.5.0.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.3.0.dist-info → pltr_cli-0.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Orchestration commands for managing builds, jobs, and schedules.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
import json
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
from ..services.orchestration import OrchestrationService
|
|
11
|
+
from ..utils.formatting import OutputFormatter
|
|
12
|
+
from ..utils.progress import SpinnerProgressTracker
|
|
13
|
+
from ..auth.base import ProfileNotFoundError, MissingCredentialsError
|
|
14
|
+
from ..utils.completion import (
|
|
15
|
+
complete_rid,
|
|
16
|
+
complete_profile,
|
|
17
|
+
complete_output_format,
|
|
18
|
+
cache_rid,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
app = typer.Typer()
|
|
22
|
+
console = Console()
|
|
23
|
+
formatter = OutputFormatter(console)
|
|
24
|
+
|
|
25
|
+
# Create sub-apps for different orchestration components
|
|
26
|
+
builds_app = typer.Typer()
|
|
27
|
+
jobs_app = typer.Typer()
|
|
28
|
+
schedules_app = typer.Typer()
|
|
29
|
+
|
|
30
|
+
# ============================================================================
|
|
31
|
+
# Build Commands
|
|
32
|
+
# ============================================================================
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@builds_app.command("get")
|
|
36
|
+
def get_build(
|
|
37
|
+
build_rid: str = typer.Argument(
|
|
38
|
+
..., help="Build Resource Identifier", autocompletion=complete_rid
|
|
39
|
+
),
|
|
40
|
+
profile: Optional[str] = typer.Option(
|
|
41
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
42
|
+
),
|
|
43
|
+
format: str = typer.Option(
|
|
44
|
+
"table",
|
|
45
|
+
"--format",
|
|
46
|
+
"-f",
|
|
47
|
+
help="Output format (table, json, csv)",
|
|
48
|
+
autocompletion=complete_output_format,
|
|
49
|
+
),
|
|
50
|
+
output: Optional[str] = typer.Option(
|
|
51
|
+
None, "--output", "-o", help="Output file path"
|
|
52
|
+
),
|
|
53
|
+
):
|
|
54
|
+
"""Get detailed information about a specific build."""
|
|
55
|
+
try:
|
|
56
|
+
cache_rid(build_rid)
|
|
57
|
+
service = OrchestrationService(profile=profile)
|
|
58
|
+
|
|
59
|
+
with SpinnerProgressTracker().track_spinner(f"Fetching build {build_rid}..."):
|
|
60
|
+
build = service.get_build(build_rid)
|
|
61
|
+
|
|
62
|
+
formatter.format_build_detail(build, format, output)
|
|
63
|
+
|
|
64
|
+
if output:
|
|
65
|
+
formatter.print_success(f"Build information saved to {output}")
|
|
66
|
+
|
|
67
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
68
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
69
|
+
raise typer.Exit(1)
|
|
70
|
+
except Exception as e:
|
|
71
|
+
formatter.print_error(f"Failed to get build: {e}")
|
|
72
|
+
raise typer.Exit(1)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@builds_app.command("create")
|
|
76
|
+
def create_build(
|
|
77
|
+
target: str = typer.Argument(..., help="Build target (JSON format)"),
|
|
78
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
79
|
+
branch_name: Optional[str] = typer.Option(
|
|
80
|
+
None, "--branch", help="Branch name for the build"
|
|
81
|
+
),
|
|
82
|
+
force_build: bool = typer.Option(
|
|
83
|
+
False, "--force", help="Force build even if no changes"
|
|
84
|
+
),
|
|
85
|
+
abort_on_failure: bool = typer.Option(
|
|
86
|
+
False, "--abort-on-failure", help="Abort on failure"
|
|
87
|
+
),
|
|
88
|
+
notifications: bool = typer.Option(
|
|
89
|
+
True, "--notifications/--no-notifications", help="Enable notifications"
|
|
90
|
+
),
|
|
91
|
+
format: str = typer.Option(
|
|
92
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
93
|
+
),
|
|
94
|
+
):
|
|
95
|
+
"""Create a new build."""
|
|
96
|
+
try:
|
|
97
|
+
service = OrchestrationService(profile=profile)
|
|
98
|
+
|
|
99
|
+
# Parse target JSON
|
|
100
|
+
try:
|
|
101
|
+
target_dict = json.loads(target)
|
|
102
|
+
except json.JSONDecodeError:
|
|
103
|
+
formatter.print_error("Invalid JSON format for target")
|
|
104
|
+
raise typer.Exit(1)
|
|
105
|
+
|
|
106
|
+
with SpinnerProgressTracker().track_spinner("Creating build..."):
|
|
107
|
+
build = service.create_build(
|
|
108
|
+
target=target_dict,
|
|
109
|
+
branch_name=branch_name,
|
|
110
|
+
force_build=force_build,
|
|
111
|
+
abort_on_failure=abort_on_failure,
|
|
112
|
+
notifications_enabled=notifications,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
formatter.print_success("Successfully created build")
|
|
116
|
+
formatter.print_info(f"Build RID: {build.get('rid', 'unknown')}")
|
|
117
|
+
formatter.format_build_detail(build, format)
|
|
118
|
+
|
|
119
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
120
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
121
|
+
raise typer.Exit(1)
|
|
122
|
+
except Exception as e:
|
|
123
|
+
formatter.print_error(f"Failed to create build: {e}")
|
|
124
|
+
raise typer.Exit(1)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@builds_app.command("cancel")
|
|
128
|
+
def cancel_build(
|
|
129
|
+
build_rid: str = typer.Argument(
|
|
130
|
+
..., help="Build Resource Identifier", autocompletion=complete_rid
|
|
131
|
+
),
|
|
132
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
133
|
+
):
|
|
134
|
+
"""Cancel a build and all its unfinished jobs."""
|
|
135
|
+
try:
|
|
136
|
+
service = OrchestrationService(profile=profile)
|
|
137
|
+
|
|
138
|
+
with SpinnerProgressTracker().track_spinner(f"Cancelling build {build_rid}..."):
|
|
139
|
+
service.cancel_build(build_rid)
|
|
140
|
+
|
|
141
|
+
formatter.print_success(f"Successfully cancelled build {build_rid}")
|
|
142
|
+
|
|
143
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
144
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
145
|
+
raise typer.Exit(1)
|
|
146
|
+
except Exception as e:
|
|
147
|
+
formatter.print_error(f"Failed to cancel build: {e}")
|
|
148
|
+
raise typer.Exit(1)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@builds_app.command("jobs")
|
|
152
|
+
def get_build_jobs(
|
|
153
|
+
build_rid: str = typer.Argument(
|
|
154
|
+
..., help="Build Resource Identifier", autocompletion=complete_rid
|
|
155
|
+
),
|
|
156
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
157
|
+
page_size: Optional[int] = typer.Option(
|
|
158
|
+
None, "--page-size", help="Number of results per page"
|
|
159
|
+
),
|
|
160
|
+
format: str = typer.Option(
|
|
161
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
162
|
+
),
|
|
163
|
+
output: Optional[str] = typer.Option(
|
|
164
|
+
None, "--output", "-o", help="Output file path"
|
|
165
|
+
),
|
|
166
|
+
):
|
|
167
|
+
"""List all jobs in a build."""
|
|
168
|
+
try:
|
|
169
|
+
cache_rid(build_rid)
|
|
170
|
+
service = OrchestrationService(profile=profile)
|
|
171
|
+
|
|
172
|
+
with SpinnerProgressTracker().track_spinner(
|
|
173
|
+
f"Fetching jobs for build {build_rid}..."
|
|
174
|
+
):
|
|
175
|
+
response = service.get_build_jobs(build_rid, page_size=page_size)
|
|
176
|
+
|
|
177
|
+
jobs = response.get("jobs", [])
|
|
178
|
+
|
|
179
|
+
if not jobs:
|
|
180
|
+
formatter.print_warning("No jobs found for this build")
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
formatter.format_jobs_list(jobs, format, output)
|
|
184
|
+
|
|
185
|
+
if output:
|
|
186
|
+
formatter.print_success(f"Jobs list saved to {output}")
|
|
187
|
+
|
|
188
|
+
if response.get("next_page_token"):
|
|
189
|
+
formatter.print_info(
|
|
190
|
+
"More results available. Use pagination token to fetch next page."
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
194
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
195
|
+
raise typer.Exit(1)
|
|
196
|
+
except Exception as e:
|
|
197
|
+
formatter.print_error(f"Failed to get build jobs: {e}")
|
|
198
|
+
raise typer.Exit(1)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@builds_app.command("search")
|
|
202
|
+
def search_builds(
|
|
203
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
204
|
+
page_size: Optional[int] = typer.Option(
|
|
205
|
+
None, "--page-size", help="Number of results per page"
|
|
206
|
+
),
|
|
207
|
+
format: str = typer.Option(
|
|
208
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
209
|
+
),
|
|
210
|
+
output: Optional[str] = typer.Option(
|
|
211
|
+
None, "--output", "-o", help="Output file path"
|
|
212
|
+
),
|
|
213
|
+
):
|
|
214
|
+
"""Search for builds."""
|
|
215
|
+
try:
|
|
216
|
+
service = OrchestrationService(profile=profile)
|
|
217
|
+
|
|
218
|
+
with SpinnerProgressTracker().track_spinner("Searching builds..."):
|
|
219
|
+
response = service.search_builds(page_size=page_size)
|
|
220
|
+
|
|
221
|
+
builds = response.get("builds", [])
|
|
222
|
+
|
|
223
|
+
if not builds:
|
|
224
|
+
formatter.print_warning("No builds found")
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
formatter.format_builds_list(builds, format, output)
|
|
228
|
+
|
|
229
|
+
if output:
|
|
230
|
+
formatter.print_success(f"Builds list saved to {output}")
|
|
231
|
+
|
|
232
|
+
if response.get("next_page_token"):
|
|
233
|
+
formatter.print_info(
|
|
234
|
+
"More results available. Use pagination token to fetch next page."
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
238
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
239
|
+
raise typer.Exit(1)
|
|
240
|
+
except Exception as e:
|
|
241
|
+
formatter.print_error(f"Failed to search builds: {e}")
|
|
242
|
+
raise typer.Exit(1)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# ============================================================================
|
|
246
|
+
# Job Commands
|
|
247
|
+
# ============================================================================
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@jobs_app.command("get")
|
|
251
|
+
def get_job(
|
|
252
|
+
job_rid: str = typer.Argument(
|
|
253
|
+
..., help="Job Resource Identifier", autocompletion=complete_rid
|
|
254
|
+
),
|
|
255
|
+
profile: Optional[str] = typer.Option(
|
|
256
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
257
|
+
),
|
|
258
|
+
format: str = typer.Option(
|
|
259
|
+
"table",
|
|
260
|
+
"--format",
|
|
261
|
+
"-f",
|
|
262
|
+
help="Output format (table, json, csv)",
|
|
263
|
+
autocompletion=complete_output_format,
|
|
264
|
+
),
|
|
265
|
+
output: Optional[str] = typer.Option(
|
|
266
|
+
None, "--output", "-o", help="Output file path"
|
|
267
|
+
),
|
|
268
|
+
):
|
|
269
|
+
"""Get detailed information about a specific job."""
|
|
270
|
+
try:
|
|
271
|
+
cache_rid(job_rid)
|
|
272
|
+
service = OrchestrationService(profile=profile)
|
|
273
|
+
|
|
274
|
+
with SpinnerProgressTracker().track_spinner(f"Fetching job {job_rid}..."):
|
|
275
|
+
job = service.get_job(job_rid)
|
|
276
|
+
|
|
277
|
+
formatter.format_job_detail(job, format, output)
|
|
278
|
+
|
|
279
|
+
if output:
|
|
280
|
+
formatter.print_success(f"Job information saved to {output}")
|
|
281
|
+
|
|
282
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
283
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
284
|
+
raise typer.Exit(1)
|
|
285
|
+
except Exception as e:
|
|
286
|
+
formatter.print_error(f"Failed to get job: {e}")
|
|
287
|
+
raise typer.Exit(1)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
@jobs_app.command("get-batch")
|
|
291
|
+
def get_jobs_batch(
|
|
292
|
+
job_rids: str = typer.Argument(
|
|
293
|
+
..., help="Comma-separated list of Job RIDs (max 500)"
|
|
294
|
+
),
|
|
295
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
296
|
+
format: str = typer.Option(
|
|
297
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
298
|
+
),
|
|
299
|
+
output: Optional[str] = typer.Option(
|
|
300
|
+
None, "--output", "-o", help="Output file path"
|
|
301
|
+
),
|
|
302
|
+
):
|
|
303
|
+
"""Get multiple jobs in batch (max 500)."""
|
|
304
|
+
try:
|
|
305
|
+
# Parse job RIDs
|
|
306
|
+
rids_list = [rid.strip() for rid in job_rids.split(",")]
|
|
307
|
+
|
|
308
|
+
if len(rids_list) > 500:
|
|
309
|
+
formatter.print_error("Maximum batch size is 500 jobs")
|
|
310
|
+
raise typer.Exit(1)
|
|
311
|
+
|
|
312
|
+
service = OrchestrationService(profile=profile)
|
|
313
|
+
|
|
314
|
+
with SpinnerProgressTracker().track_spinner(
|
|
315
|
+
f"Fetching {len(rids_list)} jobs..."
|
|
316
|
+
):
|
|
317
|
+
response = service.get_jobs_batch(rids_list)
|
|
318
|
+
|
|
319
|
+
jobs = response.get("jobs", [])
|
|
320
|
+
|
|
321
|
+
if not jobs:
|
|
322
|
+
formatter.print_warning("No jobs found")
|
|
323
|
+
return
|
|
324
|
+
|
|
325
|
+
formatter.format_jobs_list(jobs, format, output)
|
|
326
|
+
|
|
327
|
+
if output:
|
|
328
|
+
formatter.print_success(f"Jobs information saved to {output}")
|
|
329
|
+
|
|
330
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
331
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
332
|
+
raise typer.Exit(1)
|
|
333
|
+
except Exception as e:
|
|
334
|
+
formatter.print_error(f"Failed to get jobs batch: {e}")
|
|
335
|
+
raise typer.Exit(1)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
# ============================================================================
|
|
339
|
+
# Schedule Commands
|
|
340
|
+
# ============================================================================
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@schedules_app.command("get")
|
|
344
|
+
def get_schedule(
|
|
345
|
+
schedule_rid: str = typer.Argument(
|
|
346
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
347
|
+
),
|
|
348
|
+
profile: Optional[str] = typer.Option(
|
|
349
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
350
|
+
),
|
|
351
|
+
preview: bool = typer.Option(False, "--preview", help="Enable preview mode"),
|
|
352
|
+
format: str = typer.Option(
|
|
353
|
+
"table",
|
|
354
|
+
"--format",
|
|
355
|
+
"-f",
|
|
356
|
+
help="Output format (table, json, csv)",
|
|
357
|
+
autocompletion=complete_output_format,
|
|
358
|
+
),
|
|
359
|
+
output: Optional[str] = typer.Option(
|
|
360
|
+
None, "--output", "-o", help="Output file path"
|
|
361
|
+
),
|
|
362
|
+
):
|
|
363
|
+
"""Get detailed information about a specific schedule."""
|
|
364
|
+
try:
|
|
365
|
+
cache_rid(schedule_rid)
|
|
366
|
+
service = OrchestrationService(profile=profile)
|
|
367
|
+
|
|
368
|
+
with SpinnerProgressTracker().track_spinner(
|
|
369
|
+
f"Fetching schedule {schedule_rid}..."
|
|
370
|
+
):
|
|
371
|
+
schedule = service.get_schedule(schedule_rid, preview=preview)
|
|
372
|
+
|
|
373
|
+
formatter.format_schedule_detail(schedule, format, output)
|
|
374
|
+
|
|
375
|
+
if output:
|
|
376
|
+
formatter.print_success(f"Schedule information saved to {output}")
|
|
377
|
+
|
|
378
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
379
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
380
|
+
raise typer.Exit(1)
|
|
381
|
+
except Exception as e:
|
|
382
|
+
formatter.print_error(f"Failed to get schedule: {e}")
|
|
383
|
+
raise typer.Exit(1)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@schedules_app.command("create")
|
|
387
|
+
def create_schedule(
|
|
388
|
+
action: str = typer.Argument(..., help="Schedule action (JSON format)"),
|
|
389
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
390
|
+
display_name: Optional[str] = typer.Option(
|
|
391
|
+
None, "--name", help="Display name for the schedule"
|
|
392
|
+
),
|
|
393
|
+
description: Optional[str] = typer.Option(
|
|
394
|
+
None, "--description", help="Schedule description"
|
|
395
|
+
),
|
|
396
|
+
trigger: Optional[str] = typer.Option(
|
|
397
|
+
None, "--trigger", help="Trigger configuration (JSON format)"
|
|
398
|
+
),
|
|
399
|
+
preview: bool = typer.Option(False, "--preview", help="Enable preview mode"),
|
|
400
|
+
format: str = typer.Option(
|
|
401
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
402
|
+
),
|
|
403
|
+
):
|
|
404
|
+
"""Create a new schedule."""
|
|
405
|
+
try:
|
|
406
|
+
service = OrchestrationService(profile=profile)
|
|
407
|
+
|
|
408
|
+
# Parse action JSON
|
|
409
|
+
try:
|
|
410
|
+
action_dict = json.loads(action)
|
|
411
|
+
except json.JSONDecodeError:
|
|
412
|
+
formatter.print_error("Invalid JSON format for action")
|
|
413
|
+
raise typer.Exit(1)
|
|
414
|
+
|
|
415
|
+
# Parse trigger JSON if provided
|
|
416
|
+
trigger_dict = None
|
|
417
|
+
if trigger:
|
|
418
|
+
try:
|
|
419
|
+
trigger_dict = json.loads(trigger)
|
|
420
|
+
except json.JSONDecodeError:
|
|
421
|
+
formatter.print_error("Invalid JSON format for trigger")
|
|
422
|
+
raise typer.Exit(1)
|
|
423
|
+
|
|
424
|
+
with SpinnerProgressTracker().track_spinner("Creating schedule..."):
|
|
425
|
+
schedule = service.create_schedule(
|
|
426
|
+
action=action_dict,
|
|
427
|
+
display_name=display_name,
|
|
428
|
+
description=description,
|
|
429
|
+
trigger=trigger_dict,
|
|
430
|
+
preview=preview,
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
formatter.print_success("Successfully created schedule")
|
|
434
|
+
formatter.print_info(f"Schedule RID: {schedule.get('rid', 'unknown')}")
|
|
435
|
+
formatter.format_schedule_detail(schedule, format)
|
|
436
|
+
|
|
437
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
438
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
439
|
+
raise typer.Exit(1)
|
|
440
|
+
except Exception as e:
|
|
441
|
+
formatter.print_error(f"Failed to create schedule: {e}")
|
|
442
|
+
raise typer.Exit(1)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
@schedules_app.command("delete")
|
|
446
|
+
def delete_schedule(
|
|
447
|
+
schedule_rid: str = typer.Argument(
|
|
448
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
449
|
+
),
|
|
450
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
451
|
+
confirm: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
452
|
+
):
|
|
453
|
+
"""Delete a schedule."""
|
|
454
|
+
try:
|
|
455
|
+
if not confirm:
|
|
456
|
+
typer.confirm(
|
|
457
|
+
f"Are you sure you want to delete schedule {schedule_rid}?", abort=True
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
service = OrchestrationService(profile=profile)
|
|
461
|
+
|
|
462
|
+
with SpinnerProgressTracker().track_spinner(
|
|
463
|
+
f"Deleting schedule {schedule_rid}..."
|
|
464
|
+
):
|
|
465
|
+
service.delete_schedule(schedule_rid)
|
|
466
|
+
|
|
467
|
+
formatter.print_success(f"Successfully deleted schedule {schedule_rid}")
|
|
468
|
+
|
|
469
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
470
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
471
|
+
raise typer.Exit(1)
|
|
472
|
+
except Exception as e:
|
|
473
|
+
formatter.print_error(f"Failed to delete schedule: {e}")
|
|
474
|
+
raise typer.Exit(1)
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
@schedules_app.command("pause")
|
|
478
|
+
def pause_schedule(
|
|
479
|
+
schedule_rid: str = typer.Argument(
|
|
480
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
481
|
+
),
|
|
482
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
483
|
+
):
|
|
484
|
+
"""Pause a schedule."""
|
|
485
|
+
try:
|
|
486
|
+
service = OrchestrationService(profile=profile)
|
|
487
|
+
|
|
488
|
+
with SpinnerProgressTracker().track_spinner(
|
|
489
|
+
f"Pausing schedule {schedule_rid}..."
|
|
490
|
+
):
|
|
491
|
+
service.pause_schedule(schedule_rid)
|
|
492
|
+
|
|
493
|
+
formatter.print_success(f"Successfully paused schedule {schedule_rid}")
|
|
494
|
+
|
|
495
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
496
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
497
|
+
raise typer.Exit(1)
|
|
498
|
+
except Exception as e:
|
|
499
|
+
formatter.print_error(f"Failed to pause schedule: {e}")
|
|
500
|
+
raise typer.Exit(1)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
@schedules_app.command("unpause")
|
|
504
|
+
def unpause_schedule(
|
|
505
|
+
schedule_rid: str = typer.Argument(
|
|
506
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
507
|
+
),
|
|
508
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
509
|
+
):
|
|
510
|
+
"""Unpause a schedule."""
|
|
511
|
+
try:
|
|
512
|
+
service = OrchestrationService(profile=profile)
|
|
513
|
+
|
|
514
|
+
with SpinnerProgressTracker().track_spinner(
|
|
515
|
+
f"Unpausing schedule {schedule_rid}..."
|
|
516
|
+
):
|
|
517
|
+
service.unpause_schedule(schedule_rid)
|
|
518
|
+
|
|
519
|
+
formatter.print_success(f"Successfully unpaused schedule {schedule_rid}")
|
|
520
|
+
|
|
521
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
522
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
523
|
+
raise typer.Exit(1)
|
|
524
|
+
except Exception as e:
|
|
525
|
+
formatter.print_error(f"Failed to unpause schedule: {e}")
|
|
526
|
+
raise typer.Exit(1)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@schedules_app.command("run")
|
|
530
|
+
def run_schedule(
|
|
531
|
+
schedule_rid: str = typer.Argument(
|
|
532
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
533
|
+
),
|
|
534
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
535
|
+
):
|
|
536
|
+
"""Execute a schedule immediately."""
|
|
537
|
+
try:
|
|
538
|
+
service = OrchestrationService(profile=profile)
|
|
539
|
+
|
|
540
|
+
with SpinnerProgressTracker().track_spinner(
|
|
541
|
+
f"Running schedule {schedule_rid}..."
|
|
542
|
+
):
|
|
543
|
+
service.run_schedule(schedule_rid)
|
|
544
|
+
|
|
545
|
+
formatter.print_success(f"Successfully triggered schedule {schedule_rid}")
|
|
546
|
+
|
|
547
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
548
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
549
|
+
raise typer.Exit(1)
|
|
550
|
+
except Exception as e:
|
|
551
|
+
formatter.print_error(f"Failed to run schedule: {e}")
|
|
552
|
+
raise typer.Exit(1)
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
@schedules_app.command("replace")
|
|
556
|
+
def replace_schedule(
|
|
557
|
+
schedule_rid: str = typer.Argument(
|
|
558
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
559
|
+
),
|
|
560
|
+
action: str = typer.Argument(..., help="Schedule action (JSON format)"),
|
|
561
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
562
|
+
display_name: Optional[str] = typer.Option(
|
|
563
|
+
None, "--name", help="Display name for the schedule"
|
|
564
|
+
),
|
|
565
|
+
description: Optional[str] = typer.Option(
|
|
566
|
+
None, "--description", help="Schedule description"
|
|
567
|
+
),
|
|
568
|
+
trigger: Optional[str] = typer.Option(
|
|
569
|
+
None, "--trigger", help="Trigger configuration (JSON format)"
|
|
570
|
+
),
|
|
571
|
+
preview: bool = typer.Option(False, "--preview", help="Enable preview mode"),
|
|
572
|
+
format: str = typer.Option(
|
|
573
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
574
|
+
),
|
|
575
|
+
):
|
|
576
|
+
"""Replace an existing schedule."""
|
|
577
|
+
try:
|
|
578
|
+
service = OrchestrationService(profile=profile)
|
|
579
|
+
|
|
580
|
+
# Parse action JSON
|
|
581
|
+
try:
|
|
582
|
+
action_dict = json.loads(action)
|
|
583
|
+
except json.JSONDecodeError:
|
|
584
|
+
formatter.print_error("Invalid JSON format for action")
|
|
585
|
+
raise typer.Exit(1)
|
|
586
|
+
|
|
587
|
+
# Parse trigger JSON if provided
|
|
588
|
+
trigger_dict = None
|
|
589
|
+
if trigger:
|
|
590
|
+
try:
|
|
591
|
+
trigger_dict = json.loads(trigger)
|
|
592
|
+
except json.JSONDecodeError:
|
|
593
|
+
formatter.print_error("Invalid JSON format for trigger")
|
|
594
|
+
raise typer.Exit(1)
|
|
595
|
+
|
|
596
|
+
with SpinnerProgressTracker().track_spinner(
|
|
597
|
+
f"Replacing schedule {schedule_rid}..."
|
|
598
|
+
):
|
|
599
|
+
schedule = service.replace_schedule(
|
|
600
|
+
schedule_rid=schedule_rid,
|
|
601
|
+
action=action_dict,
|
|
602
|
+
display_name=display_name,
|
|
603
|
+
description=description,
|
|
604
|
+
trigger=trigger_dict,
|
|
605
|
+
preview=preview,
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
formatter.print_success(f"Successfully replaced schedule {schedule_rid}")
|
|
609
|
+
formatter.format_schedule_detail(schedule, format)
|
|
610
|
+
|
|
611
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
612
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
613
|
+
raise typer.Exit(1)
|
|
614
|
+
except Exception as e:
|
|
615
|
+
formatter.print_error(f"Failed to replace schedule: {e}")
|
|
616
|
+
raise typer.Exit(1)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
# ============================================================================
|
|
620
|
+
# Main app setup
|
|
621
|
+
# ============================================================================
|
|
622
|
+
|
|
623
|
+
# Add sub-apps to main app
|
|
624
|
+
app.add_typer(builds_app, name="builds", help="Manage builds")
|
|
625
|
+
app.add_typer(jobs_app, name="jobs", help="Manage jobs")
|
|
626
|
+
app.add_typer(schedules_app, name="schedules", help="Manage schedules")
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
@app.callback()
|
|
630
|
+
def main():
|
|
631
|
+
"""
|
|
632
|
+
Orchestration operations for managing builds, jobs, and schedules.
|
|
633
|
+
|
|
634
|
+
This module provides commands to:
|
|
635
|
+
- Create, monitor, and cancel builds
|
|
636
|
+
- View job details and statuses
|
|
637
|
+
- Create, manage, and execute schedules
|
|
638
|
+
|
|
639
|
+
All operations require Resource Identifiers (RIDs) like:
|
|
640
|
+
ri.orchestration.main.build.12345678-1234-1234-1234-123456789abc
|
|
641
|
+
"""
|
|
642
|
+
pass
|