python-package-folder 4.3.5__py3-none-any.whl → 5.0.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.
@@ -10,19 +10,13 @@ It can be invoked via:
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- import os
14
- import shutil
15
13
  import subprocess
16
14
  import sys
17
15
  from pathlib import Path
18
16
 
19
- try:
20
- from importlib import resources
21
- except ImportError:
22
- import importlib_resources as resources # type: ignore[no-redef]
23
-
24
17
  from .manager import BuildManager
25
18
  from .utils import find_project_root, find_source_directory
19
+ from .version_calculator import resolve_version
26
20
 
27
21
 
28
22
  def is_github_actions() -> bool:
@@ -30,225 +24,6 @@ def is_github_actions() -> bool:
30
24
  return os.getenv("GITHUB_ACTIONS") == "true"
31
25
 
32
26
 
33
- def check_node_available() -> bool:
34
- """Check if Node.js is available."""
35
- return shutil.which("node") is not None
36
-
37
-
38
- def resolve_version_via_semantic_release(
39
- project_root: Path,
40
- subfolder_path: Path | None = None,
41
- package_name: str | None = None,
42
- repository: str | None = None,
43
- repository_url: str | None = None,
44
- ) -> tuple[str | None, str | None]:
45
- """
46
- Resolve the next version using semantic-release via Node.js script.
47
-
48
- Args:
49
- project_root: Root directory of the project
50
- subfolder_path: Optional path to subfolder (relative to project_root) for Workflow 1
51
- package_name: Optional package name for subfolder builds
52
- repository: Optional target repository ('pypi', 'testpypi', or 'azure')
53
- repository_url: Optional repository URL (required for Azure Artifacts)
54
-
55
- Returns:
56
- Tuple of (version string if a release is determined, error message if any)
57
- Returns (None, None) if no release or no error, (None, error_msg) on error
58
- """
59
- # Note: Node.js availability should be checked before calling this function
60
- # This check is a safety fallback
61
- if not check_node_available():
62
- if is_github_actions():
63
- error_msg = """Node.js is not available in this GitHub Actions workflow.
64
-
65
- To fix this, add the following steps BEFORE running python-package-folder:
66
-
67
- - name: Setup Node.js
68
- uses: actions/setup-node@v4
69
- with:
70
- node-version: '20'
71
-
72
- - name: Install semantic-release
73
- run: |
74
- npm install -g semantic-release semantic-release-commit-filter
75
-
76
- Alternatively, provide --version explicitly to skip automatic version resolution."""
77
- print(f"Error: {error_msg}", file=sys.stderr)
78
- return None, error_msg
79
- else:
80
- error_msg = "Node.js not found. Cannot resolve version via semantic-release."
81
- print(f"Error: {error_msg}", file=sys.stderr)
82
- return None, error_msg
83
-
84
- # Try to find the script in multiple locations:
85
- # 1. Project root / scripts (for development or when script is in repo)
86
- # 2. Package installation directory / scripts (for installed package)
87
- # - For normal installs: direct file path
88
- # - For zip/pex installs: extract to temporary file using as_file()
89
-
90
- # Track temporary file context for cleanup
91
- temp_script_context = None
92
-
93
- try:
94
- # First, try project root (development)
95
- dev_script = project_root / "scripts" / "get-next-version.cjs"
96
- if dev_script.exists():
97
- script_path = dev_script
98
- else:
99
- # Try to locate script in installed package using importlib.resources
100
- script_path = None
101
- diagnostic_info = []
102
-
103
- # Try importlib.resources approach
104
- try:
105
- package = resources.files("python_package_folder")
106
- script_resource = package / "scripts" / "get-next-version.cjs"
107
-
108
- diagnostic_info.append(f"Checked importlib.resources: python_package_folder/scripts/get-next-version.cjs")
109
-
110
- if script_resource.is_file():
111
- # Try direct path conversion first (normal file system install)
112
- try:
113
- script_path_candidate = Path(str(script_resource))
114
- if script_path_candidate.exists():
115
- script_path = script_path_candidate
116
- diagnostic_info.append(f"Found via direct path: {script_path}")
117
- except (TypeError, ValueError) as e:
118
- diagnostic_info.append(f"Direct path conversion failed: {e}")
119
-
120
- # If direct path didn't work, try as_file() for zip/pex installs
121
- if script_path is None:
122
- try:
123
- temp_script_context = resources.as_file(script_resource)
124
- script_path = temp_script_context.__enter__()
125
- diagnostic_info.append(f"Found via as_file() (temp): {script_path}")
126
- except (TypeError, ValueError, OSError) as e:
127
- diagnostic_info.append(f"as_file() extraction failed: {e}")
128
- else:
129
- # Try to list what's actually in the scripts directory
130
- try:
131
- scripts_dir = package / "scripts"
132
- if scripts_dir.is_dir():
133
- available_files = list(scripts_dir.iterdir())
134
- diagnostic_info.append(f"Scripts directory exists. Available files: {[f.name for f in available_files]}")
135
- else:
136
- diagnostic_info.append("Scripts directory does not exist in package")
137
- except Exception as e:
138
- diagnostic_info.append(f"Could not list scripts directory: {e}")
139
- except (ImportError, ModuleNotFoundError, TypeError, AttributeError, OSError) as e:
140
- diagnostic_info.append(f"importlib.resources failed: {type(e).__name__}: {e}")
141
-
142
- # Fallback: try relative to package directory
143
- if script_path is None:
144
- package_dir = Path(__file__).parent
145
- fallback_script = package_dir / "scripts" / "get-next-version.cjs"
146
- diagnostic_info.append(f"Checked fallback path: {fallback_script}")
147
- if fallback_script.exists():
148
- script_path = fallback_script
149
- diagnostic_info.append(f"Found via fallback: {script_path}")
150
- else:
151
- diagnostic_info.append(f"Fallback path does not exist")
152
-
153
- if not script_path:
154
- error_msg = "Could not locate get-next-version.cjs script"
155
- error_msg += "\n\nDiagnostic information:"
156
- for info in diagnostic_info:
157
- error_msg += f"\n - {info}"
158
- error_msg += (
159
- "\n\nThis usually means the script was not included in the installed package."
160
- "\nPlease ensure you're using the latest version of python-package-folder."
161
- "\nIf the issue persists, report this as a bug."
162
- )
163
- print(f"Error: {error_msg}", file=sys.stderr)
164
- return None, error_msg
165
-
166
- # Build command arguments
167
- cmd = ["node", str(script_path), str(project_root)]
168
- if subfolder_path and package_name:
169
- # Workflow 1: subfolder build
170
- rel_path = (
171
- subfolder_path.relative_to(project_root)
172
- if subfolder_path.is_absolute()
173
- else subfolder_path
174
- )
175
- cmd.extend([str(rel_path), package_name])
176
- elif package_name:
177
- # Main package build with package_name (for registry queries)
178
- # Pass null for subfolder_path, then package_name
179
- cmd.extend(["", package_name])
180
- # Workflow 2: main package without package_name (no additional args needed)
181
-
182
- # Add repository information if provided
183
- if repository:
184
- cmd.append(repository)
185
- if repository_url:
186
- cmd.append(repository_url)
187
-
188
- result = subprocess.run(
189
- cmd,
190
- capture_output=True,
191
- text=True,
192
- cwd=project_root,
193
- check=False,
194
- )
195
-
196
- if result.returncode != 0:
197
- # Collect error details
198
- error_details = []
199
- if result.stderr:
200
- error_details.append(f"stderr: {result.stderr}")
201
- if result.stdout:
202
- error_details.append(f"stdout: {result.stdout}")
203
-
204
- error_msg = "semantic-release version resolution failed"
205
- if error_details:
206
- error_msg += f": {'; '.join(error_details)}"
207
-
208
- print(f"Error: {error_msg}", file=sys.stderr)
209
- return None, error_msg
210
-
211
- version = result.stdout.strip()
212
- if version and version != "none":
213
- return version, None
214
-
215
- return None, None
216
- except FileNotFoundError:
217
- # Node.js not found (shouldn't happen if check_node_available() passed, but handle gracefully)
218
- if is_github_actions():
219
- error_msg = """Node.js is not available in this GitHub Actions workflow.
220
-
221
- To fix this, add the following steps BEFORE running python-package-folder:
222
-
223
- - name: Setup Node.js
224
- uses: actions/setup-node@v4
225
- with:
226
- node-version: '20'
227
-
228
- - name: Install semantic-release
229
- run: |
230
- npm install -g semantic-release semantic-release-commit-filter
231
-
232
- Alternatively, provide --version explicitly to skip automatic version resolution."""
233
- print(f"Error: {error_msg}", file=sys.stderr)
234
- return None, error_msg
235
- else:
236
- error_msg = "Node.js not found. Cannot resolve version via semantic-release."
237
- print(f"Error: {error_msg}", file=sys.stderr)
238
- return None, error_msg
239
- except Exception as e:
240
- # Other errors (e.g., permission issues, script not found)
241
- error_msg = f"Error resolving version via semantic-release: {e}"
242
- print(f"Error: {error_msg}", file=sys.stderr)
243
- return None, error_msg
244
- finally:
245
- # Clean up temporary file if we extracted from zip/pex
246
- # This must be at function level to ensure cleanup even on early return
247
- if temp_script_context is not None:
248
- try:
249
- temp_script_context.__exit__(None, None, None)
250
- except Exception:
251
- pass
252
27
 
