python-semantic-release 10.2.0__py3-none-any.whl → 10.5.2__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-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/METADATA +14 -12
- {python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/RECORD +24 -20
- semantic_release/changelog/context.py +1 -1
- semantic_release/cli/commands/version.py +124 -39
- semantic_release/cli/config.py +8 -3
- semantic_release/cli/github_actions_output.py +96 -7
- semantic_release/cli/masking_filter.py +1 -3
- semantic_release/cli/util.py +2 -2
- semantic_release/commit_parser/__init__.py +23 -0
- semantic_release/commit_parser/conventional/__init__.py +17 -0
- semantic_release/commit_parser/conventional/options.py +72 -0
- semantic_release/commit_parser/conventional/options_monorepo.py +90 -0
- semantic_release/commit_parser/{conventional.py → conventional/parser.py} +85 -127
- semantic_release/commit_parser/conventional/parser_monorepo.py +467 -0
- semantic_release/errors.py +16 -0
- semantic_release/gitproject.py +187 -20
- semantic_release/version/algorithm.py +5 -18
- semantic_release/version/declarations/pattern.py +2 -2
- semantic_release/version/translator.py +23 -5
- semantic_release/version/version.py +9 -0
- {python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/WHEEL +0 -0
- {python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/entry_points.txt +0 -0
- {python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/licenses/LICENSE +0 -0
- {python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/top_level.txt +0 -0
{python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/METADATA
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-semantic-release
|
|
3
|
-
Version: 10.2
|
|
3
|
+
Version: 10.5.2
|
|
4
4
|
Summary: Automatic Semantic Versioning for Python projects
|
|
5
|
-
Author-email: Rolf Erik Lekang <me@rolflekang.com>
|
|
5
|
+
Author-email: Rolf Erik Lekang <me@rolflekang.com>, codejedi365 <codejedi365@gmail.com>
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: changelog, https://github.com/python-semantic-release/python-semantic-release/blob/master/CHANGELOG.md
|
|
8
8
|
Project-URL: documentation, https://python-semantic-release.readthedocs.io
|
|
@@ -17,7 +17,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
-
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Requires-Python: ~=3.8
|
|
21
22
|
Description-Content-Type: text/x-rst
|
|
22
23
|
License-File: LICENSE
|
|
23
24
|
Requires-Dist: click~=8.1.0
|
|
@@ -26,7 +27,7 @@ Requires-Dist: gitpython~=3.0
|
|
|
26
27
|
Requires-Dist: requests~=2.25
|
|
27
28
|
Requires-Dist: jinja2~=3.1
|
|
28
29
|
Requires-Dist: python-gitlab<7.0.0,>=4.0.0
|
|
29
|
-
Requires-Dist: tomlkit~=0.
|
|
30
|
+
Requires-Dist: tomlkit~=0.13.0
|
|
30
31
|
Requires-Dist: dotty-dict~=1.3
|
|
31
32
|
Requires-Dist: importlib-resources~=6.0
|
|
32
33
|
Requires-Dist: pydantic~=2.0
|
|
@@ -35,11 +36,12 @@ Requires-Dist: shellingham~=1.5
|
|
|
35
36
|
Requires-Dist: Deprecated~=1.2
|
|
36
37
|
Provides-Extra: build
|
|
37
38
|
Requires-Dist: build~=1.2; extra == "build"
|
|
39
|
+
Requires-Dist: tomlkit~=0.13.0; extra == "build"
|
|
38
40
|
Provides-Extra: docs
|
|
39
|
-
Requires-Dist: Sphinx~=
|
|
40
|
-
Requires-Dist: sphinxcontrib-apidoc==0.
|
|
41
|
+
Requires-Dist: Sphinx~=7.4; extra == "docs"
|
|
42
|
+
Requires-Dist: sphinxcontrib-apidoc==0.6.0; extra == "docs"
|
|
41
43
|
Requires-Dist: sphinx-autobuild==2024.2.4; extra == "docs"
|
|
42
|
-
Requires-Dist: furo~=
|
|
44
|
+
Requires-Dist: furo~=2025.9; extra == "docs"
|
|
43
45
|
Provides-Extra: test
|
|
44
46
|
Requires-Dist: coverage[toml]~=7.0; extra == "test"
|
|
45
47
|
Requires-Dist: filelock~=3.15; extra == "test"
|
|
@@ -48,9 +50,9 @@ Requires-Dist: freezegun~=1.5; extra == "test"
|
|
|
48
50
|
Requires-Dist: pyyaml~=6.0; extra == "test"
|
|
49
51
|
Requires-Dist: pytest~=8.3; extra == "test"
|
|
50
52
|
Requires-Dist: pytest-clarity~=1.0; extra == "test"
|
|
51
|
-
Requires-Dist: pytest-cov<
|
|
53
|
+
Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "test"
|
|
52
54
|
Requires-Dist: pytest-env~=1.0; extra == "test"
|
|
53
|
-
Requires-Dist: pytest-lazy-fixtures~=1.
|
|
55
|
+
Requires-Dist: pytest-lazy-fixtures~=1.4; extra == "test"
|
|
54
56
|
Requires-Dist: pytest-mock~=3.0; extra == "test"
|
|
55
57
|
Requires-Dist: pytest-order~=1.3; extra == "test"
|
|
56
58
|
Requires-Dist: pytest-pretty~=1.2; extra == "test"
|
|
@@ -58,7 +60,7 @@ Requires-Dist: pytest-xdist~=3.0; extra == "test"
|
|
|
58
60
|
Requires-Dist: responses~=0.25.0; extra == "test"
|
|
59
61
|
Requires-Dist: requests-mock~=1.10; extra == "test"
|
|
60
62
|
Provides-Extra: dev
|
|
61
|
-
Requires-Dist: pre-commit~=3
|
|
63
|
+
Requires-Dist: pre-commit~=4.3; extra == "dev"
|
|
62
64
|
Requires-Dist: tox~=4.11; extra == "dev"
|
|
63
65
|
Requires-Dist: ruff==0.6.1; extra == "dev"
|
|
64
66
|
Provides-Extra: mypy
|
|
@@ -88,5 +90,5 @@ The usage information and examples for this GitHub Action is available under
|
|
|
88
90
|
the `GitHub Actions section`_ of `python-semantic-release.readthedocs.io`_.
|
|
89
91
|
|
|
90
92
|
.. _python-semantic-release: https://pypi.org/project/python-semantic-release/
|
|
91
|
-
.. _python-semantic-release.readthedocs.io: https://python-semantic-release.readthedocs.io/en/
|
|
92
|
-
.. _GitHub Actions section: https://python-semantic-release.readthedocs.io/en/
|
|
93
|
+
.. _python-semantic-release.readthedocs.io: https://python-semantic-release.readthedocs.io/en/stable/
|
|
94
|
+
.. _GitHub Actions section: https://python-semantic-release.readthedocs.io/en/stable/configuration/automatic-releases/github-actions.html
|
{python_semantic_release-10.2.0.dist-info → python_semantic_release-10.5.2.dist-info}/RECORD
RENAMED
|
@@ -1,40 +1,44 @@
|
|
|
1
|
-
python_semantic_release-10.2.
|
|
1
|
+
python_semantic_release-10.5.2.dist-info/licenses/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
|
|
2
2
|
semantic_release/__init__.py,sha256=tRJWhrn_dUt0QycXD2DoJSfEP5uwmxngH7jvbG2i-hA,1317
|
|
3
3
|
semantic_release/__main__.py,sha256=pksxr6g1vkKq98Q1lShsxG8tk55IMiSMHzAHKyFU5x0,1704
|
|
4
4
|
semantic_release/const.py,sha256=wInJR7vcOgT1ysm5VuJQ6lD_ZGYnCwRVKz7Uz3htQc4,861
|
|
5
5
|
semantic_release/enums.py,sha256=vrEw1UNRcNrFjPqOFnuUzfeoqKj0ChixVVlyk5fqbng,1744
|
|
6
|
-
semantic_release/errors.py,sha256=
|
|
7
|
-
semantic_release/gitproject.py,sha256=
|
|
6
|
+
semantic_release/errors.py,sha256=FyocaqHbRhux-iNmCf9nI7awyUaGKjG9_5C_QDvhEas,3399
|
|
7
|
+
semantic_release/gitproject.py,sha256=qF4GVZh-aaS4bVV3OmFQLmXMAxHNFyZCwUaWPtUmZ1k,16546
|
|
8
8
|
semantic_release/globals.py,sha256=IBhBbhZr2jx8dmpySnnu9m9jOGYu9Yu-vqHvAGQxgnw,464
|
|
9
9
|
semantic_release/helpers.py,sha256=2uQXOiuiemiviVD52SH2FF6cn14p_gqvREeHvP7dexw,10012
|
|
10
10
|
semantic_release/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
semantic_release/changelog/__init__.py,sha256=Bg6Xe5Vt32rWoMscW-hd4sUwiZqzWmsg4CD1EhMesMY,262
|
|
12
|
-
semantic_release/changelog/context.py,sha256=
|
|
12
|
+
semantic_release/changelog/context.py,sha256=234LLcB_uuGaQ5N_zTbcQYF27ZwYIBmicIWkhFs7-aQ,5993
|
|
13
13
|
semantic_release/changelog/release_history.py,sha256=kX6D9VReq85wnHz0D6JpmJJCfWA6axV6RToSM0O5laU,10602
|
|
14
14
|
semantic_release/changelog/template.py,sha256=eqOjtVfBbksgTK4CAZOajfkaAcKueJ-FhFv99U3-J5E,5695
|
|
15
15
|
semantic_release/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
semantic_release/cli/changelog_writer.py,sha256=2jP5b0LK61Y2tb22GQSFFmwHwXd2WjbopgsMAmsQsfY,9284
|
|
17
17
|
semantic_release/cli/cli_context.py,sha256=Nop71LdVCJOeSUHgTXunMyK3xAu_QKQC2cRp1QBVkX0,4134
|
|
18
|
-
semantic_release/cli/config.py,sha256=
|
|
18
|
+
semantic_release/cli/config.py,sha256=zNXlJHZBnFk2GEemgCg2Yw42EWihtFMot1twI7bEN-g,33668
|
|
19
19
|
semantic_release/cli/const.py,sha256=h7XE2D0D__TAZSrUUtVszwvzpkHTMOiQCf97XQNbEvA,163
|
|
20
|
-
semantic_release/cli/github_actions_output.py,sha256=
|
|
21
|
-
semantic_release/cli/masking_filter.py,sha256=
|
|
22
|
-
semantic_release/cli/util.py,sha256=
|
|
20
|
+
semantic_release/cli/github_actions_output.py,sha256=yC0nsMvEFGACjDwB8DdmGKwNGI8aIIhDxRHrmcS7tzA,5410
|
|
21
|
+
semantic_release/cli/masking_filter.py,sha256=7t7XFL7Iy4QTvaYevZ-jnTkJBz15GoBw1vjW3hihe38,3159
|
|
22
|
+
semantic_release/cli/util.py,sha256=4rf4xDHb7l-XpdcFNtslFz1xHslnBu6cTgWHXVnQXQs,3746
|
|
23
23
|
semantic_release/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
semantic_release/cli/commands/changelog.py,sha256=wJfd4VVfrGnu2jnIpG25cdVcbXIX-ElKl3b2jdtPPa0,5391
|
|
25
25
|
semantic_release/cli/commands/generate_config.py,sha256=2xZOu3NpyhBp0pWr7d8ugKl_kjqQgpSsSMHq5wHTfrE,1699
|
|
26
26
|
semantic_release/cli/commands/main.py,sha256=u1zhkkvKCZ2TtUqjzvdFTe5UZsvfws_pjqqo6CY0bBo,4351
|
|
27
27
|
semantic_release/cli/commands/publish.py,sha256=CE_LJTxFnc337MfpsfdJopi7QCwwE13GqGNQ-dNgWis,2871
|
|
28
|
-
semantic_release/cli/commands/version.py,sha256=
|
|
29
|
-
semantic_release/commit_parser/__init__.py,sha256=
|
|
28
|
+
semantic_release/cli/commands/version.py,sha256=1zJ96_WSQh4bY_75P3eTJTfwrEZcJGHf7XJO2yA66SA,29459
|
|
29
|
+
semantic_release/commit_parser/__init__.py,sha256=uCC2YI-EDPUAa6TwWYJA8TS7baWE2bXrLEGcrhJKofI,1323
|
|
30
30
|
semantic_release/commit_parser/_base.py,sha256=DLsHnbXG-39JkUbcnsBCSV2GmV35w1rasyoMhK8G0UE,3058
|
|
31
31
|
semantic_release/commit_parser/angular.py,sha256=MY_fo9F4EZ-ac8wYzBR0uD94O5Li2D-8zEMR01wss4c,18534
|
|
32
|
-
semantic_release/commit_parser/conventional.py,sha256=Iyy8txkshK8HikizFVa7pnJHBSWDhOhF45zR866QxQM,18672
|
|
33
32
|
semantic_release/commit_parser/emoji.py,sha256=0VecUMMcj43UaKDZ2GaFFUG26zOJAvXsEobTHaXNkk0,17749
|
|
34
33
|
semantic_release/commit_parser/scipy.py,sha256=gA9TfmrxGVvtv6kki6N_9abJx-_WlpBsSX2TBh0YgPw,19463
|
|
35
34
|
semantic_release/commit_parser/tag.py,sha256=bVO2XghM0G_eW2rG9Xc2q5TPsjtxr-xcHK5RpE1u_HM,3537
|
|
36
35
|
semantic_release/commit_parser/token.py,sha256=1_q8mJ4SRu7kNfa-Nxr8fEyuvCfjPgiPEitqSP1KR5g,7904
|
|
37
36
|
semantic_release/commit_parser/util.py,sha256=hcLjc16o7l6y_5Hfl8IxmF4ijaJD62JdjdB2DJWAe-g,3959
|
|
37
|
+
semantic_release/commit_parser/conventional/__init__.py,sha256=JHPL3S6trM4Le9MXnXc6iPYxxQnE4j0LG83_BWIomOw,602
|
|
38
|
+
semantic_release/commit_parser/conventional/options.py,sha256=AnRgTRMF-3X5QonTqq6bqJEbmGgQBzppyRZ79hct28g,2598
|
|
39
|
+
semantic_release/commit_parser/conventional/options_monorepo.py,sha256=7OCpuaYhw01bfoffTGfPgEWzRRyVsdsq_n2eo8Dt8-8,3210
|
|
40
|
+
semantic_release/commit_parser/conventional/parser.py,sha256=Pex26cvMqAKx9NPH3KROYg7k76R0Nsbs4aHor5SbMZg,16671
|
|
41
|
+
semantic_release/commit_parser/conventional/parser_monorepo.py,sha256=nVAc_gK4tJ5UM_rd9KbXgBWeBgrI_q2-vav3_4748r8,21189
|
|
38
42
|
semantic_release/data/templates/conventional/md/.release_notes.md.j2,sha256=DlMVAJMGqE27TwJ-2kviYaFhd3uWqXiU6Ikl15Ukne8,2512
|
|
39
43
|
semantic_release/data/templates/conventional/md/CHANGELOG.md.j2,sha256=FZmrQ-qOIoSoJmAa_NFaRelfmqUpypU2xlDeScdGOf4,729
|
|
40
44
|
semantic_release/data/templates/conventional/md/.components/changelog_header.md.j2,sha256=qNxTuSr59CV_yyimVU_RYp5azCnK0l6nJ03Zf0u5Ugg,166
|
|
@@ -64,17 +68,17 @@ semantic_release/hvcs/remote_hvcs_base.py,sha256=QtkjdMy9l-c7UOtyPz25cqVOkCk4IU-
|
|
|
64
68
|
semantic_release/hvcs/token_auth.py,sha256=ZjT56-NIPB4OKIt1qwHCu1TavXnrWFIBl9ARlg56hgU,663
|
|
65
69
|
semantic_release/hvcs/util.py,sha256=PUNV4yUlpzDtNCFmh2joaPdU4JyfUBnVp0zaQsT9EDQ,2871
|
|
66
70
|
semantic_release/version/__init__.py,sha256=CLhtGQry9dLIij5XyRa9ZevxU_1p8tjMTSQ-K_GMpWM,270
|
|
67
|
-
semantic_release/version/algorithm.py,sha256=
|
|
71
|
+
semantic_release/version/algorithm.py,sha256=IxgYNF78W7qdMzdV4WsoljwfJgB-sn2XdfkevD0aZlo,16254
|
|
68
72
|
semantic_release/version/declaration.py,sha256=eot_lUyFaEhzK4bPncfv9tahf51LdxZP6EaS54h3aAs,3635
|
|
69
|
-
semantic_release/version/translator.py,sha256=
|
|
70
|
-
semantic_release/version/version.py,sha256=
|
|
73
|
+
semantic_release/version/translator.py,sha256=iIfu3WreB9qqPHgqJLILbBluVQQNcpP0DEsnn_WzAaM,3689
|
|
74
|
+
semantic_release/version/version.py,sha256=Y3Qqqv7CypirikT7jNqqFMNAvR2UjV-VQx-c2G0mZc0,14519
|
|
71
75
|
semantic_release/version/declarations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
76
|
semantic_release/version/declarations/enum.py,sha256=3n5Py9DoFkmItIdsmtQrJgmAhepTv_1EnogzSdXu1Wg,244
|
|
73
77
|
semantic_release/version/declarations/i_version_replacer.py,sha256=oP6BxJuxwI44roI6448tomShv1sMoy9ry8TlhhIQtfc,2416
|
|
74
|
-
semantic_release/version/declarations/pattern.py,sha256=
|
|
78
|
+
semantic_release/version/declarations/pattern.py,sha256=sKk0uQpJjWVZc8RJUjxQoEPUvFLxXNGGBow5h1IqCTM,8378
|
|
75
79
|
semantic_release/version/declarations/toml.py,sha256=2K4DtX5Qq1iHT8cG8mISPTMmp50w6Av0KmLAKZPYqq8,4931
|
|
76
|
-
python_semantic_release-10.2.
|
|
77
|
-
python_semantic_release-10.2.
|
|
78
|
-
python_semantic_release-10.2.
|
|
79
|
-
python_semantic_release-10.2.
|
|
80
|
-
python_semantic_release-10.2.
|
|
80
|
+
python_semantic_release-10.5.2.dist-info/METADATA,sha256=RMojFB6HaaUcQbydFl05KFC6aIj2OhRVxHRRVeqZrqI,4064
|
|
81
|
+
python_semantic_release-10.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
82
|
+
python_semantic_release-10.5.2.dist-info/entry_points.txt,sha256=kzkCyDJsMOwgpFwEWKE9wxN1tXaUP6g6GIO4xtc0QuE,162
|
|
83
|
+
python_semantic_release-10.5.2.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
|
|
84
|
+
python_semantic_release-10.5.2.dist-info/RECORD,,
|
|
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING
|
|
|
10
10
|
import click
|
|
11
11
|
import shellingham # type: ignore[import]
|
|
12
12
|
from click_option_group import MutuallyExclusiveOptionGroup, optgroup
|
|
13
|
-
from git import Repo
|
|
13
|
+
from git import GitCommandError, Repo
|
|
14
14
|
from requests import HTTPError
|
|
15
15
|
|
|
16
16
|
from semantic_release.changelog.release_history import ReleaseHistory
|
|
@@ -18,18 +18,27 @@ from semantic_release.cli.changelog_writer import (
|
|
|
18
18
|
generate_release_notes,
|
|
19
19
|
write_changelog_files,
|
|
20
20
|
)
|
|
21
|
-
from semantic_release.cli.github_actions_output import
|
|
21
|
+
from semantic_release.cli.github_actions_output import (
|
|
22
|
+
PersistenceMode,
|
|
23
|
+
VersionGitHubActionsOutput,
|
|
24
|
+
)
|
|
22
25
|
from semantic_release.cli.util import noop_report, rprint
|
|
23
26
|
from semantic_release.const import DEFAULT_SHELL, DEFAULT_VERSION
|
|
24
27
|
from semantic_release.enums import LevelBump
|
|
25
28
|
from semantic_release.errors import (
|
|
26
29
|
BuildDistributionsError,
|
|
30
|
+
DetachedHeadGitError,
|
|
27
31
|
GitCommitEmptyIndexError,
|
|
32
|
+
GitFetchError,
|
|
28
33
|
InternalError,
|
|
34
|
+
LocalGitError,
|
|
29
35
|
UnexpectedResponse,
|
|
36
|
+
UnknownUpstreamBranchError,
|
|
37
|
+
UpstreamBranchChangedError,
|
|
30
38
|
)
|
|
31
39
|
from semantic_release.gitproject import GitProject
|
|
32
40
|
from semantic_release.globals import logger
|
|
41
|
+
from semantic_release.hvcs.github import Github
|
|
33
42
|
from semantic_release.hvcs.remote_hvcs_base import RemoteHvcsBase
|
|
34
43
|
from semantic_release.version.algorithm import (
|
|
35
44
|
next_version,
|
|
@@ -71,10 +80,13 @@ def is_forced_prerelease(
|
|
|
71
80
|
)
|
|
72
81
|
|
|
73
82
|
|
|
74
|
-
def last_released(
|
|
83
|
+
def last_released(
|
|
84
|
+
repo_dir: Path, tag_format: str, add_partial_tags: bool = False
|
|
85
|
+
) -> tuple[Tag, Version] | None:
|
|
75
86
|
with Repo(str(repo_dir)) as git_repo:
|
|
76
87
|
ts_and_vs = tags_and_versions(
|
|
77
|
-
git_repo.tags,
|
|
88
|
+
git_repo.tags,
|
|
89
|
+
VersionTranslator(tag_format=tag_format, add_partial_tags=add_partial_tags),
|
|
78
90
|
)
|
|
79
91
|
|
|
80
92
|
return ts_and_vs[0] if ts_and_vs else None
|
|
@@ -445,7 +457,11 @@ def version( # noqa: C901
|
|
|
445
457
|
if print_last_released or print_last_released_tag:
|
|
446
458
|
# TODO: get tag format a better way
|
|
447
459
|
if not (
|
|
448
|
-
last_release := last_released(
|
|
460
|
+
last_release := last_released(
|
|
461
|
+
config.repo_dir,
|
|
462
|
+
tag_format=config.tag_format,
|
|
463
|
+
add_partial_tags=config.add_partial_tags,
|
|
464
|
+
)
|
|
449
465
|
):
|
|
450
466
|
logger.warning("No release tags found.")
|
|
451
467
|
return
|
|
@@ -466,7 +482,16 @@ def version( # noqa: C901
|
|
|
466
482
|
major_on_zero = runtime.major_on_zero
|
|
467
483
|
no_verify = runtime.no_git_verify
|
|
468
484
|
opts = runtime.global_cli_options
|
|
469
|
-
|
|
485
|
+
add_partial_tags = config.add_partial_tags
|
|
486
|
+
gha_output = VersionGitHubActionsOutput(
|
|
487
|
+
gh_client=hvcs_client if isinstance(hvcs_client, Github) else None,
|
|
488
|
+
mode=(
|
|
489
|
+
PersistenceMode.TEMPORARY
|
|
490
|
+
if opts.noop or (not commit_changes and not create_tag)
|
|
491
|
+
else PersistenceMode.PERMANENT
|
|
492
|
+
),
|
|
493
|
+
released=False,
|
|
494
|
+
)
|
|
470
495
|
|
|
471
496
|
forced_level_bump = None if not force_level else LevelBump.from_string(force_level)
|
|
472
497
|
prerelease = is_forced_prerelease(
|
|
@@ -479,6 +504,17 @@ def version( # noqa: C901
|
|
|
479
504
|
logger.info("Forcing use of %s as the prerelease token", prerelease_token)
|
|
480
505
|
translator.prerelease_token = prerelease_token
|
|
481
506
|
|
|
507
|
+
# Check if the repository is shallow and unshallow it if necessary
|
|
508
|
+
# This ensures we have the full history for commit analysis
|
|
509
|
+
project = GitProject(
|
|
510
|
+
directory=runtime.repo_dir,
|
|
511
|
+
commit_author=runtime.commit_author,
|
|
512
|
+
credential_masker=runtime.masker,
|
|
513
|
+
)
|
|
514
|
+
if project.is_shallow_clone():
|
|
515
|
+
logger.info("Repository is a shallow clone, converting to full clone...")
|
|
516
|
+
project.git_unshallow(noop=opts.noop)
|
|
517
|
+
|
|
482
518
|
# Only push if we're committing changes
|
|
483
519
|
if push_changes and not commit_changes and not create_tag:
|
|
484
520
|
logger.info("changes will not be pushed because --no-commit disables pushing")
|
|
@@ -537,7 +573,8 @@ def version( # noqa: C901
|
|
|
537
573
|
|
|
538
574
|
# Update GitHub Actions output value with new version & set delayed write
|
|
539
575
|
gha_output.version = new_version
|
|
540
|
-
|
|
576
|
+
if isinstance(hvcs_client, Github):
|
|
577
|
+
ctx.call_on_close(gha_output.write_if_possible)
|
|
541
578
|
|
|
542
579
|
# Make string variant of version or appropriate tag as necessary
|
|
543
580
|
version_to_print = str(new_version) if not print_only_tag else new_version.as_tag()
|
|
@@ -572,6 +609,12 @@ def version( # noqa: C901
|
|
|
572
609
|
if print_only or print_only_tag:
|
|
573
610
|
return
|
|
574
611
|
|
|
612
|
+
# TODO: need a better way as this is inconsistent if releasing older version patches
|
|
613
|
+
if last_release := last_released(config.repo_dir, tag_format=config.tag_format):
|
|
614
|
+
# If we have a last release, we can set the previous version for the
|
|
615
|
+
# GitHub Actions output
|
|
616
|
+
gha_output.prev_version = last_release[1]
|
|
617
|
+
|
|
575
618
|
with Repo(str(runtime.repo_dir)) as git_repo:
|
|
576
619
|
release_history = ReleaseHistory.from_git_history(
|
|
577
620
|
repo=git_repo,
|
|
@@ -641,10 +684,27 @@ def version( # noqa: C901
|
|
|
641
684
|
click.echo("Build failed, aborting release", err=True)
|
|
642
685
|
ctx.exit(1)
|
|
643
686
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
687
|
+
license_cfg = runtime.project_metadata.get(
|
|
688
|
+
"license-expression",
|
|
689
|
+
runtime.project_metadata.get(
|
|
690
|
+
"license",
|
|
691
|
+
"",
|
|
692
|
+
),
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
license_cfg = "" if not isinstance(license_cfg, (str, dict)) else license_cfg
|
|
696
|
+
license_cfg = (
|
|
697
|
+
license_cfg.get("text", "") if isinstance(license_cfg, dict) else license_cfg
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
gha_output.release_notes = release_notes = generate_release_notes(
|
|
701
|
+
hvcs_client,
|
|
702
|
+
release=release_history.released[new_version],
|
|
703
|
+
template_dir=runtime.template_dir,
|
|
704
|
+
history=release_history,
|
|
705
|
+
style=runtime.changelog_style,
|
|
706
|
+
mask_initial_release=runtime.changelog_mask_initial_release,
|
|
707
|
+
license_name="" if not isinstance(license_cfg, str) else license_cfg,
|
|
648
708
|
)
|
|
649
709
|
|
|
650
710
|
# Preparing for committing changes; we always stage files even if we're not committing them in order to support a two-stage commit
|
|
@@ -662,13 +722,14 @@ def version( # noqa: C901
|
|
|
662
722
|
)
|
|
663
723
|
except GitCommitEmptyIndexError:
|
|
664
724
|
logger.info("No local changes to add to any commit, skipping")
|
|
725
|
+
commit_changes = False
|
|
665
726
|
|
|
666
727
|
# Tag the version after potentially creating a new HEAD commit.
|
|
667
728
|
# This way if no source code is modified, i.e. all metadata updates
|
|
668
729
|
# are disabled, and the changelog generation is disabled or it's not
|
|
669
730
|
# modified, then the HEAD commit will be tagged as a release commit
|
|
670
731
|
# despite not being made by PSR
|
|
671
|
-
if
|
|
732
|
+
if create_tag:
|
|
672
733
|
project.git_tag(
|
|
673
734
|
tag_name=new_version.as_tag(),
|
|
674
735
|
message=new_version.as_tag(),
|
|
@@ -676,12 +737,42 @@ def version( # noqa: C901
|
|
|
676
737
|
noop=opts.noop,
|
|
677
738
|
)
|
|
678
739
|
|
|
740
|
+
with Repo(str(runtime.repo_dir)) as git_repo:
|
|
741
|
+
gha_output.commit_sha = git_repo.head.commit.hexsha
|
|
742
|
+
|
|
679
743
|
if push_changes:
|
|
680
744
|
remote_url = runtime.hvcs_client.remote_url(
|
|
681
745
|
use_token=not runtime.ignore_token_for_push
|
|
682
746
|
)
|
|
683
747
|
|
|
684
748
|
if commit_changes:
|
|
749
|
+
# Verify that the upstream branch has not changed before pushing
|
|
750
|
+
# This prevents conflicts if another commit was pushed while we were preparing the release
|
|
751
|
+
# We check HEAD~1 because we just made a release commit
|
|
752
|
+
try:
|
|
753
|
+
project.verify_upstream_unchanged(
|
|
754
|
+
local_ref="HEAD~1",
|
|
755
|
+
upstream_ref=config.remote.name,
|
|
756
|
+
noop=opts.noop,
|
|
757
|
+
)
|
|
758
|
+
except UpstreamBranchChangedError as exc:
|
|
759
|
+
click.echo(str(exc), err=True)
|
|
760
|
+
click.echo(
|
|
761
|
+
"Upstream branch has changed. Please pull the latest changes and try again.",
|
|
762
|
+
err=True,
|
|
763
|
+
)
|
|
764
|
+
ctx.exit(1)
|
|
765
|
+
except (
|
|
766
|
+
DetachedHeadGitError,
|
|
767
|
+
GitCommandError,
|
|
768
|
+
UnknownUpstreamBranchError,
|
|
769
|
+
GitFetchError,
|
|
770
|
+
LocalGitError,
|
|
771
|
+
) as exc:
|
|
772
|
+
click.echo(str(exc), err=True)
|
|
773
|
+
click.echo("Unable to verify upstream due to error!", err=True)
|
|
774
|
+
ctx.exit(1)
|
|
775
|
+
|
|
685
776
|
# TODO: integrate into push branch
|
|
686
777
|
with Repo(str(runtime.repo_dir)) as git_repo:
|
|
687
778
|
active_branch = git_repo.active_branch.name
|
|
@@ -699,6 +790,27 @@ def version( # noqa: C901
|
|
|
699
790
|
tag=new_version.as_tag(),
|
|
700
791
|
noop=opts.noop,
|
|
701
792
|
)
|
|
793
|
+
# Create or update partial tags for releases
|
|
794
|
+
if add_partial_tags and not prerelease:
|
|
795
|
+
partial_tags = [new_version.as_major_tag(), new_version.as_minor_tag()]
|
|
796
|
+
# If build metadata is set, also retag the version without the metadata
|
|
797
|
+
if build_metadata:
|
|
798
|
+
partial_tags.append(new_version.as_patch_tag())
|
|
799
|
+
|
|
800
|
+
for partial_tag in partial_tags:
|
|
801
|
+
project.git_tag(
|
|
802
|
+
tag_name=partial_tag,
|
|
803
|
+
message=f"{partial_tag} => {new_version.as_tag()}",
|
|
804
|
+
isotimestamp=commit_date.isoformat(),
|
|
805
|
+
noop=opts.noop,
|
|
806
|
+
force=True,
|
|
807
|
+
)
|
|
808
|
+
project.git_push_tag(
|
|
809
|
+
remote_url=remote_url,
|
|
810
|
+
tag=partial_tag,
|
|
811
|
+
noop=opts.noop,
|
|
812
|
+
force=True,
|
|
813
|
+
)
|
|
702
814
|
|
|
703
815
|
# Update GitHub Actions output value now that release has occurred
|
|
704
816
|
gha_output.released = True
|
|
@@ -710,33 +822,6 @@ def version( # noqa: C901
|
|
|
710
822
|
logger.info("Remote does not support releases. Skipping release creation...")
|
|
711
823
|
return
|
|
712
824
|
|
|
713
|
-
license_cfg = runtime.project_metadata.get(
|
|
714
|
-
"license-expression",
|
|
715
|
-
runtime.project_metadata.get(
|
|
716
|
-
"license",
|
|
717
|
-
"",
|
|
718
|
-
),
|
|
719
|
-
)
|
|
720
|
-
|
|
721
|
-
if not isinstance(license_cfg, (str, dict)) or license_cfg is None:
|
|
722
|
-
license_cfg = ""
|
|
723
|
-
|
|
724
|
-
license_name = (
|
|
725
|
-
license_cfg.get("text", "")
|
|
726
|
-
if isinstance(license_cfg, dict)
|
|
727
|
-
else license_cfg or ""
|
|
728
|
-
)
|
|
729
|
-
|
|
730
|
-
release_notes = generate_release_notes(
|
|
731
|
-
hvcs_client,
|
|
732
|
-
release=release_history.released[new_version],
|
|
733
|
-
template_dir=runtime.template_dir,
|
|
734
|
-
history=release_history,
|
|
735
|
-
style=runtime.changelog_style,
|
|
736
|
-
mask_initial_release=runtime.changelog_mask_initial_release,
|
|
737
|
-
license_name=license_name,
|
|
738
|
-
)
|
|
739
|
-
|
|
740
825
|
exception: Exception | None = None
|
|
741
826
|
help_message = ""
|
|
742
827
|
try:
|
semantic_release/cli/config.py
CHANGED
|
@@ -39,6 +39,7 @@ from semantic_release.cli.masking_filter import MaskingFilter
|
|
|
39
39
|
from semantic_release.commit_parser import (
|
|
40
40
|
AngularCommitParser,
|
|
41
41
|
CommitParser,
|
|
42
|
+
ConventionalCommitMonorepoParser,
|
|
42
43
|
ConventionalCommitParser,
|
|
43
44
|
EmojiCommitParser,
|
|
44
45
|
ParseResult,
|
|
@@ -71,9 +72,10 @@ class HvcsClient(str, Enum):
|
|
|
71
72
|
GITEA = "gitea"
|
|
72
73
|
|
|
73
74
|
|
|
74
|
-
_known_commit_parsers:
|
|
75
|
-
"conventional": ConventionalCommitParser,
|
|
75
|
+
_known_commit_parsers: dict[str, type[CommitParser[Any, Any]]] = {
|
|
76
76
|
"angular": AngularCommitParser,
|
|
77
|
+
"conventional": ConventionalCommitParser,
|
|
78
|
+
"conventional-monorepo": ConventionalCommitMonorepoParser,
|
|
77
79
|
"emoji": EmojiCommitParser,
|
|
78
80
|
"scipy": ScipyCommitParser,
|
|
79
81
|
"tag": TagCommitParser,
|
|
@@ -364,6 +366,7 @@ class RawConfig(BaseModel):
|
|
|
364
366
|
remote: RemoteConfig = RemoteConfig()
|
|
365
367
|
no_git_verify: bool = False
|
|
366
368
|
tag_format: str = "v{version}"
|
|
369
|
+
add_partial_tags: bool = False
|
|
367
370
|
publish: PublishConfig = PublishConfig()
|
|
368
371
|
version_toml: Optional[Tuple[str, ...]] = None
|
|
369
372
|
version_variables: Optional[Tuple[str, ...]] = None
|
|
@@ -825,7 +828,9 @@ class RuntimeContext:
|
|
|
825
828
|
|
|
826
829
|
# version_translator
|
|
827
830
|
version_translator = VersionTranslator(
|
|
828
|
-
tag_format=raw.tag_format,
|
|
831
|
+
tag_format=raw.tag_format,
|
|
832
|
+
prerelease_token=branch_config.prerelease_token,
|
|
833
|
+
add_partial_tags=raw.add_partial_tags,
|
|
829
834
|
)
|
|
830
835
|
|
|
831
836
|
build_cmd_env = {}
|
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from re import compile as regexp
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
4
7
|
|
|
5
8
|
from semantic_release.globals import logger
|
|
6
9
|
from semantic_release.version.version import Version
|
|
7
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from semantic_release.hvcs.github import Github
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PersistenceMode(Enum):
|
|
18
|
+
TEMPORARY = "temporary"
|
|
19
|
+
PERMANENT = "permanent"
|
|
20
|
+
|
|
8
21
|
|
|
9
22
|
class VersionGitHubActionsOutput:
|
|
10
23
|
OUTPUT_ENV_VAR = "GITHUB_OUTPUT"
|
|
11
24
|
|
|
12
25
|
def __init__(
|
|
13
26
|
self,
|
|
27
|
+
gh_client: Github | None = None,
|
|
28
|
+
mode: PersistenceMode = PersistenceMode.PERMANENT,
|
|
14
29
|
released: bool | None = None,
|
|
15
30
|
version: Version | None = None,
|
|
31
|
+
commit_sha: str | None = None,
|
|
32
|
+
release_notes: str | None = None,
|
|
33
|
+
prev_version: Version | None = None,
|
|
16
34
|
) -> None:
|
|
35
|
+
self._gh_client = gh_client
|
|
36
|
+
self._mode = mode
|
|
17
37
|
self._released = released
|
|
18
38
|
self._version = version
|
|
39
|
+
self._commit_sha = commit_sha
|
|
40
|
+
self._release_notes = release_notes
|
|
41
|
+
self._prev_version = prev_version
|
|
19
42
|
|
|
20
43
|
@property
|
|
21
44
|
def released(self) -> bool | None:
|
|
@@ -23,7 +46,7 @@ class VersionGitHubActionsOutput:
|
|
|
23
46
|
|
|
24
47
|
@released.setter
|
|
25
48
|
def released(self, value: bool) -> None:
|
|
26
|
-
if
|
|
49
|
+
if not isinstance(value, bool):
|
|
27
50
|
raise TypeError("output 'released' is boolean")
|
|
28
51
|
self._released = value
|
|
29
52
|
|
|
@@ -33,7 +56,7 @@ class VersionGitHubActionsOutput:
|
|
|
33
56
|
|
|
34
57
|
@version.setter
|
|
35
58
|
def version(self, value: Version) -> None:
|
|
36
|
-
if
|
|
59
|
+
if not isinstance(value, Version):
|
|
37
60
|
raise TypeError("output 'released' should be a Version")
|
|
38
61
|
self._version = value
|
|
39
62
|
|
|
@@ -45,26 +68,92 @@ class VersionGitHubActionsOutput:
|
|
|
45
68
|
def is_prerelease(self) -> bool | None:
|
|
46
69
|
return self.version.is_prerelease if self.version is not None else None
|
|
47
70
|
|
|
71
|
+
@property
|
|
72
|
+
def commit_sha(self) -> str | None:
|
|
73
|
+
return self._commit_sha if self._commit_sha else None
|
|
74
|
+
|
|
75
|
+
@commit_sha.setter
|
|
76
|
+
def commit_sha(self, value: str) -> None:
|
|
77
|
+
if not isinstance(value, str):
|
|
78
|
+
raise TypeError("output 'commit_sha' should be a string")
|
|
79
|
+
|
|
80
|
+
if not regexp(r"^[0-9a-f]{40}$").match(value):
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"output 'commit_sha' should be a valid 40-hex-character SHA"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
self._commit_sha = value
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def release_notes(self) -> str | None:
|
|
89
|
+
return self._release_notes if self._release_notes else None
|
|
90
|
+
|
|
91
|
+
@release_notes.setter
|
|
92
|
+
def release_notes(self, value: str) -> None:
|
|
93
|
+
if not isinstance(value, str):
|
|
94
|
+
raise TypeError("output 'release_notes' should be a string")
|
|
95
|
+
self._release_notes = value
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def prev_version(self) -> Version | None:
|
|
99
|
+
if not self.released:
|
|
100
|
+
return self.version
|
|
101
|
+
return self._prev_version if self._prev_version else None
|
|
102
|
+
|
|
103
|
+
@prev_version.setter
|
|
104
|
+
def prev_version(self, value: Version) -> None:
|
|
105
|
+
if not isinstance(value, Version):
|
|
106
|
+
raise TypeError("output 'prev_version' should be a Version")
|
|
107
|
+
self._prev_version = value
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def gh_client(self) -> Github:
|
|
111
|
+
if not self._gh_client:
|
|
112
|
+
raise ValueError("GitHub client not set, cannot create links")
|
|
113
|
+
return self._gh_client
|
|
114
|
+
|
|
48
115
|
def to_output_text(self) -> str:
|
|
49
|
-
missing = set()
|
|
116
|
+
missing: set[str] = set()
|
|
50
117
|
if self.version is None:
|
|
51
118
|
missing.add("version")
|
|
52
119
|
if self.released is None:
|
|
53
120
|
missing.add("released")
|
|
121
|
+
if self.released:
|
|
122
|
+
if self.release_notes is None:
|
|
123
|
+
missing.add("release_notes")
|
|
124
|
+
if self._mode is PersistenceMode.PERMANENT and self.commit_sha is None:
|
|
125
|
+
missing.add("commit_sha")
|
|
54
126
|
|
|
55
127
|
if missing:
|
|
56
128
|
raise ValueError(
|
|
57
129
|
f"some required outputs were not set: {', '.join(missing)}"
|
|
58
130
|
)
|
|
59
131
|
|
|
60
|
-
|
|
132
|
+
output_values: dict[str, Any] = {
|
|
61
133
|
"released": str(self.released).lower(),
|
|
62
134
|
"version": str(self.version),
|
|
63
135
|
"tag": self.tag,
|
|
64
136
|
"is_prerelease": str(self.is_prerelease).lower(),
|
|
137
|
+
"link": self.gh_client.create_release_url(self.tag) if self.tag else "",
|
|
138
|
+
"previous_version": str(self.prev_version) if self.prev_version else "",
|
|
139
|
+
"commit_sha": self.commit_sha if self.commit_sha else "",
|
|
65
140
|
}
|
|
66
141
|
|
|
67
|
-
|
|
142
|
+
multiline_output_values: dict[str, str] = {
|
|
143
|
+
"release_notes": self.release_notes if self.release_notes else "",
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
output_lines = [
|
|
147
|
+
*[f"{key}={value!s}{os.linesep}" for key, value in output_values.items()],
|
|
148
|
+
*[
|
|
149
|
+
f"{key}<<EOF{os.linesep}{value}EOF{os.linesep}"
|
|
150
|
+
if value
|
|
151
|
+
else f"{key}={os.linesep}"
|
|
152
|
+
for key, value in multiline_output_values.items()
|
|
153
|
+
],
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
return str.join("", output_lines)
|
|
68
157
|
|
|
69
158
|
def write_if_possible(self, filename: str | None = None) -> None:
|
|
70
159
|
output_file = filename or os.getenv(self.OUTPUT_ENV_VAR)
|
|
@@ -72,5 +161,5 @@ class VersionGitHubActionsOutput:
|
|
|
72
161
|
logger.info("not writing GitHub Actions output, as no file specified")
|
|
73
162
|
return
|
|
74
163
|
|
|
75
|
-
with open(output_file, "
|
|
76
|
-
f.write(self.to_output_text())
|
|
164
|
+
with open(output_file, "ab") as f:
|
|
165
|
+
f.write(self.to_output_text().encode("utf-8"))
|
|
@@ -62,9 +62,7 @@ class MaskingFilter(LoggingFilter):
|
|
|
62
62
|
|
|
63
63
|
def mask(self, msg: str) -> str:
|
|
64
64
|
if not isinstance(msg, str):
|
|
65
|
-
logger.debug(
|
|
66
|
-
"cannot mask object of type %s", type(msg)
|
|
67
|
-
)
|
|
65
|
+
logger.debug("cannot mask object of type %s", type(msg))
|
|
68
66
|
return msg
|
|
69
67
|
for mask, values in self._redact_patterns.items():
|
|
70
68
|
repl_string = (
|