chipfoundry-cli 2.4.5__tar.gz → 2.4.6__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.5
3
+ Version: 2.4.6
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
@@ -681,6 +681,10 @@ cf pull [--project-name NAME]
681
681
  **Prerequisites:** `cf login`, `cf link` (or `cf init`), `cf config`
682
682
 
683
683
  - Downloads project results from SFTP server
684
+ - **Resolves the remote results directory by `platform_project_id` (UUID), not by project name** — survives case changes (e.g. `kyttar` → `Kyttar`) and renames on the platform without manual intervention
685
+ - First asks the platform API for the canonical project name and tries `outgoing/results/<canonical_name>`
686
+ - If that path is missing, falls back to scanning `outgoing/results/*/config/project.json` for a matching `platform_project_id`
687
+ - Pass `--project-name NAME` to bypass UUID resolution and force a literal directory lookup (debugging / unlinked legacy use)
684
688
  - Saves to `sftp-output/<project_name>/`
685
689
  - **Automatically updates** your local `.cf/project.json` with the pulled version (preserving the platform link)
686
690
  - **Syncs with the platform** and displays admin review notes if your project has been reviewed
@@ -885,20 +889,26 @@ The CLI tracks your project submission state through the `submission_state` fiel
885
889
  - Connects to SFTP server securely
886
890
  - Shows clean connection status
887
891
 
888
- 2. **Download:**
892
+ 2. **Resolve remote directory by UUID:**
893
+ - Looks up the canonical project name from the platform via `platform_project_id`
894
+ - Tries `outgoing/results/<canonical_name>` first
895
+ - If that path is missing, scans `outgoing/results/*/config/project.json` for a directory whose embedded `platform_project_id` matches yours
896
+ - Warns if your local project name differs from the canonical platform name (the local copy is corrected automatically in step 4)
897
+
898
+ 3. **Download:**
889
899
  - Downloads all project results recursively
890
900
  - Shows professional download progress
891
901
  - Saves to `sftp-output/<project_name>/`
892
902
 
893
- 3. **Config Update:**
903
+ 4. **Config Update:**
894
904
  - **Automatically merges** the pulled `project.json` with your local version (preserving the platform link)
895
905
 
896
- 4. **Platform Sync:**
906
+ 5. **Platform Sync:**
897
907
  - Sends the updated `project.json` to the platform
898
908
  - Records the pull timestamp on the platform
899
909
  - Fetches and displays any admin review notes
900
910
 
901
- 5. **Success:**
911
+ 6. **Success:**
902
912
  - Shows confirmation of downloaded files, sync status, and review notes
903
913
 
904
914
  ---
@@ -655,6 +655,10 @@ cf pull [--project-name NAME]
655
655
  **Prerequisites:** `cf login`, `cf link` (or `cf init`), `cf config`
656
656
 
657
657
  - Downloads project results from SFTP server
658
+ - **Resolves the remote results directory by `platform_project_id` (UUID), not by project name** — survives case changes (e.g. `kyttar` → `Kyttar`) and renames on the platform without manual intervention
659
+ - First asks the platform API for the canonical project name and tries `outgoing/results/<canonical_name>`
660
+ - If that path is missing, falls back to scanning `outgoing/results/*/config/project.json` for a matching `platform_project_id`
661
+ - Pass `--project-name NAME` to bypass UUID resolution and force a literal directory lookup (debugging / unlinked legacy use)
658
662
  - Saves to `sftp-output/<project_name>/`
659
663
  - **Automatically updates** your local `.cf/project.json` with the pulled version (preserving the platform link)
660
664
  - **Syncs with the platform** and displays admin review notes if your project has been reviewed
@@ -859,20 +863,26 @@ The CLI tracks your project submission state through the `submission_state` fiel
859
863
  - Connects to SFTP server securely
860
864
  - Shows clean connection status
861
865
 
