common-python-tasks 0.5.0__py3-none-any.whl → 0.6.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.
- common_python_tasks/docker.py +2 -2
- common_python_tasks/docker_compose.py +2 -2
- common_python_tasks/github.py +51 -4
- common_python_tasks/project.py +49 -3
- common_python_tasks/tasks.py +256 -9
- {common_python_tasks-0.5.0.dist-info → common_python_tasks-0.6.0.dist-info}/METADATA +8 -7
- {common_python_tasks-0.5.0.dist-info → common_python_tasks-0.6.0.dist-info}/RECORD +9 -9
- {common_python_tasks-0.5.0.dist-info → common_python_tasks-0.6.0.dist-info}/WHEEL +1 -1
- {common_python_tasks-0.5.0.dist-info → common_python_tasks-0.6.0.dist-info}/licenses/LICENSE +0 -0
common_python_tasks/docker.py
CHANGED
|
@@ -190,7 +190,7 @@ def prune_images_keep(
|
|
|
190
190
|
if line not in lines
|
|
191
191
|
]
|
|
192
192
|
|
|
193
|
-
tags_in_order
|
|
193
|
+
tags_in_order = []
|
|
194
194
|
seen_tags: set[str] = set()
|
|
195
195
|
for entry in lines:
|
|
196
196
|
try:
|
|
@@ -509,7 +509,7 @@ def build_image(
|
|
|
509
509
|
for t in tags_to_use
|
|
510
510
|
]
|
|
511
511
|
|
|
512
|
-
all_tags
|
|
512
|
+
all_tags = []
|
|
513
513
|
for resolved_tag in [*short_tags, *full_tags]:
|
|
514
514
|
if resolved_tag not in all_tags:
|
|
515
515
|
all_tags.append(resolved_tag)
|
|
@@ -414,8 +414,8 @@ def load_compose_files(
|
|
|
414
414
|
)
|
|
415
415
|
]
|
|
416
416
|
|
|
417
|
-
temp_config_files
|
|
418
|
-
addon_template_vars
|
|
417
|
+
temp_config_files = []
|
|
418
|
+
addon_template_vars = {}
|
|
419
419
|
|
|
420
420
|
if "db" in compose_addons and compose_type == "fastapi":
|
|
421
421
|
alembic_path, alembic_cleanup = ensure_alembic_config(compose_type)
|
common_python_tasks/github.py
CHANGED
|
@@ -344,6 +344,52 @@ def github_api_request(
|
|
|
344
344
|
return GitHubClient().api_request(method, path, payload=payload)
|
|
345
345
|
|
|
346
346
|
|
|
347
|
+
def create_pull_request(
|
|
348
|
+
title: str,
|
|
349
|
+
head: str,
|
|
350
|
+
base: str,
|
|
351
|
+
body: str | None = None,
|
|
352
|
+
draft: bool = False,
|
|
353
|
+
) -> dict[str, Any] | None:
|
|
354
|
+
"""Create a GitHub pull request for the current repository.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
title: Pull request title.
|
|
358
|
+
head: Source branch name.
|
|
359
|
+
base: Base branch name.
|
|
360
|
+
body: Optional pull request body.
|
|
361
|
+
draft: Whether to create the pull request as a draft.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
The GitHub API response for the created pull request, or `None` when
|
|
365
|
+
repository information is unavailable.
|
|
366
|
+
"""
|
|
367
|
+
repository = get_github_repository()
|
|
368
|
+
token = get_github_token()
|
|
369
|
+
|
|
370
|
+
if repository is None:
|
|
371
|
+
LOGGER.debug(
|
|
372
|
+
"Skipping pull request creation because this is not a GitHub repository"
|
|
373
|
+
)
|
|
374
|
+
return None
|
|
375
|
+
if token is None:
|
|
376
|
+
utils.fatal(
|
|
377
|
+
"GITHUB_TOKEN or GH_TOKEN environment variable must be set to open a GitHub pull request"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
return GitHubClient(repository=repository, token=token).api_request(
|
|
381
|
+
"POST",
|
|
382
|
+
"/pulls",
|
|
383
|
+
payload={
|
|
384
|
+
"title": title,
|
|
385
|
+
"head": head,
|
|
386
|
+
"base": base,
|
|
387
|
+
"body": body or "",
|
|
388
|
+
"draft": draft,
|
|
389
|
+
},
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
|
|
347
393
|
def publish_github_release(
|
|
348
394
|
tag_name: str,
|
|
349
395
|
release_name: str | None = None,
|
|
@@ -475,7 +521,8 @@ def get_github_release_asset_paths(
|
|
|
475
521
|
asset_sources: Optional list of paths or glob patterns. When a string is
|
|
476
522
|
provided (including via `GITHUB_RELEASE_ASSETS`), values are
|
|
477
523
|
interpreted as colon-separated paths or glob patterns.
|
|
478
|
-
If not provided, the default value is `dist/*`.
|
|
524
|
+
If not provided, the default value is `dist/*`. An empty list
|
|
525
|
+
explicitly disables asset selection.
|
|
479
526
|
|
|
480
527
|
Returns:
|
|
481
528
|
A sorted list of existing asset paths.
|
|
@@ -496,7 +543,7 @@ def get_github_release_asset_paths(
|
|
|
496
543
|
else:
|
|
497
544
|
source_items = ["dist/*"]
|
|
498
545
|
|
|
499
|
-
asset_paths
|
|
546
|
+
asset_paths = []
|
|
500
547
|
for part in source_items:
|
|
501
548
|
if any(char in part for char in "*?[]"):
|
|
502
549
|
asset_paths.extend(
|
|
@@ -513,7 +560,7 @@ def get_github_release_asset_paths(
|
|
|
513
560
|
elif path.exists():
|
|
514
561
|
LOGGER.warning("Ignoring non-file GitHub release asset path: %s", path)
|
|
515
562
|
|
|
516
|
-
if not asset_paths and explicit_assets:
|
|
563
|
+
if not asset_paths and explicit_assets and source_items:
|
|
517
564
|
utils.fatal(
|
|
518
565
|
"No GitHub Release assets were found for the configured asset paths: "
|
|
519
566
|
+ ":".join(source_items)
|
|
@@ -588,7 +635,7 @@ def upload_github_release_assets(
|
|
|
588
635
|
Returns:
|
|
589
636
|
A list of decoded JSON responses for the uploaded assets.
|
|
590
637
|
"""
|
|
591
|
-
uploaded_assets
|
|
638
|
+
uploaded_assets = []
|
|
592
639
|
for asset_path in asset_paths:
|
|
593
640
|
LOGGER.info("Uploading GitHub Release asset: %s", asset_path)
|
|
594
641
|
uploaded = upload_github_release_asset(release_id, asset_path)
|
common_python_tasks/project.py
CHANGED
|
@@ -8,7 +8,7 @@ from enum import StrEnum, auto
|
|
|
8
8
|
from functools import lru_cache
|
|
9
9
|
from importlib import metadata
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
11
|
+
from typing import Any, Sequence
|
|
12
12
|
|
|
13
13
|
from packaging.specifiers import SpecifierSet
|
|
14
14
|
from packaging.version import Version
|
|
@@ -179,14 +179,60 @@ def get_package_manager_build_command(wheel_only: bool = False) -> list[str]:
|
|
|
179
179
|
return command
|
|
180
180
|
|
|
181
181
|
|
|
182
|
-
def
|
|
182
|
+
def get_package_manager_update_command(dependencies: Sequence[str] | None = None) -> list[str]:
|
|
183
|
+
"""Return the dependency update command for the selected package manager.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
dependencies: Optional dependency names to update. When omitted, all
|
|
187
|
+
dependencies are updated.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Command tokens for the dependency update command.
|
|
191
|
+
"""
|
|
192
|
+
if dependencies is None:
|
|
193
|
+
dependencies = []
|
|
194
|
+
|
|
195
|
+
package_manager = PackageManager(get_package_manager())
|
|
196
|
+
if package_manager == PackageManager.UV:
|
|
197
|
+
command = ["uv", "sync", "--upgrade"]
|
|
198
|
+
for dependency in dependencies:
|
|
199
|
+
command.extend(["--upgrade-package", dependency])
|
|
200
|
+
return command
|
|
201
|
+
|
|
202
|
+
return ["poetry", "update", *dependencies]
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def get_package_manager_publish_command(
|
|
206
|
+
repository: str | None = None,
|
|
207
|
+
repository_url: str | None = None,
|
|
208
|
+
) -> list[str]:
|
|
183
209
|
"""Return the publish command for the selected package manager.
|
|
184
210
|
|
|
211
|
+
Args:
|
|
212
|
+
repository: Optional configured repository name to publish to.
|
|
213
|
+
repository_url: Optional repository upload URL to publish to.
|
|
214
|
+
|
|
185
215
|
Returns:
|
|
186
216
|
Command tokens for the package publish command.
|
|
187
217
|
"""
|
|
218
|
+
if repository is not None and repository_url is not None:
|
|
219
|
+
utils.fatal("Specify either `repository` or `repository_url`, not both.")
|
|
220
|
+
|
|
188
221
|
package_manager = PackageManager(get_package_manager())
|
|
189
|
-
|
|
222
|
+
command = [package_manager.value, "publish"]
|
|
223
|
+
if repository_url is not None:
|
|
224
|
+
if package_manager == PackageManager.POETRY:
|
|
225
|
+
utils.fatal(
|
|
226
|
+
"Poetry publish only supports configured repository names. "
|
|
227
|
+
"Pass `repository` instead of `repository_url`."
|
|
228
|
+
)
|
|
229
|
+
command += ["--publish-url", repository_url]
|
|
230
|
+
elif repository is not None:
|
|
231
|
+
if package_manager == PackageManager.UV:
|
|
232
|
+
command += ["--index", repository]
|
|
233
|
+
else:
|
|
234
|
+
command += ["-r", repository]
|
|
235
|
+
return command
|
|
190
236
|
|
|
191
237
|
|
|
192
238
|
@lru_cache
|
common_python_tasks/tasks.py
CHANGED
|
@@ -2,8 +2,10 @@ import contextvars
|
|
|
2
2
|
import inspect
|
|
3
3
|
import logging
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
from functools import partial, wraps
|
|
6
7
|
from pathlib import Path
|
|
8
|
+
from typing import Callable
|
|
7
9
|
|
|
8
10
|
from common_python_tasks.utils import confirm
|
|
9
11
|
from poethepoet_tasks import TaskCollection
|
|
@@ -116,13 +118,17 @@ def _wrap_task_function(func: callable, task_name: str | None) -> callable:
|
|
|
116
118
|
|
|
117
119
|
|
|
118
120
|
def _script(
|
|
119
|
-
func=None,
|
|
121
|
+
func: Callable | None = None,
|
|
120
122
|
task_name: str | None = None,
|
|
121
123
|
help: str | None = None,
|
|
122
124
|
task_args: bool = True,
|
|
123
125
|
options: dict | None = None,
|
|
124
|
-
tags: tuple[str, ...] =
|
|
126
|
+
tags: tuple[str, ...] | None = None,
|
|
125
127
|
):
|
|
128
|
+
|
|
129
|
+
if tags is None:
|
|
130
|
+
tags = ()
|
|
131
|
+
|
|
126
132
|
if func is None:
|
|
127
133
|
return partial(
|
|
128
134
|
_script,
|
|
@@ -956,18 +962,28 @@ def push_image(debug: bool = False) -> None:
|
|
|
956
962
|
|
|
957
963
|
|
|
958
964
|
@tasks.script(task_name="publish-package", tags=["packaging", "common"])
|
|
959
|
-
def publish_package(
|
|
965
|
+
def publish_package(
|
|
966
|
+
build_first: bool = True,
|
|
967
|
+
repository: str | None = None,
|
|
968
|
+
repository_url: str | None = None,
|
|
969
|
+
) -> None:
|
|
960
970
|
"""Publish the package to the PyPI server.
|
|
961
971
|
|
|
962
972
|
Args:
|
|
963
973
|
build_first: If `True`, build the package before publishing.
|
|
974
|
+
repository: Optional configured repository name to publish to.
|
|
975
|
+
repository_url: Optional repository upload URL to publish to.
|
|
964
976
|
"""
|
|
965
977
|
from .project import get_package_manager_publish_command
|
|
966
978
|
from .utils import run_command
|
|
967
979
|
|
|
968
980
|
if build_first:
|
|
969
981
|
build_package(clean_dist=True)
|
|
970
|
-
run_command(
|
|
982
|
+
run_command(
|
|
983
|
+
get_package_manager_publish_command(
|
|
984
|
+
repository=repository, repository_url=repository_url
|
|
985
|
+
)
|
|
986
|
+
)
|
|
971
987
|
|
|
972
988
|
|
|
973
989
|
@tasks.script(
|
|
@@ -1000,7 +1016,8 @@ def publish_github_release(
|
|
|
1000
1016
|
release_name or os.getenv("GITHUB_RELEASE_NAME") or resolved_tag_name
|
|
1001
1017
|
)
|
|
1002
1018
|
resolved_body = body or os.getenv("GITHUB_RELEASE_BODY")
|
|
1003
|
-
|
|
1019
|
+
# Poe supplies `[]` when an optional repeated CLI argument is omitted.
|
|
1020
|
+
asset_paths = get_github_release_asset_paths(assets or None)
|
|
1004
1021
|
|
|
1005
1022
|
return publish_github_release_helper(
|
|
1006
1023
|
resolved_tag_name,
|
|
@@ -1012,6 +1029,205 @@ def publish_github_release(
|
|
|
1012
1029
|
)
|
|
1013
1030
|
|
|
1014
1031
|
|
|
1032
|
+
def _get_default_branch() -> str:
|
|
1033
|
+
from .utils import run_command
|
|
1034
|
+
|
|
1035
|
+
result = run_command(
|
|
1036
|
+
["git", "symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"],
|
|
1037
|
+
capture_output=True,
|
|
1038
|
+
acceptable_returncodes={0, 1},
|
|
1039
|
+
)
|
|
1040
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
1041
|
+
return result.stdout.strip().rsplit("/", 1)[-1]
|
|
1042
|
+
return "main"
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
def _get_current_branch() -> str:
|
|
1046
|
+
from .utils import fatal, run_command
|
|
1047
|
+
|
|
1048
|
+
result = run_command(["git", "branch", "--show-current"], capture_output=True)
|
|
1049
|
+
if not result.stdout.strip():
|
|
1050
|
+
fatal("Unable to determine current git branch.")
|
|
1051
|
+
return result.stdout.strip()
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
def _dependency_branch_token(name: str) -> str:
|
|
1055
|
+
return re.sub(r"[^a-z0-9._-]+", "-", name.lower()).strip("-") or "updates"
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
def _dependency_update_branch_name(dependency_names: list[str]) -> str:
|
|
1059
|
+
if not dependency_names:
|
|
1060
|
+
return "deps/update-dependencies"
|
|
1061
|
+
|
|
1062
|
+
branch_name = "deps/" + "-".join(
|
|
1063
|
+
_dependency_branch_token(name) for name in dependency_names[:5]
|
|
1064
|
+
)
|
|
1065
|
+
if len(dependency_names) > 5:
|
|
1066
|
+
branch_name = f"{branch_name}-and-more"
|
|
1067
|
+
return branch_name[:80].rstrip("-")
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
def _extract_changed_dependency_names_from_diff(diff_output: str) -> list[str]:
|
|
1071
|
+
dependency_names: set[str] = set()
|
|
1072
|
+
for line in diff_output.splitlines():
|
|
1073
|
+
if not line or line.startswith(("+++", "---", "@@", "diff ", "index ")):
|
|
1074
|
+
continue
|
|
1075
|
+
if line[0] not in {" ", "+", "-"}:
|
|
1076
|
+
continue
|
|
1077
|
+
|
|
1078
|
+
text = line[1:].strip()
|
|
1079
|
+
lock_match = re.match(r'name\s*=\s*"([^"]+)"', text)
|
|
1080
|
+
if lock_match is not None:
|
|
1081
|
+
dependency_names.add(lock_match.group(1))
|
|
1082
|
+
continue
|
|
1083
|
+
|
|
1084
|
+
dependency_match = re.match(r'"([A-Za-z0-9_.-]+)(?:\[|\s|[<>=!~;(),"]|$)', text)
|
|
1085
|
+
if dependency_match is not None:
|
|
1086
|
+
dependency_names.add(dependency_match.group(1))
|
|
1087
|
+
|
|
1088
|
+
return sorted(dependency_names)
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
def _get_changed_dependency_names() -> list[str]:
|
|
1092
|
+
from .utils import run_command
|
|
1093
|
+
|
|
1094
|
+
return _extract_changed_dependency_names_from_diff(
|
|
1095
|
+
run_command(
|
|
1096
|
+
[
|
|
1097
|
+
"git",
|
|
1098
|
+
"diff",
|
|
1099
|
+
"--unified=3",
|
|
1100
|
+
"--",
|
|
1101
|
+
"pyproject.toml",
|
|
1102
|
+
"poetry.lock",
|
|
1103
|
+
"uv.lock",
|
|
1104
|
+
],
|
|
1105
|
+
capture_output=True,
|
|
1106
|
+
).stdout
|
|
1107
|
+
)
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
def _get_dependency_update_changed_files() -> list[Path]:
|
|
1111
|
+
from .utils import run_command
|
|
1112
|
+
|
|
1113
|
+
result = run_command(
|
|
1114
|
+
[
|
|
1115
|
+
"git",
|
|
1116
|
+
"status",
|
|
1117
|
+
"--porcelain",
|
|
1118
|
+
"--",
|
|
1119
|
+
"pyproject.toml",
|
|
1120
|
+
"poetry.lock",
|
|
1121
|
+
"uv.lock",
|
|
1122
|
+
],
|
|
1123
|
+
capture_output=True,
|
|
1124
|
+
)
|
|
1125
|
+
return [Path(line[3:]) for line in result.stdout.splitlines() if line]
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
def _ensure_clean_dependency_update_worktree() -> None:
|
|
1129
|
+
from .git import get_dirty_files
|
|
1130
|
+
from .utils import fatal
|
|
1131
|
+
|
|
1132
|
+
if get_dirty_files():
|
|
1133
|
+
fatal(
|
|
1134
|
+
"Repository has uncommitted changes. "
|
|
1135
|
+
"Commit or stash them before creating a dependency update branch, commit, or pull request."
|
|
1136
|
+
)
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
def _dependency_update_title(dependency_names: list[str]) -> str:
|
|
1140
|
+
if not dependency_names:
|
|
1141
|
+
return "chore(deps): update dependencies"
|
|
1142
|
+
if len(dependency_names) == 1:
|
|
1143
|
+
return f"chore(deps): update {dependency_names[0]}"
|
|
1144
|
+
return "chore(deps): update " + ", ".join(dependency_names[:5])
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
@tasks.script(task_name="update-dependencies", tags=["packaging", "common"])
|
|
1148
|
+
def update_dependencies(
|
|
1149
|
+
*dependencies: str,
|
|
1150
|
+
branch: bool = False,
|
|
1151
|
+
branch_name: str | None = None,
|
|
1152
|
+
commit: bool = False,
|
|
1153
|
+
pr: bool = False,
|
|
1154
|
+
draft: bool = False,
|
|
1155
|
+
run_tests: bool = False,
|
|
1156
|
+
) -> None:
|
|
1157
|
+
"""Update project dependencies with Poetry or uv.
|
|
1158
|
+
|
|
1159
|
+
Args:
|
|
1160
|
+
*dependencies: Optional dependency names to update. When omitted, update
|
|
1161
|
+
all dependencies.
|
|
1162
|
+
branch: If `True`, create a dependency update branch after updating.
|
|
1163
|
+
branch_name: Optional branch name to use instead of generating one.
|
|
1164
|
+
commit: If `True`, commit the dependency update files.
|
|
1165
|
+
pr: If `True`, create and push a branch, commit the changes, and open
|
|
1166
|
+
a GitHub pull request.
|
|
1167
|
+
draft: If `True`, create the pull request as a draft.
|
|
1168
|
+
run_tests: If `True`, run the test task before committing.
|
|
1169
|
+
"""
|
|
1170
|
+
from .github import create_pull_request
|
|
1171
|
+
from .project import get_package_manager_update_command
|
|
1172
|
+
from .utils import run_command
|
|
1173
|
+
|
|
1174
|
+
should_create_branch = branch or branch_name is not None or pr
|
|
1175
|
+
if should_create_branch or commit:
|
|
1176
|
+
_ensure_clean_dependency_update_worktree()
|
|
1177
|
+
|
|
1178
|
+
run_command(get_package_manager_update_command(dependencies))
|
|
1179
|
+
if not _get_dependency_update_changed_files():
|
|
1180
|
+
LOGGER.info(
|
|
1181
|
+
"Dependency update completed with no lockfile or pyproject changes."
|
|
1182
|
+
)
|
|
1183
|
+
return
|
|
1184
|
+
|
|
1185
|
+
if run_tests:
|
|
1186
|
+
test()
|
|
1187
|
+
|
|
1188
|
+
changed_dependency_names = _get_changed_dependency_names() or sorted(dependencies)
|
|
1189
|
+
if should_create_branch:
|
|
1190
|
+
run_command(
|
|
1191
|
+
[
|
|
1192
|
+
"git",
|
|
1193
|
+
"checkout",
|
|
1194
|
+
"-b",
|
|
1195
|
+
branch_name or _dependency_update_branch_name(changed_dependency_names),
|
|
1196
|
+
]
|
|
1197
|
+
)
|
|
1198
|
+
|
|
1199
|
+
if commit or pr:
|
|
1200
|
+
run_command(
|
|
1201
|
+
[
|
|
1202
|
+
"git",
|
|
1203
|
+
"add",
|
|
1204
|
+
*[
|
|
1205
|
+
path
|
|
1206
|
+
for path in (
|
|
1207
|
+
Path("pyproject.toml"),
|
|
1208
|
+
Path("poetry.lock"),
|
|
1209
|
+
Path("uv.lock"),
|
|
1210
|
+
)
|
|
1211
|
+
if path.exists()
|
|
1212
|
+
],
|
|
1213
|
+
]
|
|
1214
|
+
)
|
|
1215
|
+
run_command(
|
|
1216
|
+
["git", "commit", "-m", _dependency_update_title(changed_dependency_names)]
|
|
1217
|
+
)
|
|
1218
|
+
|
|
1219
|
+
if pr:
|
|
1220
|
+
current_branch = _get_current_branch()
|
|
1221
|
+
run_command(["git", "push", "-u", "origin", current_branch])
|
|
1222
|
+
create_pull_request(
|
|
1223
|
+
title=_dependency_update_title(changed_dependency_names),
|
|
1224
|
+
head=current_branch,
|
|
1225
|
+
base=_get_default_branch(),
|
|
1226
|
+
body="Automated dependency update.",
|
|
1227
|
+
draft=draft,
|
|
1228
|
+
)
|
|
1229
|
+
|
|
1230
|
+
|
|
1015
1231
|
@tasks.script(task_name="build-package", tags=["packaging", "build", "common"])
|
|
1016
1232
|
def build_package(wheel_only: bool = False, clean_dist: bool = False) -> None:
|
|
1017
1233
|
"""Build the package (wheel and sdist)."""
|
|
@@ -1088,13 +1304,21 @@ def changelog() -> None:
|
|
|
1088
1304
|
print(_changelog())
|
|
1089
1305
|
|
|
1090
1306
|
|
|
1091
|
-
def _build_and_publish_release_package(
|
|
1307
|
+
def _build_and_publish_release_package(
|
|
1308
|
+
release_tag: str,
|
|
1309
|
+
repository: str | None = None,
|
|
1310
|
+
repository_url: str | None = None,
|
|
1311
|
+
) -> None:
|
|
1092
1312
|
from .utils import run_command
|
|
1093
1313
|
|
|
1094
1314
|
package_published = False
|
|
1095
1315
|
try:
|
|
1096
1316
|
build_package(clean_dist=True)
|
|
1097
|
-
publish_package(
|
|
1317
|
+
publish_package(
|
|
1318
|
+
build_first=False,
|
|
1319
|
+
repository=repository,
|
|
1320
|
+
repository_url=repository_url,
|
|
1321
|
+
)
|
|
1098
1322
|
package_published = True
|
|
1099
1323
|
finally:
|
|
1100
1324
|
if not package_published:
|
|
@@ -1121,6 +1345,8 @@ def _run_release_flow(
|
|
|
1121
1345
|
container_env: list[str] | None = None,
|
|
1122
1346
|
container_envfile: list[str] | None = None,
|
|
1123
1347
|
assets: list[str] | None = None,
|
|
1348
|
+
repository: str | None = None,
|
|
1349
|
+
repository_url: str | None = None,
|
|
1124
1350
|
pre_script: str | None = None,
|
|
1125
1351
|
post_script: str | None = None,
|
|
1126
1352
|
) -> None:
|
|
@@ -1170,7 +1396,14 @@ def _run_release_flow(
|
|
|
1170
1396
|
if dry_run:
|
|
1171
1397
|
log_dry_run("Would push tags to origin")
|
|
1172
1398
|
log_dry_run("Would build package with clean_dist=True")
|
|
1173
|
-
|
|
1399
|
+
if repository is None and repository_url is None:
|
|
1400
|
+
log_dry_run("Would publish package with build_first=False")
|
|
1401
|
+
else:
|
|
1402
|
+
log_dry_run(
|
|
1403
|
+
"Would publish package with build_first=False repository=%s repository_url=%s",
|
|
1404
|
+
repository,
|
|
1405
|
+
repository_url,
|
|
1406
|
+
)
|
|
1174
1407
|
if include_containers:
|
|
1175
1408
|
log_dry_run(
|
|
1176
1409
|
"Would build container image with debug=%s no_cache=%s plain=%s single_arch=%s",
|
|
@@ -1187,7 +1420,9 @@ def _run_release_flow(
|
|
|
1187
1420
|
run_command(["sh", "-lc", post_script], env=hook_env, dry_run=False)
|
|
1188
1421
|
return
|
|
1189
1422
|
|
|
1190
|
-
_build_and_publish_release_package(
|
|
1423
|
+
_build_and_publish_release_package(
|
|
1424
|
+
hook_env["RELEASE_TAG"], repository=repository, repository_url=repository_url
|
|
1425
|
+
)
|
|
1191
1426
|
|
|
1192
1427
|
if include_containers:
|
|
1193
1428
|
build_image(
|
|
@@ -1236,6 +1471,8 @@ def release(
|
|
|
1236
1471
|
container_env: list[str] | None = None,
|
|
1237
1472
|
container_envfile: list[str] | None = None,
|
|
1238
1473
|
assets: list[str] | None = None,
|
|
1474
|
+
repository: str | None = None,
|
|
1475
|
+
repository_url: str | None = None,
|
|
1239
1476
|
pre_script: str | None = None,
|
|
1240
1477
|
post_script: str | None = None,
|
|
1241
1478
|
) -> None:
|
|
@@ -1255,6 +1492,8 @@ def release(
|
|
|
1255
1492
|
`KEY=VALUE` values.
|
|
1256
1493
|
container_envfile: Repeated list of container environment files.
|
|
1257
1494
|
assets: Optional repeated list of release asset patterns or paths.
|
|
1495
|
+
repository: Optional configured repository name to publish to.
|
|
1496
|
+
repository_url: Optional repository upload URL to publish to.
|
|
1258
1497
|
pre_script: Optional shell command to run before the release steps.
|
|
1259
1498
|
post_script: Optional shell command to run after the release completes.
|
|
1260
1499
|
"""
|
|
@@ -1271,6 +1510,8 @@ def release(
|
|
|
1271
1510
|
container_env=container_env,
|
|
1272
1511
|
container_envfile=container_envfile,
|
|
1273
1512
|
assets=assets,
|
|
1513
|
+
repository=repository,
|
|
1514
|
+
repository_url=repository_url,
|
|
1274
1515
|
pre_script=pre_script,
|
|
1275
1516
|
post_script=post_script,
|
|
1276
1517
|
)
|
|
@@ -1282,6 +1523,8 @@ def release_without_containers(
|
|
|
1282
1523
|
stage: str | None = None,
|
|
1283
1524
|
dry_run: bool = False,
|
|
1284
1525
|
assets: list[str] | None = None,
|
|
1526
|
+
repository: str | None = None,
|
|
1527
|
+
repository_url: str | None = None,
|
|
1285
1528
|
pre_script: str | None = None,
|
|
1286
1529
|
post_script: str | None = None,
|
|
1287
1530
|
) -> None:
|
|
@@ -1292,6 +1535,8 @@ def release_without_containers(
|
|
|
1292
1535
|
stage: Optional pre-release stage to apply: `alpha`, `beta`, or `rc`.
|
|
1293
1536
|
dry_run: If `True`, only perform a dry-run version bump.
|
|
1294
1537
|
assets: Optional repeated list of release asset patterns or paths.
|
|
1538
|
+
repository: Optional configured repository name to publish to.
|
|
1539
|
+
repository_url: Optional repository upload URL to publish to.
|
|
1295
1540
|
pre_script: Optional shell command to run before the release steps.
|
|
1296
1541
|
post_script: Optional shell command to run after the release completes.
|
|
1297
1542
|
"""
|
|
@@ -1301,6 +1546,8 @@ def release_without_containers(
|
|
|
1301
1546
|
dry_run=dry_run,
|
|
1302
1547
|
include_containers=False,
|
|
1303
1548
|
assets=assets,
|
|
1549
|
+
repository=repository,
|
|
1550
|
+
repository_url=repository_url,
|
|
1304
1551
|
pre_script=pre_script,
|
|
1305
1552
|
post_script=post_script,
|
|
1306
1553
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: common-python-tasks
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Opinionated Poe the Poet tasks for Python package development.
|
|
5
5
|
Project-URL: Homepage, http://github.com/ci-sourcerer/common-python-tasks
|
|
6
6
|
Project-URL: Source, http://github.com/ci-sourcerer/common-python-tasks.git
|
|
@@ -55,7 +55,7 @@ To install a specific release, set the environment variable `COMMON_PYTHON_TASKS
|
|
|
55
55
|
curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add_common_python_tasks.py \
|
|
56
56
|
| jq -r '.content' \
|
|
57
57
|
| base64 -d \
|
|
58
|
-
| COMMON_PYTHON_TASKS_VERSION=0.
|
|
58
|
+
| COMMON_PYTHON_TASKS_VERSION=0.6.0 python3
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
This will complete the following steps.
|
|
@@ -75,7 +75,7 @@ There's no real reason to run the automated script; I just like automating every
|
|
|
75
75
|
```toml
|
|
76
76
|
[project]
|
|
77
77
|
dependencies = [
|
|
78
|
-
"common-python-tasks==0.
|
|
78
|
+
"common-python-tasks==0.6.0" # Always pin to a specific version
|
|
79
79
|
]
|
|
80
80
|
|
|
81
81
|
[tool.poe]
|
|
@@ -115,6 +115,7 @@ Internal tasks are used by other tasks and are not meant to be run directly.
|
|
|
115
115
|
| `push-image` | Push the Docker image for this project to the container registry. | containers, packaging, release |
|
|
116
116
|
| `publish-package` | Publish the package to the PyPI server. | common, packaging |
|
|
117
117
|
| `publish-github-release` | Publish or update a GitHub Release for the current repository. | common, packaging, release |
|
|
118
|
+
| `update-dependencies` | Update project dependencies with Poetry or uv. | common, packaging |
|
|
118
119
|
| `build-package` | Build the package (wheel and sdist). | build, common, packaging |
|
|
119
120
|
| `bump-version` | Bump the project version. | common, packaging |
|
|
120
121
|
| `changelog` | Print the changelog for the current version based on git history and git-cliff. | common, packaging, release |
|
|
@@ -309,8 +310,8 @@ By default, `tasks()` exposes the common task set. You can still include or excl
|
|
|
309
310
|
```toml
|
|
310
311
|
[project]
|
|
311
312
|
name = "simple-cli-tool"
|
|
312
|
-
version = "0.
|
|
313
|
-
dependencies = ["common-python-tasks==0.
|
|
313
|
+
version = "0.6.0"
|
|
314
|
+
dependencies = ["common-python-tasks==0.6.0"]
|
|
314
315
|
|
|
315
316
|
[tool.poe]
|
|
316
317
|
include_script = "common_python_tasks:tasks()"
|
|
@@ -322,7 +323,7 @@ Available tasks: common defaults such as `format`, `lint`, `test`, and `build`.
|
|
|
322
323
|
|
|
323
324
|
```toml
|
|
324
325
|
[project]
|
|
325
|
-
dependencies = ["common-python-tasks==0.
|
|
326
|
+
dependencies = ["common-python-tasks==0.6.0"]
|
|
326
327
|
|
|
327
328
|
[tool.poe]
|
|
328
329
|
include_script = "common_python_tasks:tasks(include_tags=['common', 'containers'])"
|
|
@@ -338,7 +339,7 @@ Available tasks: All tasks including `build-image` and `push-image`.
|
|
|
338
339
|
|
|
339
340
|
```toml
|
|
340
341
|
[project]
|
|
341
|
-
dependencies = ["common-python-tasks==0.
|
|
342
|
+
dependencies = ["common-python-tasks==0.6.0"]
|
|
342
343
|
|
|
343
344
|
[tool.poe]
|
|
344
345
|
include_script = "common_python_tasks:tasks()"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
common_python_tasks/__init__.py,sha256=A-qMF818PGbDxM_DH9l1HwQMV-tXn8CZZiVQy-F_sLc,550
|
|
2
2
|
common_python_tasks/__main__.py,sha256=AZiLLusMDs0rZIIBuCDbt6jABlQD-kEwIQIep7GxgEc,3019
|
|
3
|
-
common_python_tasks/docker.py,sha256=
|
|
4
|
-
common_python_tasks/docker_compose.py,sha256=
|
|
3
|
+
common_python_tasks/docker.py,sha256=cbVesXb8PocchkIkvyhhX3XYM38G8MX-_BHFYSRvWNI,19672
|
|
4
|
+
common_python_tasks/docker_compose.py,sha256=P6yaHyG4AUGb8kD0qI8En-gyaZT4gFqP6ocWXWDfnqE,21018
|
|
5
5
|
common_python_tasks/env.py,sha256=X-v2gX6SJluvkjU7M941UbrMZ73vHnxwLeaBWRUxeLc,15678
|
|
6
6
|
common_python_tasks/git.py,sha256=wJ3gePpWE4fhNJYZCEWTDFrhHqaOVkaQveHeiGIbCHo,11188
|
|
7
|
-
common_python_tasks/github.py,sha256=
|
|
8
|
-
common_python_tasks/project.py,sha256=
|
|
9
|
-
common_python_tasks/tasks.py,sha256=
|
|
7
|
+
common_python_tasks/github.py,sha256=UjoL_eJIg6NLQ6kch_uZOjj77PeNguqNKtYmYVSkLX8,20392
|
|
8
|
+
common_python_tasks/project.py,sha256=07dXipGt5ZMqWNcsU_5bFX-CYFzsVNaVP2SN81nWDCk,22442
|
|
9
|
+
common_python_tasks/tasks.py,sha256=BDrWDmKX5_aTMw5JIeXEetlviw1dFkoXQTake6v3dCc,62704
|
|
10
10
|
common_python_tasks/utils.py,sha256=ej4nKFPMFhu1wSgkL9x50DML_sPoPmR6aGcIMyAmfN8,19586
|
|
11
11
|
common_python_tasks/data/dockerfile_extensions/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
common_python_tasks/data/fastapi/alembic.ini.j2,sha256=IVXmnF1pJvW3o8dXBLIVhmng7DyXu_sWXx_W3VlAcGE,910
|
|
@@ -22,7 +22,7 @@ common_python_tasks/data/generic/Dockerfile.deps.j2,sha256=rCGsBwLHQIRsGFzDbiRi_
|
|
|
22
22
|
common_python_tasks/data/generic/Dockerfile.j2,sha256=UG-QxIuFT27j925LsghPl5Wqcw5wNsPPuqB6rcRngz0,7263
|
|
23
23
|
common_python_tasks/data/generic/cliff.toml,sha256=po1MnEGEEgrpyBz3XLWr0h7emXb6ASX63lrU2r6o240,77
|
|
24
24
|
common_python_tasks/data/generic/pytest.ini,sha256=RHak5QrLzKHvUBjFmaaiOYFrd_8YBRQubXEOT0NJfco,134
|
|
25
|
-
common_python_tasks-0.
|
|
26
|
-
common_python_tasks-0.
|
|
27
|
-
common_python_tasks-0.
|
|
28
|
-
common_python_tasks-0.
|
|
25
|
+
common_python_tasks-0.6.0.dist-info/METADATA,sha256=Kvp10JnUuI_GtW7ex4TeeIa5QAQcMd2qaGGH_EtC21M,22687
|
|
26
|
+
common_python_tasks-0.6.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
27
|
+
common_python_tasks-0.6.0.dist-info/licenses/LICENSE,sha256=RsSweM-DyzxFPx38fQOJqHrKyeT9Fiz8rO7yox-fOsw,1070
|
|
28
|
+
common_python_tasks-0.6.0.dist-info/RECORD,,
|
{common_python_tasks-0.5.0.dist-info → common_python_tasks-0.6.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|