python-semantic-release 10.0.1__py3-none-any.whl → 10.1.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-semantic-release
3
- Version: 10.0.1
3
+ Version: 10.1.0
4
4
  Summary: Automatic Semantic Versioning for Python projects
5
5
  Author-email: Rolf Erik Lekang <me@rolflekang.com>
6
6
  License: MIT
@@ -25,7 +25,7 @@ Requires-Dist: click-option-group~=0.5
25
25
  Requires-Dist: gitpython~=3.0
26
26
  Requires-Dist: requests~=2.25
27
27
  Requires-Dist: jinja2~=3.1
28
- Requires-Dist: python-gitlab<6.0.0,>=4.0.0
28
+ Requires-Dist: python-gitlab<7.0.0,>=4.0.0
29
29
  Requires-Dist: tomlkit~=0.11
30
30
  Requires-Dist: dotty-dict~=1.3
31
31
  Requires-Dist: importlib-resources~=6.0
@@ -62,7 +62,7 @@ Requires-Dist: pre-commit~=3.5; extra == "dev"
62
62
  Requires-Dist: tox~=4.11; extra == "dev"
63
63
  Requires-Dist: ruff==0.6.1; extra == "dev"
64
64
  Provides-Extra: mypy
65
- Requires-Dist: mypy==1.15.0; extra == "mypy"
65
+ Requires-Dist: mypy==1.16.0; extra == "mypy"
66
66
  Requires-Dist: types-Deprecated~=1.2; extra == "mypy"
67
67
  Requires-Dist: types-requests~=2.32.0; extra == "mypy"
68
68
  Requires-Dist: types-pyyaml~=6.0; extra == "mypy"
@@ -1,4 +1,4 @@
1
- python_semantic_release-10.0.1.dist-info/licenses/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
1
+ python_semantic_release-10.1.0.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
@@ -13,9 +13,9 @@ semantic_release/changelog/context.py,sha256=WeLQ2BvYEWunIF8XEl6ldQE4IRg0d7r8mYS
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
- semantic_release/cli/changelog_writer.py,sha256=oaaHnEspJMcdGtmgy0xyJV_7U2kBDhO3d_0ewr7N0rA,9284
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=uz8ifzPkM5inyiZmvLjbSv5v1oqCsg-2ocEwQiYXpwc,33458
18
+ semantic_release/cli/config.py,sha256=4UCx4-jzKpggb7dZM3fnZoi8rPiUGWtEmLiCfWlro7I,33458
19
19
  semantic_release/cli/const.py,sha256=h7XE2D0D__TAZSrUUtVszwvzpkHTMOiQCf97XQNbEvA,163
20
20
  semantic_release/cli/github_actions_output.py,sha256=5m0IwIUu-Ntse_Uwrxhn5lYmaVN16JUyOADvmEgsYxg,2293
21
21
  semantic_release/cli/masking_filter.py,sha256=GsTyaoZbUVJLXVMqeXhCttXK84UnBQ8cNDSHxd52sOc,3218
@@ -25,16 +25,16 @@ semantic_release/cli/commands/changelog.py,sha256=wJfd4VVfrGnu2jnIpG25cdVcbXIX-E
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=xBi_Y2M7gEpf7CSponCITTuVtxirhTdGsm7XlRGg05Q,25721
28
+ semantic_release/cli/commands/version.py,sha256=E061zBntS7Wg5c2ftzl8ya5NjBqFRYBLR73KU5lKE5U,25684
29
29
  semantic_release/commit_parser/__init__.py,sha256=6euiDgj9bwOx1rP96vUjq090usviXkbo7OVOnRBGfcw,742
30
- semantic_release/commit_parser/_base.py,sha256=oDifeTmFDpS238cp_DDrGzfidaKeAD5olCB5IM4Q6z8,3058
31
- semantic_release/commit_parser/angular.py,sha256=dcJ7r9Aw6xlecPlzlwjonmlX3mlrgAPDZbRG6t2-6-w,19249
30
+ semantic_release/commit_parser/_base.py,sha256=DLsHnbXG-39JkUbcnsBCSV2GmV35w1rasyoMhK8G0UE,3058
31
+ semantic_release/commit_parser/angular.py,sha256=MY_fo9F4EZ-ac8wYzBR0uD94O5Li2D-8zEMR01wss4c,18534
32
32
  semantic_release/commit_parser/conventional.py,sha256=Iyy8txkshK8HikizFVa7pnJHBSWDhOhF45zR866QxQM,18672
33
33
  semantic_release/commit_parser/emoji.py,sha256=0VecUMMcj43UaKDZ2GaFFUG26zOJAvXsEobTHaXNkk0,17749
34
- semantic_release/commit_parser/scipy.py,sha256=aysk2r_jImZU2ovqNv5Us0abSO20Po7TQwUiKh8-7W0,19463
34
+ semantic_release/commit_parser/scipy.py,sha256=gA9TfmrxGVvtv6kki6N_9abJx-_WlpBsSX2TBh0YgPw,19463
35
35
  semantic_release/commit_parser/tag.py,sha256=bVO2XghM0G_eW2rG9Xc2q5TPsjtxr-xcHK5RpE1u_HM,3537
36
- semantic_release/commit_parser/token.py,sha256=ECgi7eeSgk3Biq1Y_ChbFJZQLkrUpNvGhIaEOXrNC4M,7904
37
- semantic_release/commit_parser/util.py,sha256=_ACiopznjwINn4t1zPHl8bxZEc0zOAURTycNU-sXs3M,3959
36
+ semantic_release/commit_parser/token.py,sha256=1_q8mJ4SRu7kNfa-Nxr8fEyuvCfjPgiPEitqSP1KR5g,7904
37
+ semantic_release/commit_parser/util.py,sha256=hcLjc16o7l6y_5Hfl8IxmF4ijaJD62JdjdB2DJWAe-g,3959
38
38
  semantic_release/data/templates/conventional/md/.release_notes.md.j2,sha256=DlMVAJMGqE27TwJ-2kviYaFhd3uWqXiU6Ikl15Ukne8,2512
39
39
  semantic_release/data/templates/conventional/md/CHANGELOG.md.j2,sha256=FZmrQ-qOIoSoJmAa_NFaRelfmqUpypU2xlDeScdGOf4,729
40
40
  semantic_release/data/templates/conventional/md/.components/changelog_header.md.j2,sha256=qNxTuSr59CV_yyimVU_RYp5azCnK0l6nJ03Zf0u5Ugg,166
@@ -42,7 +42,7 @@ semantic_release/data/templates/conventional/md/.components/changelog_init.md.j2
42
42
  semantic_release/data/templates/conventional/md/.components/changelog_update.md.j2,sha256=uVF4wbbjTMvl6Kbsq9xy3YIrj-uhBnHylEfA7S76aHI,2606
43
43
  semantic_release/data/templates/conventional/md/.components/changes.md.j2,sha256=8uI1-wiUJkxM2ZoA8bk7tVkHWSK-mknmXYd3KHLOKAE,5554
44
44
  semantic_release/data/templates/conventional/md/.components/first_release.md.j2,sha256=-S2aJV3ka4YicLs8UF6BEV-CDnL8iXLcNRRIiENFrYE,421
45
- semantic_release/data/templates/conventional/md/.components/macros.md.j2,sha256=RzBVwKSCb-WmRIMFVQL9U157mAih-PzZ_iRcfyWkG20,8196
45
+ semantic_release/data/templates/conventional/md/.components/macros.md.j2,sha256=RMvhwNScNmBgasGxsHI4WBodiJyZWa3_AMITvaqOqQY,6534
46
46
  semantic_release/data/templates/conventional/md/.components/unreleased_changes.md.j2,sha256=HRLj6cyRfPZXC0s-0Av6s0Gp3jKxWg9AIEtIXBVqJuY,177
47
47
  semantic_release/data/templates/conventional/md/.components/versioned_changes.md.j2,sha256=KbU7D_n_VqET7q2CLwBQ7931dvO7xQklADw-oY6ujlY,502
48
48
  semantic_release/data/templates/conventional/rst/CHANGELOG.rst.j2,sha256=VmkXEMHiPBdZ1Z47QMxnJBZA0NbFSbKenUbThQVFAGY,731
@@ -51,7 +51,7 @@ semantic_release/data/templates/conventional/rst/.components/changelog_init.rst.
51
51
  semantic_release/data/templates/conventional/rst/.components/changelog_update.rst.j2,sha256=x23-qk9owJrOQaHx8SgSnIZECITjPf1R2awfv9EOHN0,2604
52
52
  semantic_release/data/templates/conventional/rst/.components/changes.rst.j2,sha256=RJdKG28Cv-pov6I61O1W9KoYCIj1vkHC4_wHTs4zGvM,6922
53
53
  semantic_release/data/templates/conventional/rst/.components/first_release.rst.j2,sha256=huaO-B3BRs7h2LRks2a6-656W2qzURkzLiyuKvYxMTg,462
54
- semantic_release/data/templates/conventional/rst/.components/macros.rst.j2,sha256=WLNUD2H2V-5vrwT7TKelwQ2wclLcZxFs0E2Lk3Ld10U,9096
54
+ semantic_release/data/templates/conventional/rst/.components/macros.rst.j2,sha256=6XquxXKWNH-RQR5-D7JGFrDghGQUNqu7KE3mr8dJxt8,7299
55
55
  semantic_release/data/templates/conventional/rst/.components/unreleased_changes.rst.j2,sha256=ARBhc1ZpKwehGKDvOMqukmN59mTJiHzHsS7rOfKYCt8,202
56
56
  semantic_release/data/templates/conventional/rst/.components/versioned_changes.rst.j2,sha256=5THfdfYRjHNEQZVUDt112124hFEZxu7J4qIdgn54O1Q,553
57
57
  semantic_release/hvcs/__init__.py,sha256=JwoaLOF-12L-OBo_9-tOXXhdiHKeVungA9865to2oZk,494
@@ -73,8 +73,8 @@ semantic_release/version/declarations/enum.py,sha256=3n5Py9DoFkmItIdsmtQrJgmAhep
73
73
  semantic_release/version/declarations/i_version_replacer.py,sha256=oP6BxJuxwI44roI6448tomShv1sMoy9ry8TlhhIQtfc,2416
74
74
  semantic_release/version/declarations/pattern.py,sha256=MpUmsHYGAVAuFSKSb29FLcWeUCEHG_TRyhMO-2DWAAs,8308
75
75
  semantic_release/version/declarations/toml.py,sha256=2K4DtX5Qq1iHT8cG8mISPTMmp50w6Av0KmLAKZPYqq8,4931
