unitysvc-services 0.1.1__py3-none-any.whl → 0.2.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.
@@ -57,9 +57,7 @@ class ServiceDataPublisher:
57
57
  with open(full_path, "rb") as f:
58
58
  return base64.b64encode(f.read()).decode("ascii")
59
59
 
60
- def resolve_file_references(
61
- self, data: dict[str, Any], base_path: Path
62
- ) -> dict[str, Any]:
60
+ def resolve_file_references(self, data: dict[str, Any], base_path: Path) -> dict[str, Any]:
63
61
  """Recursively resolve file references and include content in data."""
64
62
  result: dict[str, Any] = {}
65
63
 
@@ -70,11 +68,7 @@ class ServiceDataPublisher:
70
68
  elif isinstance(value, list):
71
69
  # Process lists
72
70
  result[key] = [
73
- (
74
- self.resolve_file_references(item, base_path)
75
- if isinstance(item, dict)
76
- else item
77
- )
71
+ (self.resolve_file_references(item, base_path) if isinstance(item, dict) else item)
78
72
  for item in value
79
73
  ]
80
74
  elif key == "file_path" and isinstance(value, str):
@@ -87,9 +81,7 @@ class ServiceDataPublisher:
87
81
  content = self.load_file_content(Path(value), base_path)
88
82
  result["file_content"] = content
89
83
  except Exception as e:
90
- raise ValueError(
91
- f"Failed to load file content from '{value}': {e}"
92
- )
84
+ raise ValueError(f"Failed to load file content from '{value}': {e}")
93
85
  else:
94
86
  result[key] = value
95
87
 
@@ -172,10 +164,7 @@ class ServiceDataPublisher:
172
164
  )
173
165
 
174
166
  # If service_name is not in listing data, find it from service files in the same directory
175
- if (
176
- "service_name" not in data_with_content
177
- or not data_with_content["service_name"]
178
- ):
167
+ if "service_name" not in data_with_content or not data_with_content["service_name"]:
179
168
  # Find all service files in the same directory
180
169
  service_files = find_files_by_schema(data_file.parent, "service_v1")
181
170
 
@@ -185,9 +174,7 @@ class ServiceDataPublisher:
185
174
  f"Listing files must be in the same directory as a service definition."
186
175
  )
187
176
  elif len(service_files) > 1:
188
- service_names = [
189
- data.get("name", "unknown") for _, _, data in service_files
190
- ]
177
+ service_names = [data.get("name", "unknown") for _, _, data in service_files]
191
178
  raise ValueError(
192
179
  f"Multiple services found in {data_file.parent}: {', '.join(service_names)}. "
193
180
  f"Please add 'service_name' field to {data_file.name} to specify which "
@@ -201,9 +188,7 @@ class ServiceDataPublisher:
201
188
  else:
202
189
  # service_name is provided in listing data, find the matching service to get version
203
190
  service_name = data_with_content["service_name"]
204
- service_files = find_files_by_schema(
205
- data_file.parent, "service_v1", field_filter=(("name", service_name),)
206
- )
191
+ service_files = find_files_by_schema(data_file.parent, "service_v1", field_filter=(("name", service_name),))
207
192
 
208
193
  if not service_files:
209
194
  raise ValueError(
@@ -320,9 +305,7 @@ class ServiceDataPublisher:
320
305
 
321
306
  # Convert convenience fields (logo only for sellers, no terms_of_service)
322
307
  base_path = data_file.parent
323
- data = convert_convenience_fields_to_documents(
324
- data, base_path, logo_field="logo", terms_field=None
325
- )
308
+ data = convert_convenience_fields_to_documents(data, base_path, logo_field="logo", terms_field=None)
326
309
 
327
310
  # Resolve file references and include content
328
311
  data_with_content = self.resolve_file_references(data, base_path)
@@ -376,10 +359,7 @@ class ServiceDataPublisher:
376
359
  "total": 0,
377
360
  "success": 0,
378
361
  "failed": 0,
379
- "errors": [
380
- {"file": "validation", "error": error}
381
- for error in validation_errors
382
- ],
362
+ "errors": [{"file": "validation", "error": error} for error in validation_errors],
383
363
  }
384
364
 
385
365
  offering_files = self.find_offering_files(data_dir)
@@ -415,10 +395,7 @@ class ServiceDataPublisher:
415
395
  "total": 0,
416
396
  "success": 0,
417
397
  "failed": 0,
418
- "errors": [
419
- {"file": "validation", "error": error}
420
- for error in validation_errors
421
- ],
398
+ "errors": [{"file": "validation", "error": error} for error in validation_errors],
422
399
  }
