chipfoundry-cli 2.4.6__tar.gz → 2.4.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: chipfoundry-cli
3
- Version: 2.4.6
3
+ Version: 2.4.9
4
4
  Summary: CLI tool to automate ChipFoundry project submission to SFTP server
5
5
  Home-page: https://chipfoundry.io
6
6
  License: Apache-2.0
@@ -389,6 +389,59 @@ def _prompt_with_default(label: str, current: Optional[str], detected: Optional[
389
389
  return raw
390
390
 
391
391
 
392
+ def _shuttle_sort_key(shuttle: dict) -> str:
393
+ """Sort shuttles by date while handling null/missing dates safely."""
394
+ tapeout_date = shuttle.get("tapeout_date")
395
+ if isinstance(tapeout_date, str) and tapeout_date.strip():
396
+ return tapeout_date
397
+ return "9999-12-31"
398
+
399
+
400
+ def _confirm_new_project_creation() -> bool:
401
+ """Ask for explicit confirmation before creating a new platform project."""
402
+ return click.confirm(
403
+ "Create a NEW platform project now? "
404
+ "(Select 'No' if you intended to link an existing project with `cf link`.)",
405
+ default=False,
406
+ )
407
+
408
+
409
+ def _prompt_init_platform_action() -> str:
410
+ """Ask whether init should link to an existing project or create a new one."""
411
+ console.print("\n[bold]Platform action[/bold]")
412
+ console.print(" [cyan]1[/cyan]. Link to an existing platform project")
413
+ console.print(" [cyan]2[/cyan]. Create a new platform project")
414
+ choice = console.input("Select option [1/2, default 1]: ").strip()
415
+ if choice in ("", "1"):
416
+ return "link"
417
+ if choice == "2":
418
+ return "create"
419
+ console.print("[yellow]Invalid selection — defaulting to linking an existing project.[/yellow]")
420
+ return "link"
421
+
422
+
423
+ def _choose_platform_project(projects: List[dict]) -> Optional[dict]:
424
+ """Show a numbered project list and return the selected project, if any."""
425
+ console.print("\n[bold]Your platform projects:[/bold]")
426
+ for i, p in enumerate(projects, 1):
427
+ status_str = p.get('status', 'unknown')
428
+ shuttle_str = f" — {p.get('shuttle_name', '')}" if p.get('shuttle_name') else ""
429
+ console.print(f" [cyan]{i}[/cyan]. {p['name']}{shuttle_str} [{status_str}]")
430
+ console.print(f" [cyan]{len(projects) + 1}[/cyan]. Create a new platform project")
431
+
432
+ choice = console.input("\nSelect project number: ").strip()
433
+ try:
434
+ idx = int(choice) - 1
435
+ if 0 <= idx < len(projects):
436
+ return projects[idx]
437
+ if idx == len(projects):
438
+ return None
439
+ except ValueError:
440
+ pass
441
+ console.print("[red]Invalid selection.[/red]")
442
+ return None
443
+
444
+
392
445
  @main.command('init')
393
446
  @click.option('--project-root', required=False, type=click.Path(file_okay=False), help='Project directory (defaults to current directory).')
394
447
  @click.option('--shuttle', default=None, help='Shuttle name or ID to associate with the project.')
@@ -539,12 +592,43 @@ def init(project_root, shuttle, description):
539
592
  console.print(f" Portal: {portal_url}/projects/{platform_id}")
540
593
  return
541
594
 
595
+ if api_key:
596
+ try:
597
+ projects = _api_get("/projects/me")
598
+ except SystemExit:
599
+ projects = []
600
+ if projects:
601
+ action = _prompt_init_platform_action()
602
+ if action == "link":
603
+ selected = _choose_platform_project(projects)
604
+ if selected:
605
+ proj['platform_project_id'] = selected['id']
606
+ if selected.get('name'):
607
+ old_name = proj.get('name')
608
+ proj['name'] = selected['name']
609
+ if old_name and old_name != selected['name']:
610
+ console.print(
611
+ f"[yellow]Updated project name: '{old_name}' → '{selected['name']}' "
612
+ "(synced from platform)[/yellow]"
613
+ )
614
+ with open(project_json_path, 'w') as f:
615
+ json.dump(data, f, indent=2)
616
+ portal_url = _get_portal_url()
617
+ console.print(f"\n[green]✓ Linked to existing platform project[/green]")
618
+ console.print(f" Name: {selected['name']}")
619
+ console.print(f" ID: {selected['id']}")
620
+ if github_repo_url:
621
+ console.print(f" GitHub: {github_repo_url}")
622
+ console.print(f" Portal: {portal_url}/projects/{selected['id']}")
623
+ return
624
+ console.print("[dim]Continuing with new project creation.[/dim]")
625
+
542
626
  shuttle_id = shuttle
543
627
  if not shuttle_id:
544
628
  try:
545
629
  shuttles = _api_get("/shuttles/available")
546
630
  if shuttles:
547
- shuttles.sort(key=lambda s: s.get('tapeout_date', '9999-12-31'))
631
+ shuttles.sort(key=_shuttle_sort_key)
548
632
  console.print("\n[bold]Available shuttles:[/bold]")
549
633
  for i, s in enumerate(shuttles, 1):
550
634
  deadline = s.get('tapeout_date', '')
@@ -571,6 +655,13 @@ def init(project_root, shuttle, description):
571
655
  if github_repo_url:
572
656
  create_data["github_repo_url"] = github_repo_url
573
657
 
658
+ if not _confirm_new_project_creation():
659
+ with open(project_json_path, 'w') as f:
660
+ json.dump(data, f, indent=2)
661
+ console.print("[yellow]Skipped platform project creation.[/yellow]")
662
+ console.print("[dim]Tip: Run [bold]cf link[/bold] to select an existing platform project.[/dim]")
663
+ return
664
+
574
665
  try:
575
666
  project_resp = _api_post("/projects", create_data)
576
667
  new_id = project_resp.get('id')
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "chipfoundry-cli"
3
- version = "2.4.6"
3
+ version = "2.4.9"
4
4
  description = "CLI tool to automate ChipFoundry project submission to SFTP server"
5
5
  authors = ["ChipFoundry <marwan.abbas@chipfoundry.io>"]
6
6
  readme = "README.md"
File without changes