76
- python_semantic_release-10.0.1.dist-info/METADATA,sha256=z8-uQWknrvrheWKsXOStSmdSKWCjeac5R-zCATki9tY,3913
77
- python_semantic_release-10.0.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
78
- python_semantic_release-10.0.1.dist-info/entry_points.txt,sha256=kzkCyDJsMOwgpFwEWKE9wxN1tXaUP6g6GIO4xtc0QuE,162
79
- python_semantic_release-10.0.1.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
80
- python_semantic_release-10.0.1.dist-info/RECORD,,
76
+ python_semantic_release-10.1.0.dist-info/METADATA,sha256=d1umjuI-8VC5XbF-PYRHyKCjrKcu84URpK3xqwbl1j0,3913
77
+ python_semantic_release-10.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
78
+ python_semantic_release-10.1.0.dist-info/entry_points.txt,sha256=kzkCyDJsMOwgpFwEWKE9wxN1tXaUP6g6GIO4xtc0QuE,162
79
+ python_semantic_release-10.1.0.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
80
+ python_semantic_release-10.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -269,7 +269,7 @@ def generate_release_notes(
269
269
  environment(autoescape=False, template_dir=tpl_dir)
270
270
  )
271
271
 
272
- # TODO: Remove in v10
272
+ # TODO: Remove in v11
273
273
  release_notes_env.globals["context"] = release_notes_env.globals["ctx"] = {
274
274
  "history": history,
275
275
  "mask_initial_release": mask_initial_release,
@@ -142,14 +142,10 @@ def apply_version_to_source_files(
142
142
  if not noop:
143
143
  logger.debug("Updating version %s in repository files...", version)
144
144
 
145
- paths = list(
146
- map(
147
- lambda decl, new_version=version, noop=noop: ( # type: ignore[misc]
148
- decl.update_file_w_version(new_version=new_version, noop=noop)
149
- ),
150
- version_declarations,
151
- )
152
- )
145
+ paths = [
146
+ decl.update_file_w_version(new_version=version, noop=noop)
147
+ for decl in version_declarations
148
+ ]
153
149
 
154
150
  repo_filepaths = [
155
151
  str(updated_file.relative_to(repo_dir))
@@ -650,10 +646,9 @@ def version( # noqa: C901
650
646
  credential_masker=runtime.masker,
651
647
  )
652
648
 
653
- # Preparing for committing changes
649
+ # Preparing for committing changes; we always stage files even if we're not committing them in order to support a two-stage commit
650
+ project.git_add(paths=all_paths_to_add, noop=opts.noop)
654
651
  if commit_changes:
655
- project.git_add(paths=all_paths_to_add, noop=opts.noop)
656
-
657
652
  # NOTE: If we haven't modified any source code then we skip trying to make a commit
658
653
  # and any tag that we apply will be to the HEAD commit (made outside of
659
654
  # running PSR
@@ -148,7 +148,7 @@ class DefaultChangelogTemplatesConfig(BaseModel):
148
148
 
149
149
 
150
150
  class ChangelogConfig(BaseModel):
151
- # TODO: BREAKING CHANGE v10, move to DefaultChangelogTemplatesConfig
151
+ # TODO: BREAKING CHANGE v11, move to DefaultChangelogTemplatesConfig
152
152
  changelog_file: str = ""
153
153
  """Deprecated! Moved to 'default_templates.changelog_file'"""
154
154
 
@@ -191,7 +191,7 @@ class ChangelogConfig(BaseModel):
191
191
 
192
192
  @model_validator(mode="after")
193
193
  def move_changelog_file(self) -> Self:
194
- # TODO: Remove this method in v10
194
+ # TODO: Remove this method in v11
195
195
  if not self.changelog_file:
196
196
  return self
197
197
 
@@ -441,7 +441,7 @@ class RawConfig(BaseModel):
441
441
  parser_opts_type = None
442
442
  # If the commit parser is a known one, pull the default options object from it
443
443
  if self.commit_parser in _known_commit_parsers:
444
- # TODO: BREAKING CHANGE v10
444
+ # TODO: BREAKING CHANGE v11
445
445
  # parser_opts_type = (
446
446
  # _known_commit_parsers[self.commit_parser]
447
447
  # .get_default_options()
@@ -454,7 +454,7 @@ class RawConfig(BaseModel):
454
454
  try:
455
455
  # if its a custom parser, try to import it and pull the default options object type
456
456
  custom_class = dynamic_import(self.commit_parser)
457
- # TODO: BREAKING CHANGE v10
457
+ # TODO: BREAKING CHANGE v11
458
458
  # parser_opts_type = custom_class.get_default_options().__class__
459
459
  if hasattr(custom_class, "parser_options"):
460
460
  parser_opts_type = custom_class.parser_options
@@ -695,7 +695,7 @@ class RuntimeContext:
695
695
  ) from err
696
696
 
697
697
  commit_parser_opts_class = commit_parser_cls.parser_options
698
- # TODO: Breaking change v10
698
+ # TODO: Breaking change v11
699
699
  # commit_parser_opts_class = commit_parser_cls.get_default_options().__class__
700
700
  try:
701
701
  commit_parser = commit_parser_cls(
@@ -74,7 +74,7 @@ class CommitParser(ABC, Generic[_TT, _OPTS]):
74
74
  options if options is not None else self.get_default_options()
75
75
  )
76
76
 
77
- # TODO: BREAKING CHANGE v10, add abstract method for all custom parsers
77
+ # TODO: BREAKING CHANGE v11, add abstract method for all custom parsers
78
78
  # @staticmethod
79
79
  # @abstractmethod
80
80
  def get_default_options(self) -> _OPTS:
@@ -94,11 +94,9 @@ class AngularParserOptions(ParserOptions):
94
94
  default_bump_level: LevelBump = LevelBump.NO_RELEASE
95
95
  """The minimum bump level to apply to valid commit message."""
96
96
 
97
- # TODO: breaking change v10, change default to True
98
97
  parse_squash_commits: bool = False
99
98
  """Toggle flag for whether or not to parse squash commits"""
100
99
 
101
- # TODO: breaking change v10, change default to True
102
100
  ignore_merge_commits: bool = False
103
101
  """Toggle flag for whether or not to ignore merge commits"""
104
102
 
@@ -236,15 +234,11 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
236
234
  ) -> dict[str, list[str]]:
237
235
  if (match := breaking_re.match(text)) and (brk_desc := match.group(1)):
238
236
  accumulator["breaking_descriptions"].append(brk_desc)
239
- # TODO: breaking change v10, removes breaking change footers from descriptions
240
- # return accumulator
241
237
 
242
238
  elif (match := self.notice_selector.match(text)) and (
243
239
  notice := match.group("notice")
244
240
  ):
245
241
  accumulator["notices"].append(notice)
246
- # TODO: breaking change v10, removes notice footers from descriptions
247
- # return accumulator
248
242
 
249
243
  elif match := self.issue_selector.search(text):
250
244
  # if match := self.issue_selector.search(text):
@@ -265,8 +259,6 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
265
259
  accumulator["linked_issues"] = sort_numerically(
266
260
  set(accumulator["linked_issues"]).union(new_issue_refs)
267
261
  )
268
- # TODO: breaking change v10, removes resolution footers from descriptions
269
- # return accumulator
270
262
 
271
263
  # Prevent appending duplicate descriptions
272
264
  if text not in accumulator["descriptions"]:
@@ -287,9 +279,6 @@ class AngularCommitParser(CommitParser[ParseResult, AngularParserOptions]):
287
279
  linked_merge_request = ""
288
280
  if mr_match := self.mr_selector.search(parsed_subject):
289
281
  linked_merge_request = mr_match.group("mr_number")
290
- # TODO: breaking change v10, removes PR number from subject/descriptions
291
- # expects changelog template to format the line accordingly
292
- # parsed_subject = self.pr_selector.sub("", parsed_subject).strip()
293
282
 
294
283
  body_components: dict[str, list[str]] = reduce(
295
284
  self.commit_body_components_separator,
@@ -145,7 +145,7 @@ class ScipyParserOptions(ParserOptions):
145
145
  one of these prefixes, it will not be considered a valid commit message.
146
146
  """
147
147
 
148
- # TODO: breaking v10, make consistent with AngularParserOptions
148
+ # TODO: breaking v11, make consistent with AngularParserOptions
149
149
  default_level_bump: LevelBump = LevelBump.NO_RELEASE
150
150
  """The minimum bump level to apply to valid commit message."""
151
151
 
@@ -161,7 +161,7 @@ class ScipyParserOptions(ParserOptions):
161
161
  return self._tag_to_level
162
162
 
163
163
  def __post_init__(self) -> None:
164
- # TODO: breaking v10, remove as the name is now consistent
164
+ # TODO: breaking v11, remove as the name is now consistent
165
165
  self.default_bump_level = self.default_level_bump
166
166
  self._tag_to_level: dict[str, LevelBump] = {
167
167
  str(tag): level
@@ -150,7 +150,7 @@ class ParsedCommit(NamedTuple):
150
150
  """A convience method to create a ParsedCommit object from a ParsedMessageResult object and a Commit object."""
151
151
  return ParsedCommit(
152
152
  bump=parsed_message_result.bump,
153
- # TODO: breaking v10, swap back to type rather than category
153
+ # TODO: breaking v11, swap back to type rather than category
154
154
  type=parsed_message_result.category,
155
155
  scope=parsed_message_result.scope,
156
156
  descriptions=list(parsed_message_result.descriptions),
@@ -6,7 +6,7 @@ from functools import reduce
6
6
  from re import MULTILINE, compile as regexp
7
7
  from typing import TYPE_CHECKING
8
8
 
9
- # TODO: remove in v10
9
+ # TODO: remove in v11
10
10
  from semantic_release.helpers import (
11
11
  sort_numerically, # noqa: F401 # TODO: maintained for compatibility
12
12
  )
@@ -6,41 +6,50 @@
6
6
  %}
7
7
 
8
8
 
9
+ {#
10
+ MACRO: Capitalize the first letter of a string only
11
+ #}{% macro capitalize_first_letter_only(sentence)
12
+ %}{{ (sentence[0] | upper) ~ sentence[1:]
13
+ }}{% endmacro
14
+ %}
15
+
16
+
9
17
  {#
10
18
  MACRO: commit message links or PR/MR links of commit
11
19
  #}{% macro commit_msg_links(commit)
12
20
  %}{% if commit.error is undefined
13
- %}{% set commit_hash_link = format_link(
14
- commit.hexsha | commit_hash_url,
15
- "`%s`" | format(commit.short_hash)
16
- )
17
21
  %}{#
18
- #}{% set summary_line = commit.descriptions[0] | safe
19
- %}{% set summary_line = [
20
- summary_line.split(" ", maxsplit=1)[0] | capitalize,
21
- summary_line.split(" ", maxsplit=1)[1]
22
- ] | join(" ")
22
+ # # Initialize variables
23
+ #}{% set link_references = []
24
+ %}{% set summary_line = capitalize_first_letter_only(
25
+ commit.descriptions[0] | safe
26
+ )
23
27
  %}{#
24
28
  #}{% if commit.linked_merge_request != ""
25
29
  %}{# # Add PR references with a link to the PR
26
- #}{% set pr_num = commit.linked_merge_request
27
- %}{% set pr_link = format_link(pr_num | pull_request_url, pr_num)
28
- %}{#
29
- # TODO: breaking change v10, remove summary line replacers as PSR will do it for us
30
- #}{% set summary_line = summary_line | replace("(pull request", "(") | replace("(" ~ pr_num ~ ")", "") | trim
31
- %}{% set summary_line = "%s (%s, %s)" | format(
32
- summary_line,
33
- pr_link,
34
- commit_hash_link,
30
+ #}{% set _ = link_references.append(
31
+ format_link(
32
+ commit.linked_merge_request | pull_request_url,
33
+ commit.linked_merge_request
34
+ )
35
35
  )
36
+ %}{% endif
37
+ %}{#
38
+ # # DEFAULT: Always include the commit hash as a link
39
+ #}{% set _ = link_references.append(
40
+ format_link(
41
+ commit.hexsha | commit_hash_url,
42
+ "`%s`" | format(commit.short_hash)
43
+ )
44
+ )
36
45
  %}{#
37
- # DEFAULT: No PR identifier found, so just append commit hash as url to the commit summary_line
38
- #}{% else
39
- %}{% set summary_line = "%s (%s)" | format(summary_line, commit_hash_link)
46
+ #}{% set formatted_links = ""
47
+ %}{% if link_references | length > 0
48
+ %}{% set formatted_links = " (%s)" | format(link_references | join(", "))
40
49
  %}{% endif
41
50
  %}{#
42
51
  # Return the modified summary_line
43
- #}{{ summary_line
52
+ #}{{ summary_line ~ formatted_links
44
53
  }}{% endif
45
54
  %}{% endmacro
46
55
  %}
@@ -71,24 +80,21 @@
71
80
 
72
81
 
73
82
  {#
74
- MACRO: format the breaking changes description by:
75
- - Capitalizing the description
83
+ MACRO: format a commit descriptions list by:
84
+ - Capitalizing the first line of the description
76
85
  - Adding an optional scope prefix
77
- #}{% macro format_breaking_changes_description(commit)
78
- %}{% set ns = namespace(full_description="")
86
+ - Joining the rest of the descriptions with a double newline
87
+ #}{% macro format_attr_paragraphs(commit, attribute)
88
+ %}{# NOTE: requires namespace because of the way Jinja2 handles variable scoping with loops
89
+ #}{% set ns = namespace(full_description="")
79
90
  %}{#
80
91
  #}{% if commit.error is undefined
81
- %}{% for paragraph in commit.breaking_descriptions
92
+ %}{% for paragraph in commit | attr(attribute)
82
93
  %}{% if paragraph | trim | length > 0
83
94
  %}{#
84
- #}{% set paragraph_text = [
85
- paragraph.split(" ", maxsplit=1)[0] | capitalize,
86
- paragraph.split(" ", maxsplit=1)[1]
87
- ] | join(" ") | trim | safe
88
- %}{#
89
95
  #}{% set ns.full_description = [
90
96
  ns.full_description,
91
- paragraph_text
97
+ capitalize_first_letter_only(paragraph) | trim | safe,
92
98
  ] | join("\n\n")
93
99
  %}{#
94
100
  #}{% endif
@@ -108,65 +114,48 @@
108
114
  %}
109
115
 
110
116
 
117
+ {#
118
+ MACRO: format the breaking changes description by:
119
+ - Capitalizing the description
120
+ - Adding an optional scope prefix
121
+ #}{% macro format_breaking_changes_description(commit)
122
+ %}{{ format_attr_paragraphs(commit, 'breaking_descriptions')
123
+ }}{% endmacro
124
+ %}
125
+
126
+
111
127
  {#
112
128
  MACRO: format the release notice by:
113
129
  - Capitalizing the description
114
130
  - Adding an optional scope prefix
115
131
  #}{% macro format_release_notice(commit)
116
- %}{% set ns = namespace(full_description="")
117
- %}{#
118
- #}{% if commit.error is undefined
119
- %}{% for paragraph in commit.release_notices
120
- %}{% if paragraph | trim | length > 0
121
- %}{#
122
- #}{% set paragraph_text = [
123
- paragraph.split(" ", maxsplit=1)[0] | capitalize,
124
- paragraph.split(" ", maxsplit=1)[1]
125
- ] | join(" ") | trim | safe
126
- %}{#
127
- #}{% set ns.full_description = [
128
- ns.full_description,
129
- paragraph_text
130
- ] | join("\n\n")
131
- %}{#
132
- #}{% endif
133
- %}{% endfor
134
- %}{#
135
- #}{% set ns.full_description = ns.full_description | trim
136
- %}{#
137
- #}{% if commit.scope
138
- %}{% set ns.full_description = "**%s**: %s" | format(
139
- commit.scope, ns.full_description
140
- )
141
- %}{% endif
142
- %}{% endif
143
- %}{#
144
- #}{{ ns.full_description
132
+ %}{{ format_attr_paragraphs(commit, "release_notices")
145
133
  }}{% endmacro
146
134
  %}
147
135
 
148
136
 
149
137
  {#
150
- MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
151
- - Commits are sorted based on the commit type and the commit message
152
- - Commits are grouped by the commit type
153
- - parameter: ns (namespace) object with a commits list
154
- - returns None but modifies the ns.commits list in place
155
- #}{% macro apply_alphabetical_ordering_by_descriptions(ns)
138
+ MACRO: order commits alphabetically by scope and attribute
139
+ - Commits are sorted based on scope and then the attribute alphabetically
140
+ - Commits without scope are placed first and sorted alphabetically by the attribute
141
+ - parameter: ns (namespace) object with a commits list
142
+ - parameter: attr (string) attribute to sort by
143
+ - returns None but modifies the ns.commits list in place
144
+ #}{% macro order_commits_alphabetically_by_scope_and_attr(ns, attr)
156
145
  %}{% set ordered_commits = []
157
146
  %}{#
158
147
  # # Eliminate any ParseError commits from input set
159
148
  #}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
160
149
  %}{#
161
- # # grab all commits with no scope and sort alphabetically by the first line of the commit message
162
- #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='descriptions.0')
163
- %}{{ ordered_commits.append(commit) | default("", true)
164
- }}{% endfor
150
+ # # grab all commits with no scope and sort alphabetically by attr
151
+ #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute=attr)
152
+ %}{% set _ = ordered_commits.append(commit)
153
+ %}{% endfor
165
154
  %}{#
166
- # # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
167
- #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,descriptions.0')
168
- %}{{ ordered_commits.append(commit) | default("", true)
169
- }}{% endfor
155
+ # # grab all commits with a scope and sort alphabetically by the scope and then attr
156
+ #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute=(['scope', attr] | join(",")))
157
+ %}{% set _ = ordered_commits.append(commit)
158
+ %}{% endfor
170
159
  %}{#
171
160
  # # Return the ordered commits
172
161
  #}{% set ns.commits = ordered_commits
@@ -174,6 +163,18 @@
174
163
  %}
175
164
 
176
165
 
166
+ {#
167
+ MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
168
+ - Commits are sorted based on the commit type and the commit message
169
+ - Commits are grouped by the commit type
170
+ - parameter: ns (namespace) object with a commits list
171
+ - returns None but modifies the ns.commits list in place
172
+ #}{% macro apply_alphabetical_ordering_by_descriptions(ns)
173
+ %}{% set _ = order_commits_alphabetically_by_scope_and_attr(ns, 'descriptions.0')
174
+ %}{% endmacro
175
+ %}
176
+
177
+
177
178
  {#
178
179
  MACRO: apply smart ordering of commits objects based on alphabetized breaking changes and then scopes
179
180
  - Commits are sorted based on the commit type and the commit message
@@ -181,23 +182,7 @@
181
182
  - parameter: ns (namespace) object with a commits list
182
183
  - returns None but modifies the ns.commits list in place
183
184
  #}{% macro apply_alphabetical_ordering_by_brk_descriptions(ns)
184
- %}{% set ordered_commits = []
185
- %}{#
186
- # # Eliminate any ParseError commits from input set
187
- #}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
188
- %}{#
189
- # # grab all commits with no scope and sort alphabetically by the first line of the commit message
190
- #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='breaking_descriptions.0')
191
- %}{{ ordered_commits.append(commit) | default("", true)
192
- }}{% endfor
193
- %}{#
194
- # # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
195
- #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,breaking_descriptions.0')
196
- %}{{ ordered_commits.append(commit) | default("", true)
197
- }}{% endfor
198
- %}{#
199
- # # Return the ordered commits
200
- #}{% set ns.commits = ordered_commits
185
+ %}{% set _ = order_commits_alphabetically_by_scope_and_attr(ns, 'breaking_descriptions.0')
201
186
  %}{% endmacro
202
187
  %}
203
188
 
@@ -209,22 +194,6 @@
209
194
  - parameter: ns (namespace) object with a commits list
210
195
  - returns None but modifies the ns.commits list in place
211
196
  #}{% macro apply_alphabetical_ordering_by_release_notices(ns)
212
- %}{% set ordered_commits = []
213
- %}{#
214
- # # Eliminate any ParseError commits from input set
215
- #}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
216
- %}{#
217
- # # grab all commits with no scope and sort alphabetically by the first line of the commit message
218
- #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='release_notices.0')
219
- %}{{ ordered_commits.append(commit) | default("", true)
220
- }}{% endfor
221
- %}{#
222
- # # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
223
- #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,release_notices.0')
224
- %}{{ ordered_commits.append(commit) | default("", true)
225
- }}{% endfor
226
- %}{#
227
- # # Return the ordered commits
228
- #}{% set ns.commits = ordered_commits
197
+ %}{% set _ = order_commits_alphabetically_by_scope_and_attr(ns, 'release_notices.0')
229
198
  %}{% endmacro
230
199
  %}
@@ -1,3 +1,11 @@
1
+ {#
2
+ MACRO: Capitalize the first letter of a string only
3
+ #}{% macro capitalize_first_letter_only(sentence)
4
+ %}{{ (sentence[0] | upper) ~ sentence[1:]
5
+ }}{% endmacro
6
+ %}
7
+
8
+
1
9
  {#
2
10
  MACRO: format a post-paragraph link reference in RST
3
11
  #}{% macro format_link_reference(link, label)
@@ -6,6 +14,49 @@
6
14
  %}
7
15
 
8
16
 
17
+ {# MACRO: generate a heading underline that matches the exact length of the header #}
18
+ {% macro generate_heading_underline(header, underline_char)
19
+ %}{% set header_underline = []
20
+ %}{% for _ in header
21
+ %}{% set __ = header_underline.append(underline_char)
22
+ %}{% endfor
23
+ %}{# # Print out the header underline
24
+ #}{{ header_underline | join
25
+ }}{% endmacro
26
+ %}
27
+
28
+
29
+ {#
30
+ MACRO: formats a commit message for a non-inline RST link for a commit hash and/or PR/MR
31
+ #}{% macro commit_msg_links(commit)
32
+ %}{% if commit.error is undefined
33
+ %}{#
34
+ # # Initialize variables
35
+ #}{% set link_references = []
36
+ %}{% set summary_line = capitalize_first_letter_only(
37
+ commit.descriptions[0] | safe
38
+ )
39
+ %}{#
40
+ #}{% if commit.linked_merge_request != ""
41
+ %}{# # Add PR/MR references with a link to the PR/MR
42
+ #}{% set _ = link_references.append("`%s`_" | format(commit.linked_merge_request))
43
+ %}{% endif
44
+ %}{#
45
+ # DEFAULT: Always include the commit hash as a link
46
+ #}{% set _ = link_references.append("`%s`_" | format(commit.short_hash))
47
+ %}{#
48
+ #}{% set formatted_links = ""
49
+ %}{% if link_references | length > 0
50
+ %}{% set formatted_links = " (%s)" | format(link_references | join(", "))
51
+ %}{% endif
52
+ %}{#
53
+ # Return the modified summary_line
54
+ #}{{ summary_line ~ formatted_links
55
+ }}{% endif
56
+ %}{% endmacro
57
+ %}
58
+
59
+
9
60
  {#
10
61
  MACRO: format commit summary line
11
62
  #}{% macro format_commit_summary_line(commit)
@@ -50,72 +101,21 @@
50
101
 
51
102
 
52
103
  {#
53
- MACRO: formats a commit message for a non-inline RST link for a commit hash and/or PR/MR
54
- #}{% macro commit_msg_links(commit, hvcs_type)
55
- %}{% if commit.error is undefined
56
- %}{% set commit_hash_link = "`%s`_" | format(commit.short_hash)
57
- %}{#
58
- #}{% set summary_line = commit.descriptions[0] | safe
59
- %}{% set summary_line = [
60
- summary_line.split(" ", maxsplit=1)[0] | capitalize,
61
- summary_line.split(" ", maxsplit=1)[1]
62
- ] | join(" ")
63
- %}{#
64
- #}{% if commit.linked_merge_request != ""
65
- %}{# # Add PR references with a link to the PR
66
- #}{% set pr_link = "`%s`_" | format(commit.linked_merge_request)
67
- %}{#
68
- # TODO: breaking change v10, remove summary line replacers as PSR will do it for us
69
- #}{% set summary_line = summary_line | replace("(pull request ", "(") | replace("(" ~ commit.linked_merge_request ~ ")", "") | trim
70
- %}{% set summary_line = "%s (%s, %s)" | format(
71
- summary_line,
72
- pr_link,
73
- commit_hash_link,
74
- )
75
- %}{#
76
- # DEFAULT: No PR identifier found, so just append a commit hash as url to the commit summary_line
77
- #}{% else
78
- %}{% set summary_line = "%s (%s)" | format(summary_line, commit_hash_link)
79
- %}{% endif
80
- %}{#
81
- # Return the modified summary_line
82
- #}{{ summary_line
83
- }}{% endif
84
- %}{% endmacro
85
- %}
86
-
87
-
88
- {# MACRO: generate a heading underline that matches the exact length of the header #}
89
- {% macro generate_heading_underline(header, underline_char)
90
- %}{% set header_underline = []
91
- %}{% for _ in header
92
- %}{{ header_underline.append(underline_char) | default("", true)
93
- }}{% endfor
94
- %}{# # Print out the header underline
95
- #}{{ header_underline | join
96
- }}{% endmacro
97
- %}
98
-
99
-
100
- {#
101
- MACRO: format the breaking changes description by:
102
- - Capitalizing the description
104
+ MACRO: format a commit descriptions list by:
105
+ - Capitalizing the first line of the description
103
106
  - Adding an optional scope prefix
104
- #}{% macro format_breaking_changes_description(commit)
105
- %}{% set ns = namespace(full_description="")
107
+ - Joining the rest of the descriptions with a double newline
108
+ #}{% macro format_attr_paragraphs(commit, attribute)
109
+ %}{# NOTE: requires namespace because of the way Jinja2 handles variable scoping with loops
110
+ #}{% set ns = namespace(full_description="")
106
111
  %}{#
107
112
  #}{% if commit.error is undefined
108
- %}{% for paragraph in commit.breaking_descriptions
113
+ %}{% for paragraph in commit | attr(attribute)
109
114
  %}{% if paragraph | trim | length > 0
110
115
  %}{#
111
- #}{% set paragraph_text = [
112
- paragraph.split(" ", maxsplit=1)[0] | capitalize,
113
- paragraph.split(" ", maxsplit=1)[1]
114
- ] | join(" ") | trim | safe
115
- %}{#
116
116
  #}{% set ns.full_description = [
117
117
  ns.full_description,
118
- paragraph_text
118
+ capitalize_first_letter_only(paragraph) | trim | safe,
119
119
  ] | join("\n\n")
120
120
  %}{#
121
121
  #}{% endif
@@ -135,65 +135,48 @@
135
135
  %}
136
136
 
137
137
 
138
+ {#
139
+ MACRO: format the breaking changes description by:
140
+ - Capitalizing the description
141
+ - Adding an optional scope prefix
142
+ #}{% macro format_breaking_changes_description(commit)
143
+ %}{{ format_attr_paragraphs(commit, 'breaking_descriptions')
144
+ }}{% endmacro
145
+ %}
146
+
147
+
138
148
  {#
139
149
  MACRO: format the release notice by:
140
150
  - Capitalizing the description
141
151
  - Adding an optional scope prefix
142
152
  #}{% macro format_release_notice(commit)
143
- %}{% set ns = namespace(full_description="")
144
- %}{#
145
- #}{% if commit.error is undefined
146
- %}{% for paragraph in commit.release_notices
147
- %}{% if paragraph | trim | length > 0
148
- %}{#
149
- #}{% set paragraph_text = [
150
- paragraph.split(" ", maxsplit=1)[0] | capitalize,
151
- paragraph.split(" ", maxsplit=1)[1]
152
- ] | join(" ") | trim | safe
153
- %}{#
154
- #}{% set ns.full_description = [
155
- ns.full_description,
156
- paragraph_text
157
- ] | join("\n\n")
158
- %}{#
159
- #}{% endif
160
- %}{% endfor
161
- %}{#
162
- #}{% set ns.full_description = ns.full_description | trim
163
- %}{#
164
- #}{% if commit.scope
165
- %}{% set ns.full_description = "**%s**: %s" | format(
166
- commit.scope, ns.full_description
167
- )
168
- %}{% endif
169
- %}{% endif
170
- %}{#
171
- #}{{ ns.full_description
153
+ %}{{ format_attr_paragraphs(commit, "release_notices")
172
154
  }}{% endmacro
173
155
  %}
174
156
 
175
157
 
176
158
  {#
177
- MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
178
- - Commits are sorted based on the commit type and the commit message
179
- - Commits are grouped by the commit type
180
- - parameter: ns (namespace) object with a commits list
181
- - returns None but modifies the ns.commits list in place
182
- #}{% macro apply_alphabetical_ordering_by_descriptions(ns)
159
+ MACRO: order commits alphabetically by scope and attribute
160
+ - Commits are sorted based on scope and then the attribute alphabetically
161
+ - Commits without scope are placed first and sorted alphabetically by the attribute
162
+ - parameter: ns (namespace) object with a commits list
163
+ - parameter: attr (string) attribute to sort by
164
+ - returns None but modifies the ns.commits list in place
165
+ #}{% macro order_commits_alphabetically_by_scope_and_attr(ns, attr)
183
166
  %}{% set ordered_commits = []
184
167
  %}{#
185
168
  # # Eliminate any ParseError commits from input set
186
169
  #}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
187
170
  %}{#
188
- # # grab all commits with no scope and sort alphabetically by the first line of the commit message
189
- #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='descriptions.0')
190
- %}{{ ordered_commits.append(commit) | default("", true)
191
- }}{% endfor
171
+ # # grab all commits with no scope and sort alphabetically by attr
172
+ #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute=attr)
173
+ %}{% set _ = ordered_commits.append(commit)
174
+ %}{% endfor
192
175
  %}{#
193
- # # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
194
- #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,descriptions.0')
195
- %}{{ ordered_commits.append(commit) | default("", true)
196
- }}{% endfor
176
+ # # grab all commits with a scope and sort alphabetically by the scope and then attr
177
+ #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute=(['scope', attr] | join(",")))
178
+ %}{% set _ = ordered_commits.append(commit)
179
+ %}{% endfor
197
180
  %}{#
198
181
  # # Return the ordered commits
199
182
  #}{% set ns.commits = ordered_commits
@@ -201,6 +184,18 @@
201
184
  %}
202
185
 
203
186
 
187
+ {#
188
+ MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
189
+ - Commits are sorted based on the commit type and the commit message
190
+ - Commits are grouped by the commit type
191
+ - parameter: ns (namespace) object with a commits list
192
+ - returns None but modifies the ns.commits list in place
193
+ #}{% macro apply_alphabetical_ordering_by_descriptions(ns)
194
+ %}{% set _ = order_commits_alphabetically_by_scope_and_attr(ns, 'descriptions.0')
195
+ %}{% endmacro
196
+ %}
197
+
198
+
204
199
  {#
205
200
  MACRO: apply smart ordering of commits objects based on alphabetized breaking changes and then scopes
206
201
  - Commits are sorted based on the commit type and the commit message
@@ -208,23 +203,7 @@
208
203
  - parameter: ns (namespace) object with a commits list
209
204
  - returns None but modifies the ns.commits list in place
210
205
  #}{% macro apply_alphabetical_ordering_by_brk_descriptions(ns)
211
- %}{% set ordered_commits = []
212
- %}{#
213
- # # Eliminate any ParseError commits from input set
214
- #}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
215
- %}{#
216
- # # grab all commits with no scope and sort alphabetically by the first line of the commit message
217
- #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='breaking_descriptions.0')
218
- %}{{ ordered_commits.append(commit) | default("", true)
219
- }}{% endfor
220
- %}{#
221
- # # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
222
- #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,breaking_descriptions.0')
223
- %}{{ ordered_commits.append(commit) | default("", true)
224
- }}{% endfor
225
- %}{#
226
- # # Return the ordered commits
227
- #}{% set ns.commits = ordered_commits
206
+ %}{% set _ = order_commits_alphabetically_by_scope_and_attr(ns, 'breaking_descriptions.0')
228
207
  %}{% endmacro
229
208
  %}
230
209
 
@@ -236,22 +215,6 @@
236
215
  - parameter: ns (namespace) object with a commits list
237
216
  - returns None but modifies the ns.commits list in place
238
217
  #}{% macro apply_alphabetical_ordering_by_release_notices(ns)
239
- %}{% set ordered_commits = []
240
- %}{#
241
- # # Eliminate any ParseError commits from input set
242
- #}{% set filtered_commits = ns.commits | rejectattr("error", "defined") | list
243
- %}{#
244
- # # grab all commits with no scope and sort alphabetically by the first line of the commit message
245
- #}{% for commit in filtered_commits | rejectattr("scope") | sort(attribute='release_notices.0')
246
- %}{{ ordered_commits.append(commit) | default("", true)
247
- }}{% endfor
248
- %}{#
249
- # # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
250
- #}{% for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,release_notices.0')
251
- %}{{ ordered_commits.append(commit) | default("", true)
252
- }}{% endfor
253
- %}{#
254
- # # Return the ordered commits
255
- #}{% set ns.commits = ordered_commits
218
+ %}{% set _ = order_commits_alphabetically_by_scope_and_attr(ns, 'release_notices.0')
256
219
  %}{% endmacro
257
220
  %}