423
400
 
424
401
  listing_files = self.find_listing_files(data_dir)
@@ -487,6 +464,55 @@ class ServiceDataPublisher:
487
464
 
488
465
  return results
489
466
 
467
+ def publish_all_models(self, data_dir: Path) -> dict[str, Any]:
468
+ """
469
+ Publish all data types in the correct order.
470
+
471
+ Publishing order:
472
+ 1. Sellers - Must exist before listings
473
+ 2. Providers - Must exist before offerings
474
+ 3. Service Offerings - Must exist before listings
475
+ 4. Service Listings - Depends on sellers, providers, and offerings
476
+
477
+ Returns a dict with results for each data type and overall summary.
478
+ """
479
+ all_results: dict[str, Any] = {
480
+ "sellers": {},
481
+ "providers": {},
482
+ "offerings": {},
483
+ "listings": {},
484
+ "total_success": 0,
485
+ "total_failed": 0,
486
+ "total_found": 0,
487
+ }
488
+
489
+ # Publish in order: sellers -> providers -> offerings -> listings
490
+ publish_order = [
491
+ ("sellers", self.publish_all_sellers),
492
+ ("providers", self.publish_all_providers),
493
+ ("offerings", self.publish_all_offerings),
494
+ ("listings", self.publish_all_listings),
495
+ ]
496
+
497
+ for data_type, publish_method in publish_order:
498
+ try:
499
+ results = publish_method(data_dir)
500
+ all_results[data_type] = results
501
+ all_results["total_success"] += results["success"]
502
+ all_results["total_failed"] += results["failed"]
503
+ all_results["total_found"] += results["total"]
504
+ except Exception as e:
505
+ # If a publish method fails catastrophically, record the error
506
+ all_results[data_type] = {
507
+ "total": 0,
508
+ "success": 0,
509
+ "failed": 1,
510
+ "errors": [{"file": "N/A", "error": str(e)}],
511
+ }
512
+ all_results["total_failed"] += 1
513
+
514
+ return all_results
515
+
490
516
  def close(self):
491
517
  """Close the HTTP client."""
492
518
  self.client.close()
@@ -505,34 +531,145 @@ app = typer.Typer(help="Publish data to backend")
505
531
  console = Console()
506
532
 
507
533
 
