python-semantic-release 9.2.2__tar.gz → 9.3.1__tar.gz

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.
Files changed (145) hide show
  1. {python-semantic-release-9.2.2/python_semantic_release.egg-info → python-semantic-release-9.3.1}/PKG-INFO +2 -2
  2. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/pyproject.toml +2 -2
  3. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1/python_semantic_release.egg-info}/PKG-INFO +2 -2
  4. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/python_semantic_release.egg-info/requires.txt +1 -1
  5. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/__init__.py +1 -1
  6. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/version.py +79 -86
  7. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/errors.py +7 -0
  8. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/version/algorithm.py +84 -60
  9. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/test_version.py +4 -4
  10. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/util.py +10 -5
  11. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/AUTHORS.rst +0 -0
  12. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/LICENSE +0 -0
  13. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/MANIFEST.in +0 -0
  14. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/README.rst +0 -0
  15. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/Makefile +0 -0
  16. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/algorithm.rst +0 -0
  17. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/automatic-releases/cronjobs.rst +0 -0
  18. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/automatic-releases/github-actions.rst +0 -0
  19. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/automatic-releases/index.rst +0 -0
  20. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/automatic-releases/travis.rst +0 -0
  21. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/changelog_templates.rst +0 -0
  22. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/commands.rst +0 -0
  23. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/commit-parsing.rst +0 -0
  24. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/conf.py +0 -0
  25. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/configuration.rst +0 -0
  26. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/contributing.rst +0 -0
  27. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/contributors.rst +0 -0
  28. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/github-action.rst +0 -0
  29. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/index.rst +0 -0
  30. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/make.bat +0 -0
  31. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/migrating_from_v7.rst +0 -0
  32. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/multibranch_releases.rst +0 -0
  33. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/strict_mode.rst +0 -0
  34. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/docs/troubleshooting.rst +0 -0
  35. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/python_semantic_release.egg-info/SOURCES.txt +0 -0
  36. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/python_semantic_release.egg-info/dependency_links.txt +0 -0
  37. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/python_semantic_release.egg-info/entry_points.txt +0 -0
  38. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/python_semantic_release.egg-info/top_level.txt +0 -0
  39. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/__main__.py +0 -0
  40. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/changelog/__init__.py +0 -0
  41. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/changelog/context.py +0 -0
  42. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/changelog/release_history.py +0 -0
  43. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/changelog/template.py +0 -0
  44. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/__init__.py +0 -0
  45. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/__init__.py +0 -0
  46. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/changelog.py +0 -0
  47. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/cli_context.py +0 -0
  48. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/generate_config.py +0 -0
  49. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/main.py +0 -0
  50. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/commands/publish.py +0 -0
  51. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/common.py +0 -0
  52. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/config.py +0 -0
  53. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/const.py +0 -0
  54. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/github_actions_output.py +0 -0
  55. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/masking_filter.py +0 -0
  56. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/cli/util.py +0 -0
  57. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/__init__.py +0 -0
  58. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/_base.py +0 -0
  59. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/angular.py +0 -0
  60. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/emoji.py +0 -0
  61. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/scipy.py +0 -0
  62. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/tag.py +0 -0
  63. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/token.py +0 -0
  64. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/commit_parser/util.py +0 -0
  65. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/const.py +0 -0
  66. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/data/templates/CHANGELOG.md.j2 +0 -0
  67. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/data/templates/release_notes.md.j2 +0 -0
  68. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/enums.py +0 -0
  69. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/helpers.py +0 -0
  70. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/__init__.py +0 -0
  71. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/_base.py +0 -0
  72. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/bitbucket.py +0 -0
  73. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/gitea.py +0 -0
  74. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/github.py +0 -0
  75. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/gitlab.py +0 -0
  76. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/token_auth.py +0 -0
  77. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/hvcs/util.py +0 -0
  78. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/version/__init__.py +0 -0
  79. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/version/declaration.py +0 -0
  80. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/version/translator.py +0 -0
  81. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/semantic_release/version/version.py +0 -0
  82. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/setup.cfg +0 -0
  83. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/__init__.py +0 -0
  84. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/__init__.py +0 -0
  85. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/conftest.py +0 -0
  86. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/test_changelog.py +0 -0
  87. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/test_generate_config.py +0 -0
  88. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/test_help.py +0 -0
  89. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/test_main.py +0 -0
  90. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/command_line/test_publish.py +0 -0
  91. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/conftest.py +0 -0
  92. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/const.py +0 -0
  93. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/__init__.py +0 -0
  94. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/commit_parsers.py +0 -0
  95. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/example_project.py +0 -0
  96. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/git_repo.py +0 -0
  97. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/__init__.py +0 -0
  98. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/git_flow/__init__.py +0 -0
  99. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/git_flow/repo_w_2_release_channels.py +0 -0
  100. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/git_flow/repo_w_3_release_channels.py +0 -0
  101. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/github_flow/__init__.py +0 -0
  102. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/github_flow/repo_w_release_channels.py +0 -0
  103. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/trunk_based_dev/__init__.py +0 -0
  104. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/trunk_based_dev/repo_w_no_tags.py +0 -0
  105. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/trunk_based_dev/repo_w_prereleases.py +0 -0
  106. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/repos/trunk_based_dev/repo_w_tags.py +0 -0
  107. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/fixtures/scipy.py +0 -0
  108. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/scenario/__init__.py +0 -0
  109. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/scenario/test_next_version.py +0 -0
  110. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/scenario/test_release_history.py +0 -0
  111. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/scenario/test_template_render.py +0 -0
  112. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/__init__.py +0 -0
  113. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/__init__.py +0 -0
  114. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/changelog/__init__.py +0 -0
  115. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/changelog/test_default_changelog.py +0 -0
  116. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/changelog/test_release_notes.py +0 -0
  117. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/changelog/test_template.py +0 -0
  118. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/cli/__init__.py +0 -0
  119. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/cli/test_config.py +0 -0
  120. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/cli/test_github_actions_output.py +0 -0
  121. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/cli/test_masking_filter.py +0 -0
  122. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/cli/test_util.py +0 -0
  123. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/cli/test_version.py +0 -0
  124. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/__init__.py +0 -0
  125. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/helper.py +0 -0
  126. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/test_angular.py +0 -0
  127. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/test_emoji.py +0 -0
  128. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/test_scipy.py +0 -0
  129. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/test_tag.py +0 -0
  130. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/test_token.py +0 -0
  131. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/commit_parser/test_util.py +0 -0
  132. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/__init__.py +0 -0
  133. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test__base.py +0 -0
  134. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test_bitbucket.py +0 -0
  135. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test_gitea.py +0 -0
  136. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test_github.py +0 -0
  137. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test_gitlab.py +0 -0
  138. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test_token_auth.py +0 -0
  139. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/hvcs/test_util.py +0 -0
  140. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/test_helpers.py +0 -0
  141. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/version/__init__.py +0 -0
  142. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/version/test_algorithm.py +0 -0
  143. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/version/test_declaration.py +0 -0
  144. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/version/test_translator.py +0 -0
  145. {python-semantic-release-9.2.2 → python-semantic-release-9.3.1}/tests/unit/semantic_release/version/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-semantic-release