253
28
 
254
29
  def main() -> int:
@@ -310,7 +85,7 @@ def main() -> int:
310
85
  )
311
86
  parser.add_argument(
312
87
  "--version",
313
- help="Set a specific version before building (PEP 440 format, e.g., '1.2.3'). Optional: if omitted, version will be resolved via semantic-release when needed.",
88
+ help="Set a specific version before building (PEP 440 format, e.g., '1.2.3'). Optional: if omitted, version will be resolved via conventional commits when needed.",
314
89
  )
315
90
  parser.add_argument(
316
91
  "--package-name",
@@ -391,51 +166,12 @@ def main() -> int:
391
166
  and src_dir != project_root
392
167
  )
393
168
 
394
- # Resolve version via semantic-release if not provided and needed
169
+ # Resolve version via conventional commits if not provided and needed
395
170
  resolved_version = args.version
396
171
  if not resolved_version and not args.analyze_only:
397
172
  # Version is needed for subfolder builds or when publishing main package
398
173
  if is_subfolder or args.publish:
399
- print("No --version provided, attempting to resolve via semantic-release...")
400
-
401
- # Check Node.js availability upfront
402
- if not check_node_available():
403
- if is_github_actions():
404
- error_msg = """Node.js is not available in this GitHub Actions workflow.
405
-
406
- To fix this, add the following steps BEFORE running python-package-folder:
407
-
408
- - name: Setup Node.js
409
- uses: actions/setup-node@v4
410
- with:
411
- node-version: '20'
412
-
413
- - name: Install semantic-release
414
- run: |
415
- npm install -g semantic-release semantic-release-commit-filter
416
-
417
- Alternatively, provide --version explicitly to skip automatic version resolution."""
418
- print(f"Error: {error_msg}", file=sys.stderr)
419
- else:
420
- print(
421
- "Error: Node.js is not available. Cannot resolve version via semantic-release.",
422
- file=sys.stderr,
423
- )
424
- print(
425
- "Please install Node.js or provide --version explicitly.",
426
- file=sys.stderr,
427
- )
428
- return 1
429
-
430
- # Log that Node.js is available (for debugging)
431
- node_version = subprocess.run(
432
- ["node", "--version"],
433
- capture_output=True,
434
- text=True,
435
- check=False,
436
- )
437
- if node_version.returncode == 0:
438
- print(f"Node.js detected: {node_version.stdout.strip()}")
174
+ print("No --version provided, attempting to resolve via conventional commits...")
439
175
 
