python-package-folder 4.3.6__py3-none-any.whl → 5.0.1__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 +20 -281
- python_package_folder/version_calculator.py +597 -0
- python_package_folder-5.0.1.dist-info/METADATA +192 -0
- {python_package_folder-4.3.6.dist-info → python_package_folder-5.0.1.dist-info}/RECORD +7 -7
- python_package_folder/scripts/get-next-version.cjs +0 -668
- python_package_folder-4.3.6.dist-info/METADATA +0 -952
- {python_package_folder-4.3.6.dist-info → python_package_folder-5.0.1.dist-info}/WHEEL +0 -0
- {python_package_folder-4.3.6.dist-info → python_package_folder-5.0.1.dist-info}/entry_points.txt +0 -0
- {python_package_folder-4.3.6.dist-info → python_package_folder-5.0.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,19 +10,22 @@ It can be invoked via:
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import logging
|
|
13
14
|
import os
|
|
14
|
-
import shutil
|
|
15
15
|
import subprocess
|
|
16
16
|
import sys
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
|
-
try:
|
|
20
|
-
from importlib import resources
|
|
21
|
-
except ImportError:
|
|
22
|
-
import importlib_resources as resources # type: ignore[no-redef]
|
|
23
|
-
|
|
24
19
|
from .manager import BuildManager
|
|
25
20
|
from .utils import find_project_root, find_source_directory
|
|
21
|
+
from .version_calculator import resolve_version
|
|
22
|
+
|
|
23
|
+
# Configure logging for version resolution
|
|
24
|
+
logging.basicConfig(
|
|
25
|
+
level=logging.INFO,
|
|
26
|
+
format="%(levelname)s: %(message)s",
|
|
27
|
+
handlers=[logging.StreamHandler(sys.stderr)],
|
|
28
|
+
)
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
def is_github_actions() -> bool:
|
|
@@ -30,225 +33,6 @@ def is_github_actions() -> bool:
|
|
|
30
33
|
return os.getenv("GITHUB_ACTIONS") == "true"
|
|
31
34
|
|
|
32
35
|
|
|
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
36
|
|
|
253
37
|
|
|
254
38
|
def main() -> int:
|
|
@@ -310,7 +94,7 @@ def main() -> int:
|
|
|
310
94
|
)
|
|
311
95
|
parser.add_argument(
|
|
312
96
|
"--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
|
|
97
|
+
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
98
|
)
|
|
315
99
|
parser.add_argument(
|
|
316
100
|
"--package-name",
|
|
@@ -391,51 +175,12 @@ def main() -> int:
|
|
|
391
175
|
and src_dir != project_root
|
|
392
176
|
)
|
|
393
177
|
|
|
394
|
-
# Resolve version via
|
|
178
|
+
# Resolve version via conventional commits if not provided and needed
|
|
395
179
|
resolved_version = args.version
|
|
396
180
|
if not resolved_version and not args.analyze_only:
|
|
397
181
|
# Version is needed for subfolder builds or when publishing main package
|
|
398
182
|
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()}")
|
|
183
|
+
print("No --version provided, attempting to resolve via conventional commits...")
|
|
439
184
|
|
|
440
185
|
# Get repository info if publishing
|
|
441
186
|
repository = args.publish if args.publish else None
|
|
@@ -448,10 +193,10 @@ Alternatively, provide --version explicitly to skip automatic version resolution
|
|
|
448
193
|
" ", "-"
|
|
449
194
|
).lower().strip("-")
|
|
450
195
|
subfolder_rel_path = src_dir.relative_to(project_root)
|
|
451
|
-
resolved_version, error_details =
|
|
196
|
+
resolved_version, error_details = resolve_version(
|
|
452
197
|
project_root,
|
|
453
|
-
|
|
454
|
-
|
|
198
|
+
package_name=package_name,
|
|
199
|
+
subfolder_path=subfolder_rel_path,
|
|
455
200
|
repository=repository,
|
|
456
201
|
repository_url=repository_url,
|
|
457
202
|
)
|
|
@@ -470,31 +215,25 @@ Alternatively, provide --version explicitly to skip automatic version resolution
|
|
|
470
215
|
except Exception:
|
|
471
216
|
pass
|
|
472
217
|
|
|
473
|
-
resolved_version, error_details =
|
|
218
|
+
resolved_version, error_details = resolve_version(
|
|
474
219
|
project_root,
|
|
475
|
-
subfolder_path=None,
|
|
476
220
|
package_name=package_name_for_registry,
|
|
221
|
+
subfolder_path=None,
|
|
477
222
|
repository=repository,
|
|
478
223
|
repository_url=repository_url,
|
|
479
224
|
)
|
|
480
225
|
|
|
481
226
|
if resolved_version:
|
|
482
|
-
print(f"Resolved version via
|
|
227
|
+
print(f"Resolved version via conventional commits: {resolved_version}")
|
|
483
228
|
else:
|
|
484
229
|
error_msg = (
|
|
485
|
-
"Could not resolve version via
|
|
230
|
+
"Could not resolve version via conventional commits.\n"
|
|
486
231
|
"This could mean:\n"
|
|
487
232
|
" - No release is needed (no relevant commits)\n"
|
|
488
|
-
" -
|
|
233
|
+
" - No baseline version found (no registry version or git tags)\n"
|
|
489
234
|
)
|
|
490
235
|
if error_details:
|
|
491
236
|
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
237
|
error_msg += "\n - Or provide --version explicitly"
|
|
499
238
|
print(f"Error: {error_msg}", file=sys.stderr)
|
|
500
239
|
return 1
|