3
- Version: 9.2.2
3
+ Version: 9.3.1
4
4
  Summary: Automatic Semantic Versioning for Python projects
5
5
  Author-email: Rolf Erik Lekang <me@rolflekang.com>
6
6
  License: MIT
@@ -53,7 +53,7 @@ Requires-Dist: types-pytest-lazy-fixture>=0.6.3.3; extra == "test"
53
53
  Provides-Extra: dev
54
54
  Requires-Dist: pre-commit; extra == "dev"
55
55
  Requires-Dist: tox; extra == "dev"
56
- Requires-Dist: ruff==0.3.2; extra == "dev"
56
+ Requires-Dist: ruff==0.3.3; extra == "dev"
57
57
  Provides-Extra: mypy
58
58
  Requires-Dist: mypy; extra == "mypy"
59
59
  Requires-Dist: types-requests; extra == "mypy"
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "python-semantic-release"
9
- version = "9.2.2"
9
+ version = "9.3.1"
10
10
  description = "Automatic Semantic Versioning for Python projects"
11
11
  requires-python = ">=3.8"
12
12
  license = { text = "MIT" }
@@ -68,7 +68,7 @@ test = [
68
68
  "requests-mock>=1.10.0,<2",
69
69
  "types-pytest-lazy-fixture>=0.6.3.3",
70
70
  ]