508
- @app.command("providers")
509
- def publish_providers(
510
- data_path: Path | None = typer.Argument(
511
- None,
512
- help="Path to provider file or directory (default: ./data or UNITYSVC_DATA_DIR env var)",
513
- ),
514
- backend_url: str | None = typer.Option(
534
+ @app.callback(invoke_without_command=True)
535
+ def publish_callback(
536
+ ctx: typer.Context,
537
+ data_path: Path | None = typer.Option(
515
538
  None,
516
- "--backend-url",
517
- "-u",
518
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
539
+ "--data-path",
540
+ "-d",
541
+ help="Path to data directory (default: current directory)",
519
542
  ),
520
- api_key: str | None = typer.Option(
543
+ ):
544
+ """
545
+ Publish data to backend.
546
+
547
+ When called without a subcommand, publishes all data types in order:
548
+ sellers → providers → offerings → listings.
549
+
550
+ Use subcommands to publish specific data types:
551
+ - providers: Publish only providers
552
+ - sellers: Publish only sellers
553
+ - offerings: Publish only service offerings
554
+ - listings: Publish only service listings
555
+
556
+ Required environment variables:
557
+ - UNITYSVC_BASE_URL: Backend API URL
558
+ - UNITYSVC_API_KEY: API key for authentication
559
+ """
560
+ # If a subcommand was invoked, skip this callback logic
561
+ if ctx.invoked_subcommand is not None:
562
+ return
563
+
564
+ # No subcommand - publish all
565
+ # Set data path
566
+ if data_path is None:
567
+ data_path = Path.cwd()
568
+
569
+ if not data_path.is_absolute():
570
+ data_path = Path.cwd() / data_path
571
+
572
+ if not data_path.exists():
573
+ console.print(f"[red]✗[/red] Path not found: {data_path}", style="bold red")
574
+ raise typer.Exit(code=1)
575
+
576
+ # Get backend URL from environment
577
+ backend_url = os.getenv("UNITYSVC_BASE_URL")
578
+ if not backend_url:
579
+ console.print(
580
+ "[red]✗[/red] UNITYSVC_BASE_URL environment variable not set.",
581
+ style="bold red",
582
+ )
583
+ raise typer.Exit(code=1)
584
+
585
+ # Get API key from environment
586
+ api_key = os.getenv("UNITYSVC_API_KEY")
587
+ if not api_key:
588
+ console.print(
589
+ "[red]✗[/red] UNITYSVC_API_KEY environment variable not set.",
590
+ style="bold red",
591
+ )
592
+ raise typer.Exit(code=1)
593
+
594
+ console.print(f"[bold blue]Publishing all data from:[/bold blue] {data_path}")
595
+ console.print(f"[bold blue]Backend URL:[/bold blue] {backend_url}\n")
596
+
597
+ try:
598
+ with ServiceDataPublisher(backend_url, api_key) as publisher:
599
+ # Call the publish_all_models method
600
+ all_results = publisher.publish_all_models(data_path)
601
+
602
+ # Display results for each data type
603
+ data_type_display_names = {
604
+ "sellers": "Sellers",
605
+ "providers": "Providers",
606
+ "offerings": "Service Offerings",
607
+ "listings": "Service Listings",
608
+ }
609
+
610
+ for data_type in ["sellers", "providers", "offerings", "listings"]:
611
+ display_name = data_type_display_names[data_type]
612
+ results = all_results[data_type]
613
+
614
+ console.print(f"\n[bold cyan]{'=' * 60}[/bold cyan]")
615
+ console.print(f"[bold cyan]{display_name}[/bold cyan]")
616
+ console.print(f"[bold cyan]{'=' * 60}[/bold cyan]\n")
617
+
618
+ console.print(f" Total found: {results['total']}")
619
+ console.print(f" [green]✓ Success:[/green] {results['success']}")
620
+ console.print(f" [red]✗ Failed:[/red] {results['failed']}")
621
+
622
+ # Display errors if any
623
+ if results.get("errors"):
624
+ console.print(f"\n[bold red]Errors in {display_name}:[/bold red]")
625
+ for error in results["errors"]:
626
+ # Check if this is a skipped item
627
+ if isinstance(error, dict) and error.get("error", "").startswith("skipped"):
628
+ continue
629
+ console.print(f" [red]✗[/red] {error.get('file', 'unknown')}")
630
+ console.print(f" {error.get('error', 'unknown error')}")
631
+
632
+ # Final summary
633
+ console.print(f"\n[bold cyan]{'=' * 60}[/bold cyan]")
634
+ console.print("[bold]Final Publishing Summary[/bold]")
635
+ console.print(f"[bold cyan]{'=' * 60}[/bold cyan]\n")
636
+ console.print(f" Total found: {all_results['total_found']}")
637
+ console.print(f" [green]✓ Success:[/green] {all_results['total_success']}")
638
+ console.print(f" [red]✗ Failed:[/red] {all_results['total_failed']}")
639
+
640
+ if all_results["total_failed"] > 0:
641
+ console.print(
642
+ f"\n[yellow]⚠[/yellow] Completed with {all_results['total_failed']} failure(s)",
643
+ style="bold yellow",
644
+ )
645
+ raise typer.Exit(code=1)
646
+ else:
647
+ console.print(
648
+ "\n[green]✓[/green] All data published successfully!",
649
+ style="bold green",
650
+ )
651
+
652
+ except typer.Exit:
653
+ raise
654
+ except Exception as e:
655
+ console.print(f"[red]✗[/red] Failed to publish all data: {e}", style="bold red")
656
+ raise typer.Exit(code=1)
657
+
658
+
659
+ @app.command("providers")
660
+ def publish_providers(
661
+ data_path: Path | None = typer.Option(
521
662
  None,
522
- "--api-key",
523
- "-k",
524
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
663
+ "--data-path",
664
+ "-d",
665
+ help="Path to provider file or directory (default: current directory)",
525
666
  ),
526
667
  ):
527
668
  """Publish provider(s) from a file or directory."""
528
669
 
529
670
  # Set data path
530
671
  if data_path is None:
531
- data_path_str = os.getenv("UNITYSVC_DATA_DIR")
532
- if data_path_str:
533
- data_path = Path(data_path_str)
534
- else:
535
- data_path = Path.cwd() / "data"
672
+ data_path = Path.cwd()
536
673
 
537
674
  if not data_path.is_absolute():
538
675
  data_path = Path.cwd() / data_path
@@ -541,20 +678,20 @@ def publish_providers(
541
678
  console.print(f"[red]✗[/red] Path not found: {data_path}", style="bold red")
542
679
  raise typer.Exit(code=1)
543
680
 
544
- # Get backend URL from argument or environment
545
- backend_url = backend_url or os.getenv("UNITYSVC_BACKEND_URL")
681
+ # Get backend URL from environment
682
+ backend_url = os.getenv("UNITYSVC_BASE_URL")
546
683
  if not backend_url:
547
684
  console.print(
548
- "[red]✗[/red] Backend URL not provided. Use --backend-url or set UNITYSVC_BACKEND_URL env var.",
685
+ "[red]✗[/red] UNITYSVC_BASE_URL environment variable not set.",
549
686
  style="bold red",
550
687
  )
551
688
  raise typer.Exit(code=1)
552
689
 
553
- # Get API key from argument or environment
554
- api_key = api_key or os.getenv("UNITYSVC_API_KEY")
690
+ # Get API key from environment
691
+ api_key = os.getenv("UNITYSVC_API_KEY")
555
692
  if not api_key:
556
693
  console.print(
557
- "[red]✗[/red] API key not provided. Use --api-key or set UNITYSVC_API_KEY env var.",
694
+ "[red]✗[/red] UNITYSVC_API_KEY environment variable not set.",
558
695
  style="bold red",
559
696
  )
560
697
  raise typer.Exit(code=1)
@@ -593,39 +730,23 @@ def publish_providers(
593
730
  except typer.Exit:
594
731
  raise
595
732
  except Exception as e:
596
- console.print(
597
- f"[red]✗[/red] Failed to publish providers: {e}", style="bold red"
598
- )
733
+ console.print(f"[red]✗[/red] Failed to publish providers: {e}", style="bold red")
599
734
  raise typer.Exit(code=1)
600
735
 
601
736
 
602
737
  @app.command("sellers")
603
738
  def publish_sellers(
604
- data_path: Path | None = typer.Argument(
605
- None,
606
- help="Path to seller file or directory (default: ./data or UNITYSVC_DATA_DIR env var)",
607
- ),
608
- backend_url: str | None = typer.Option(
739
+ data_path: Path | None = typer.Option(
609
740
  None,
610
- "--backend-url",
611
- "-u",
612
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
613
- ),
614
- api_key: str | None = typer.Option(
615
- None,
616
- "--api-key",
617
- "-k",
618
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
741
+ "--data-path",
742
+ "-d",
743
+ help="Path to seller file or directory (default: current directory)",
619
744
  ),
620
745
  ):
621
746
  """Publish seller(s) from a file or directory."""
622
747
  # Set data path
623
748
  if data_path is None:
624
- data_path_str = os.getenv("UNITYSVC_DATA_DIR")
625
- if data_path_str:
626
- data_path = Path(data_path_str)
627
- else:
628
- data_path = Path.cwd() / "data"
749
+ data_path = Path.cwd()
629
750
 
630
751
  if not data_path.is_absolute():
631
752
  data_path = Path.cwd() / data_path
@@ -634,20 +755,20 @@ def publish_sellers(
634
755
  console.print(f"[red]✗[/red] Path not found: {data_path}", style="bold red")
635
756
  raise typer.Exit(code=1)
636
757
 
637
- # Get backend URL
638
- backend_url = backend_url or os.getenv("UNITYSVC_BACKEND_URL")
758
+ # Get backend URL from environment
759
+ backend_url = os.getenv("UNITYSVC_BASE_URL")
639
760
  if not backend_url:
640
761
  console.print(
641
- "[red]✗[/red] Backend URL not provided. Use --backend-url or set UNITYSVC_BACKEND_URL env var.",
762
+ "[red]✗[/red] UNITYSVC_BASE_URL environment variable not set.",
642
763
  style="bold red",
643
764
  )
644
765
  raise typer.Exit(code=1)
645
766
 
646
- # Get API key
647
- api_key = api_key or os.getenv("UNITYSVC_API_KEY")
767
+ # Get API key from environment
768
+ api_key = os.getenv("UNITYSVC_API_KEY")
648
769
  if not api_key:
649
770
  console.print(
650
- "[red]✗[/red] API key not provided. Use --api-key or set UNITYSVC_API_KEY env var.",
771
+ "[red]✗[/red] UNITYSVC_API_KEY environment variable not set.",
651
772
  style="bold red",
652
773
  )
653
774
  raise typer.Exit(code=1)
@@ -679,9 +800,7 @@ def publish_sellers(
679
800
  console.print(f" {error['error']}")
680
801
  raise typer.Exit(code=1)
681
802
  else:
682
- console.print(
683
- "\n[green]✓[/green] All sellers published successfully!"
684
- )
803
+ console.print("\n[green]✓[/green] All sellers published successfully!")
685
804
 
686
805
  except typer.Exit:
687
806
  raise
@@ -692,31 +811,17 @@ def publish_sellers(
692
811
 
693
812
  @app.command("offerings")
694
813
  def publish_offerings(
695
- data_path: Path | None = typer.Argument(
696
- None,
697
- help="Path to service offering file or directory (default: ./data or UNITYSVC_DATA_DIR env var)",
698
- ),
699
- backend_url: str | None = typer.Option(
700
- None,
701
- "--backend-url",
702
- "-u",
703
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
704
- ),
705
- api_key: str | None = typer.Option(
814
+ data_path: Path | None = typer.Option(
706
815
  None,
707
- "--api-key",
708
- "-k",
709
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
816
+ "--data-path",
817
+ "-d",
818
+ help="Path to service offering file or directory (default: current directory)",
710
819
  ),
711
820
  ):
712
821
  """Publish service offering(s) from a file or directory."""
713
822
  # Set data path
714
823
  if data_path is None:
715
- data_path_str = os.getenv("UNITYSVC_DATA_DIR")
716
- if data_path_str:
717
- data_path = Path(data_path_str)
718
- else:
719
- data_path = Path.cwd() / "data"
824
+ data_path = Path.cwd()
720
825
 
721
826
  if not data_path.is_absolute():
722
827
  data_path = Path.cwd() / data_path
@@ -725,20 +830,20 @@ def publish_offerings(
725
830
  console.print(f"[red]✗[/red] Path not found: {data_path}", style="bold red")
726
831
  raise typer.Exit(code=1)
727
832
 
728
- # Get backend URL from argument or environment
729
- backend_url = backend_url or os.getenv("UNITYSVC_BACKEND_URL")
833
+ # Get backend URL from environment
834
+ backend_url = os.getenv("UNITYSVC_BASE_URL")
730
835
  if not backend_url:
731
836
  console.print(
732
- "[red]✗[/red] Backend URL not provided. Use --backend-url or set UNITYSVC_BACKEND_URL env var.",
837
+ "[red]✗[/red] UNITYSVC_BASE_URL environment variable not set.",
733
838
  style="bold red",
734
839
  )
735
840
  raise typer.Exit(code=1)
736
841
 
737
- # Get API key from argument or environment
738
- api_key = api_key or os.getenv("UNITYSVC_API_KEY")
842
+ # Get API key from environment
843
+ api_key = os.getenv("UNITYSVC_API_KEY")
739
844
  if not api_key:
740
845
  console.print(
741
- "[red]✗[/red] API key not provided. Use --api-key or set UNITYSVC_API_KEY env var.",
846
+ "[red]✗[/red] UNITYSVC_API_KEY environment variable not set.",
742
847
  style="bold red",
743
848
  )
744
849
  raise typer.Exit(code=1)
@@ -750,15 +855,11 @@ def publish_offerings(
750
855
  console.print(f"[blue]Publishing service offering:[/blue] {data_path}")
751
856
  console.print(f"[blue]Backend URL:[/blue] {backend_url}\n")
752
857
  result = publisher.post_service_offering(data_path)
753
- console.print(
754
- "[green]✓[/green] Service offering published successfully!"
755
- )
858
+ console.print("[green]✓[/green] Service offering published successfully!")
756
859
  console.print(f"[cyan]Response:[/cyan] {json.dumps(result, indent=2)}")
757
860
  # Handle directory
758
861
  else:
759
- console.print(
760
- f"[blue]Scanning for service offerings in:[/blue] {data_path}"
761
- )
862
+ console.print(f"[blue]Scanning for service offerings in:[/blue] {data_path}")
762
863
  console.print(f"[blue]Backend URL:[/blue] {backend_url}\n")
763
864
  results = publisher.publish_all_offerings(data_path)
764
865
 
@@ -774,47 +875,29 @@ def publish_offerings(
774
875
  console.print(f" {error['error']}")
775
876
  raise typer.Exit(code=1)
776
877
  else:
777
- console.print(
778
- "\n[green]✓[/green] All service offerings published successfully!"
779
- )
878
+ console.print("\n[green]✓[/green] All service offerings published successfully!")
780
879
 
781
880
  except typer.Exit:
782
881
  raise
783
882
  except Exception as e:
784
- console.print(
785
- f"[red]✗[/red] Failed to publish service offerings: {e}", style="bold red"
786
- )
883
+ console.print(f"[red]✗[/red] Failed to publish service offerings: {e}", style="bold red")
787
884
  raise typer.Exit(code=1)
788
885
 
789
886
 
790
887
  @app.command("listings")
791
888
  def publish_listings(
792
- data_path: Path | None = typer.Argument(
793
- None,
794
- help="Path to service listing file or directory (default: ./data or UNITYSVC_DATA_DIR env var)",
795
- ),
796
- backend_url: str | None = typer.Option(
889
+ data_path: Path | None = typer.Option(
797
890
  None,
798
- "--backend-url",
799
- "-u",
800
- help="UnitySVC backend URL (default: from UNITYSVC_BACKEND_URL env var)",
801
- ),
802
- api_key: str | None = typer.Option(
803
- None,
804
- "--api-key",
805
- "-k",
806
- help="API key for authentication (default: from UNITYSVC_API_KEY env var)",
891
+ "--data-path",
892
+ "-d",
893
+ help="Path to service listing file or directory (default: current directory)",
807
894
  ),
808
895
  ):
809
896
  """Publish service listing(s) from a file or directory."""
810
897
 
811
898
  # Set data path
812
899
  if data_path is None:
813
- data_path_str = os.getenv("UNITYSVC_DATA_DIR")
814
- if data_path_str:
815
- data_path = Path(data_path_str)
816
- else:
817
- data_path = Path.cwd() / "data"
900
+ data_path = Path.cwd()
818
901
 
819
902
  if not data_path.is_absolute():
820
903
  data_path = Path.cwd() / data_path
@@ -823,20 +906,20 @@ def publish_listings(
823
906
  console.print(f"[red]✗[/red] Path not found: {data_path}", style="bold red")
824
907
  raise typer.Exit(code=1)
825
908
 
826
- # Get backend URL from argument or environment
827
- backend_url = backend_url or os.getenv("UNITYSVC_BACKEND_URL")
909
+ # Get backend URL from environment
910
+ backend_url = os.getenv("UNITYSVC_BASE_URL")
828
911
  if not backend_url:
829
912
  console.print(
830
- "[red]✗[/red] Backend URL not provided. Use --backend-url or set UNITYSVC_BACKEND_URL env var.",
913
+ "[red]✗[/red] UNITYSVC_BASE_URL environment variable not set.",
831
914
  style="bold red",
832
915
  )
833
916
  raise typer.Exit(code=1)
834
917
 
835
- # Get API key from argument or environment
836
- api_key = api_key or os.getenv("UNITYSVC_API_KEY")
918
+ # Get API key from environment
919
+ api_key = os.getenv("UNITYSVC_API_KEY")
837
920
  if not api_key:
838
921
  console.print(
839
- "[red]✗[/red] API key not provided. Use --api-key or set UNITYSVC_API_KEY env var.",
922
+ "[red]✗[/red] UNITYSVC_API_KEY environment variable not set.",
840
923
  style="bold red",
841
924
  )
842
925
  raise typer.Exit(code=1)
@@ -848,15 +931,11 @@ def publish_listings(
848
931
  console.print(f"[blue]Publishing service listing:[/blue] {data_path}")
849
932
  console.print(f"[blue]Backend URL:[/blue] {backend_url}\n")
850
933
  result = publisher.post_service_listing(data_path)
851
- console.print(
852
- "[green]✓[/green] Service listing published successfully!"
853
- )
934
+ console.print("[green]✓[/green] Service listing published successfully!")
854
935
  console.print(f"[cyan]Response:[/cyan] {json.dumps(result, indent=2)}")
855
936
  # Handle directory
856
937
  else:
857
- console.print(
858
- f"[blue]Scanning for service listings in:[/blue] {data_path}"
859
- )
938
+ console.print(f"[blue]Scanning for service listings in:[/blue] {data_path}")
860
939
  console.print(f"[blue]Backend URL:[/blue] {backend_url}\n")
861
940
  results = publisher.publish_all_listings(data_path)
862
941
 
@@ -872,14 +951,10 @@ def publish_listings(
872
951
  console.print(f" {error['error']}")
873
952
  raise typer.Exit(code=1)
874
953
  else:
875
- console.print(
876
- "\n[green]✓[/green] All service listings published successfully!"
877
- )
954
+ console.print("\n[green]✓[/green] All service listings published successfully!")
878
955
 
879
956
  except typer.Exit:
880
957
  raise
881
958
  except Exception as e:
882
- console.print(
883
- f"[red]✗[/red] Failed to publish service listings: {e}", style="bold red"
884
- )
959
+ console.print(f"[red]✗[/red] Failed to publish service listings: {e}", style="bold red")
885
960
  raise typer.Exit(code=1)