python-semantic-release 9.5.0__py3-none-any.whl → 9.7.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_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/METADATA +3 -3
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/RECORD +26 -25
- semantic_release/__init__.py +1 -1
- semantic_release/changelog/context.py +3 -1
- semantic_release/cli/commands/changelog.py +2 -1
- semantic_release/cli/commands/publish.py +8 -0
- semantic_release/cli/commands/version.py +113 -43
- semantic_release/cli/config.py +94 -19
- semantic_release/commit_parser/_base.py +13 -4
- semantic_release/commit_parser/angular.py +7 -2
- semantic_release/commit_parser/emoji.py +5 -0
- semantic_release/commit_parser/scipy.py +12 -13
- semantic_release/commit_parser/tag.py +5 -0
- semantic_release/errors.py +22 -1
- semantic_release/hvcs/__init__.py +10 -1
- semantic_release/hvcs/_base.py +32 -109
- semantic_release/hvcs/bitbucket.py +87 -140
- semantic_release/hvcs/gitea.py +61 -71
- semantic_release/hvcs/github.py +120 -156
- semantic_release/hvcs/gitlab.py +34 -76
- semantic_release/hvcs/remote_hvcs_base.py +193 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/AUTHORS.rst +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/LICENSE +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/WHEEL +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/entry_points.txt +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/top_level.txt +0 -0
{python_semantic_release-9.5.0.dist-info → python_semantic_release-9.7.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-semantic-release
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.7.0
|
|
4
4
|
Summary: Automatic Semantic Versioning for Python projects
|
|
5
5
|
Author-email: Rolf Erik Lekang <me@rolflekang.com>
|
|
6
6
|
License: MIT
|
|
@@ -35,14 +35,14 @@ Requires-Dist: shellingham ~=1.5
|
|
|
35
35
|
Provides-Extra: dev
|
|
36
36
|
Requires-Dist: pre-commit ~=3.5 ; extra == 'dev'
|
|
37
37
|
Requires-Dist: tox ~=4.11 ; extra == 'dev'
|
|
38
|
-
Requires-Dist: ruff ==0.4.
|
|
38
|
+
Requires-Dist: ruff ==0.4.2 ; extra == 'dev'
|
|
39
39
|
Provides-Extra: docs
|
|
40
40
|
Requires-Dist: Sphinx ~=6.0 ; extra == 'docs'
|
|
41
41
|
Requires-Dist: sphinxcontrib-apidoc ==0.5.0 ; extra == 'docs'
|
|
42
42
|
Requires-Dist: sphinx-autobuild ==2024.2.4 ; extra == 'docs'
|
|
43
43
|
Requires-Dist: furo ~=2024.1 ; extra == 'docs'
|
|
44
44
|
Provides-Extra: mypy
|
|
45
|
-
Requires-Dist: mypy ==1.
|
|
45
|
+
Requires-Dist: mypy ==1.10.0 ; extra == 'mypy'
|
|
46
46
|
Requires-Dist: types-requests ~=2.31.0 ; extra == 'mypy'
|
|
47
47
|
Provides-Extra: test
|
|
48
48
|
Requires-Dist: coverage[toml] ~=7.0 ; extra == 'test'
|
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
semantic_release/__init__.py,sha256=
|
|
1
|
+
semantic_release/__init__.py,sha256=YntTmtPFc-fYThwdkIDrGo6S89Mz4851VAoDyOj_zoo,870
|
|
2
2
|
semantic_release/__main__.py,sha256=vXOARLV7KHeVXgpOMU0Q-8wovpdsOrtTsycxulI5xIE,106
|
|
3
3
|
semantic_release/const.py,sha256=Z1o2QNh60wSLeF-_1TemMBjU3ZXbV0XghnUFsbTVfOs,831
|
|
4
4
|
semantic_release/enums.py,sha256=D5B_reQGGKQQT22HO5PUtvn2Bok3fkht6TfJtXkmAUg,1020
|
|
5
|
-
semantic_release/errors.py,sha256=
|
|
5
|
+
semantic_release/errors.py,sha256=2hrKuCRWN5O_0z-C2Owf6gcTUe2MpP4Y27nHoUzJBng,1695
|
|
6
6
|
semantic_release/helpers.py,sha256=d1jOX0SNyqPc_3wr14xR25FfpqhMd4Ev7MNBOWlScc0,5581
|
|
7
7
|
semantic_release/changelog/__init__.py,sha256=Bg6Xe5Vt32rWoMscW-hd4sUwiZqzWmsg4CD1EhMesMY,262
|
|
8
|
-
semantic_release/changelog/context.py,sha256=
|
|
8
|
+
semantic_release/changelog/context.py,sha256=YAtv_svSbRsRUqHfTbmfJRpE5xkOEUxmYaBINYJyXLE,1051
|
|
9
9
|
semantic_release/changelog/release_history.py,sha256=ShzZpxTjhxka6TMbzOzYzG3EuCH8j3xjUQzll-FKcCo,6675
|
|
10
10
|
semantic_release/changelog/template.py,sha256=JqZcjdozM9-059Sa8PfiHxYNeyZFa0jxk_beyRLv5sU,4640
|
|
11
11
|
semantic_release/cli/__init__.py,sha256=gwAYhZO-4TR0tKCkQ4GqutWsL--0CII2_dcbrElI4M4,419
|
|
12
12
|
semantic_release/cli/common.py,sha256=cVQUI7Uaac_nJ7VEXuJ7Q9pVJpuMVRvE7bBl_i96g20,1439
|
|
13
|
-
semantic_release/cli/config.py,sha256=
|
|
13
|
+
semantic_release/cli/config.py,sha256=1q7tNFC4Re8gcctZyIGSKcj6qZ59W5mx9ed2yk5bgSA,20389
|
|
14
14
|
semantic_release/cli/const.py,sha256=S8oNNpSaKdZxcAs7PAKEjQHic0czoJBGd7XHo57FOzw,39
|
|
15
15
|
semantic_release/cli/github_actions_output.py,sha256=Wy4jEIpSFgoMyJqq4FD7scIpgovivutFLZ7Fs4y2CUY,2110
|
|
16
16
|
semantic_release/cli/masking_filter.py,sha256=DxqjiJyABlzwwwZ1r8JGQpb6QrF00StJFm0-2-s5Fv0,3071
|
|
17
17
|
semantic_release/cli/util.py,sha256=FyXaBkeL7nXKjy3X9rQLEwvn7p46xPekp2V8Z-5MVrk,3755
|
|
18
18
|
semantic_release/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
semantic_release/cli/commands/changelog.py,sha256=
|
|
19
|
+
semantic_release/cli/commands/changelog.py,sha256=rNZwWucEbR2BjbmgHQa9R1nJk5Fu0Ph3U3wh-daH42Q,4197
|
|
20
20
|
semantic_release/cli/commands/cli_context.py,sha256=fOLTUKb4UnZGQ6zVhftuvdfZ7fK7bDDIvj7Ud5yU98c,3443
|
|
21
21
|
semantic_release/cli/commands/generate_config.py,sha256=2xZOu3NpyhBp0pWr7d8ugKl_kjqQgpSsSMHq5wHTfrE,1699
|
|
22
22
|
semantic_release/cli/commands/main.py,sha256=LuL-O0LGonI5fQTZn0AUtYv2Ei_CYyNqYHMF_wN4InI,2900
|
|
23
|
-
semantic_release/cli/commands/publish.py,sha256=
|
|
24
|
-
semantic_release/cli/commands/version.py,sha256=
|
|
23
|
+
semantic_release/cli/commands/publish.py,sha256=ZA7DuEGxZdIT9wUwP1S24qi1RdcKV-1FnYci-PvyXIg,1958
|
|
24
|
+
semantic_release/cli/commands/version.py,sha256=liG9q4f_pH0ISGMODJ-qYbIv-OoLggfOx6RCOnA7ow8,25912
|
|
25
25
|
semantic_release/commit_parser/__init__.py,sha256=cv5HFBdw7OJd4Laj4Ex8ZZ5Tml8GwXgQcXW6Pasr2Ao,615
|
|
26
|
-
semantic_release/commit_parser/_base.py,sha256=
|
|
27
|
-
semantic_release/commit_parser/angular.py,sha256=
|
|
28
|
-
semantic_release/commit_parser/emoji.py,sha256=
|
|
29
|
-
semantic_release/commit_parser/scipy.py,sha256=
|
|
30
|
-
semantic_release/commit_parser/tag.py,sha256=
|
|
26
|
+
semantic_release/commit_parser/_base.py,sha256=D2dY8dALV3QPK0XOLZru9btMW5dlx9YSmDIe3v5T0QA,3004
|
|
27
|
+
semantic_release/commit_parser/angular.py,sha256=ERWeTBTFNIBOaTIopY4Vff0KbeFwrSQWbADe3smVW-8,4579
|
|
28
|
+
semantic_release/commit_parser/emoji.py,sha256=M6zgqsXqegLK5FxZGyfsOPM3vOsJkPKVAjnGATOhwa4,3452
|
|
29
|
+
semantic_release/commit_parser/scipy.py,sha256=uRNLSXH4LApxm8xSyUil23WVO3C8VEFRCnwTIKZbyQk,5879
|
|
30
|
+
semantic_release/commit_parser/tag.py,sha256=SAop9INQvKOwktNmVypKFngd6xHmY_XZrLUWChUjz84,3353
|
|
31
31
|
semantic_release/commit_parser/token.py,sha256=UxYAwEylPvp4x39RqNA9ITcgkaSRDEH7A5XDDJ3tdiM,1505
|
|
32
32
|
semantic_release/commit_parser/util.py,sha256=vLcVDErZrExM55jMffos0hyMbNVQoJ-PeeVDG1Ej51I,730
|
|
33
33
|
semantic_release/data/templates/CHANGELOG.md.j2,sha256=GB3YJwgVrhlcb-g5ESdEh_Gsysb_Texxv-Ip2LjulC0,1066
|
|
34
34
|
semantic_release/data/templates/release_notes.md.j2,sha256=27uIHgG6iYmqdMaoWFP5LJRZcrO-3paqFzHHHsGpXXE,465
|
|
35
|
-
semantic_release/hvcs/__init__.py,sha256=
|
|
36
|
-
semantic_release/hvcs/_base.py,sha256=
|
|
37
|
-
semantic_release/hvcs/bitbucket.py,sha256=
|
|
38
|
-
semantic_release/hvcs/gitea.py,sha256=
|
|
39
|
-
semantic_release/hvcs/github.py,sha256=
|
|
40
|
-
semantic_release/hvcs/gitlab.py,sha256=
|
|
35
|
+
semantic_release/hvcs/__init__.py,sha256=JwoaLOF-12L-OBo_9-tOXXhdiHKeVungA9865to2oZk,494
|
|
36
|
+
semantic_release/hvcs/_base.py,sha256=9-iTqTPSbiEevKbCBP9K2hq4c-2T4wPbeLWe-kAxBzo,2607
|
|
37
|
+
semantic_release/hvcs/bitbucket.py,sha256=tMpl69CbZSQ8cdgiqtIzf7WSz8OQwDInGpoq-9tQr3k,9216
|
|
38
|
+
semantic_release/hvcs/gitea.py,sha256=CSItRSJU39hohO3oE-ohX65Er_s2nVrDqvfc7KQtmv8,11152
|
|
39
|
+
semantic_release/hvcs/github.py,sha256=34ZMGttmqcTcY6_D-SRn-HxUJxNT4WwBNEwYlsHC420,18287
|
|
40
|
+
semantic_release/hvcs/gitlab.py,sha256=JtHWBaNGSMB8MTiznEhvuMm_M8lLceZPaGndzOx39Vk,6249
|
|
41
|
+
semantic_release/hvcs/remote_hvcs_base.py,sha256=plZkc5cSaiTxgIR5HhlEWrYoyWzzSXr-Jw3aXbMK_iA,6055
|
|
41
42
|
semantic_release/hvcs/token_auth.py,sha256=ZjT56-NIPB4OKIt1qwHCu1TavXnrWFIBl9ARlg56hgU,663
|
|
42
43
|
semantic_release/hvcs/util.py,sha256=PNKXApgL2np9lpnKjAbo77toRgElLPXrbS1q7621waI,2886
|
|
43
44
|
semantic_release/version/__init__.py,sha256=CLhtGQry9dLIij5XyRa9ZevxU_1p8tjMTSQ-K_GMpWM,270
|
|
@@ -45,10 +46,10 @@ semantic_release/version/algorithm.py,sha256=-9ulTy1z4u-jUvbc-FrvEdFL7Omc3O3HhaP
|
|
|
45
46
|
semantic_release/version/declaration.py,sha256=f6Ld7hIhrqvDrRBapJHr-KDimuyo-4IG8009Zu9BIgU,7357
|
|
46
47
|
semantic_release/version/translator.py,sha256=P1noIsVBn8u6zNOFjG0xKYOWapxqf_PHSMvMeLJ9kXg,3050
|
|
47
48
|
semantic_release/version/version.py,sha256=6PCtSbLP88U1daoxnCwHc--YguZo4waGNLqJ5JfeczE,14175
|
|
48
|
-
python_semantic_release-9.
|
|
49
|
-
python_semantic_release-9.
|
|
50
|
-
python_semantic_release-9.
|
|
51
|
-
python_semantic_release-9.
|
|
52
|
-
python_semantic_release-9.
|
|
53
|
-
python_semantic_release-9.
|
|
54
|
-
python_semantic_release-9.
|
|
49
|
+
python_semantic_release-9.7.0.dist-info/AUTHORS.rst,sha256=XOReVvpymEFUPsS2QPH97jlfJBVrxwS2eu8-jVAe4gk,230
|
|
50
|
+
python_semantic_release-9.7.0.dist-info/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
|
|
51
|
+
python_semantic_release-9.7.0.dist-info/METADATA,sha256=jiFhqNG1gByE9-iM8EOMljPsuxhc-XIBXcugDJ9tJ1M,5336
|
|
52
|
+
python_semantic_release-9.7.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
53
|
+
python_semantic_release-9.7.0.dist-info/entry_points.txt,sha256=qojUBx_Ywf4u7KgP6NWlDaBDymZVUGQ7m5wF2duC2F0,95
|
|
54
|
+
python_semantic_release-9.7.0.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
|
|
55
|
+
python_semantic_release-9.7.0.dist-info/RECORD,,
|
semantic_release/__init__.py
CHANGED
|
@@ -14,6 +14,7 @@ if TYPE_CHECKING:
|
|
|
14
14
|
class ChangelogContext:
|
|
15
15
|
repo_name: str
|
|
16
16
|
repo_owner: str
|
|
17
|
+
hvcs_type: str
|
|
17
18
|
history: ReleaseHistory
|
|
18
19
|
filters: tuple[Callable[..., Any], ...] = ()
|
|
19
20
|
|
|
@@ -31,5 +32,6 @@ def make_changelog_context(
|
|
|
31
32
|
repo_name=hvcs_client.repo_name,
|
|
32
33
|
repo_owner=hvcs_client.owner,
|
|
33
34
|
history=release_history,
|
|
34
|
-
|
|
35
|
+
hvcs_type=hvcs_client.__class__.__name__.lower(),
|
|
36
|
+
filters=(*hvcs_client.get_changelog_context_filters(),),
|
|
35
37
|
)
|
|
@@ -14,6 +14,7 @@ from semantic_release.cli.common import (
|
|
|
14
14
|
render_release_notes,
|
|
15
15
|
)
|
|
16
16
|
from semantic_release.cli.util import noop_report
|
|
17
|
+
from semantic_release.hvcs.remote_hvcs_base import RemoteHvcsBase
|
|
17
18
|
|
|
18
19
|
if TYPE_CHECKING:
|
|
19
20
|
from semantic_release.cli.commands.cli_context import CliContextObj
|
|
@@ -79,7 +80,7 @@ def changelog(cli_ctx: CliContextObj, release_tag: str | None = None) -> None:
|
|
|
79
80
|
else:
|
|
80
81
|
recursive_render(template_dir, environment=env, _root_dir=repo.working_dir)
|
|
81
82
|
|
|
82
|
-
if release_tag:
|
|
83
|
+
if release_tag and isinstance(hvcs_client, RemoteHvcsBase):
|
|
83
84
|
if runtime.global_cli_options.noop:
|
|
84
85
|
noop_report(
|
|
85
86
|
f"would have posted changelog to the release for tag {release_tag}"
|
|
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
import click
|
|
7
7
|
|
|
8
8
|
from semantic_release.cli.util import noop_report
|
|
9
|
+
from semantic_release.hvcs.remote_hvcs_base import RemoteHvcsBase
|
|
9
10
|
from semantic_release.version import tags_and_versions
|
|
10
11
|
|
|
11
12
|
if TYPE_CHECKING:
|
|
@@ -45,6 +46,13 @@ def publish(cli_ctx: CliContextObj, tag: str = "latest") -> None:
|
|
|
45
46
|
f"No tags found with format {translator.tag_format!r}, couldn't "
|
|
46
47
|
"identify latest version"
|
|
47
48
|
)
|
|
49
|
+
|
|
50
|
+
if not isinstance(hvcs_client, RemoteHvcsBase):
|
|
51
|
+
log.info(
|
|
52
|
+
"Remote does not support artifact upload. Exiting with no action taken..."
|
|
53
|
+
)
|
|
54
|
+
ctx.exit(0)
|
|
55
|
+
|
|
48
56
|
if runtime.global_cli_options.noop:
|
|
49
57
|
noop_report(
|
|
50
58
|
"would have uploaded files matching any of the globs "
|
|
@@ -25,12 +25,13 @@ from semantic_release.cli.util import indented, noop_report, rprint
|
|
|
25
25
|
from semantic_release.const import DEFAULT_SHELL, DEFAULT_VERSION
|
|
26
26
|
from semantic_release.enums import LevelBump
|
|
27
27
|
from semantic_release.errors import UnexpectedResponse
|
|
28
|
+
from semantic_release.hvcs.remote_hvcs_base import RemoteHvcsBase
|
|
28
29
|
from semantic_release.version import Version, next_version, tags_and_versions
|
|
29
30
|
|
|
30
31
|
log = logging.getLogger(__name__)
|
|
31
32
|
|
|
32
33
|
if TYPE_CHECKING: # pragma: no cover
|
|
33
|
-
from typing import ContextManager, Iterable
|
|
34
|
+
from typing import ContextManager, Iterable, Mapping
|
|
34
35
|
|
|
35
36
|
from git import Repo
|
|
36
37
|
from git.refs.tag import Tag
|
|
@@ -41,7 +42,7 @@ if TYPE_CHECKING: # pragma: no cover
|
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
def is_forced_prerelease(
|
|
44
|
-
|
|
45
|
+
as_prerelease: bool, forced_level_bump: LevelBump | None, prerelease: bool
|
|
45
46
|
) -> bool:
|
|
46
47
|
"""
|
|
47
48
|
Determine if this release is forced to have prerelease on/off.
|
|
@@ -50,8 +51,17 @@ def is_forced_prerelease(
|
|
|
50
51
|
it's False.
|
|
51
52
|
Otherwise (``force_level is None``) use the value of ``prerelease``
|
|
52
53
|
"""
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
local_vars = list(locals().items())
|
|
55
|
+
log.debug(
|
|
56
|
+
"%s: %s",
|
|
57
|
+
is_forced_prerelease.__name__,
|
|
58
|
+
", ".join(f"{k} = {v}" for k, v in local_vars),
|
|
59
|
+
)
|
|
60
|
+
return (
|
|
61
|
+
as_prerelease
|
|
62
|
+
or forced_level_bump is LevelBump.PRERELEASE_REVISION
|
|
63
|
+
or ((forced_level_bump is None) and prerelease)
|
|
64
|
+
)
|
|
55
65
|
|
|
56
66
|
|
|
57
67
|
def last_released(
|
|
@@ -62,16 +72,41 @@ def last_released(
|
|
|
62
72
|
|
|
63
73
|
|
|
64
74
|
def version_from_forced_level(
|
|
65
|
-
repo: Repo,
|
|
75
|
+
repo: Repo, forced_level_bump: LevelBump, translator: VersionTranslator
|
|
66
76
|
) -> Version:
|
|
67
77
|
ts_and_vs = tags_and_versions(repo.tags, translator)
|
|
68
78
|
|
|
69
79
|
# If we have no tags, return the default version
|
|
70
80
|
if not ts_and_vs:
|
|
71
|
-
return Version.parse(DEFAULT_VERSION).bump(
|
|
81
|
+
return Version.parse(DEFAULT_VERSION).bump(forced_level_bump)
|
|
72
82
|
|
|
73
83
|
_, latest_version = ts_and_vs[0]
|
|
74
|
-
|
|
84
|
+
if forced_level_bump is not LevelBump.PRERELEASE_REVISION:
|
|
85
|
+
return latest_version.bump(forced_level_bump)
|
|
86
|
+
|
|
87
|
+
# We need to find the latest version with the prerelease token
|
|
88
|
+
# we're looking for, and return that version + an increment to
|
|
89
|
+
# the prerelease revision.
|
|
90
|
+
|
|
91
|
+
# NOTE this can probably be cleaned up.
|
|
92
|
+
# ts_and_vs are in order, so check if we're looking at prereleases
|
|
93
|
+
# for the same (major, minor, patch) as the latest version.
|
|
94
|
+
# If we are, we can increment the revision and we're done. If
|
|
95
|
+
# we don't find a prerelease targeting this version with the same
|
|
96
|
+
# token as the one we're looking to prerelease, we can use revision 1.
|
|
97
|
+
for _, version in ts_and_vs:
|
|
98
|
+
if not (
|
|
99
|
+
version.major == latest_version.major
|
|
100
|
+
and version.minor == latest_version.minor
|
|
101
|
+
and version.patch == latest_version.patch
|
|
102
|
+
):
|
|
103
|
+
break
|
|
104
|
+
if (
|
|
105
|
+
version.is_prerelease
|
|
106
|
+
and version.prerelease_token == translator.prerelease_token
|
|
107
|
+
):
|
|
108
|
+
return version.bump(LevelBump.PRERELEASE_REVISION)
|
|
109
|
+
return latest_version.to_prerelease(token=translator.prerelease_token, revision=1)
|
|
75
110
|
|
|
76
111
|
|
|
77
112
|
def apply_version_to_source_files(
|
|
@@ -100,7 +135,9 @@ def apply_version_to_source_files(
|
|
|
100
135
|
return paths
|
|
101
136
|
|
|
102
137
|
|
|
103
|
-
def shell(
|
|
138
|
+
def shell(
|
|
139
|
+
cmd: str, *, env: Mapping[str, str] | None = None, check: bool = True
|
|
140
|
+
) -> subprocess.CompletedProcess:
|
|
104
141
|
shell: str | None
|
|
105
142
|
try:
|
|
106
143
|
shell, _ = shellingham.detect_shell()
|
|
@@ -114,6 +151,7 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
|
|
|
114
151
|
|
|
115
152
|
return subprocess.run(
|
|
116
153
|
[shell, "-c" if shell != "cmd" else "/c", cmd], # noqa: S603
|
|
154
|
+
env=(env or {}),
|
|
117
155
|
check=check,
|
|
118
156
|
)
|
|
119
157
|
|
|
@@ -145,10 +183,10 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
|
|
|
145
183
|
help="Print the last released version tag and exit",
|
|
146
184
|
)
|
|
147
185
|
@click.option(
|
|
148
|
-
"--prerelease",
|
|
149
|
-
"
|
|
186
|
+
"--as-prerelease",
|
|
187
|
+
"as_prerelease",
|
|
150
188
|
is_flag=True,
|
|
151
|
-
help="
|
|
189
|
+
help="Ensure the next version to be released is a prerelease version",
|
|
152
190
|
)
|
|
153
191
|
@click.option(
|
|
154
192
|
"--prerelease-token",
|
|
@@ -160,19 +198,25 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
|
|
|
160
198
|
"--major",
|
|
161
199
|
"force_level",
|
|
162
200
|
flag_value="major",
|
|
163
|
-
help="
|
|
201
|
+
help="Force the next version to be a major release",
|
|
164
202
|
)
|
|
165
203
|
@click.option(
|
|
166
204
|
"--minor",
|
|
167
205
|
"force_level",
|
|
168
206
|
flag_value="minor",
|
|
169
|
-
help="
|
|
207
|
+
help="Force the next version to be a minor release",
|
|
170
208
|
)
|
|
171
209
|
@click.option(
|
|
172
210
|
"--patch",
|
|
173
211
|
"force_level",
|
|
174
212
|
flag_value="patch",
|
|
175
|
-
help="
|
|
213
|
+
help="Force the next version to be a patch release",
|
|
214
|
+
)
|
|
215
|
+
@click.option(
|
|
216
|
+
"--prerelease",
|
|
217
|
+
"force_level",
|
|
218
|
+
flag_value="prerelease_revision",
|
|
219
|
+
help="Force the next version to be a prerelease",
|
|
176
220
|
)
|
|
177
221
|
@click.option(
|
|
178
222
|
"--commit/--no-commit",
|
|
@@ -224,7 +268,7 @@ def version( # noqa: C901
|
|
|
224
268
|
print_only_tag: bool = False,
|
|
225
269
|
print_last_released: bool = False,
|
|
226
270
|
print_last_released_tag: bool = False,
|
|
227
|
-
|
|
271
|
+
as_prerelease: bool = False,
|
|
228
272
|
prerelease_token: str | None = None,
|
|
229
273
|
force_level: str | None = None,
|
|
230
274
|
commit_changes: bool = True,
|
|
@@ -271,9 +315,10 @@ def version( # noqa: C901
|
|
|
271
315
|
ctx.exit(0)
|
|
272
316
|
|
|
273
317
|
parser = runtime.commit_parser
|
|
318
|
+
forced_level_bump = None if not force_level else LevelBump.from_string(force_level)
|
|
274
319
|
prerelease = is_forced_prerelease(
|
|
275
|
-
|
|
276
|
-
|
|
320
|
+
as_prerelease=as_prerelease,
|
|
321
|
+
forced_level_bump=forced_level_bump,
|
|
277
322
|
prerelease=runtime.prerelease,
|
|
278
323
|
)
|
|
279
324
|
hvcs_client = runtime.hvcs_client
|
|
@@ -306,23 +351,19 @@ def version( # noqa: C901
|
|
|
306
351
|
log.info("No vcs release will be created because pushing changes is disabled")
|
|
307
352
|
make_vcs_release &= push_changes
|
|
308
353
|
|
|
309
|
-
if
|
|
310
|
-
log.warning("Forcing prerelease due to '--prerelease' command-line flag")
|
|
311
|
-
elif force_level:
|
|
354
|
+
if forced_level_bump:
|
|
312
355
|
log.warning(
|
|
313
|
-
"Forcing
|
|
314
|
-
"'--prerelease' flag",
|
|
356
|
+
"Forcing a '%s' release due to '--%s' command-line flag",
|
|
315
357
|
force_level,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
"Forcing a %s level bump due to '--force' command-line option", force_level
|
|
358
|
+
(
|
|
359
|
+
force_level
|
|
360
|
+
if forced_level_bump is not LevelBump.PRERELEASE_REVISION
|
|
361
|
+
else "prerelease"
|
|
362
|
+
),
|
|
322
363
|
)
|
|
323
364
|
|
|
324
365
|
new_version = version_from_forced_level(
|
|
325
|
-
repo=repo,
|
|
366
|
+
repo=repo, forced_level_bump=forced_level_bump, translator=translator
|
|
326
367
|
)
|
|
327
368
|
|
|
328
369
|
# We only turn the forced version into a prerelease if the user has specified
|
|
@@ -347,6 +388,17 @@ def version( # noqa: C901
|
|
|
347
388
|
if build_metadata:
|
|
348
389
|
new_version.build_metadata = build_metadata
|
|
349
390
|
|
|
391
|
+
if as_prerelease:
|
|
392
|
+
before_conversion, new_version = (
|
|
393
|
+
new_version,
|
|
394
|
+
new_version.to_prerelease(token=translator.prerelease_token),
|
|
395
|
+
)
|
|
396
|
+
log.info(
|
|
397
|
+
"Converting %s to %s due to '--as-prerelease' command-line option",
|
|
398
|
+
before_conversion,
|
|
399
|
+
new_version,
|
|
400
|
+
)
|
|
401
|
+
|
|
350
402
|
gha_output.released = False
|
|
351
403
|
gha_output.version = new_version
|
|
352
404
|
ctx.call_on_close(gha_output.write_if_possible)
|
|
@@ -458,7 +510,35 @@ def version( # noqa: C901
|
|
|
458
510
|
"[bold green]:hammer_and_wrench: Running build command: "
|
|
459
511
|
+ build_command
|
|
460
512
|
)
|
|
461
|
-
shell(
|
|
513
|
+
shell(
|
|
514
|
+
build_command,
|
|
515
|
+
check=True,
|
|
516
|
+
env=dict(
|
|
517
|
+
filter(
|
|
518
|
+
lambda k_v: k_v[1] is not None, # type: ignore
|
|
519
|
+
{
|
|
520
|
+
"NEW_VERSION": str(new_version),
|
|
521
|
+
"PATH": os.getenv("PATH", ""),
|
|
522
|
+
"HOME": os.getenv("HOME", None),
|
|
523
|
+
"VIRTUAL_ENV": os.getenv("VIRTUAL_ENV", None),
|
|
524
|
+
# affects build decisions
|
|
525
|
+
"CI": os.getenv("CI", None),
|
|
526
|
+
# Identifies which CI environment
|
|
527
|
+
"GITHUB_ACTIONS": os.getenv("GITHUB_ACTIONS", None),
|
|
528
|
+
"GITLAB_CI": os.getenv("GITLAB_CI", None),
|
|
529
|
+
"GITEA_ACTIONS": os.getenv("GITEA_ACTIONS", None),
|
|
530
|
+
"BITBUCKET_CI": (
|
|
531
|
+
str(True).lower()
|
|
532
|
+
if os.getenv("BITBUCKET_REPO_FULL_NAME", None)
|
|
533
|
+
else None
|
|
534
|
+
),
|
|
535
|
+
"PSR_DOCKER_GITHUB_ACTION": os.getenv(
|
|
536
|
+
"PSR_DOCKER_GITHUB_ACTION", None
|
|
537
|
+
),
|
|
538
|
+
}.items(),
|
|
539
|
+
)
|
|
540
|
+
),
|
|
541
|
+
)
|
|
462
542
|
except subprocess.CalledProcessError as exc:
|
|
463
543
|
ctx.fail(str(exc))
|
|
464
544
|
|
|
@@ -601,7 +681,7 @@ def version( # noqa: C901
|
|
|
601
681
|
|
|
602
682
|
gha_output.released = True
|
|
603
683
|
|
|
604
|
-
if make_vcs_release:
|
|
684
|
+
if make_vcs_release and isinstance(hvcs_client, RemoteHvcsBase):
|
|
605
685
|
if opts.noop:
|
|
606
686
|
noop_report(
|
|
607
687
|
f"would have created a release for the tag {new_version.as_tag()!r}"
|
|
@@ -630,10 +710,11 @@ def version( # noqa: C901
|
|
|
630
710
|
noop_report(f"would have uploaded the following assets: {runtime.assets}")
|
|
631
711
|
else:
|
|
632
712
|
try:
|
|
633
|
-
|
|
713
|
+
hvcs_client.create_release(
|
|
634
714
|
tag=new_version.as_tag(),
|
|
635
715
|
release_notes=release_notes,
|
|
636
716
|
prerelease=new_version.is_prerelease,
|
|
717
|
+
assets=assets,
|
|
637
718
|
)
|
|
638
719
|
except HTTPError as err:
|
|
639
720
|
log.exception(err)
|
|
@@ -654,15 +735,4 @@ def version( # noqa: C901
|
|
|
654
735
|
log.exception(e)
|
|
655
736
|
ctx.fail(str(e))
|
|
656
737
|
|
|
657
|
-
for asset in assets:
|
|
658
|
-
log.info("Uploading asset %s", asset)
|
|
659
|
-
try:
|
|
660
|
-
hvcs_client.upload_asset(release_id, asset)
|
|
661
|
-
except HTTPError as err:
|
|
662
|
-
log.exception(err)
|
|
663
|
-
ctx.fail(str.join("\n", [str(err), "Failed to upload asset!"]))
|
|
664
|
-
except Exception as e:
|
|
665
|
-
log.exception(e)
|
|
666
|
-
ctx.fail(str(e))
|
|
667
|
-
|
|
668
738
|
return str(new_version)
|
semantic_release/cli/config.py
CHANGED
|
@@ -39,8 +39,13 @@ from semantic_release.commit_parser import (
|
|
|
39
39
|
TagCommitParser,
|
|
40
40
|
)
|
|
41
41
|
from semantic_release.const import COMMIT_MESSAGE, DEFAULT_COMMIT_AUTHOR, SEMVER_REGEX
|
|
42
|
-
from semantic_release.errors import
|
|
42
|
+
from semantic_release.errors import (
|
|
43
|
+
InvalidConfiguration,
|
|
44
|
+
NotAReleaseBranch,
|
|
45
|
+
ParserLoadError,
|
|
46
|
+
)
|
|
43
47
|
from semantic_release.helpers import dynamic_import
|
|
48
|
+
from semantic_release.hvcs.remote_hvcs_base import RemoteHvcsBase
|
|
44
49
|
from semantic_release.version import VersionTranslator
|
|
45
50
|
from semantic_release.version.declaration import (
|
|
46
51
|
PatternVersionDeclaration,
|
|
@@ -141,13 +146,22 @@ class RemoteConfig(BaseModel):
|
|
|
141
146
|
def set_default_token(self) -> Self:
|
|
142
147
|
# Set the default token name for the given VCS when no user input is given
|
|
143
148
|
if not self.token and self.type in _known_hvcs:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
env_token = EnvConfigVar(env=default_token_name).getvalue()
|
|
147
|
-
if env_token:
|
|
148
|
-
self.token = env_token
|
|
149
|
+
if env_token := self._get_default_token():
|
|
150
|
+
self.token = env_token
|
|
149
151
|
return self
|
|
150
152
|
|
|
153
|
+
def _get_default_token(self) -> str | None:
|
|
154
|
+
hvcs_client_class = _known_hvcs[self.type]
|
|
155
|
+
default_hvcs_instance = hvcs_client_class("git@example.com:owner/project.git")
|
|
156
|
+
if not isinstance(default_hvcs_instance, RemoteHvcsBase):
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
default_token_name = default_hvcs_instance.DEFAULT_ENV_TOKEN_NAME
|
|
160
|
+
if not default_token_name:
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
return EnvConfigVar(env=default_token_name).getvalue()
|
|
164
|
+
|
|
151
165
|
@model_validator(mode="after")
|
|
152
166
|
def check_url_scheme(self) -> Self:
|
|
153
167
|
if self.url and isinstance(self.url, str):
|
|
@@ -222,18 +236,50 @@ class RawConfig(BaseModel):
|
|
|
222
236
|
parser_opts_type = None
|
|
223
237
|
# If the commit parser is a known one, pull the default options object from it
|
|
224
238
|
if self.commit_parser in _known_commit_parsers:
|
|
239
|
+
# TODO: BREAKING CHANGE v10
|
|
240
|
+
# parser_opts_type = (
|
|
241
|
+
# _known_commit_parsers[self.commit_parser]
|
|
242
|
+
# .get_default_options()
|
|
243
|
+
# .__class__
|
|
244
|
+
# )
|
|
225
245
|
parser_opts_type = _known_commit_parsers[
|
|
226
246
|
self.commit_parser
|
|
227
247
|
].parser_options
|
|
228
248
|
else:
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
249
|
+
try:
|
|
250
|
+
# if its a custom parser, try to import it and pull the default options object type
|
|
251
|
+
custom_class = dynamic_import(self.commit_parser)
|
|
252
|
+
# TODO: BREAKING CHANGE v10
|
|
253
|
+
# parser_opts_type = custom_class.get_default_options().__class__
|
|
254
|
+
if hasattr(custom_class, "parser_options"):
|
|
255
|
+
parser_opts_type = custom_class.parser_options
|
|
256
|
+
|
|
257
|
+
except ModuleNotFoundError as err:
|
|
258
|
+
raise ParserLoadError(
|
|
259
|
+
str.join(
|
|
260
|
+
"\n",
|
|
261
|
+
[
|
|
262
|
+
str(err),
|
|
263
|
+
"Unable to import your custom parser! Check your configuration!",
|
|
264
|
+
],
|
|
265
|
+
)
|
|
266
|
+
) from err
|
|
267
|
+
|
|
268
|
+
except AttributeError as err:
|
|
269
|
+
raise ParserLoadError(
|
|
270
|
+
str.join(
|
|
271
|
+
"\n",
|
|
272
|
+
[
|
|
273
|
+
str(err),
|
|
274
|
+
"Unable to find your custom parser class inside the given module.",
|
|
275
|
+
"Check your configuration!",
|
|
276
|
+
],
|
|
277
|
+
)
|
|
278
|
+
) from err
|
|
233
279
|
|
|
234
280
|
# from either the custom opts class or the known parser opts class, create an instance
|
|
235
281
|
if callable(parser_opts_type):
|
|
236
|
-
opts_obj = parser_opts_type()
|
|
282
|
+
opts_obj: Any = parser_opts_type()
|
|
237
283
|
# if the opts object is a dataclass, wrap it in a RootModel so it can be transformed to a Mapping
|
|
238
284
|
opts_obj = (
|
|
239
285
|
opts_obj if not is_dataclass(opts_obj) else RootModel(opts_obj)
|
|
@@ -373,15 +419,44 @@ class RuntimeContext:
|
|
|
373
419
|
branch_config = cls.select_branch_options(raw.branches, active_branch)
|
|
374
420
|
|
|
375
421
|
# commit_parser
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
422
|
+
try:
|
|
423
|
+
commit_parser_cls = (
|
|
424
|
+
_known_commit_parsers[raw.commit_parser]
|
|
425
|
+
if raw.commit_parser in _known_commit_parsers
|
|
426
|
+
else dynamic_import(raw.commit_parser)
|
|
427
|
+
)
|
|
428
|
+
except ModuleNotFoundError as err:
|
|
429
|
+
raise ParserLoadError(
|
|
430
|
+
str.join(
|
|
431
|
+
"\n",
|
|
432
|
+
[
|
|
433
|
+
str(err),
|
|
434
|
+
"Unable to import your custom parser! Check your configuration!",
|
|
435
|
+
],
|
|
436
|
+
)
|
|
437
|
+
) from err
|
|
438
|
+
except AttributeError as err:
|
|
439
|
+
raise ParserLoadError(
|
|
440
|
+
str.join(
|
|
441
|
+
"\n",
|
|
442
|
+
[
|
|
443
|
+
str(err),
|
|
444
|
+
"Unable to find the parser class inside the given module",
|
|
445
|
+
],
|
|
446
|
+
)
|
|
447
|
+
) from err
|
|
381
448
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
)
|
|
449
|
+
commit_parser_opts_class = commit_parser_cls.parser_options
|
|
450
|
+
# TODO: Breaking change v10
|
|
451
|
+
# commit_parser_opts_class = commit_parser_cls.get_default_options().__class__
|
|
452
|
+
try:
|
|
453
|
+
commit_parser = commit_parser_cls(
|
|
454
|
+
options=commit_parser_opts_class(**raw.commit_parser_options)
|
|
455
|
+
)
|
|
456
|
+
except TypeError as err:
|
|
457
|
+
raise ParserLoadError(
|
|
458
|
+
str.join("\n", [str(err), f"Failed to initialize {raw.commit_parser}"])
|
|
459
|
+
) from err
|
|
385
460
|
|
|
386
461
|
# We always exclude PSR's own release commits from the Changelog
|
|
387
462
|
# when parsing commits
|
|
@@ -65,10 +65,19 @@ class CommitParser(ABC, Generic[_TT, _OPTS]):
|
|
|
65
65
|
...
|
|
66
66
|
"""
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
# TODO: Deprecate in lieu of get_default_options()
|
|
69
|
+
parser_options: type[ParserOptions] = ParserOptions
|
|
70
|
+
|
|
71
|
+
def __init__(self, options: _OPTS | None = None) -> None:
|
|
72
|
+
self.options: _OPTS = (
|
|
73
|
+
options if options is not None else self.get_default_options()
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# TODO: BREAKING CHANGE v10, add abstract method for all custom parsers
|
|
77
|
+
# @staticmethod
|
|
78
|
+
# @abstractmethod
|
|
79
|
+
def get_default_options(self) -> _OPTS:
|
|
80
|
+
return self.parser_options() # type: ignore
|
|
72
81
|
|
|
73
82
|
@abstractmethod
|
|
74
83
|
def parse(self, commit: Commit) -> _TT: ...
|