71
- dev = ["pre-commit", "tox", "ruff==0.3.2"]
71
+ dev = ["pre-commit", "tox", "ruff==0.3.3"]
72
72
  mypy = ["mypy", "types-requests"]
73
73
 
74
74
  [tool.pytest.ini_options]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-semantic-release
3
- Version: 9.2.2
3
+ Version: 9.3.1
4
4
  Summary: Automatic Semantic Versioning for Python projects
5
5
  Author-email: Rolf Erik Lekang <me@rolflekang.com>
6
6
  License: MIT
@@ -53,7 +53,7 @@ Requires-Dist: types-pytest-lazy-fixture>=0.6.3.3; extra == "test"
53
53
  Provides-Extra: dev
54
54
  Requires-Dist: pre-commit; extra == "dev"
55
55
  Requires-Dist: tox; extra == "dev"
56
- Requires-Dist: ruff==0.3.2; extra == "dev"
56
+ Requires-Dist: ruff==0.3.3; extra == "dev"
57
57
  Provides-Extra: mypy
58
58
  Requires-Dist: mypy; extra == "mypy"
59
59
  Requires-Dist: types-requests; extra == "mypy"
@@ -14,7 +14,7 @@ shellingham>=1.5.0.post1
14
14
  [dev]
15
15
  pre-commit
16
16
  tox
17
- ruff==0.3.2
17
+ ruff==0.3.3
18
18
 
19
19
  [docs]
20
20
  Sphinx<=6.0.0
@@ -24,7 +24,7 @@ from semantic_release.version import (
24
24
  tags_and_versions,
25
25
  )
26
26
 
27
- __version__ = "9.2.2"
27
+ __version__ = "9.3.1"
28
28
 
29
29
 
30
30
  def setup_hook(argv: list[str]) -> None:
@@ -375,13 +375,71 @@ def version( # noqa: C901
375
375
 
376
376
  rprint(f"[bold green]The next version is: [white]{new_version!s}[/white]! :rocket:")
377
377
 
378
+ rh = ReleaseHistory.from_git_history(
379
+ repo=repo,
380
+ translator=translator,
381
+ commit_parser=parser,
382
+ exclude_commit_patterns=changelog_excluded_commit_patterns,
383
+ )
384
+
385
+ commit_date = datetime.now()
386
+ try:
387
+ rh = rh.release(
388
+ new_version,
389
+ tagger=commit_author,
390
+ committer=commit_author,
391
+ tagged_date=commit_date,
392
+ )
393
+ except ValueError as ve:
394
+ ctx.fail(str(ve))
395
+
396
+ all_paths_to_add: list[str] = []
397
+
398
+ if update_changelog:
399
+ changelog_context = make_changelog_context(
400
+ hvcs_client=hvcs_client, release_history=rh
401
+ )
402
+ changelog_context.bind_to_environment(env)
403
+
404
+ if template_dir.is_dir():
405
+ if opts.noop:
406
+ noop_report(
407
+ f"would have recursively rendered the template directory "
408
+ f"{template_dir!r} relative to {repo.working_dir!r}. "
409
+ "Paths which would be modified by this operation cannot be "
410
+ "determined in no-op mode."
411
+ )
412
+ else:
413
+ all_paths_to_add.extend(
414
+ recursive_render(
415
+ template_dir, environment=env, _root_dir=repo.working_dir
416
+ )
417
+ )
418
+
419
+ else:
420
+ log.info(
421
+ "Path %r not found, using default changelog template", template_dir
422
+ )
423
+ if opts.noop:
424
+ noop_report(
425
+ "would have written your changelog to "
426
+ + str(changelog_file.relative_to(repo.working_dir))
427
+ )
428
+ else:
429
+ changelog_text = render_default_changelog_file(env)
430
+ changelog_file.write_text(f"{changelog_text}\n", encoding="utf-8")
431
+
432
+ all_paths_to_add.append(str(changelog_file.relative_to(repo.working_dir)))
433
+
434
+ # Apply the new version to the source files
378
435
  files_with_new_version_written = apply_version_to_source_files(
379
436
  repo=repo,
380
437
  version_declarations=runtime.version_declarations,
381
438
  version=new_version,
382
439
  noop=opts.noop,
383
440
  )
384
- all_paths_to_add = files_with_new_version_written + (assets or [])
441
+ all_paths_to_add.extend(files_with_new_version_written)
442
+ all_paths_to_add.extend(assets or [])
385
443
 
386
444
  # Build distributions before committing any changes - this way if the
387
445
  # build fails, modifications to the source code won't be committed
@@ -404,19 +462,11 @@ def version( # noqa: C901
404
462
 
405
463
  # Commit changes
406
464
  if commit_changes and opts.noop:
407
- # Indents the newlines so that terminal formatting is happy - note the
408
- # git commit line of the output is 24 spaces indented too
409
- # Only this message needs such special handling because of the newlines
410
- # that might be in a commit message between the subject and body
411
- indented_commit_message = commit_message.format(version=new_version).replace(
412
- "\n\n", "\n\n" + " " * 24
413
- )
414
465
  noop_report(
415
466
  indented(
416
467
  f"""
417
468
  would have run:
418
469
  git add {" ".join(all_paths_to_add)}
419
- git commit -m "{indented_commit_message}"
420
470
  """
421
471
  )
422
472
  )
@@ -432,80 +482,6 @@ def version( # noqa: C901
432
482
  except GitCommandError: # noqa: PERF203
433
483
  log.warning("Failed to add path (%s) to index", updated_path)
434
484
 
435
- rh = ReleaseHistory.from_git_history(
436
- repo=repo,
437
- translator=translator,
438
- commit_parser=parser,
439
- exclude_commit_patterns=changelog_excluded_commit_patterns,
440
- )
441
-
442
- commit_date = datetime.now()
443
- try:
444
- rh = rh.release(
445
- new_version,
446
- tagger=commit_author,
447
- committer=commit_author,
448
- tagged_date=commit_date,
449
- )
450
- except ValueError as ve:
451
- ctx.fail(str(ve))
452
-
453
- changelog_context = make_changelog_context(
454
- hvcs_client=hvcs_client, release_history=rh
455
- )
456
- changelog_context.bind_to_environment(env)
457
-
458
- updated_paths: list[str] = []
459
- if update_changelog:
460
- if template_dir.is_dir():
461
- if opts.noop:
462
- noop_report(
463
- f"would have recursively rendered the template directory "
464
- f"{template_dir!r} relative to {repo.working_dir!r}. "
465
- "Paths which would be modified by this operation cannot be "
466
- "determined in no-op mode."
467
- )
468
- else:
469
- updated_paths = recursive_render(
470
- template_dir, environment=env, _root_dir=repo.working_dir
471
- )
472
-
473
- else:
474
- log.info(
475
- "Path %r not found, using default changelog template", template_dir
476
- )
477
- if opts.noop:
478
- noop_report(
479
- "would have written your changelog to "
480
- + str(changelog_file.relative_to(repo.working_dir))
481
- )
482
- else:
483
- changelog_text = render_default_changelog_file(env)
484
- changelog_file.write_text(f"{changelog_text}\n", encoding="utf-8")
485
-
486
- updated_paths = [str(changelog_file.relative_to(repo.working_dir))]
487
-
488
- if commit_changes and opts.noop:
489
- noop_report(
490
- indented(
491
- f"""
492
- would have run:
493
- git add {" ".join(updated_paths)}
494
- """
495
- )
496
- )
497
- elif commit_changes:
498
- # Anything changed here should be staged.
499
- # TODO: in future this loop should be 1 line:
500
- # repo.index.add(updated_paths, force=False) # noqa: ERA001
501
- # but since 'force' is deliberally ineffective (as in docstring) in gitpython 3.1.18
502
- # we have to do manually add each filepath, and catch the exception if it is an ignored file
503
- for updated_path in updated_paths:
504
- try:
505
- repo.git.add(updated_path)
506
- except GitCommandError: # noqa: PERF203
507
- log.warning("Failed to add path (%s) to index", updated_path)
508
-
509
485
  def custom_git_environment() -> ContextManager[None]:
510
486
  """
511
487
  git.custom_environment is a context manager but
@@ -541,7 +517,16 @@ def version( # noqa: C901
541
517
  if commit_author
542
518
  else ""
543
519
  )
544
- command += "git commit -m '{commit_message.format(version=v)}'"
520
+
521
+ # Indents the newlines so that terminal formatting is happy - note the
522
+ # git commit line of the output is 24 spaces indented too
523
+ # Only this message needs such special handling because of the newlines
524
+ # that might be in a commit message between the subject and body
525
+ indented_commit_message = commit_message.format(version=new_version).replace(
526
+ "\n\n", "\n\n" + " " * 24
527
+ )
528
+
529
+ command += f"git commit -m '{indented_commit_message}'"
545
530
 
546
531
  noop_report(
547
532
  indented(
@@ -600,12 +585,17 @@ def version( # noqa: C901
600
585
  indented(
601
586
  f"""
602
587
  would have run:
603
- git push --tags {runtime.masker.mask(remote_url)} {active_branch}
588
+ git push {runtime.masker.mask(remote_url)} tag {new_version.as_tag()}
604
589
  """ # noqa: E501
605
590
  )
606
591
  )
607
592
  elif create_tag:
608
- repo.git.push("--tags", remote_url, active_branch)
593
+ # push specific tag refspec (that we made) to remote
594
+ # ---------------
595
+ # Resolves issue #803 where a tag that already existed was pushed and caused
596
+ # a failure. Its not clear why there was an incorrect tag (likely user error change)
597
+ # but we will avoid possibly pushing an separate tag that we didn't create.
598
+ repo.git.push(remote_url, "tag", new_version.as_tag())
609
599
 
610
600
  gha_output.released = True
611
601
 
@@ -619,6 +609,9 @@ def version( # noqa: C901
619
609
  # Use a new, non-configurable environment for release notes -
620
610
  # not user-configurable at the moment
621
611
  release_note_environment = environment(template_dir=runtime.template_dir)
612
+ changelog_context = make_changelog_context(
613
+ hvcs_client=hvcs_client, release_history=rh
614
+ )
622
615
  changelog_context.bind_to_environment(release_note_environment)
623
616
 
624
617
  template = get_release_notes_template(template_dir)
@@ -31,3 +31,10 @@ class CommitParseError(SemanticReleaseBaseError):
31
31
  Raised when a commit cannot be parsed by a commit parser. Custom commit parsers
32
32
  should also raise this Exception
33
33
  """
34
+
35
+
36
+ class MissingMergeBaseError(SemanticReleaseBaseError):
37
+ """
38
+ Raised when the merge base cannot be found with the current history. Generally
39
+ because of a shallow git clone.
40
+ """
@@ -4,12 +4,10 @@ import logging
4
4
  from queue import Queue
5
5
  from typing import TYPE_CHECKING, Iterable
6
6
 
7
- from semantic_release.commit_parser import (
8
- ParsedCommit,
9
- )
7
+ from semantic_release.commit_parser import ParsedCommit
10
8
  from semantic_release.const import DEFAULT_VERSION
11
9
  from semantic_release.enums import LevelBump
12
- from semantic_release.errors import InvalidVersion
10
+ from semantic_release.errors import InvalidVersion, MissingMergeBaseError
13
11
  from semantic_release.version.version import Version
14
12
 
15
13
  if TYPE_CHECKING:
@@ -278,9 +276,9 @@ def next_version(
278
276
  """
279
277
  # Step 1. All tags, sorted descending by semver ordering rules
280
278
  all_git_tags_as_versions = tags_and_versions(repo.tags, translator)
281
- all_full_release_tags_and_versions = [
282
- (t, v) for t, v in all_git_tags_as_versions if not v.is_prerelease
283
- ]
279
+ all_full_release_tags_and_versions = list(
280
+ filter(lambda t_v: not t_v[1].is_prerelease, all_git_tags_as_versions)
281
+ )
284
282
  log.info(
285
283
  "Found %s full releases (excluding prereleases)",
286
284
  len(all_full_release_tags_and_versions),
@@ -291,30 +289,59 @@ def next_version(
291
289
  iter(all_full_release_tags_and_versions),
292
290
  (None, translator.from_string(DEFAULT_VERSION)),
293
291
  )
294
- if latest_full_release_tag is None:
295
- # Workaround - we can safely scan the extra commits on this
296
- # branch if it's never been released, but we have no other
297
- # guarantees that other branches exist
298
- log.info(
299
- "No full releases have been made yet, the default version to use is %s",
300
- latest_full_release_version,
292
+
293
+ # we can safely scan the extra commits on this
294
+ # branch if it's never been released, but we have no other
295
+ # guarantees that other branches exist
296
+ # Note the merge_base might be on our current branch, it's not
297
+ # necessarily the merge base of the current branch with `main`
298
+ other_ref = (
299
+ repo.active_branch
300
+ if latest_full_release_tag is None
301
+ else latest_full_release_tag.name
302
+ )
303
+
304
+ # Conditional log message to inform what was chosen as the comparison point
305
+ # to find the merge base of the current branch with the latest full release
306
+ log_msg = (
307
+ str.join(
308
+ ", ",
309
+ [
310
+ "No full releases have been made yet",
311
+ f"the default version to use is {latest_full_release_version}",
312
+ ],
301
313
  )
302
- merge_bases = repo.merge_base(repo.active_branch, repo.active_branch)
303
- else:
304
- # Note the merge_base might be on our current branch, it's not
305
- # necessarily the merge base of the current branch with `main`
306
- log.info(
307
- "The last full release was %s, tagged as %r",
308
- latest_full_release_version,
309
- latest_full_release_tag,
314
+ if latest_full_release_tag is None
315
+ else str.join(
316
+ ", ",
317
+ [
318
+ f"The last full release was {latest_full_release_version}",
319
+ f"tagged as {latest_full_release_tag!r}",
320
+ ],
310
321
  )
311
- merge_bases = repo.merge_base(latest_full_release_tag.name, repo.active_branch)
322
+ )
323
+
324
+ log.info(log_msg)
325
+ merge_bases = repo.merge_base(other_ref, repo.active_branch)
326
+
327
+ if len(merge_bases) < 1:
328
+ raise MissingMergeBaseError(
329
+ f"Unable to find merge-base between {other_ref} and {repo.active_branch.name}"
330
+ )
331
+
312
332
  if len(merge_bases) > 1:
313
333
  raise NotImplementedError(
314
- "This branch has more than one merge-base with the "
315
- "latest version, which is not yet supported"
334
+ str.join(
335
+ " ",
336
+ [
337
+ "This branch has more than one merge-base with the",
338
+ "latest version, which is not yet supported",
339
+ ],
340
+ )
316
341
  )
342
+
317
343
  merge_base = merge_bases[0]
344
+
318
345
  if merge_base is None:
319
346
  str_tag_name = (
320
347
  "None" if latest_full_release_tag is None else latest_full_release_tag.name
@@ -350,6 +377,23 @@ def next_version(
350
377
  tag_format=translator.tag_format,
351
378
  )
352
379
 
380
+ # We only include pre-releases here if doing a prerelease.
381
+ # If it's not a prerelease, we need to include commits back
382
+ # to the last full version in consideration for what kind of
383
+ # bump to produce. However if we're doing a prerelease, we can
384
+ # include prereleases here to potentially consider a smaller portion
385
+ # of history (from a prerelease since the last full release, onwards)
386
+
387
+ # Note that a side-effect of this is, if at some point the configuration
388
+ # for a particular branch pattern changes w.r.t. prerelease=True/False,
389
+ # the new kind of version will be produced from the commits already
390
+ # included in a prerelease since the last full release on the branch
391
+ tag_sha_2_version_lookup = {
392
+ tag.commit.hexsha: (tag, version)
393
+ for tag, version in all_git_tags_as_versions
394
+ if prerelease or not version.is_prerelease
395
+ }
396
+
353
397
  # N.B. these should be sorted so long as we iterate the commits in reverse order
354
398
  for commit in commits_since_last_full_release:
355
399
  parse_result = commit_parser.parse(commit)
@@ -360,44 +404,24 @@ def next_version(
360
404
  )
361
405
  parsed_levels.add(parse_result.bump)
362
406
 
363
- # We only include pre-releases here if doing a prerelease.
364
- # If it's not a prerelease, we need to include commits back
365
- # to the last full version in consideration for what kind of
366
- # bump to produce. However if we're doing a prerelease, we can
367
- # include prereleases here to potentially consider a smaller portion
368
- # of history (from a prerelease since the last full release, onwards)
369
-
370
- # Note that a side-effect of this is, if at some point the configuration
371
- # for a particular branch pattern changes w.r.t. prerelease=True/False,
372
- # the new kind of version will be produced from the commits already
373
- # included in a prerelease since the last full release on the branch
374
- for tag, version in (
375
- (tag, version)
376
- for tag, version in all_git_tags_as_versions
377
- if prerelease or not version.is_prerelease
378
- ):
379
- log.debug(
380
- "testing if tag %r (%s) matches commit %s",
381
- tag.name,
382
- tag.commit.hexsha,
383
- commit.hexsha,
384
- )
385
- if tag.commit == commit:
386
- latest_version = version
387
- log.debug(
388
- "tag %r (%s) matches commit %s. the latest version is %s",
389
- tag.name,
390
- tag.commit.hexsha,
391
- commit.hexsha,
392
- latest_version,
393
- )
394
- break
395
- else:
407
+ log.debug("checking if commit %s matches any tags", commit.hexsha)
408
+ t_v = tag_sha_2_version_lookup.get(commit.hexsha, None)
409
+
410
+ if t_v is None:
396
411
  # If we haven't found the latest prerelease on the branch,
397
- # keep the outer loop going to look for it
412
+ # keep the loop going to look for it
398
413
  log.debug("no tags correspond to commit %s", commit.hexsha)
399
414
  continue
400
- # If we found it in the inner loop, break the outer loop too
415
+
416
+ # Unpack the tuple
417
+ tag, latest_version = t_v
418
+ log.debug(
419
+ "tag %r (%s) matches commit %s. the latest version is %s",
420
+ tag.name,
421
+ tag.commit.hexsha,
422
+ commit.hexsha,
423
+ latest_version,
424
+ )
401
425
  break
402
426
 
403
427
  log.debug(
@@ -672,18 +672,19 @@ def test_version_tag_only_push(
672
672
  def test_version_only_update_files_no_git_actions(
673
673
  mocked_git_push: MagicMock,
674
674
  repo_with_single_branch_and_prereleases_angular_commits: Repo,
675
- use_release_notes_template: UseReleaseNotesTemplateFn,
676
675
  retrieve_runtime_context: RetrieveRuntimeContextFn,
677
676
  cli_runner: CliRunner,
678
677
  tmp_path_factory: pytest.TempPathFactory,
679
678
  example_pyproject_toml: Path,
680
679
  example_project_dir: ExProjectDir,
680
+ example_changelog_md: Path,
681
681
  ) -> None:
682
682
  # Setup
683
- use_release_notes_template()
684
683
  runtime_context_with_tags = retrieve_runtime_context(
685
684
  repo_with_single_branch_and_prereleases_angular_commits
686
685
  )
686
+ # Remove the previously created changelog to allow for it to be generated
687
+ example_changelog_md.unlink()
687
688
 
688
689
  # Arrange
689
690
  expected_new_version = "0.3.0"
@@ -718,8 +719,7 @@ def test_version_only_update_files_no_git_actions(
718
719
  # Files that should receive version change
719
720
  expected_changed_files = sorted(
720
721
  [
721
- # CHANGELOG.md is not included as no modification to Git History
722
- # (no commit or tag) has been made
722
+ "CHANGELOG.md",
723
723
  "pyproject.toml",
724
724
  f"src/{EXAMPLE_PROJECT_NAME}/_version.py",
725
725
  ]
@@ -106,11 +106,16 @@ def netrc_file(machine: str) -> NamedTemporaryFile:
106
106
 
107
107
 
108
108
  def flatten_dircmp(dcmp: filecmp.dircmp) -> list[str]:
109
- return dcmp.diff_files + [
110
- os.sep.join((directory, file))
111
- for directory, cmp in dcmp.subdirs.items()
112
- for file in flatten_dircmp(cmp)
113
- ]
109
+ return (
110
+ dcmp.diff_files
111
+ + dcmp.left_only
112
+ + dcmp.right_only
113
+ + [
114
+ os.sep.join((directory, file))
115
+ for directory, cmp in dcmp.subdirs.items()
116
+ for file in flatten_dircmp(cmp)
117
+ ]
118
+ )
114
119
 
115
120
 
116
121
  def xdist_sort_hack(it: Iterable[_R]) -> Iterable[_R]: