python-semantic-release 9.12.2__py3-none-any.whl → 9.14.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.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/METADATA +2 -2
- {python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/RECORD +31 -28
- {python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/WHEEL +1 -1
- semantic_release/__init__.py +1 -1
- semantic_release/changelog/context.py +9 -0
- semantic_release/cli/changelog_writer.py +5 -4
- semantic_release/cli/commands/changelog.py +1 -0
- semantic_release/cli/commands/version.py +1 -0
- semantic_release/cli/config.py +4 -0
- semantic_release/commit_parser/angular.py +60 -33
- semantic_release/commit_parser/emoji.py +86 -39
- semantic_release/commit_parser/scipy.py +30 -81
- semantic_release/commit_parser/token.py +30 -0
- semantic_release/commit_parser/util.py +35 -4
- semantic_release/data/templates/angular/md/.components/changelog_init.md.j2 +14 -7
- semantic_release/data/templates/angular/md/.components/changelog_update.md.j2 +16 -7
- semantic_release/data/templates/angular/md/.components/changes.md.j2 +40 -12
- semantic_release/data/templates/angular/md/.components/first_release.md.j2 +11 -0
- semantic_release/data/templates/angular/md/.components/macros.md.j2 +69 -0
- semantic_release/data/templates/angular/md/.release_notes.md.j2 +13 -1
- semantic_release/data/templates/angular/md/CHANGELOG.md.j2 +1 -4
- semantic_release/data/templates/angular/rst/.components/changelog_init.rst.j2 +19 -12
- semantic_release/data/templates/angular/rst/.components/changelog_update.rst.j2 +16 -7
- semantic_release/data/templates/angular/rst/.components/changes.rst.j2 +59 -19
- semantic_release/data/templates/angular/rst/.components/first_release.rst.j2 +20 -0
- semantic_release/data/templates/angular/rst/.components/macros.rst.j2 +83 -2
- semantic_release/data/templates/angular/rst/CHANGELOG.rst.j2 +1 -4
- {python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/AUTHORS.rst +0 -0
- {python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/LICENSE +0 -0
- {python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/entry_points.txt +0 -0
- {python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/top_level.txt +0 -0
{python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.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.14.0
|
|
4
4
|
Summary: Automatic Semantic Versioning for Python projects
|
|
5
5
|
Author-email: Rolf Erik Lekang <me@rolflekang.com>
|
|
6
6
|
License: MIT
|
|
@@ -44,7 +44,7 @@ Requires-Dist: sphinxcontrib-apidoc==0.5.0; extra == "docs"
|
|
|
44
44
|
Requires-Dist: sphinx-autobuild==2024.2.4; extra == "docs"
|
|
45
45
|
Requires-Dist: furo~=2024.1; extra == "docs"
|
|
46
46
|
Provides-Extra: mypy
|
|
47
|
-
Requires-Dist: mypy==1.
|
|
47
|
+
Requires-Dist: mypy==1.13.0; extra == "mypy"
|
|
48
48
|
Requires-Dist: types-requests~=2.32.0; extra == "mypy"
|
|
49
49
|
Provides-Extra: test
|
|
50
50
|
Requires-Dist: coverage[toml]~=7.0; extra == "test"
|
{python_semantic_release-9.12.2.dist-info → python_semantic_release-9.14.0.dist-info}/RECORD
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
semantic_release/__init__.py,sha256=
|
|
1
|
+
semantic_release/__init__.py,sha256=kHQQzNnUYSMycf0e29x0t_WKKyKzPNRw9RkN73SVOpw,1229
|
|
2
2
|
semantic_release/__main__.py,sha256=kuotDU7aFKrCBeAJUPWrbIxgJWAmrXUMnztCqWMDMPY,1292
|
|
3
3
|
semantic_release/const.py,sha256=Z1o2QNh60wSLeF-_1TemMBjU3ZXbV0XghnUFsbTVfOs,831
|
|
4
4
|
semantic_release/enums.py,sha256=D5B_reQGGKQQT22HO5PUtvn2Bok3fkht6TfJtXkmAUg,1020
|
|
@@ -7,45 +7,48 @@ semantic_release/gitproject.py,sha256=izWc4NLdUzAwxGG_fJeqqHW9ivSrPcWBzSaOijQx4f
|
|
|
7
7
|
semantic_release/globals.py,sha256=imI9WKGa6MS2pTRAZiWZ2qIJup2eWnBz3OZmIj2YIHM,158
|
|
8
8
|
semantic_release/helpers.py,sha256=d1jOX0SNyqPc_3wr14xR25FfpqhMd4Ev7MNBOWlScc0,5581
|
|
9
9
|
semantic_release/changelog/__init__.py,sha256=Bg6Xe5Vt32rWoMscW-hd4sUwiZqzWmsg4CD1EhMesMY,262
|
|
10
|
-
semantic_release/changelog/context.py,sha256=
|
|
10
|
+
semantic_release/changelog/context.py,sha256=AQY9ZH1c5LjkyMcZyZG8Kjeyg0qvG_ueOWifgshtLWY,5354
|
|
11
11
|
semantic_release/changelog/release_history.py,sha256=8RU6A4FMgWwwjndOO4WKjbSzPWgVsYbdcZol1xUPnfo,7815
|
|
12
12
|
semantic_release/changelog/template.py,sha256=J1YJDI_SnXtBbTxoahN0NaVVHN7grOFghLwE9wDjxik,5685
|
|
13
13
|
semantic_release/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
semantic_release/cli/changelog_writer.py,sha256=
|
|
14
|
+
semantic_release/cli/changelog_writer.py,sha256=4XWAiH2qv3WBLxPm0D0S31-0XDm2QwSwyopiUmjUdJk,9029
|
|
15
15
|
semantic_release/cli/cli_context.py,sha256=23eyV6KWIpUckUSWILEd7t9dixp-QCY5-kGZnyucEYY,4114
|
|
16
|
-
semantic_release/cli/config.py,sha256=
|
|
16
|
+
semantic_release/cli/config.py,sha256=XpFT5asSe65ye3Q63h9HaDJ4lTzWKyUBXyn_tZSdamk,30884
|
|
17
17
|
semantic_release/cli/const.py,sha256=h7XE2D0D__TAZSrUUtVszwvzpkHTMOiQCf97XQNbEvA,163
|
|
18
18
|
semantic_release/cli/github_actions_output.py,sha256=VYIOb5x5h8eEJdSlXM_mkhT9xXtYi-RgxvnoM7iUn8s,2288
|
|
19
19
|
semantic_release/cli/masking_filter.py,sha256=DxqjiJyABlzwwwZ1r8JGQpb6QrF00StJFm0-2-s5Fv0,3071
|
|
20
20
|
semantic_release/cli/util.py,sha256=FyXaBkeL7nXKjy3X9rQLEwvn7p46xPekp2V8Z-5MVrk,3755
|
|
21
21
|
semantic_release/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
-
semantic_release/cli/commands/changelog.py,sha256=
|
|
22
|
+
semantic_release/cli/commands/changelog.py,sha256=6SLdz8zHuLDXnB8JWz8NSko9c5YNLMmRoBw_9DrkRok,3834
|
|
23
23
|
semantic_release/cli/commands/generate_config.py,sha256=2xZOu3NpyhBp0pWr7d8ugKl_kjqQgpSsSMHq5wHTfrE,1699
|
|
24
24
|
semantic_release/cli/commands/main.py,sha256=wHG51tbaAHKra21nRe3-FAfQT81-e5PGhv0KnerS15c,4100
|
|
25
25
|
semantic_release/cli/commands/publish.py,sha256=SZQlIewvqyIC14dkIIVVFetE0tPsKbO1cUyxnZsicrw,2845
|
|
26
|
-
semantic_release/cli/commands/version.py,sha256=
|
|
26
|
+
semantic_release/cli/commands/version.py,sha256=z4UNNmQ0Fo2e-SKPzmF1CF517X5mk8oaiGttYJAiVzA,24000
|
|
27
27
|
semantic_release/commit_parser/__init__.py,sha256=cv5HFBdw7OJd4Laj4Ex8ZZ5Tml8GwXgQcXW6Pasr2Ao,615
|
|
28
28
|
semantic_release/commit_parser/_base.py,sha256=t-Z9ALgAe7aZpYXz1mk3Fe-uAvipgKdNrq4Okg_WW9c,3026
|
|
29
|
-
semantic_release/commit_parser/angular.py,sha256=
|
|
30
|
-
semantic_release/commit_parser/emoji.py,sha256=
|
|
31
|
-
semantic_release/commit_parser/scipy.py,sha256=
|
|
29
|
+
semantic_release/commit_parser/angular.py,sha256=a1AmgstkclzJnRWqSsF4cuO8awuOJe7VAG__1W7WF7U,7276
|
|
30
|
+
semantic_release/commit_parser/emoji.py,sha256=4OQ5yyHBNC-pA7d6KP_pMjKxutwVaBvO_ydqCT1KtJA,5849
|
|
31
|
+
semantic_release/commit_parser/scipy.py,sha256=u_5OWOeM2V7_jZzYfEicKqx0GJBsAqIOfzRX_4cmOqk,3973
|
|
32
32
|
semantic_release/commit_parser/tag.py,sha256=4uwIKBqUM2SE6UTGIw-a7B6Jg1OONXmGwXsTyL3yZBA,3490
|
|
33
|
-
semantic_release/commit_parser/token.py,sha256
|
|
34
|
-
semantic_release/commit_parser/util.py,sha256=
|
|
35
|
-
semantic_release/data/templates/angular/md/.release_notes.md.j2,sha256=
|
|
36
|
-
semantic_release/data/templates/angular/md/CHANGELOG.md.j2,sha256=
|
|
33
|
+
semantic_release/commit_parser/token.py,sha256=-C1ZKG7pdbcGT2nc3-L2APLUUDGTXkbDeNi5mvvUwjk,2621
|
|
34
|
+
semantic_release/commit_parser/util.py,sha256=b9lud_FBjsmimLrvILf_NXvZ2wg8JPDmA364hcfM6is,1710
|
|
35
|
+
semantic_release/data/templates/angular/md/.release_notes.md.j2,sha256=1wGyJGiML0FeSsHeywj4gv5qhAZHvs0wvea7eCIGiwM,558
|
|
36
|
+
semantic_release/data/templates/angular/md/CHANGELOG.md.j2,sha256=FZmrQ-qOIoSoJmAa_NFaRelfmqUpypU2xlDeScdGOf4,729
|
|
37
37
|
semantic_release/data/templates/angular/md/.components/changelog_header.md.j2,sha256=qNxTuSr59CV_yyimVU_RYp5azCnK0l6nJ03Zf0u5Ugg,166
|
|
38
|
-
semantic_release/data/templates/angular/md/.components/changelog_init.md.j2,sha256=
|
|
39
|
-
semantic_release/data/templates/angular/md/.components/changelog_update.md.j2,sha256=
|
|
40
|
-
semantic_release/data/templates/angular/md/.components/changes.md.j2,sha256=
|
|
38
|
+
semantic_release/data/templates/angular/md/.components/changelog_init.md.j2,sha256=MyEQdWUemGXKWDhvpTmubZdozd3iaLECZAI1VRlE7mg,862
|
|
39
|
+
semantic_release/data/templates/angular/md/.components/changelog_update.md.j2,sha256=uVF4wbbjTMvl6Kbsq9xy3YIrj-uhBnHylEfA7S76aHI,2606
|
|
40
|
+
semantic_release/data/templates/angular/md/.components/changes.md.j2,sha256=PAt_vMMoP5uMbDQZKemx26m13TNGGAOmBVD1sUU-KNo,1701
|
|
41
|
+
semantic_release/data/templates/angular/md/.components/first_release.md.j2,sha256=jMUZiLwhMqAOjdYOCphJxJr8C411cKRzhsabyebj_AY,162
|
|
42
|
+
semantic_release/data/templates/angular/md/.components/macros.md.j2,sha256=rvMLeThRRmCVyF_utN0j6wrWL5PVb4TYraunOWWcdu4,2275
|
|
41
43
|
semantic_release/data/templates/angular/md/.components/unreleased_changes.md.j2,sha256=HRLj6cyRfPZXC0s-0Av6s0Gp3jKxWg9AIEtIXBVqJuY,177
|
|
42
44
|
semantic_release/data/templates/angular/md/.components/versioned_changes.md.j2,sha256=2Hky2mBrC4jltz3mvaiPDD0KQP0ELe5Ag75HgaLpaIE,257
|
|
43
|
-
semantic_release/data/templates/angular/rst/CHANGELOG.rst.j2,sha256=
|
|
45
|
+
semantic_release/data/templates/angular/rst/CHANGELOG.rst.j2,sha256=VmkXEMHiPBdZ1Z47QMxnJBZA0NbFSbKenUbThQVFAGY,731
|
|
44
46
|
semantic_release/data/templates/angular/rst/.components/changelog_header.rst.j2,sha256=c9xN1SEYLFwMvPYXYKt-ZbYPn2-Ss0V7zepEtFFj3Os,200
|
|
45
|
-
semantic_release/data/templates/angular/rst/.components/changelog_init.rst.j2,sha256=
|
|
46
|
-
semantic_release/data/templates/angular/rst/.components/changelog_update.rst.j2,sha256=
|
|
47
|
-
semantic_release/data/templates/angular/rst/.components/changes.rst.j2,sha256=
|
|
48
|
-
semantic_release/data/templates/angular/rst/.components/
|
|
47
|
+
semantic_release/data/templates/angular/rst/.components/changelog_init.rst.j2,sha256=XD0l3eTyz1yydLKsmSqBk-u8RnO-RdQ2Q8uWezHMAWw,866
|
|
48
|
+
semantic_release/data/templates/angular/rst/.components/changelog_update.rst.j2,sha256=x23-qk9owJrOQaHx8SgSnIZECITjPf1R2awfv9EOHN0,2604
|
|
49
|
+
semantic_release/data/templates/angular/rst/.components/changes.rst.j2,sha256=REgnXdUDQKH2_BakQ-zbQtS4-MJMYKtA1jBXYFhfSjk,2915
|
|
50
|
+
semantic_release/data/templates/angular/rst/.components/first_release.rst.j2,sha256=tChYsdSFMaB0DU9KROYSxijdb7tqaN1psKmDMbrVrJw,443
|
|
51
|
+
semantic_release/data/templates/angular/rst/.components/macros.rst.j2,sha256=C4JkbfM9mfal-fMJJp6dPUT45PsqwfsCFu4pfZe34QI,3176
|
|
49
52
|
semantic_release/data/templates/angular/rst/.components/unreleased_changes.rst.j2,sha256=ARBhc1ZpKwehGKDvOMqukmN59mTJiHzHsS7rOfKYCt8,202
|
|
50
53
|
semantic_release/data/templates/angular/rst/.components/versioned_changes.rst.j2,sha256=NZfn1W14QochiAJ43oNKmcrCn_vgfbkKtvOTAw1jEc8,530
|
|
51
54
|
semantic_release/hvcs/__init__.py,sha256=JwoaLOF-12L-OBo_9-tOXXhdiHKeVungA9865to2oZk,494
|
|
@@ -62,10 +65,10 @@ semantic_release/version/algorithm.py,sha256=ofx_bIWq6ptJVr-ekI11IzxzDEctDKFiVwa
|
|
|
62
65
|
semantic_release/version/declaration.py,sha256=f6Ld7hIhrqvDrRBapJHr-KDimuyo-4IG8009Zu9BIgU,7357
|
|
63
66
|
semantic_release/version/translator.py,sha256=P1noIsVBn8u6zNOFjG0xKYOWapxqf_PHSMvMeLJ9kXg,3050
|
|
64
67
|
semantic_release/version/version.py,sha256=6PCtSbLP88U1daoxnCwHc--YguZo4waGNLqJ5JfeczE,14175
|
|
65
|
-
python_semantic_release-9.
|
|
66
|
-
python_semantic_release-9.
|
|
67
|
-
python_semantic_release-9.
|
|
68
|
-
python_semantic_release-9.
|
|
69
|
-
python_semantic_release-9.
|
|
70
|
-
python_semantic_release-9.
|
|
71
|
-
python_semantic_release-9.
|
|
68
|
+
python_semantic_release-9.14.0.dist-info/AUTHORS.rst,sha256=XOReVvpymEFUPsS2QPH97jlfJBVrxwS2eu8-jVAe4gk,230
|
|
69
|
+
python_semantic_release-9.14.0.dist-info/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
|
|
70
|
+
python_semantic_release-9.14.0.dist-info/METADATA,sha256=tY6DDyFypAxFHo8kVuuCecr3h_siBZ7RO88JOQAIZQ4,3571
|
|
71
|
+
python_semantic_release-9.14.0.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
|
|
72
|
+
python_semantic_release-9.14.0.dist-info/entry_points.txt,sha256=r2Jql3GTQyugQnvf34l2eXk1O_Qx6llR_xixG1ZWgD0,105
|
|
73
|
+
python_semantic_release-9.14.0.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
|
|
74
|
+
python_semantic_release-9.14.0.dist-info/RECORD,,
|
semantic_release/__init__.py
CHANGED
|
@@ -23,6 +23,7 @@ class ReleaseNotesContext:
|
|
|
23
23
|
hvcs_type: str
|
|
24
24
|
version: Version
|
|
25
25
|
release: Release
|
|
26
|
+
mask_initial_release: bool
|
|
26
27
|
filters: tuple[Callable[..., Any], ...] = ()
|
|
27
28
|
|
|
28
29
|
def bind_to_environment(self, env: Environment) -> Environment:
|
|
@@ -53,6 +54,7 @@ class ChangelogContext:
|
|
|
53
54
|
changelog_mode: Literal["update", "init"]
|
|
54
55
|
prev_changelog_file: str
|
|
55
56
|
changelog_insertion_flag: str
|
|
57
|
+
mask_initial_release: bool
|
|
56
58
|
filters: tuple[Callable[..., Any], ...] = ()
|
|
57
59
|
|
|
58
60
|
def bind_to_environment(self, env: Environment) -> Environment:
|
|
@@ -69,6 +71,7 @@ def make_changelog_context(
|
|
|
69
71
|
mode: ChangelogMode,
|
|
70
72
|
prev_changelog_file: Path,
|
|
71
73
|
insertion_flag: str,
|
|
74
|
+
mask_initial_release: bool,
|
|
72
75
|
) -> ChangelogContext:
|
|
73
76
|
return ChangelogContext(
|
|
74
77
|
repo_name=hvcs_client.repo_name,
|
|
@@ -76,6 +79,7 @@ def make_changelog_context(
|
|
|
76
79
|
history=release_history,
|
|
77
80
|
changelog_mode=mode.value,
|
|
78
81
|
changelog_insertion_flag=insertion_flag,
|
|
82
|
+
mask_initial_release=mask_initial_release,
|
|
79
83
|
prev_changelog_file=str(prev_changelog_file),
|
|
80
84
|
hvcs_type=hvcs_client.__class__.__name__.lower(),
|
|
81
85
|
filters=(
|
|
@@ -111,6 +115,11 @@ def convert_md_to_rst(md_content: str) -> str:
|
|
|
111
115
|
"bullets": (regexp(r"^(\s*)-(\s)"), r"\1*\2"),
|
|
112
116
|
# Replace markdown inline raw content with rst inline raw content
|
|
113
117
|
"raw-inline": (regexp(r"(?<=\s)(`[^`]+`)(?![`_])"), r"`\1`"),
|
|
118
|
+
# Replace markdown inline link with rst inline link
|
|
119
|
+
"link-inline": (
|
|
120
|
+
regexp(r"(?<=\s)\[([^\]]+)\]\(([^)]+)\)(?=\s|$)"),
|
|
121
|
+
r"`\1 <\2>`_",
|
|
122
|
+
),
|
|
114
123
|
}
|
|
115
124
|
|
|
116
125
|
for pattern, replacement in replacements.values():
|
|
@@ -178,6 +178,7 @@ def write_changelog_files(
|
|
|
178
178
|
mode=runtime_ctx.changelog_mode,
|
|
179
179
|
insertion_flag=runtime_ctx.changelog_insertion_flag,
|
|
180
180
|
prev_changelog_file=runtime_ctx.changelog_file,
|
|
181
|
+
mask_initial_release=runtime_ctx.changelog_mask_initial_release,
|
|
181
182
|
)
|
|
182
183
|
|
|
183
184
|
user_templates = []
|
|
@@ -226,6 +227,7 @@ def generate_release_notes(
|
|
|
226
227
|
template_dir: Path,
|
|
227
228
|
history: ReleaseHistory,
|
|
228
229
|
style: str,
|
|
230
|
+
mask_initial_release: bool,
|
|
229
231
|
) -> str:
|
|
230
232
|
users_tpl_file = template_dir / DEFAULT_RELEASE_NOTES_TPL_FILE
|
|
231
233
|
|
|
@@ -251,6 +253,7 @@ def generate_release_notes(
|
|
|
251
253
|
hvcs_type=hvcs_client.__class__.__name__.lower(),
|
|
252
254
|
version=release["version"],
|
|
253
255
|
release=release,
|
|
256
|
+
mask_initial_release=mask_initial_release,
|
|
254
257
|
filters=(*hvcs_client.get_changelog_context_filters(), autofit_text_width),
|
|
255
258
|
).bind_to_environment(
|
|
256
259
|
# Use a new, non-configurable environment for release notes -
|
|
@@ -259,11 +262,9 @@ def generate_release_notes(
|
|
|
259
262
|
)
|
|
260
263
|
|
|
261
264
|
# TODO: Remove in v10
|
|
262
|
-
release_notes_env.globals["context"] = {
|
|
263
|
-
"history": history,
|
|
264
|
-
}
|
|
265
|
-
release_notes_env.globals["ctx"] = {
|
|
265
|
+
release_notes_env.globals["context"] = release_notes_env.globals["ctx"] = {
|
|
266
266
|
"history": history,
|
|
267
|
+
"mask_initial_release": mask_initial_release,
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
return render_release_notes(
|
semantic_release/cli/config.py
CHANGED
|
@@ -123,6 +123,8 @@ class ChangelogEnvironmentConfig(BaseModel):
|
|
|
123
123
|
class DefaultChangelogTemplatesConfig(BaseModel):
|
|
124
124
|
changelog_file: str = "CHANGELOG.md"
|
|
125
125
|
output_format: ChangelogOutputFormat = ChangelogOutputFormat.NONE
|
|
126
|
+
# TODO: Breaking Change v10, it will become True
|
|
127
|
+
mask_initial_release: bool = False
|
|
126
128
|
|
|
127
129
|
@model_validator(mode="after")
|
|
128
130
|
def interpret_output_format(self) -> Self:
|
|
@@ -511,6 +513,7 @@ class RuntimeContext:
|
|
|
511
513
|
version_declarations: Tuple[VersionDeclarationABC, ...]
|
|
512
514
|
hvcs_client: hvcs.HvcsBase
|
|
513
515
|
changelog_insertion_flag: str
|
|
516
|
+
changelog_mask_initial_release: bool
|
|
514
517
|
changelog_mode: ChangelogMode
|
|
515
518
|
changelog_file: Path
|
|
516
519
|
changelog_style: str
|
|
@@ -795,6 +798,7 @@ class RuntimeContext:
|
|
|
795
798
|
hvcs_client=hvcs_client,
|
|
796
799
|
changelog_file=changelog_file,
|
|
797
800
|
changelog_mode=raw.changelog.mode,
|
|
801
|
+
changelog_mask_initial_release=raw.changelog.default_templates.mask_initial_release,
|
|
798
802
|
changelog_insertion_flag=raw.changelog.insertion_flag,
|
|
799
803
|
assets=raw.assets,
|
|
800
804
|
commit_author=commit_author,
|
|
@@ -8,19 +8,26 @@ from __future__ import annotations
|
|
|
8
8
|
import logging
|
|
9
9
|
import re
|
|
10
10
|
from functools import reduce
|
|
11
|
+
from itertools import zip_longest
|
|
11
12
|
from re import compile as regexp
|
|
12
13
|
from typing import TYPE_CHECKING, Tuple
|
|
13
14
|
|
|
14
15
|
from pydantic.dataclasses import dataclass
|
|
15
16
|
|
|
16
17
|
from semantic_release.commit_parser._base import CommitParser, ParserOptions
|
|
17
|
-
from semantic_release.commit_parser.token import
|
|
18
|
+
from semantic_release.commit_parser.token import (
|
|
19
|
+
ParsedCommit,
|
|
20
|
+
ParsedMessageResult,
|
|
21
|
+
ParseError,
|
|
22
|
+
ParseResult,
|
|
23
|
+
)
|
|
18
24
|
from semantic_release.commit_parser.util import breaking_re, parse_paragraphs
|
|
19
25
|
from semantic_release.enums import LevelBump
|
|
20
26
|
|
|
21
27
|
if TYPE_CHECKING:
|
|
22
28
|
from git.objects.commit import Commit
|
|
23
29
|
|
|
30
|
+
|
|
24
31
|
logger = logging.getLogger(__name__)
|
|
25
32
|
|
|
26
33
|
|
|
@@ -65,11 +72,16 @@ class AngularParserOptions(ParserOptions):
|
|
|
65
72
|
default_bump_level: LevelBump = LevelBump.NO_RELEASE
|
|
66
73
|
|
|
67
74
|
def __post_init__(self) -> None:
|
|
68
|
-
self.tag_to_level
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
self.tag_to_level: dict[str, LevelBump] = dict(
|
|
76
|
+
[
|
|
77
|
+
# we have to do a type ignore as zip_longest provides a type that is not specific enough
|
|
78
|
+
# for our expected output. Due to the empty second array, we know the first is always longest
|
|
79
|
+
# and that means no values in the first entry of the tuples will ever be a LevelBump.
|
|
80
|
+
*zip_longest(self.allowed_tags, (), fillvalue=self.default_bump_level), # type: ignore[list-item]
|
|
81
|
+
*zip_longest(self.patch_tags, (), fillvalue=LevelBump.PATCH), # type: ignore[list-item]
|
|
82
|
+
*zip_longest(self.minor_tags, (), fillvalue=LevelBump.MINOR), # type: ignore[list-item]
|
|
83
|
+
]
|
|
84
|
+
)
|
|
73
85
|
|
|
74
86
|
|
|
75
87
|
class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
|
|
@@ -98,6 +110,10 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
|
|
|
98
110
|
),
|
|
99
111
|
flags=re.DOTALL,
|
|
100
112
|
)
|
|
113
|
+
# GitHub & Gitea use (#123), GitLab uses (!123), and BitBucket uses (pull request #123)
|
|
114
|
+
self.mr_selector = regexp(
|
|
115
|
+
r"[\t ]+\((?:pull request )?(?P<mr_number>[#!]\d+)\)[\t ]*$"
|
|
116
|
+
)
|
|
101
117
|
|
|
102
118
|
@staticmethod
|
|
103
119
|
def get_default_options() -> AngularParserOptions:
|
|
@@ -114,27 +130,23 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
|
|
|
114
130
|
accumulator["descriptions"].append(text)
|
|
115
131
|
return accumulator
|
|
116
132
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def parse(self, commit: Commit) -> ParseResult:
|
|
122
|
-
"""
|
|
123
|
-
Attempt to parse the commit message with a regular expression into a
|
|
124
|
-
ParseResult
|
|
125
|
-
"""
|
|
126
|
-
message = str(commit.message)
|
|
127
|
-
parsed = self.re_parser.match(message)
|
|
128
|
-
if not parsed:
|
|
129
|
-
return _logged_parse_error(
|
|
130
|
-
commit, f"Unable to parse commit message: {message}"
|
|
131
|
-
)
|
|
133
|
+
def parse_message(self, message: str) -> ParsedMessageResult | None:
|
|
134
|
+
if not (parsed := self.re_parser.match(message)):
|
|
135
|
+
return None
|
|
136
|
+
|
|
132
137
|
parsed_break = parsed.group("break")
|
|
133
138
|
parsed_scope = parsed.group("scope")
|
|
134
139
|
parsed_subject = parsed.group("subject")
|
|
135
140
|
parsed_text = parsed.group("text")
|
|
136
141
|
parsed_type = parsed.group("type")
|
|
137
142
|
|
|
143
|
+
linked_merge_request = ""
|
|
144
|
+
if mr_match := self.mr_selector.search(parsed_subject):
|
|
145
|
+
linked_merge_request = mr_match.group("mr_number")
|
|
146
|
+
# TODO: breaking change v10, removes PR number from subject/descriptions
|
|
147
|
+
# expects changelog template to format the line accordingly
|
|
148
|
+
# parsed_subject = self.pr_selector.sub("", parsed_subject).strip()
|
|
149
|
+
|
|
138
150
|
body_components: dict[str, list[str]] = reduce(
|
|
139
151
|
self.commit_body_components_separator,
|
|
140
152
|
[
|
|
@@ -157,19 +169,34 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
|
|
|
157
169
|
)
|
|
158
170
|
)
|
|
159
171
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
parsed_type
|
|
172
|
+
return ParsedMessageResult(
|
|
173
|
+
bump=level_bump,
|
|
174
|
+
type=parsed_type,
|
|
175
|
+
category=LONG_TYPE_NAMES.get(parsed_type, parsed_type),
|
|
176
|
+
scope=parsed_scope,
|
|
177
|
+
descriptions=tuple(body_components["descriptions"]),
|
|
178
|
+
breaking_descriptions=tuple(body_components["breaking_descriptions"]),
|
|
179
|
+
linked_merge_request=linked_merge_request,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Maybe this can be cached as an optimization, similar to how
|
|
183
|
+
# mypy/pytest use their own caching directories, for very large commit
|
|
184
|
+
# histories?
|
|
185
|
+
# The problem is the cache likely won't be present in CI environments
|
|
186
|
+
def parse(self, commit: Commit) -> ParseResult:
|
|
187
|
+
"""
|
|
188
|
+
Attempt to parse the commit message with a regular expression into a
|
|
189
|
+
ParseResult
|
|
190
|
+
"""
|
|
191
|
+
if not (pmsg_result := self.parse_message(str(commit.message))):
|
|
192
|
+
return _logged_parse_error(
|
|
193
|
+
commit, f"Unable to parse commit message: {commit.message!r}"
|
|
194
|
+
)
|
|
163
195
|
|
|
164
196
|
logger.debug(
|
|
165
|
-
"commit %s introduces a %s level_bump",
|
|
197
|
+
"commit %s introduces a %s level_bump",
|
|
198
|
+
commit.hexsha[:8],
|
|
199
|
+
pmsg_result.bump,
|
|
166
200
|
)
|
|
167
201
|
|
|
168
|
-
return ParsedCommit(
|
|
169
|
-
bump=level_bump,
|
|
170
|
-
type=LONG_TYPE_NAMES.get(parsed_type, parsed_type),
|
|
171
|
-
scope=parsed_scope,
|
|
172
|
-
descriptions=body_components["descriptions"],
|
|
173
|
-
breaking_descriptions=body_components["breaking_descriptions"],
|
|
174
|
-
commit=commit,
|
|
175
|
-
)
|
|
202
|
+
return ParsedCommit.from_parsed_message_result(commit, pmsg_result)
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
"""Commit parser which looks for emojis to determine the type of commit"""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import logging
|
|
6
|
+
from itertools import zip_longest
|
|
7
|
+
from re import compile as regexp
|
|
4
8
|
from typing import Tuple
|
|
5
9
|
|
|
6
10
|
from git.objects.commit import Commit
|
|
7
11
|
from pydantic.dataclasses import dataclass
|
|
8
12
|
|
|
9
13
|
from semantic_release.commit_parser._base import CommitParser, ParserOptions
|
|
10
|
-
from semantic_release.commit_parser.token import
|
|
14
|
+
from semantic_release.commit_parser.token import (
|
|
15
|
+
ParsedCommit,
|
|
16
|
+
ParsedMessageResult,
|
|
17
|
+
ParseResult,
|
|
18
|
+
)
|
|
11
19
|
from semantic_release.commit_parser.util import parse_paragraphs
|
|
12
20
|
from semantic_release.enums import LevelBump
|
|
13
21
|
|
|
@@ -41,8 +49,26 @@ class EmojiParserOptions(ParserOptions):
|
|
|
41
49
|
":robot:",
|
|
42
50
|
":green_apple:",
|
|
43
51
|
)
|
|
52
|
+
allowed_tags: Tuple[str, ...] = (
|
|
53
|
+
*major_tags,
|
|
54
|
+
*minor_tags,
|
|
55
|
+
*patch_tags,
|
|
56
|
+
)
|
|
44
57
|
default_bump_level: LevelBump = LevelBump.NO_RELEASE
|
|
45
58
|
|
|
59
|
+
def __post_init__(self) -> None:
|
|
60
|
+
self.tag_to_level: dict[str, LevelBump] = dict(
|
|
61
|
+
[
|
|
62
|
+
# we have to do a type ignore as zip_longest provides a type that is not specific enough
|
|
63
|
+
# for our expected output. Due to the empty second array, we know the first is always longest
|
|
64
|
+
# and that means no values in the first entry of the tuples will ever be a LevelBump.
|
|
65
|
+
*zip_longest(self.allowed_tags, (), fillvalue=self.default_bump_level), # type: ignore[list-item]
|
|
66
|
+
*zip_longest(self.patch_tags, (), fillvalue=LevelBump.PATCH), # type: ignore[list-item]
|
|
67
|
+
*zip_longest(self.minor_tags, (), fillvalue=LevelBump.MINOR), # type: ignore[list-item]
|
|
68
|
+
*zip_longest(self.major_tags, (), fillvalue=LevelBump.MAJOR), # type: ignore[list-item]
|
|
69
|
+
]
|
|
70
|
+
)
|
|
71
|
+
|
|
46
72
|
|
|
47
73
|
class EmojiCommitParser(CommitParser[ParseResult, EmojiParserOptions]):
|
|
48
74
|
"""
|
|
@@ -60,56 +86,77 @@ class EmojiCommitParser(CommitParser[ParseResult, EmojiParserOptions]):
|
|
|
60
86
|
# TODO: Deprecate in lieu of get_default_options()
|
|
61
87
|
parser_options = EmojiParserOptions
|
|
62
88
|
|
|
89
|
+
def __init__(self, options: EmojiParserOptions | None = None) -> None:
|
|
90
|
+
super().__init__(options)
|
|
91
|
+
prcedence_order_regex = str.join(
|
|
92
|
+
"|",
|
|
93
|
+
[
|
|
94
|
+
*self.options.major_tags,
|
|
95
|
+
*self.options.minor_tags,
|
|
96
|
+
*self.options.patch_tags,
|
|
97
|
+
],
|
|
98
|
+
)
|
|
99
|
+
self.emoji_selector = regexp(r"(?P<type>%s)" % prcedence_order_regex)
|
|
100
|
+
|
|
101
|
+
# GitHub & Gitea use (#123), GitLab uses (!123), and BitBucket uses (pull request #123)
|
|
102
|
+
self.mr_selector = regexp(
|
|
103
|
+
r"[\t ]+\((?:pull request )?(?P<mr_number>[#!]\d+)\)[\t ]*$"
|
|
104
|
+
)
|
|
105
|
+
|
|
63
106
|
@staticmethod
|
|
64
107
|
def get_default_options() -> EmojiParserOptions:
|
|
65
108
|
return EmojiParserOptions()
|
|
66
109
|
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
110
|
+
def parse_message(self, message: str) -> ParsedMessageResult:
|
|
111
|
+
subject = message.split("\n", maxsplit=1)[0]
|
|
112
|
+
|
|
113
|
+
linked_merge_request = ""
|
|
114
|
+
if mr_match := self.mr_selector.search(subject):
|
|
115
|
+
linked_merge_request = mr_match.group("mr_number")
|
|
116
|
+
# TODO: breaking change v10, removes PR number from subject/descriptions
|
|
117
|
+
# expects changelog template to format the line accordingly
|
|
118
|
+
# subject = self.mr_selector.sub("", subject).strip()
|
|
119
|
+
|
|
120
|
+
# Search for emoji of the highest importance in the subject
|
|
121
|
+
primary_emoji = (
|
|
122
|
+
match.group("type")
|
|
123
|
+
if (match := self.emoji_selector.search(subject))
|
|
124
|
+
else "Other"
|
|
70
125
|
)
|
|
71
126
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
# Loop over emojis from most important to least important
|
|
76
|
-
# Therefore, we find the highest level emoji first
|
|
77
|
-
primary_emoji = "Other"
|
|
78
|
-
for emoji in all_emojis:
|
|
79
|
-
if emoji in subject:
|
|
80
|
-
primary_emoji = emoji
|
|
81
|
-
break
|
|
82
|
-
logger.debug("Selected %s as the primary emoji", primary_emoji)
|
|
83
|
-
|
|
84
|
-
# Find which level this commit was from
|
|
85
|
-
level_bump = LevelBump.NO_RELEASE
|
|
86
|
-
if primary_emoji in self.options.major_tags:
|
|
87
|
-
level_bump = LevelBump.MAJOR
|
|
88
|
-
elif primary_emoji in self.options.minor_tags:
|
|
89
|
-
level_bump = LevelBump.MINOR
|
|
90
|
-
elif primary_emoji in self.options.patch_tags:
|
|
91
|
-
level_bump = LevelBump.PATCH
|
|
92
|
-
else:
|
|
93
|
-
level_bump = self.options.default_bump_level
|
|
94
|
-
logger.debug(
|
|
95
|
-
"commit %s introduces a level bump of %s due to the default_bump_level",
|
|
96
|
-
commit.hexsha[:8],
|
|
97
|
-
level_bump,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
logger.debug(
|
|
101
|
-
"commit %s introduces a %s level_bump", commit.hexsha[:8], level_bump
|
|
127
|
+
level_bump = self.options.tag_to_level.get(
|
|
128
|
+
primary_emoji, self.options.default_bump_level
|
|
102
129
|
)
|
|
103
130
|
|
|
104
131
|
# All emojis will remain part of the returned description
|
|
105
|
-
descriptions = parse_paragraphs(message)
|
|
106
|
-
return
|
|
132
|
+
descriptions = tuple(parse_paragraphs(message))
|
|
133
|
+
return ParsedMessageResult(
|
|
107
134
|
bump=level_bump,
|
|
108
135
|
type=primary_emoji,
|
|
109
|
-
|
|
136
|
+
category=primary_emoji,
|
|
137
|
+
scope="", # TODO: add scope support
|
|
138
|
+
# TODO: breaking change v10, removes breaking change footers from descriptions
|
|
139
|
+
# descriptions=(
|
|
140
|
+
# descriptions[:1] if level_bump is LevelBump.MAJOR else descriptions
|
|
141
|
+
# )
|
|
110
142
|
descriptions=descriptions,
|
|
111
143
|
breaking_descriptions=(
|
|
112
|
-
descriptions[1:] if level_bump is LevelBump.MAJOR else
|
|
144
|
+
descriptions[1:] if level_bump is LevelBump.MAJOR else ()
|
|
113
145
|
),
|
|
114
|
-
|
|
146
|
+
linked_merge_request=linked_merge_request,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def parse(self, commit: Commit) -> ParseResult:
|
|
150
|
+
"""
|
|
151
|
+
Attempt to parse the commit message with a regular expression into a
|
|
152
|
+
ParseResult
|
|
153
|
+
"""
|
|
154
|
+
pmsg_result = self.parse_message(str(commit.message))
|
|
155
|
+
|
|
156
|
+
logger.debug(
|
|
157
|
+
"commit %s introduces a %s level_bump",
|
|
158
|
+
commit.hexsha[:8],
|
|
159
|
+
pmsg_result.bump,
|
|
115
160
|
)
|
|
161
|
+
|
|
162
|
+
return ParsedCommit.from_parsed_message_result(commit, pmsg_result)
|