chipfoundry-cli 2.4.6__tar.gz → 2.4.10__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.
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/PKG-INFO +11 -2
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/README.md +10 -1
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/chipfoundry_cli/main.py +131 -1
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/pyproject.toml +1 -1
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/LICENSE +0 -0
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/chipfoundry_cli/__init__.py +0 -0
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/chipfoundry_cli/check_refs.py +0 -0
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/chipfoundry_cli/remote_precheck_git.py +0 -0
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/chipfoundry_cli/utils.py +0 -0
- {chipfoundry_cli-2.4.6 → chipfoundry_cli-2.4.10}/chipfoundry_cli/version_check.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: chipfoundry-cli
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.10
|
|
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
|
|
@@ -598,7 +598,7 @@ cf push [OPTIONS]
|
|
|
598
598
|
**Options:**
|
|
599
599
|
- `--project-root`: Specify project directory
|
|
600
600
|
- `--force-overwrite`: Overwrite existing files on SFTP (SFTP mode only)
|
|
601
|
-
- `--submit`: Submit the project for review after upload
|
|
601
|
+
- `--submit`: Submit the project for review after upload (shortcut for `cf push` + `cf submit`)
|
|
602
602
|
- `--dry-run`: Preview what would be uploaded
|
|
603
603
|
- `--sftp-username`: Override configured username (SFTP mode only)
|
|
604
604
|
- `--sftp-key`: Override configured key path (SFTP mode only)
|
|
@@ -659,6 +659,15 @@ What happens:
|
|
|
659
659
|
4. Staged S3 objects are deleted on success; any leftovers are expired by the bucket lifecycle after 7 days.
|
|
660
660
|
5. `--submit` submits for review on success.
|
|
661
661
|
|
|
662
|
+
### Submit a Project for Review (No Re-upload)
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
cf submit [--project-root PATH]
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
Use this when your latest `cf push` already uploaded the files you want reviewed.
|
|
669
|
+
`cf submit` moves the platform project into review without requiring another upload.
|
|
670
|
+
|
|
662
671
|
> [!TIP]
|
|
663
672
|
> Try modes in this order: `cf push` → `cf push --remote` → `cf push --https`.
|
|
664
673
|
> The SFTP mode is fastest when unrestricted, `--remote` is the best HTTPS
|
|
@@ -572,7 +572,7 @@ cf push [OPTIONS]
|
|
|
572
572
|
**Options:**
|
|
573
573
|
- `--project-root`: Specify project directory
|
|
574
574
|
- `--force-overwrite`: Overwrite existing files on SFTP (SFTP mode only)
|
|
575
|
-
- `--submit`: Submit the project for review after upload
|
|
575
|
+
- `--submit`: Submit the project for review after upload (shortcut for `cf push` + `cf submit`)
|
|
576
576
|
- `--dry-run`: Preview what would be uploaded
|
|
577
577
|
- `--sftp-username`: Override configured username (SFTP mode only)
|
|
578
578
|
- `--sftp-key`: Override configured key path (SFTP mode only)
|
|
@@ -633,6 +633,15 @@ What happens:
|
|
|
633
633
|
4. Staged S3 objects are deleted on success; any leftovers are expired by the bucket lifecycle after 7 days.
|
|
634
634
|
5. `--submit` submits for review on success.
|
|
635
635
|
|
|
636
|
+
### Submit a Project for Review (No Re-upload)
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
cf submit [--project-root PATH]
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
Use this when your latest `cf push` already uploaded the files you want reviewed.
|
|
643
|
+
`cf submit` moves the platform project into review without requiring another upload.
|
|
644
|
+
|
|
636
645
|
> [!TIP]
|
|
637
646
|
> Try modes in this order: `cf push` → `cf push --remote` → `cf push --https`.
|
|
638
647
|
> The SFTP mode is fastest when unrestricted, `--remote` is the best HTTPS
|
|
@@ -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=
|
|
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')
|
|
@@ -2769,6 +2860,45 @@ def view_tapeout_report(project_name, report_path):
|
|
|
2769
2860
|
console.print(f"[red]Failed to open tapeout report in browser: {e}[/red]")
|
|
2770
2861
|
raise click.Abort()
|
|
2771
2862
|
|
|
2863
|
+
@main.command("submit")
|
|
2864
|
+
@click.option(
|
|
2865
|
+
"--project-root",
|
|
2866
|
+
required=False,
|
|
2867
|
+
type=click.Path(exists=True, file_okay=False),
|
|
2868
|
+
help="Path to the local ChipFoundry project directory (defaults to current directory if .cf/project.json exists).",
|
|
2869
|
+
)
|
|
2870
|
+
def submit(project_root):
|
|
2871
|
+
"""Submit a project for admin review without uploading files again."""
|
|
2872
|
+
cwd_root, _ = get_project_json_from_cwd()
|
|
2873
|
+
if not project_root and cwd_root:
|
|
2874
|
+
project_root = cwd_root
|
|
2875
|
+
if not project_root:
|
|
2876
|
+
console.print(
|
|
2877
|
+
"[red]No project root specified and no .cf/project.json found in current directory.[/red]"
|
|
2878
|
+
)
|
|
2879
|
+
console.print("Provide --project-root or run from a linked project.")
|
|
2880
|
+
raise click.Abort()
|
|
2881
|
+
|
|
2882
|
+
project_root = str(Path(project_root).resolve())
|
|
2883
|
+
platform_id = _load_project_platform_id(project_root)
|
|
2884
|
+
if not platform_id:
|
|
2885
|
+
console.print("[red]Project is not linked to the platform.[/red]")
|
|
2886
|
+
console.print(
|
|
2887
|
+
"Run [bold]cf link[/bold] to connect this project, or [bold]cf init[/bold] to create a new one."
|
|
2888
|
+
)
|
|
2889
|
+
raise click.Abort()
|
|
2890
|
+
|
|
2891
|
+
config = load_user_config()
|
|
2892
|
+
if not config.get("api_key"):
|
|
2893
|
+
console.print("[red]Not logged in.[/red] Run [bold]cf login[/bold] before submitting.")
|
|
2894
|
+
raise click.Abort()
|
|
2895
|
+
|
|
2896
|
+
try:
|
|
2897
|
+
_api_post(f"/projects/{platform_id}/submit", {})
|
|
2898
|
+
console.print("[green]✓ Project submitted for review[/green]")
|
|
2899
|
+
except SystemExit:
|
|
2900
|
+
raise click.Abort()
|
|
2901
|
+
|
|
2772
2902
|
@main.command('confirm')
|
|
2773
2903
|
@click.option('--project-root', required=False, type=click.Path(exists=True, file_okay=False), help='Path to the local ChipFoundry project directory (defaults to current directory if .cf/project.json exists).')
|
|
2774
2904
|
@click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|