862
- 2. **Download:**
866
+ 2. **Resolve remote directory by UUID:**
867
+ - Looks up the canonical project name from the platform via `platform_project_id`
868
+ - Tries `outgoing/results/<canonical_name>` first
869
+ - If that path is missing, scans `outgoing/results/*/config/project.json` for a directory whose embedded `platform_project_id` matches yours
870
+ - Warns if your local project name differs from the canonical platform name (the local copy is corrected automatically in step 4)
871
+
872
+ 3. **Download:**
863
873
  - Downloads all project results recursively
864
874
  - Shows professional download progress
865
875
  - Saves to `sftp-output/<project_name>/`
866
876
 
867
- 3. **Config Update:**
877
+ 4. **Config Update:**
868
878
  - **Automatically merges** the pulled `project.json` with your local version (preserving the platform link)
869
879
 
870
- 4. **Platform Sync:**
880
+ 5. **Platform Sync:**
871
881
  - Sends the updated `project.json` to the platform
872
882
  - Records the pull timestamp on the platform
873
883
  - Fetches and displays any admin review notes
874
884
 
875
- 5. **Success:**
885
+ 6. **Success:**
876
886
  - Shows confirmation of downloaded files, sync status, and review notes
877
887
 
878
888
  ---
@@ -1,2 +1,2 @@
1
1
  """ChipFoundry CLI package: Automate project submission to SFTP."""
2
- __version__ = "2.4.1"
2
+ __version__ = "2.4.6"
@@ -2078,6 +2078,9 @@ def push(project_root, sftp_host, sftp_username, sftp_key, project_id, project_n
2078
2078
  @click.option('--sftp-key', type=click.Path(exists=True, dir_okay=False), help='Path to SFTP private key file (defaults to config).', default=None, show_default=False)
2079
2079
  def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key):
2080
2080
  """Download results/artifacts from SFTP output dir to local sftp-output/<project_name>."""
2081
+ # Track whether the user explicitly passed --project-name (overrides
2082
+ # canonical-name resolution via the platform API below).
2083
+ explicit_project_name = project_name
2081
2084
  # If .cf/project.json exists in cwd, use its project name as default
2082
2085
  _, cwd_project_name = get_project_json_from_cwd()
2083
2086
  if not project_name and cwd_project_name:
@@ -2142,16 +2145,67 @@ def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key):
2142
2145
  raise click.Abort()
2143
2146
 
2144
2147
  try:
2148
+ # Resolve the remote results directory.
2149
+ #
2150
+ # Priority:
2151
+ # 1. If the user passed --project-name explicitly, honor that name
2152
+ # verbatim (escape hatch / debugging).
2153
+ # 2. Otherwise, ask the platform API for the canonical project name
2154
+ # via the platform_project_id (UUID) and try that name first.
2155
+ # 3. If that directory does not exist on SFTP (e.g. the platform was
2156
+ # renamed but the old export directory still has the previous
2157
+ # name), scan `outgoing/results/*/config/project.json` and match
2158
+ # on `platform_project_id`. This is the authoritative UUID match
2159
+ # and survives case changes and renames.
2160
+ if explicit_project_name:
2161
+ resolved_name = explicit_project_name
2162
+ try:
2163
+ sftp.stat(f"outgoing/results/{resolved_name}")
2164
+ except Exception:
2165
+ console.print(f"[yellow]No results found for project '{resolved_name}' on SFTP server.[/yellow]")
2166
+ return
2167
+ else:
2168
+ try:
2169
+ platform_proj = _api_get(f"/projects/{platform_id}")
2170
+ except SystemExit:
2171
+ console.print(f"[red]Could not resolve canonical project name for platform_project_id={platform_id} from the platform API.[/red]")
2172
+ raise click.Abort()
2173
+ canonical_name = platform_proj.get("name") if isinstance(platform_proj, dict) else None
2174
+ if not canonical_name:
2175
+ console.print(f"[red]Platform did not return a name for project {platform_id}; cannot resolve SFTP directory.[/red]")
2176
+ raise click.Abort()
2177
+
2178
+ try:
2179
+ sftp.stat(f"outgoing/results/{canonical_name}")
2180
+ resolved_name = canonical_name
2181
+ if cwd_project_name and cwd_project_name != canonical_name:
2182
+ console.print(
2183
+ f"[yellow]Local project name '{cwd_project_name}' does not match the platform "
2184
+ f"name '{canonical_name}'. Using the platform name; your local .cf/project.json "
2185
+ f"will be updated after the pull completes.[/yellow]"
2186
+ )
2187
+ except Exception:
2188
+ console.print(
2189
+ f"[yellow]'outgoing/results/{canonical_name}' not found on SFTP. "
2190
+ f"Searching by project UUID ({platform_id})...[/yellow]"
2191
+ )
2192
+ matched_dir = _find_remote_results_dir_by_uuid(sftp, platform_id)
2193
+ if matched_dir is None:
2194
+ console.print(
2195
+ f"[yellow]No results found for project '{canonical_name}' (UUID {platform_id}) on SFTP server.[/yellow]"
2196
+ )
2197
+ return
2198
+ resolved_name = matched_dir
2199
+ console.print(
2200
+ f"[yellow]Found a results directory matching this project's UUID at "
2201
+ f"'outgoing/results/{matched_dir}'. The directory name on SFTP differs from the "
2202
+ f"platform name '{canonical_name}' — using the SFTP directory.[/yellow]"
2203
+ )
2204
+
2205
+ project_name = resolved_name
2145
2206
  remote_dir = f"outgoing/results/{project_name}"