440
176
  # Get repository info if publishing
441
177
  repository = args.publish if args.publish else None
@@ -448,10 +184,10 @@ Alternatively, provide --version explicitly to skip automatic version resolution
448
184
  " ", "-"
449
185
  ).lower().strip("-")
450
186
  subfolder_rel_path = src_dir.relative_to(project_root)
451
- resolved_version, error_details = resolve_version_via_semantic_release(
187
+ resolved_version, error_details = resolve_version(
452
188
  project_root,
453
- subfolder_rel_path,
454
- package_name,
189
+ package_name=package_name,
190
+ subfolder_path=subfolder_rel_path,
455
191
  repository=repository,
456
192
  repository_url=repository_url,
457
193
  )
@@ -470,31 +206,25 @@ Alternatively, provide --version explicitly to skip automatic version resolution
470
206
  except Exception:
471
207
  pass
472
208
 
473
- resolved_version, error_details = resolve_version_via_semantic_release(
209
+ resolved_version, error_details = resolve_version(
474
210
  project_root,
475
- subfolder_path=None,
476
211
  package_name=package_name_for_registry,
212
+ subfolder_path=None,
477
213
  repository=repository,
478
214
  repository_url=repository_url,
479
215
  )
480
216
 
481
217
  if resolved_version:
482
- print(f"Resolved version via semantic-release: {resolved_version}")
218
+ print(f"Resolved version via conventional commits: {resolved_version}")
483
219
  else:
484
220
  error_msg = (
485
- "Could not resolve version via semantic-release.\n"
221
+ "Could not resolve version via conventional commits.\n"
486
222
  "This could mean:\n"
487
223
  " - No release is needed (no relevant commits)\n"
488
- " - semantic-release is not installed or configured\n"
224
+ " - No baseline version found (no registry version or git tags)\n"
489
225
  )
490
226
  if error_details:
491
227
  error_msg += f"\nDetails: {error_details}\n"
492
- error_msg += (
493
- "\nPlease either:\n"
494
- " - Install semantic-release: npm install -g semantic-release"
495
- )
496
- if is_subfolder:
497
- error_msg += "\n - Install semantic-release-commit-filter: npm install -g semantic-release-commit-filter"
498
228
  error_msg += "\n - Or provide --version explicitly"
499
229
  print(f"Error: {error_msg}", file=sys.stderr)
500
230
  return 1