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.
- python_package_folder/python_package_folder.py +12 -282
- python_package_folder/version_calculator.py +490 -0
- python_package_folder-5.0.0.dist-info/METADATA +192 -0
- {python_package_folder-4.3.5.dist-info → python_package_folder-5.0.0.dist-info}/RECORD +7 -7
- python_package_folder/scripts/get-next-version.cjs +0 -654
- python_package_folder-4.3.5.dist-info/METADATA +0 -952
- {python_package_folder-4.3.5.dist-info → python_package_folder-5.0.0.dist-info}/WHEEL +0 -0
- {python_package_folder-4.3.5.dist-info → python_package_folder-5.0.0.dist-info}/entry_points.txt +0 -0
- {python_package_folder-4.3.5.dist-info → python_package_folder-5.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -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
|
|
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
|
|
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
|
|
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 =
|
|
187
|
+
resolved_version, error_details = resolve_version(
|
|
452
188
|
project_root,
|
|
453
|
-
|
|
454
|
-
|
|
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 =
|
|
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
|
|
218
|
+
print(f"Resolved version via conventional commits: {resolved_version}")
|
|
483
219
|
else:
|
|
484
220
|
error_msg = (
|
|
485
|
-
"Could not resolve version via
|
|
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
|
-
" -
|
|
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
|