python-semantic-release 9.5.0__py3-none-any.whl → 9.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.
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.6.0.dist-info}/METADATA +1 -1
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.6.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 +79 -40
- 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.6.0.dist-info}/AUTHORS.rst +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.6.0.dist-info}/LICENSE +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.6.0.dist-info}/WHEEL +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.6.0.dist-info}/entry_points.txt +0 -0
- {python_semantic_release-9.5.0.dist-info → python_semantic_release-9.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
semantic_release/__init__.py,sha256=
|
|
1
|
+
semantic_release/__init__.py,sha256=obnrcYcFeW96PuTVl8urJfNUD4ZZ3brgq6ORznMIPs4,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=08LLMJctxlegAzo88NXlhIqcFuKYOI3b9Psw8NqB-oU,24488
|
|
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.6.0.dist-info/AUTHORS.rst,sha256=XOReVvpymEFUPsS2QPH97jlfJBVrxwS2eu8-jVAe4gk,230
|
|
50
|
+
python_semantic_release-9.6.0.dist-info/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
|
|
51
|
+
python_semantic_release-9.6.0.dist-info/METADATA,sha256=7s6FI6zlP-PBF4hz2SHNEioGTw8TYT3tBzcsYH1gZEw,5335
|
|
52
|
+
python_semantic_release-9.6.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
53
|
+
python_semantic_release-9.6.0.dist-info/entry_points.txt,sha256=qojUBx_Ywf4u7KgP6NWlDaBDymZVUGQ7m5wF2duC2F0,95
|
|
54
|
+
python_semantic_release-9.6.0.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
|
|
55
|
+
python_semantic_release-9.6.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,6 +25,7 @@ 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__)
|
|
@@ -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(
|
|
@@ -145,10 +180,10 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
|
|
|
145
180
|
help="Print the last released version tag and exit",
|
|
146
181
|
)
|
|
147
182
|
@click.option(
|
|
148
|
-
"--prerelease",
|
|
149
|
-
"
|
|
183
|
+
"--as-prerelease",
|
|
184
|
+
"as_prerelease",
|
|
150
185
|
is_flag=True,
|
|
151
|
-
help="
|
|
186
|
+
help="Ensure the next version to be released is a prerelease version",
|
|
152
187
|
)
|
|
153
188
|
@click.option(
|
|
154
189
|
"--prerelease-token",
|
|
@@ -160,19 +195,25 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
|
|
|
160
195
|
"--major",
|
|
161
196
|
"force_level",
|
|
162
197
|
flag_value="major",
|
|
163
|
-
help="
|
|
198
|
+
help="Force the next version to be a major release",
|
|
164
199
|
)
|
|
165
200
|
@click.option(
|
|
166
201
|
"--minor",
|
|
167
202
|
"force_level",
|
|
168
203
|
flag_value="minor",
|
|
169
|
-
help="
|
|
204
|
+
help="Force the next version to be a minor release",
|
|
170
205
|
)
|
|
171
206
|
@click.option(
|
|
172
207
|
"--patch",
|
|
173
208
|
"force_level",
|
|
174
209
|
flag_value="patch",
|
|
175
|
-
help="
|
|
210
|
+
help="Force the next version to be a patch release",
|
|
211
|
+
)
|
|
212
|
+
@click.option(
|
|
213
|
+
"--prerelease",
|
|
214
|
+
"force_level",
|
|
215
|
+
flag_value="prerelease_revision",
|
|
216
|
+
help="Force the next version to be a prerelease",
|
|
176
217
|
)
|
|
177
218
|
@click.option(
|
|
178
219
|
"--commit/--no-commit",
|
|
@@ -224,7 +265,7 @@ def version( # noqa: C901
|
|
|
224
265
|
print_only_tag: bool = False,
|
|
225
266
|
print_last_released: bool = False,
|
|
226
267
|
print_last_released_tag: bool = False,
|
|
227
|
-
|
|
268
|
+
as_prerelease: bool = False,
|
|
228
269
|
prerelease_token: str | None = None,
|
|
229
270
|
force_level: str | None = None,
|
|
230
271
|
commit_changes: bool = True,
|
|
@@ -271,9 +312,10 @@ def version( # noqa: C901
|
|
|
271
312
|
ctx.exit(0)
|
|
272
313
|
|
|
273
314
|
parser = runtime.commit_parser
|
|
315
|
+
forced_level_bump = None if not force_level else LevelBump.from_string(force_level)
|
|
274
316
|
prerelease = is_forced_prerelease(
|
|
275
|
-
|
|
276
|
-
|
|
317
|
+
as_prerelease=as_prerelease,
|
|
318
|
+
forced_level_bump=forced_level_bump,
|
|
277
319
|
prerelease=runtime.prerelease,
|
|
278
320
|
)
|
|
279
321
|
hvcs_client = runtime.hvcs_client
|
|
@@ -306,23 +348,19 @@ def version( # noqa: C901
|
|
|
306
348
|
log.info("No vcs release will be created because pushing changes is disabled")
|
|
307
349
|
make_vcs_release &= push_changes
|
|
308
350
|
|
|
309
|
-
if
|
|
310
|
-
log.warning("Forcing prerelease due to '--prerelease' command-line flag")
|
|
311
|
-
elif force_level:
|
|
351
|
+
if forced_level_bump:
|
|
312
352
|
log.warning(
|
|
313
|
-
"Forcing
|
|
314
|
-
"'--prerelease' flag",
|
|
353
|
+
"Forcing a '%s' release due to '--%s' command-line flag",
|
|
315
354
|
force_level,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
"Forcing a %s level bump due to '--force' command-line option", force_level
|
|
355
|
+
(
|
|
356
|
+
force_level
|
|
357
|
+
if forced_level_bump is not LevelBump.PRERELEASE_REVISION
|
|
358
|
+
else "prerelease"
|
|
359
|
+
),
|
|
322
360
|
)
|
|
323
361
|
|
|
324
362
|
new_version = version_from_forced_level(
|
|
325
|
-
repo=repo,
|
|
363
|
+
repo=repo, forced_level_bump=forced_level_bump, translator=translator
|
|
326
364
|
)
|
|
327
365
|
|
|
328
366
|
# We only turn the forced version into a prerelease if the user has specified
|
|
@@ -347,6 +385,17 @@ def version( # noqa: C901
|
|
|
347
385
|
if build_metadata:
|
|
348
386
|
new_version.build_metadata = build_metadata
|
|
349
387
|
|
|
388
|
+
if as_prerelease:
|
|
389
|
+
before_conversion, new_version = (
|
|
390
|
+
new_version,
|
|
391
|
+
new_version.to_prerelease(token=translator.prerelease_token),
|
|
392
|
+
)
|
|
393
|
+
log.info(
|
|
394
|
+
"Converting %s to %s due to '--as-prerelease' command-line option",
|
|
395
|
+
before_conversion,
|
|
396
|
+
new_version,
|
|
397
|
+
)
|
|
398
|
+
|
|
350
399
|
gha_output.released = False
|
|
351
400
|
gha_output.version = new_version
|
|
352
401
|
ctx.call_on_close(gha_output.write_if_possible)
|
|
@@ -601,7 +650,7 @@ def version( # noqa: C901
|
|
|
601
650
|
|
|
602
651
|
gha_output.released = True
|
|
603
652
|
|
|
604
|
-
if make_vcs_release:
|
|
653
|
+
if make_vcs_release and isinstance(hvcs_client, RemoteHvcsBase):
|
|
605
654
|
if opts.noop:
|
|
606
655
|
noop_report(
|
|
607
656
|
f"would have created a release for the tag {new_version.as_tag()!r}"
|
|
@@ -630,10 +679,11 @@ def version( # noqa: C901
|
|
|
630
679
|
noop_report(f"would have uploaded the following assets: {runtime.assets}")
|
|
631
680
|
else:
|
|
632
681
|
try:
|
|
633
|
-
|
|
682
|
+
hvcs_client.create_release(
|
|
634
683
|
tag=new_version.as_tag(),
|
|
635
684
|
release_notes=release_notes,
|
|
636
685
|
prerelease=new_version.is_prerelease,
|
|
686
|
+
assets=assets,
|
|
637
687
|
)
|
|
638
688
|
except HTTPError as err:
|
|
639
689
|
log.exception(err)
|
|
@@ -654,15 +704,4 @@ def version( # noqa: C901
|
|
|
654
704
|
log.exception(e)
|
|
655
705
|
ctx.fail(str(e))
|
|
656
706
|
|
|
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
707
|
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: ...
|
|
@@ -62,13 +62,14 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
|
|
|
62
62
|
commits. See https://www.conventionalcommits.org/en/v1.0.0-beta.4/
|
|
63
63
|
"""
|
|
64
64
|
|
|
65
|
+
# TODO: Deprecate in lieu of get_default_options()
|
|
65
66
|
parser_options = AngularParserOptions
|
|
66
67
|
|
|
67
|
-
def __init__(self, options: AngularParserOptions) -> None:
|
|
68
|
+
def __init__(self, options: AngularParserOptions | None = None) -> None:
|
|
68
69
|
super().__init__(options)
|
|
69
70
|
self.re_parser = re.compile(
|
|
70
71
|
rf"""
|
|
71
|
-
(?P<type>{"|".join(options.allowed_tags)}) # e.g. feat
|
|
72
|
+
(?P<type>{"|".join(self.options.allowed_tags)}) # e.g. feat
|
|
72
73
|
(?:\((?P<scope>[^\n]+)\))? # or feat(parser)
|
|
73
74
|
(?P<break>!)?:\s+ # breaking if feat!:
|
|
74
75
|
(?P<subject>[^\n]+) # commit subject
|
|
@@ -77,6 +78,10 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
|
|
|
77
78
|
flags=re.VERBOSE | re.DOTALL,
|
|
78
79
|
)
|
|
79
80
|
|
|
81
|
+
@staticmethod
|
|
82
|
+
def get_default_options() -> AngularParserOptions:
|
|
83
|
+
return AngularParserOptions()
|
|
84
|
+
|
|
80
85
|
# Maybe this can be cached as an optimisation, similar to how
|
|
81
86
|
# mypy/pytest use their own caching directories, for very large commit
|
|
82
87
|
# histories?
|
|
@@ -57,8 +57,13 @@ class EmojiCommitParser(CommitParser[ParseResult, EmojiParserOptions]):
|
|
|
57
57
|
the commit subject in the changelog.
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
|
+
# TODO: Deprecate in lieu of get_default_options()
|
|
60
61
|
parser_options = EmojiParserOptions
|
|
61
62
|
|
|
63
|
+
@staticmethod
|
|
64
|
+
def get_default_options() -> EmojiParserOptions:
|
|
65
|
+
return EmojiParserOptions()
|
|
66
|
+
|
|
62
67
|
def parse(self, commit: Commit) -> ParseResult:
|
|
63
68
|
all_emojis = (
|
|
64
69
|
self.options.major_tags + self.options.minor_tags + self.options.patch_tags
|