common-python-tasks 0.1.0__py3-none-any.whl → 0.2.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/github.py +33 -1
- common_python_tasks/tasks.py +43 -1
- {common_python_tasks-0.1.0.dist-info → common_python_tasks-0.2.0.dist-info}/METADATA +10 -10
- {common_python_tasks-0.1.0.dist-info → common_python_tasks-0.2.0.dist-info}/RECORD +6 -6
- {common_python_tasks-0.1.0.dist-info → common_python_tasks-0.2.0.dist-info}/WHEEL +0 -0
- {common_python_tasks-0.1.0.dist-info → common_python_tasks-0.2.0.dist-info}/licenses/LICENSE +0 -0
common_python_tasks/github.py
CHANGED
|
@@ -89,7 +89,39 @@ def get_github_token() -> str | None:
|
|
|
89
89
|
Returns:
|
|
90
90
|
The GitHub token from `GITHUB_TOKEN` or `GH_TOKEN`, or `None` if unset.
|
|
91
91
|
"""
|
|
92
|
-
|
|
92
|
+
token = (os.getenv("GITHUB_TOKEN") or os.getenv("GH_TOKEN") or "").strip()
|
|
93
|
+
if token:
|
|
94
|
+
return token
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
result = utils.run_command(
|
|
98
|
+
["gh", "auth", "token"],
|
|
99
|
+
capture_output=True,
|
|
100
|
+
acceptable_returncodes={0, 1},
|
|
101
|
+
)
|
|
102
|
+
except FileNotFoundError:
|
|
103
|
+
LOGGER.warning(
|
|
104
|
+
"GitHub CLI not installed; cannot retrieve token via `gh auth token`"
|
|
105
|
+
)
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
if result is None:
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
if result.returncode != 0:
|
|
112
|
+
stderr = (result.stderr or "").strip()
|
|
113
|
+
message = "Failed to retrieve GitHub token via `gh auth token`"
|
|
114
|
+
if stderr:
|
|
115
|
+
message += f": {stderr}"
|
|
116
|
+
LOGGER.warning(message)
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
token = (result.stdout or "").strip()
|
|
120
|
+
if not token:
|
|
121
|
+
LOGGER.warning("`gh auth token` returned an empty token")
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
return token
|
|
93
125
|
|
|
94
126
|
|
|
95
127
|
def get_github_api_base_url() -> str:
|
common_python_tasks/tasks.py
CHANGED
|
@@ -112,6 +112,8 @@ def _script(
|
|
|
112
112
|
|
|
113
113
|
tasks.script = _script
|
|
114
114
|
|
|
115
|
+
NO_PROMPT_ENV_VAR = "COMMON_PYTHON_TASKS_NO_PROMPT"
|
|
116
|
+
|
|
115
117
|
|
|
116
118
|
def _should_update_release_changelog() -> bool:
|
|
117
119
|
from common_python_tasks.env import env_truthy
|
|
@@ -119,6 +121,39 @@ def _should_update_release_changelog() -> bool:
|
|
|
119
121
|
return env_truthy("RELEASE_UPDATE_CHANGELOG")
|
|
120
122
|
|
|
121
123
|
|
|
124
|
+
def _confirm_release_with_uncommitted_changes(dirty_files: list[Path]) -> bool:
|
|
125
|
+
preview = ", ".join(str(path) for path in dirty_files[:5])
|
|
126
|
+
if len(dirty_files) > 5:
|
|
127
|
+
preview = f"{preview}, ... and {len(dirty_files) - 5} more"
|
|
128
|
+
|
|
129
|
+
LOGGER.warning("Repository has uncommitted changes: %s", preview)
|
|
130
|
+
try:
|
|
131
|
+
response = input("Proceed with release anyway? [y/N]: ").strip().lower()
|
|
132
|
+
except (EOFError, OSError):
|
|
133
|
+
return False
|
|
134
|
+
return response in {"y", "yes"}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _resolve_allow_dirty_release(dirty_files: list[Path]) -> bool:
|
|
138
|
+
from common_python_tasks.utils import fatal
|
|
139
|
+
|
|
140
|
+
if not dirty_files:
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
if os.getenv(NO_PROMPT_ENV_VAR) == "1":
|
|
144
|
+
LOGGER.warning(
|
|
145
|
+
"Proceeding with release despite uncommitted changes because %s=1",
|
|
146
|
+
NO_PROMPT_ENV_VAR,
|
|
147
|
+
)
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
if _confirm_release_with_uncommitted_changes(dirty_files):
|
|
151
|
+
return True
|
|
152
|
+
|
|
153
|
+
fatal("Aborted due to uncommitted changes.")
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
|
|
122
157
|
def _update_release_changelog(release_tag: str, dry_run: bool = False) -> None:
|
|
123
158
|
from common_python_tasks.utils import prepend_changelog, run_command
|
|
124
159
|
|
|
@@ -884,6 +919,7 @@ def bump_version(
|
|
|
884
919
|
*,
|
|
885
920
|
stage: str | None = None,
|
|
886
921
|
dry_run: bool = False,
|
|
922
|
+
allow_dirty: bool = False,
|
|
887
923
|
) -> str:
|
|
888
924
|
"""Bump the project version.
|
|
889
925
|
|
|
@@ -892,6 +928,7 @@ def bump_version(
|
|
|
892
928
|
`auto` to infer the bump from git history using git-cliff.
|
|
893
929
|
stage: Optional pre-release stage to apply: `alpha`, `beta`, or `rc`.
|
|
894
930
|
dry_run: If `True`, print what would happen without making changes.
|
|
931
|
+
allow_dirty: If `True`, allow version bumping with uncommitted changes.
|
|
895
932
|
|
|
896
933
|
Returns:
|
|
897
934
|
The new version string that was/would be set.
|
|
@@ -909,7 +946,7 @@ def bump_version(
|
|
|
909
946
|
|
|
910
947
|
ensure_on_default_branch()
|
|
911
948
|
|
|
912
|
-
if get_dirty_files():
|
|
949
|
+
if get_dirty_files() and not allow_dirty:
|
|
913
950
|
fatal(
|
|
914
951
|
"Repository has uncommitted changes. "
|
|
915
952
|
"Please commit or stash changes before bumping version."
|
|
@@ -960,6 +997,7 @@ def _run_release_flow(
|
|
|
960
997
|
from common_python_tasks.git import (
|
|
961
998
|
build_release_hook_environment,
|
|
962
999
|
ensure_on_default_branch,
|
|
1000
|
+
get_dirty_files,
|
|
963
1001
|
)
|
|
964
1002
|
from common_python_tasks.utils import (
|
|
965
1003
|
log_dry_run,
|
|
@@ -971,7 +1009,10 @@ def _run_release_flow(
|
|
|
971
1009
|
post_script = post_script or os.getenv("RELEASE_POST_SCRIPT")
|
|
972
1010
|
|
|
973
1011
|
ensure_on_default_branch()
|
|
1012
|
+
allow_dirty = _resolve_allow_dirty_release(get_dirty_files())
|
|
974
1013
|
hook_env = build_release_hook_environment(component, normalized_stage, dry_run)
|
|
1014
|
+
if allow_dirty:
|
|
1015
|
+
hook_env[NO_PROMPT_ENV_VAR] = "1"
|
|
975
1016
|
if pre_script:
|
|
976
1017
|
run_command(["sh", "-lc", pre_script], env=hook_env, dry_run=False)
|
|
977
1018
|
|
|
@@ -987,6 +1028,7 @@ def _run_release_flow(
|
|
|
987
1028
|
component=hook_env["RELEASE_COMPONENT"],
|
|
988
1029
|
stage=normalized_stage,
|
|
989
1030
|
dry_run=dry_run,
|
|
1031
|
+
allow_dirty=allow_dirty,
|
|
990
1032
|
)
|
|
991
1033
|
if dry_run:
|
|
992
1034
|
log_dry_run("Would push tags to origin")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: common-python-tasks
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Opinionated Poe the Poet tasks for Python package development.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -23,7 +23,7 @@ Requires-Dist: git-cliff (>=2.12.0,<3.0.0)
|
|
|
23
23
|
Requires-Dist: isort (>=8.0.1,<9.0.0)
|
|
24
24
|
Requires-Dist: jinja2 (>=3.1.6,<4.0.0)
|
|
25
25
|
Requires-Dist: poethepoet-tasks (>=0.3.0,<0.4.0)
|
|
26
|
-
Requires-Dist: pytest (>=9.0.
|
|
26
|
+
Requires-Dist: pytest (>=9.0.3,<10.0.0)
|
|
27
27
|
Requires-Dist: pytest-cov (>=7.0.0,<8.0.0)
|
|
28
28
|
Requires-Dist: tomlkit (>=0.13.3,<0.14.0)
|
|
29
29
|
Project-URL: Homepage, http://github.com/ci-sourcerer/common-python-tasks
|
|
@@ -50,7 +50,7 @@ curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents
|
|
|
50
50
|
To install a specific release, set the environment variable `COMMON_PYTHON_TASKS_VERSION`.
|
|
51
51
|
|
|
52
52
|
```shell
|
|
53
|
-
COMMON_PYTHON_TASKS_VERSION=0.
|
|
53
|
+
COMMON_PYTHON_TASKS_VERSION=0.2.0 \
|
|
54
54
|
sh -c "$(curl -sSL https://api.github.com/repos/ci-sourcerer/common-python-tasks/contents/scripts/add-common-python-tasks.sh | jq -r '.content' | base64 -d)"
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -71,9 +71,9 @@ There's no real reason to run the automated script; I just like automating every
|
|
|
71
71
|
```toml
|
|
72
72
|
[project]
|
|
73
73
|
name = "my-awesome-project"
|
|
74
|
-
version = "0.
|
|
74
|
+
version = "0.2.0"
|
|
75
75
|
dependencies = [
|
|
76
|
-
"common-python-tasks==0.
|
|
76
|
+
"common-python-tasks==0.2.0", # Always pin to a specific version
|
|
77
77
|
]
|
|
78
78
|
|
|
79
79
|
[tool.poe]
|
|
@@ -287,8 +287,8 @@ By default, `tasks()` exposes the common task set. You can still include or excl
|
|
|
287
287
|
```toml
|
|
288
288
|
[project]
|
|
289
289
|
name = "simple-cli-tool"
|
|
290
|
-
version = "0.
|
|
291
|
-
dependencies = ["common-python-tasks==0.
|
|
290
|
+
version = "0.2.0"
|
|
291
|
+
dependencies = ["common-python-tasks==0.2.0"]
|
|
292
292
|
|
|
293
293
|
[tool.poe]
|
|
294
294
|
include_script = "common_python_tasks:tasks()"
|
|
@@ -301,8 +301,8 @@ Available tasks: common defaults such as `format`, `lint`, `test`, and `build`.
|
|
|
301
301
|
```toml
|
|
302
302
|
[project]
|
|
303
303
|
name = "containerized-app"
|
|
304
|
-
version = "0.
|
|
305
|
-
dependencies = ["common-python-tasks==0.
|
|
304
|
+
version = "0.2.0"
|
|
305
|
+
dependencies = ["common-python-tasks==0.2.0"]
|
|
306
306
|
|
|
307
307
|
[tool.poe]
|
|
308
308
|
include_script = "common_python_tasks:tasks(include_tags=['common', 'containers'])"
|
|
@@ -319,7 +319,7 @@ Available tasks: All tasks including `build-image` and `push-image`.
|
|
|
319
319
|
```toml
|
|
320
320
|
[project]
|
|
321
321
|
name = "custom-test-setup"
|
|
322
|
-
dependencies = ["common-python-tasks==0.
|
|
322
|
+
dependencies = ["common-python-tasks==0.2.0"]
|
|
323
323
|
dynamic = ["version"]
|
|
324
324
|
|
|
325
325
|
[tool.poe]
|
|
@@ -17,11 +17,11 @@ common_python_tasks/data/generic/pytest.ini,sha256=RHak5QrLzKHvUBjFmaaiOYFrd_8YB
|
|
|
17
17
|
common_python_tasks/docker.py,sha256=Pg_fySHIBdjIopme33DYdCYPwCesP9meG5T7xfKr8V8,15378
|
|
18
18
|
common_python_tasks/env.py,sha256=hRGKcad32WjFRfo2d4yQlPrZ7fGpsneIUf-_SxDYt7c,13141
|
|
19
19
|
common_python_tasks/git.py,sha256=XnirI2zNP21-pmxIKFsoG0HWEOmDJ8SzYN4eYWYN6N8,9813
|
|
20
|
-
common_python_tasks/github.py,sha256=
|
|
20
|
+
common_python_tasks/github.py,sha256=IaK-VDN0PrxLIP_ob1n1dTAFdtQHzR_QA5THrrTSuSA,18502
|
|
21
21
|
common_python_tasks/project.py,sha256=I78eQlHeRmVR5WFV_wxGyO_wxNWcYox_UYowUTE4xdU,8914
|
|
22
|
-
common_python_tasks/tasks.py,sha256=
|
|
22
|
+
common_python_tasks/tasks.py,sha256=nfcTyMAbZhfFM2zltWsh_J5AVUAEVT8pET_b685Y3ug,48798
|
|
23
23
|
common_python_tasks/utils.py,sha256=3sNB84F66suu2nUN0mG-SOuJaUctx-p9uHmDAy-Ss0g,11198
|
|
24
|
-
common_python_tasks-0.
|
|
25
|
-
common_python_tasks-0.
|
|
26
|
-
common_python_tasks-0.
|
|
27
|
-
common_python_tasks-0.
|
|
24
|
+
common_python_tasks-0.2.0.dist-info/METADATA,sha256=ctLqOYE7z1r2oDBX07svRYxDE60ECwxeJcPnQc0I224,21386
|
|
25
|
+
common_python_tasks-0.2.0.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
|
|
26
|
+
common_python_tasks-0.2.0.dist-info/licenses/LICENSE,sha256=RsSweM-DyzxFPx38fQOJqHrKyeT9Fiz8rO7yox-fOsw,1070
|
|
27
|
+
common_python_tasks-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
{common_python_tasks-0.1.0.dist-info → common_python_tasks-0.2.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|