2146
2207
  output_dir = os.path.join(os.getcwd(), "sftp-output", project_name)
2147
-
2148
- # Check if remote directory exists
2149
- try:
2150
- sftp.stat(remote_dir)
2151
- except Exception:
2152
- console.print(f"[yellow]No results found for project '{project_name}' on SFTP server.[/yellow]")
2153
- return
2154
-
2208
+
2155
2209
  # Create output directory
2156
2210
  os.makedirs(output_dir, exist_ok=True)
2157
2211
 
@@ -4735,6 +4789,34 @@ def _load_project_platform_id(project_root: str):
4735
4789
  return data.get('project', {}).get('platform_project_id')
4736
4790
 
4737
4791
 
4792
+ def _find_remote_results_dir_by_uuid(sftp, platform_id: str) -> Optional[str]:
4793
+ """Scan outgoing/results/*/config/project.json for a directory whose embedded
4794
+ platform_project_id matches `platform_id`. Returns the bare directory name
4795
+ (not the full path) of the first match, or None if no match is found.
4796
+
4797
+ Used by `cf pull` as a UUID-based fallback when the canonical project
4798
+ name from the platform does not resolve to an SFTP directory (e.g. the
4799
+ project was renamed on the platform but the old SFTP results directory
4800
+ still has the previous name on disk).
4801
+ """
4802
+ try:
4803
+ dirs = sftp.listdir("outgoing/results")
4804
+ except Exception:
4805
+ return None
4806
+
4807
+ for d in dirs:
4808
+ cfg_path = f"outgoing/results/{d}/config/project.json"
4809
+ try:
4810
+ with sftp.open(cfg_path, "r") as f:
4811
+ data = json.loads(f.read().decode("utf-8"))
4812
+ except Exception:
4813
+ continue
4814
+ proj = data.get("project", {}) if isinstance(data, dict) else {}
4815
+ if isinstance(proj, dict) and proj.get("platform_project_id") == platform_id:
4816
+ return d
4817
+ return None
4818
+
4819
+
4738
4820
  def _save_platform_id(project_root: str, platform_id: str, project_name: str = None):
4739
4821
  """Write platform_project_id (and optionally project name) into .cf/project.json."""
4740
4822
  pj = Path(project_root) / '.cf' / 'project.json'
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "chipfoundry-cli"
3
- version = "2.4.5"
3
+ version = "2.4.6"
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