pltr-cli 0.10.0__py3-none-any.whl → 0.12.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/__init__.py +1 -1
- pltr/cli.py +16 -0
- pltr/commands/admin.py +553 -9
- pltr/commands/aip_agents.py +333 -0
- pltr/commands/connectivity.py +309 -1
- pltr/commands/cp.py +103 -0
- pltr/commands/dataset.py +104 -4
- pltr/commands/mediasets.py +176 -0
- pltr/commands/ontology.py +137 -13
- pltr/commands/orchestration.py +167 -11
- pltr/commands/project.py +249 -0
- pltr/commands/resource.py +452 -0
- pltr/commands/sql.py +54 -7
- pltr/commands/third_party_applications.py +82 -0
- pltr/services/admin.py +318 -1
- pltr/services/aip_agents.py +147 -0
- pltr/services/base.py +104 -1
- pltr/services/connectivity.py +139 -0
- pltr/services/copy.py +391 -0
- pltr/services/dataset.py +80 -9
- pltr/services/mediasets.py +144 -9
- pltr/services/ontology.py +119 -1
- pltr/services/orchestration.py +133 -1
- pltr/services/project.py +136 -0
- pltr/services/resource.py +227 -0
- pltr/services/sql.py +44 -20
- pltr/services/third_party_applications.py +53 -0
- pltr/utils/formatting.py +195 -1
- pltr/utils/pagination.py +325 -0
- {pltr_cli-0.10.0.dist-info → pltr_cli-0.12.0.dist-info}/METADATA +5 -3
- pltr_cli-0.12.0.dist-info/RECORD +62 -0
- {pltr_cli-0.10.0.dist-info → pltr_cli-0.12.0.dist-info}/WHEEL +1 -1
- pltr_cli-0.10.0.dist-info/RECORD +0 -55
- {pltr_cli-0.10.0.dist-info → pltr_cli-0.12.0.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.10.0.dist-info → pltr_cli-0.12.0.dist-info}/licenses/LICENSE +0 -0
pltr/commands/orchestration.py
CHANGED
|
@@ -9,6 +9,7 @@ from rich.console import Console
|
|
|
9
9
|
|
|
10
10
|
from ..services.orchestration import OrchestrationService
|
|
11
11
|
from ..utils.formatting import OutputFormatter
|
|
12
|
+
from ..utils.pagination import PaginationConfig
|
|
12
13
|
from ..utils.progress import SpinnerProgressTracker
|
|
13
14
|
from ..auth.base import ProfileNotFoundError, MissingCredentialsError
|
|
14
15
|
from ..utils.completion import (
|
|
@@ -226,7 +227,7 @@ def get_build_jobs(
|
|
|
226
227
|
|
|
227
228
|
if response.get("next_page_token"):
|
|
228
229
|
formatter.print_info(
|
|
229
|
-
"More results available. Use
|
|
230
|
+
f"More results available. Use --page-token {response['next_page_token']} to fetch next page."
|
|
230
231
|
)
|
|
231
232
|
|
|
232
233
|
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
@@ -241,7 +242,16 @@ def get_build_jobs(
|
|
|
241
242
|
def search_builds(
|
|
242
243
|
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
243
244
|
page_size: Optional[int] = typer.Option(
|
|
244
|
-
None, "--page-size", help="Number of
|
|
245
|
+
None, "--page-size", help="Number of builds per page (default: from settings)"
|
|
246
|
+
),
|
|
247
|
+
max_pages: Optional[int] = typer.Option(
|
|
248
|
+
1, "--max-pages", help="Maximum number of pages to fetch (default: 1)"
|
|
249
|
+
),
|
|
250
|
+
page_token: Optional[str] = typer.Option(
|
|
251
|
+
None, "--page-token", help="Page token to resume from previous response"
|
|
252
|
+
),
|
|
253
|
+
all: bool = typer.Option(
|
|
254
|
+
False, "--all", help="Fetch all available pages (overrides --max-pages)"
|
|
245
255
|
),
|
|
246
256
|
format: str = typer.Option(
|
|
247
257
|
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
@@ -250,12 +260,102 @@ def search_builds(
|
|
|
250
260
|
None, "--output", "-o", help="Output file path"
|
|
251
261
|
),
|
|
252
262
|
):
|
|
253
|
-
"""
|
|
263
|
+
"""
|
|
264
|
+
Search for builds with pagination support.
|
|
265
|
+
|
|
266
|
+
By default, fetches only the first page of results. Use --all to fetch all builds,
|
|
267
|
+
or --max-pages to control how many pages to fetch.
|
|
268
|
+
|
|
269
|
+
Examples:
|
|
270
|
+
# Search first page of builds (default)
|
|
271
|
+
pltr orchestration builds search
|
|
272
|
+
|
|
273
|
+
# Search all builds
|
|
274
|
+
pltr orchestration builds search --all
|
|
275
|
+
|
|
276
|
+
# Search first 3 pages
|
|
277
|
+
pltr orchestration builds search --max-pages 3
|
|
278
|
+
|
|
279
|
+
# Resume from a specific page
|
|
280
|
+
pltr orchestration builds search --page-token abc123
|
|
281
|
+
"""
|
|
254
282
|
try:
|
|
255
283
|
service = OrchestrationService(profile=profile)
|
|
256
284
|
|
|
285
|
+
# Create pagination config
|
|
286
|
+
config = PaginationConfig(
|
|
287
|
+
page_size=page_size,
|
|
288
|
+
max_pages=max_pages,
|
|
289
|
+
page_token=page_token,
|
|
290
|
+
fetch_all=all,
|
|
291
|
+
)
|
|
292
|
+
|
|
257
293
|
with SpinnerProgressTracker().track_spinner("Searching builds..."):
|
|
258
|
-
|
|
294
|
+
result = service.search_builds_paginated(config)
|
|
295
|
+
|
|
296
|
+
if not result.data:
|
|
297
|
+
formatter.print_warning("No builds found")
|
|
298
|
+
return
|
|
299
|
+
|
|
300
|
+
# Format and display paginated results
|
|
301
|
+
if output:
|
|
302
|
+
formatter.format_paginated_output(
|
|
303
|
+
result,
|
|
304
|
+
format,
|
|
305
|
+
output,
|
|
306
|
+
formatter_fn=lambda data, fmt, out: formatter.format_builds_list(
|
|
307
|
+
data, fmt, out
|
|
308
|
+
),
|
|
309
|
+
)
|
|
310
|
+
formatter.print_success(f"Builds list saved to {output}")
|
|
311
|
+
else:
|
|
312
|
+
formatter.format_paginated_output(
|
|
313
|
+
result,
|
|
314
|
+
format,
|
|
315
|
+
formatter_fn=lambda data, fmt, out: formatter.format_builds_list(
|
|
316
|
+
data, fmt, out
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
321
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
322
|
+
raise typer.Exit(1)
|
|
323
|
+
except Exception as e:
|
|
324
|
+
formatter.print_error(f"Failed to search builds: {e}")
|
|
325
|
+
raise typer.Exit(1)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
@builds_app.command("get-batch")
|
|
329
|
+
def get_builds_batch(
|
|
330
|
+
build_rids: str = typer.Argument(
|
|
331
|
+
..., help="Comma-separated list of Build RIDs (max 100)"
|
|
332
|
+
),
|
|
333
|
+
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name"),
|
|
334
|
+
format: str = typer.Option(
|
|
335
|
+
"table", "--format", "-f", help="Output format (table, json, csv)"
|
|
336
|
+
),
|
|
337
|
+
output: Optional[str] = typer.Option(
|
|
338
|
+
None, "--output", "-o", help="Output file path"
|
|
339
|
+
),
|
|
340
|
+
):
|
|
341
|
+
"""Get multiple builds in batch (max 100)."""
|
|
342
|
+
try:
|
|
343
|
+
rids_list = [rid.strip() for rid in build_rids.split(",") if rid.strip()]
|
|
344
|
+
|
|
345
|
+
if not rids_list:
|
|
346
|
+
formatter.print_error("No valid RIDs provided")
|
|
347
|
+
raise typer.Exit(1)
|
|
348
|
+
|
|
349
|
+
if len(rids_list) > 100:
|
|
350
|
+
formatter.print_error("Maximum batch size is 100 builds")
|
|
351
|
+
raise typer.Exit(1)
|
|
352
|
+
|
|
353
|
+
service = OrchestrationService(profile=profile)
|
|
354
|
+
|
|
355
|
+
with SpinnerProgressTracker().track_spinner(
|
|
356
|
+
f"Fetching {len(rids_list)} builds..."
|
|
357
|
+
):
|
|
358
|
+
response = service.get_builds_batch(rids_list)
|
|
259
359
|
|
|
260
360
|
builds = response.get("builds", [])
|
|
261
361
|
|
|
@@ -266,18 +366,13 @@ def search_builds(
|
|
|
266
366
|
formatter.format_builds_list(builds, format, output)
|
|
267
367
|
|
|
268
368
|
if output:
|
|
269
|
-
formatter.print_success(f"Builds
|
|
270
|
-
|
|
271
|
-
if response.get("next_page_token"):
|
|
272
|
-
formatter.print_info(
|
|
273
|
-
"More results available. Use pagination token to fetch next page."
|
|
274
|
-
)
|
|
369
|
+
formatter.print_success(f"Builds information saved to {output}")
|
|
275
370
|
|
|
276
371
|
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
277
372
|
formatter.print_error(f"Authentication error: {e}")
|
|
278
373
|
raise typer.Exit(1)
|
|
279
374
|
except Exception as e:
|
|
280
|
-
formatter.print_error(f"Failed to
|
|
375
|
+
formatter.print_error(f"Failed to get builds batch: {e}")
|
|
281
376
|
raise typer.Exit(1)
|
|
282
377
|
|
|
283
378
|
|
|
@@ -655,6 +750,67 @@ def replace_schedule(
|
|
|
655
750
|
raise typer.Exit(1)
|
|
656
751
|
|
|
657
752
|
|
|
753
|
+
@schedules_app.command("runs")
|
|
754
|
+
def get_schedule_runs(
|
|
755
|
+
schedule_rid: str = typer.Argument(
|
|
756
|
+
..., help="Schedule Resource Identifier", autocompletion=complete_rid
|
|
757
|
+
),
|
|
758
|
+
profile: Optional[str] = typer.Option(
|
|
759
|
+
None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
|
|
760
|
+
),
|
|
761
|
+
page_size: Optional[int] = typer.Option(
|
|
762
|
+
None, "--page-size", help="Number of results per page"
|
|
763
|
+
),
|
|
764
|
+
page_token: Optional[str] = typer.Option(
|
|
765
|
+
None, "--page-token", help="Pagination token for next page"
|
|
766
|
+
),
|
|
767
|
+
format: str = typer.Option(
|
|
768
|
+
"table",
|
|
769
|
+
"--format",
|
|
770
|
+
"-f",
|
|
771
|
+
help="Output format (table, json, csv)",
|
|
772
|
+
autocompletion=complete_output_format,
|
|
773
|
+
),
|
|
774
|
+
output: Optional[str] = typer.Option(
|
|
775
|
+
None, "--output", "-o", help="Output file path"
|
|
776
|
+
),
|
|
777
|
+
):
|
|
778
|
+
"""List recent execution runs for a schedule."""
|
|
779
|
+
try:
|
|
780
|
+
cache_rid(schedule_rid)
|
|
781
|
+
service = OrchestrationService(profile=profile)
|
|
782
|
+
|
|
783
|
+
with SpinnerProgressTracker().track_spinner(
|
|
784
|
+
f"Fetching runs for schedule {schedule_rid}..."
|
|
785
|
+
):
|
|
786
|
+
response = service.get_schedule_runs(
|
|
787
|
+
schedule_rid, page_size=page_size, page_token=page_token
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
runs = response.get("runs", [])
|
|
791
|
+
|
|
792
|
+
if not runs:
|
|
793
|
+
formatter.print_warning("No runs found for this schedule")
|
|
794
|
+
return
|
|
795
|
+
|
|
796
|
+
formatter.format_schedule_runs_list(runs, format, output)
|
|
797
|
+
|
|
798
|
+
if output:
|
|
799
|
+
formatter.print_success(f"Runs list saved to {output}")
|
|
800
|
+
|
|
801
|
+
if response.get("next_page_token"):
|
|
802
|
+
formatter.print_info(
|
|
803
|
+
f"More results available. Use --page-token {response['next_page_token']} to fetch next page."
|
|
804
|
+
)
|
|
805
|
+
|
|
806
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
807
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
808
|
+
raise typer.Exit(1)
|
|
809
|
+
except Exception as e:
|
|
810
|
+
formatter.print_error(f"Failed to get schedule runs: {e}")
|
|
811
|
+
raise typer.Exit(1)
|
|
812
|
+
|
|
813
|
+
|
|
658
814
|
# ============================================================================
|
|
659
815
|
# Main app setup
|
|
660
816
|
# ============================================================================
|
pltr/commands/project.py
CHANGED
|
@@ -366,6 +366,229 @@ def get_projects_batch(
|
|
|
366
366
|
raise typer.Exit(1)
|
|
367
367
|
|
|
368
368
|
|
|
369
|
+
# ==================== Organization Operations ====================
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
@app.command("add-orgs")
|
|
373
|
+
def add_organizations(
|
|
374
|
+
project_rid: str = typer.Argument(
|
|
375
|
+
..., help="Project Resource Identifier", autocompletion=complete_rid
|
|
376
|
+
),
|
|
377
|
+
organization_rids: List[str] = typer.Option(
|
|
378
|
+
...,
|
|
379
|
+
"--org",
|
|
380
|
+
"-o",
|
|
381
|
+
help="Organization RID(s) to add (can specify multiple)",
|
|
382
|
+
),
|
|
383
|
+
profile: Optional[str] = typer.Option(
|
|
384
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
385
|
+
),
|
|
386
|
+
):
|
|
387
|
+
"""Add organizations to a project."""
|
|
388
|
+
try:
|
|
389
|
+
service = ProjectService(profile=profile)
|
|
390
|
+
|
|
391
|
+
with SpinnerProgressTracker().track_spinner(
|
|
392
|
+
f"Adding {len(organization_rids)} organization(s) to project {project_rid}..."
|
|
393
|
+
):
|
|
394
|
+
service.add_organizations(project_rid, organization_rids)
|
|
395
|
+
|
|
396
|
+
formatter.print_success(
|
|
397
|
+
f"Successfully added {len(organization_rids)} organization(s) to project {project_rid}"
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
401
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
402
|
+
raise typer.Exit(1)
|
|
403
|
+
except Exception as e:
|
|
404
|
+
formatter.print_error(f"Failed to add organizations: {e}")
|
|
405
|
+
raise typer.Exit(1)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@app.command("remove-orgs")
|
|
409
|
+
def remove_organizations(
|
|
410
|
+
project_rid: str = typer.Argument(
|
|
411
|
+
..., help="Project Resource Identifier", autocompletion=complete_rid
|
|
412
|
+
),
|
|
413
|
+
organization_rids: List[str] = typer.Option(
|
|
414
|
+
...,
|
|
415
|
+
"--org",
|
|
416
|
+
"-o",
|
|
417
|
+
help="Organization RID(s) to remove (can specify multiple)",
|
|
418
|
+
),
|
|
419
|
+
profile: Optional[str] = typer.Option(
|
|
420
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
421
|
+
),
|
|
422
|
+
):
|
|
423
|
+
"""Remove organizations from a project."""
|
|
424
|
+
try:
|
|
425
|
+
service = ProjectService(profile=profile)
|
|
426
|
+
|
|
427
|
+
with SpinnerProgressTracker().track_spinner(
|
|
428
|
+
f"Removing {len(organization_rids)} organization(s) from project {project_rid}..."
|
|
429
|
+
):
|
|
430
|
+
service.remove_organizations(project_rid, organization_rids)
|
|
431
|
+
|
|
432
|
+
formatter.print_success(
|
|
433
|
+
f"Successfully removed {len(organization_rids)} organization(s) from project {project_rid}"
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
437
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
438
|
+
raise typer.Exit(1)
|
|
439
|
+
except Exception as e:
|
|
440
|
+
formatter.print_error(f"Failed to remove organizations: {e}")
|
|
441
|
+
raise typer.Exit(1)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
@app.command("list-orgs")
|
|
445
|
+
def list_organizations(
|
|
446
|
+
project_rid: str = typer.Argument(
|
|
447
|
+
..., help="Project Resource Identifier", autocompletion=complete_rid
|
|
448
|
+
),
|
|
449
|
+
profile: Optional[str] = typer.Option(
|
|
450
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
451
|
+
),
|
|
452
|
+
format: str = typer.Option(
|
|
453
|
+
"table",
|
|
454
|
+
"--format",
|
|
455
|
+
"-f",
|
|
456
|
+
help="Output format (table, json, csv)",
|
|
457
|
+
autocompletion=complete_output_format,
|
|
458
|
+
),
|
|
459
|
+
output: Optional[str] = typer.Option(None, "--output", help="Output file path"),
|
|
460
|
+
page_size: Optional[int] = typer.Option(
|
|
461
|
+
None, "--page-size", help="Number of items per page"
|
|
462
|
+
),
|
|
463
|
+
):
|
|
464
|
+
"""List organizations directly applied to a project."""
|
|
465
|
+
try:
|
|
466
|
+
service = ProjectService(profile=profile)
|
|
467
|
+
|
|
468
|
+
with SpinnerProgressTracker().track_spinner(
|
|
469
|
+
f"Fetching organizations for project {project_rid}..."
|
|
470
|
+
):
|
|
471
|
+
organizations = service.list_organizations(project_rid, page_size=page_size)
|
|
472
|
+
|
|
473
|
+
if not organizations:
|
|
474
|
+
formatter.print_info("No organizations found on this project.")
|
|
475
|
+
return
|
|
476
|
+
|
|
477
|
+
# Format output
|
|
478
|
+
if format == "json":
|
|
479
|
+
if output:
|
|
480
|
+
formatter.save_to_file(organizations, output, "json")
|
|
481
|
+
else:
|
|
482
|
+
formatter.format_list(organizations)
|
|
483
|
+
elif format == "csv":
|
|
484
|
+
if output:
|
|
485
|
+
formatter.save_to_file(organizations, output, "csv")
|
|
486
|
+
else:
|
|
487
|
+
formatter.format_list(organizations)
|
|
488
|
+
else:
|
|
489
|
+
_format_organizations_table(organizations)
|
|
490
|
+
|
|
491
|
+
if output:
|
|
492
|
+
formatter.print_success(f"Organizations list saved to {output}")
|
|
493
|
+
|
|
494
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
495
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
496
|
+
raise typer.Exit(1)
|
|
497
|
+
except Exception as e:
|
|
498
|
+
formatter.print_error(f"Failed to list organizations: {e}")
|
|
499
|
+
raise typer.Exit(1)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
# ==================== Template Operations ====================
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
@app.command("create-from-template")
|
|
506
|
+
def create_from_template(
|
|
507
|
+
template_rid: str = typer.Option(
|
|
508
|
+
...,
|
|
509
|
+
"--template-rid",
|
|
510
|
+
"-t",
|
|
511
|
+
help="Template Resource Identifier",
|
|
512
|
+
autocompletion=complete_rid,
|
|
513
|
+
),
|
|
514
|
+
variable: List[str] = typer.Option(
|
|
515
|
+
...,
|
|
516
|
+
"--var",
|
|
517
|
+
"-v",
|
|
518
|
+
help="Variable values in format 'name=value' (can specify multiple)",
|
|
519
|
+
),
|
|
520
|
+
description: Optional[str] = typer.Option(
|
|
521
|
+
None, "--description", "-d", help="Project description"
|
|
522
|
+
),
|
|
523
|
+
organization_rids: Optional[List[str]] = typer.Option(
|
|
524
|
+
None,
|
|
525
|
+
"--org",
|
|
526
|
+
"-o",
|
|
527
|
+
help="Organization RIDs (can be specified multiple times)",
|
|
528
|
+
),
|
|
529
|
+
profile: Optional[str] = typer.Option(
|
|
530
|
+
None, "--profile", help="Profile name", autocompletion=complete_profile
|
|
531
|
+
),
|
|
532
|
+
format: str = typer.Option(
|
|
533
|
+
"table",
|
|
534
|
+
"--format",
|
|
535
|
+
"-f",
|
|
536
|
+
help="Output format (table, json, csv)",
|
|
537
|
+
autocompletion=complete_output_format,
|
|
538
|
+
),
|
|
539
|
+
):
|
|
540
|
+
"""Create a project from a template."""
|
|
541
|
+
try:
|
|
542
|
+
# Parse variable values
|
|
543
|
+
variable_values = {}
|
|
544
|
+
for var in variable:
|
|
545
|
+
if "=" not in var:
|
|
546
|
+
formatter.print_error(
|
|
547
|
+
f"Invalid variable format: '{var}'. Use 'name=value' format."
|
|
548
|
+
)
|
|
549
|
+
raise typer.Exit(1)
|
|
550
|
+
name, value = var.split("=", 1)
|
|
551
|
+
name = name.strip()
|
|
552
|
+
if not name:
|
|
553
|
+
formatter.print_error(f"Variable name cannot be empty: '{var}'")
|
|
554
|
+
raise typer.Exit(1)
|
|
555
|
+
variable_values[name] = value
|
|
556
|
+
|
|
557
|
+
service = ProjectService(profile=profile)
|
|
558
|
+
|
|
559
|
+
with SpinnerProgressTracker().track_spinner(
|
|
560
|
+
f"Creating project from template {template_rid}..."
|
|
561
|
+
):
|
|
562
|
+
project = service.create_project_from_template(
|
|
563
|
+
template_rid=template_rid,
|
|
564
|
+
variable_values=variable_values,
|
|
565
|
+
organization_rids=organization_rids,
|
|
566
|
+
project_description=description,
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
# Cache the RID for future completions
|
|
570
|
+
if project.get("rid"):
|
|
571
|
+
cache_rid(project["rid"])
|
|
572
|
+
|
|
573
|
+
formatter.print_success("Successfully created project from template")
|
|
574
|
+
formatter.print_info(f"Project RID: {project.get('rid', 'unknown')}")
|
|
575
|
+
|
|
576
|
+
# Format output
|
|
577
|
+
if format == "json":
|
|
578
|
+
formatter.format_dict(project)
|
|
579
|
+
elif format == "csv":
|
|
580
|
+
formatter.format_list([project])
|
|
581
|
+
else:
|
|
582
|
+
_format_project_table(project)
|
|
583
|
+
|
|
584
|
+
except (ProfileNotFoundError, MissingCredentialsError) as e:
|
|
585
|
+
formatter.print_error(f"Authentication error: {e}")
|
|
586
|
+
raise typer.Exit(1)
|
|
587
|
+
except Exception as e:
|
|
588
|
+
formatter.print_error(f"Failed to create project from template: {e}")
|
|
589
|
+
raise typer.Exit(1)
|
|
590
|
+
|
|
591
|
+
|
|
369
592
|
def _format_project_table(project: dict):
|
|
370
593
|
"""Format project information as a table."""
|
|
371
594
|
table = Table(
|
|
@@ -410,6 +633,24 @@ def _format_projects_table(projects: List[dict]):
|
|
|
410
633
|
console.print(f"\nTotal: {len(projects)} projects")
|
|
411
634
|
|
|
412
635
|
|
|
636
|
+
def _format_organizations_table(organizations: List[dict]):
|
|
637
|
+
"""Format organizations as a table."""
|
|
638
|
+
table = Table(title="Organizations", show_header=True, header_style="bold cyan")
|
|
639
|
+
table.add_column("Organization RID")
|
|
640
|
+
table.add_column("Display Name")
|
|
641
|
+
table.add_column("Description")
|
|
642
|
+
|
|
643
|
+
for org in organizations:
|
|
644
|
+
table.add_row(
|
|
645
|
+
org.get("organization_rid", "N/A"),
|
|
646
|
+
org.get("display_name", "N/A"),
|
|
647
|
+
org.get("description", "N/A"),
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
console.print(table)
|
|
651
|
+
console.print(f"\nTotal: {len(organizations)} organizations")
|
|
652
|
+
|
|
653
|
+
|
|
413
654
|
@app.callback()
|
|
414
655
|
def main():
|
|
415
656
|
"""
|
|
@@ -436,5 +677,13 @@ def main():
|
|
|
436
677
|
|
|
437
678
|
# Delete project
|
|
438
679
|
pltr project delete ri.compass.main.project.abc456
|
|
680
|
+
|
|
681
|
+
# Organization operations
|
|
682
|
+
pltr project add-orgs ri.compass.main.project.abc456 -o org-rid-1 -o org-rid-2
|
|
683
|
+
pltr project remove-orgs ri.compass.main.project.abc456 -o org-rid-1
|
|
684
|
+
pltr project list-orgs ri.compass.main.project.abc456
|
|
685
|
+
|
|
686
|
+
# Create from template
|
|
687
|
+
pltr project create-from-template -t template-rid -v "name=MyProject" -v "desc=Description"
|
|
439
688
|
"""
|
|
440
689
|
pass
|