python-semantic-release 9.8.3__tar.gz → 9.8.5__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 (155) hide show
  1. {python_semantic_release-9.8.3/python_semantic_release.egg-info → python_semantic_release-9.8.5}/PKG-INFO +4 -4
  2. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/configuration.rst +1 -1
  3. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/pyproject.toml +13 -8
  4. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5/python_semantic_release.egg-info}/PKG-INFO +4 -4
  5. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/python_semantic_release.egg-info/SOURCES.txt +3 -2
  6. python_semantic_release-9.8.5/python_semantic_release.egg-info/entry_points.txt +3 -0
  7. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/python_semantic_release.egg-info/requires.txt +3 -3
  8. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/__init__.py +20 -2
  9. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/__main__.py +1 -1
  10. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/changelog/context.py +25 -1
  11. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/changelog/release_history.py +46 -38
  12. python_semantic_release-9.8.5/semantic_release/cli/changelog_writer.py +169 -0
  13. {python_semantic_release-9.8.3/semantic_release/cli/commands → python_semantic_release-9.8.5/semantic_release/cli}/cli_context.py +34 -10
  14. python_semantic_release-9.8.5/semantic_release/cli/commands/changelog.py +129 -0
  15. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/commands/main.py +32 -2
  16. python_semantic_release-9.8.5/semantic_release/cli/commands/publish.py +101 -0
  17. python_semantic_release-9.8.5/semantic_release/cli/commands/version.py +748 -0
  18. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/config.py +67 -23
  19. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/_base.py +2 -1
  20. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/scipy.py +10 -1
  21. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/errors.py +33 -1
  22. python_semantic_release-9.8.5/semantic_release/gitproject.py +254 -0
  23. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/bitbucket.py +3 -2
  24. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/gitea.py +26 -1
  25. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/github.py +26 -1
  26. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/gitlab.py +8 -1
  27. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/remote_hvcs_base.py +2 -1
  28. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/version/algorithm.py +1 -1
  29. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/command_line/conftest.py +2 -2
  30. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/command_line/test_changelog.py +155 -33
  31. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/command_line/test_generate_config.py +22 -7
  32. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/command_line/test_help.py +21 -15
  33. python_semantic_release-9.8.5/tests/command_line/test_main.py +219 -0
  34. python_semantic_release-9.8.5/tests/command_line/test_publish.py +81 -0
  35. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/command_line/test_version.py +378 -143
  36. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/conftest.py +2 -2
  37. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/const.py +8 -0
  38. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/scenario/test_release_history.py +35 -18
  39. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/scenario/test_template_render.py +1 -1
  40. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test__base.py +5 -4
  41. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test_gitlab.py +1 -1
  42. python_semantic_release-9.8.5/tests/unit/semantic_release/version/__init__.py +0 -0
  43. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/version/test_declaration.py +10 -5
  44. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/util.py +63 -11
  45. python_semantic_release-9.8.3/python_semantic_release.egg-info/entry_points.txt +0 -3
  46. python_semantic_release-9.8.3/semantic_release/cli/__init__.py +0 -10
  47. python_semantic_release-9.8.3/semantic_release/cli/commands/changelog.py +0 -121
  48. python_semantic_release-9.8.3/semantic_release/cli/commands/publish.py +0 -66
  49. python_semantic_release-9.8.3/semantic_release/cli/commands/version.py +0 -782
  50. python_semantic_release-9.8.3/semantic_release/cli/common.py +0 -50
  51. python_semantic_release-9.8.3/tests/command_line/test_main.py +0 -170
  52. python_semantic_release-9.8.3/tests/command_line/test_publish.py +0 -37
  53. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/AUTHORS.rst +0 -0
  54. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/LICENSE +0 -0
  55. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/MANIFEST.in +0 -0
  56. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/README.rst +0 -0
  57. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/Makefile +0 -0
  58. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/algorithm.rst +0 -0
  59. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/automatic-releases/cronjobs.rst +0 -0
  60. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/automatic-releases/github-actions.rst +0 -0
  61. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/automatic-releases/index.rst +0 -0
  62. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/automatic-releases/travis.rst +0 -0
  63. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/changelog_templates.rst +0 -0
  64. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/commands.rst +0 -0
  65. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/commit-parsing.rst +0 -0
  66. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/conf.py +0 -0
  67. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/contributing.rst +0 -0
  68. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/contributors.rst +0 -0
  69. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/github-action.rst +0 -0
  70. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/index.rst +0 -0
  71. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/make.bat +0 -0
  72. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/migrating_from_v7.rst +0 -0
  73. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/multibranch_releases.rst +0 -0
  74. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/strict_mode.rst +0 -0
  75. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/docs/troubleshooting.rst +0 -0
  76. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/python_semantic_release.egg-info/dependency_links.txt +0 -0
  77. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/python_semantic_release.egg-info/top_level.txt +0 -0
  78. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/changelog/__init__.py +0 -0
  79. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/changelog/template.py +0 -0
  80. {python_semantic_release-9.8.3/semantic_release/cli/commands → python_semantic_release-9.8.5/semantic_release/cli}/__init__.py +0 -0
  81. {python_semantic_release-9.8.3/tests → python_semantic_release-9.8.5/semantic_release/cli/commands}/__init__.py +0 -0
  82. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/commands/generate_config.py +0 -0
  83. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/const.py +0 -0
  84. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/github_actions_output.py +0 -0
  85. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/masking_filter.py +0 -0
  86. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/cli/util.py +0 -0
  87. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/__init__.py +0 -0
  88. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/angular.py +0 -0
  89. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/emoji.py +0 -0
  90. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/tag.py +0 -0
  91. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/token.py +0 -0
  92. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/commit_parser/util.py +0 -0
  93. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/const.py +0 -0
  94. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/data/templates/CHANGELOG.md.j2 +0 -0
  95. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/data/templates/release_notes.md.j2 +0 -0
  96. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/enums.py +0 -0
  97. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/helpers.py +0 -0
  98. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/__init__.py +0 -0
  99. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/_base.py +0 -0
  100. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/token_auth.py +0 -0
  101. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/hvcs/util.py +0 -0
  102. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/version/__init__.py +0 -0
  103. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/version/declaration.py +0 -0
  104. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/version/translator.py +0 -0
  105. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/semantic_release/version/version.py +0 -0
  106. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/setup.cfg +0 -0
  107. {python_semantic_release-9.8.3/tests/command_line → python_semantic_release-9.8.5/tests}/__init__.py +0 -0
  108. {python_semantic_release-9.8.3/tests/scenario → python_semantic_release-9.8.5/tests/command_line}/__init__.py +0 -0
  109. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/__init__.py +0 -0
  110. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/commit_parsers.py +0 -0
  111. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/example_project.py +0 -0
  112. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/git_repo.py +0 -0
  113. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/__init__.py +0 -0
  114. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/git_flow/__init__.py +0 -0
  115. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/git_flow/repo_w_2_release_channels.py +0 -0
  116. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/git_flow/repo_w_3_release_channels.py +0 -0
  117. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/github_flow/__init__.py +0 -0
  118. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/github_flow/repo_w_release_channels.py +0 -0
  119. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/trunk_based_dev/__init__.py +0 -0
  120. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/trunk_based_dev/repo_w_no_tags.py +0 -0
  121. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/trunk_based_dev/repo_w_prereleases.py +0 -0
  122. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/repos/trunk_based_dev/repo_w_tags.py +0 -0
  123. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/fixtures/scipy.py +0 -0
  124. {python_semantic_release-9.8.3/tests/unit → python_semantic_release-9.8.5/tests/scenario}/__init__.py +0 -0
  125. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/scenario/test_next_version.py +0 -0
  126. {python_semantic_release-9.8.3/tests/unit/semantic_release → python_semantic_release-9.8.5/tests/unit}/__init__.py +0 -0
  127. {python_semantic_release-9.8.3/tests/unit/semantic_release/changelog → python_semantic_release-9.8.5/tests/unit/semantic_release}/__init__.py +0 -0
  128. {python_semantic_release-9.8.3/tests/unit/semantic_release/cli → python_semantic_release-9.8.5/tests/unit/semantic_release/changelog}/__init__.py +0 -0
  129. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/changelog/test_changelog_context.py +0 -0
  130. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/changelog/test_default_changelog.py +0 -0
  131. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/changelog/test_release_notes.py +0 -0
  132. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/changelog/test_template.py +0 -0
  133. {python_semantic_release-9.8.3/tests/unit/semantic_release/commit_parser → python_semantic_release-9.8.5/tests/unit/semantic_release/cli}/__init__.py +0 -0
  134. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/cli/test_config.py +0 -0
  135. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/cli/test_github_actions_output.py +0 -0
  136. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/cli/test_masking_filter.py +0 -0
  137. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/cli/test_util.py +0 -0
  138. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/cli/test_version.py +0 -0
  139. {python_semantic_release-9.8.3/tests/unit/semantic_release/hvcs → python_semantic_release-9.8.5/tests/unit/semantic_release/commit_parser}/__init__.py +0 -0
  140. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/commit_parser/test_angular.py +0 -0
  141. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/commit_parser/test_emoji.py +0 -0
  142. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/commit_parser/test_parsed_commit.py +0 -0
  143. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/commit_parser/test_scipy.py +0 -0
  144. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/commit_parser/test_tag.py +0 -0
  145. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/commit_parser/test_util.py +0 -0
  146. {python_semantic_release-9.8.3/tests/unit/semantic_release/version → python_semantic_release-9.8.5/tests/unit/semantic_release/hvcs}/__init__.py +0 -0
  147. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test_bitbucket.py +0 -0
  148. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test_gitea.py +0 -0
  149. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test_github.py +0 -0
  150. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test_token_auth.py +0 -0
  151. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/hvcs/test_util.py +0 -0
  152. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/test_helpers.py +0 -0
  153. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/version/test_algorithm.py +0 -0
  154. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/tests/unit/semantic_release/version/test_translator.py +0 -0
  155. {python_semantic_release-9.8.3 → python_semantic_release-9.8.5}/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.8.3
3
+ Version: 9.8.5
4
4
  Summary: Automatic Semantic Versioning for Python projects
5
5
  Author-email: Rolf Erik Lekang <me@rolflekang.com>
6
6
  License: MIT
@@ -55,10 +55,10 @@ Requires-Dist: types-pytest-lazy-fixture~=0.6.3; extra == "test"
55
55
  Provides-Extra: dev
56
56
  Requires-Dist: pre-commit~=3.5; extra == "dev"
57
57
  Requires-Dist: tox~=4.11; extra == "dev"
58
- Requires-Dist: ruff==0.4.9; extra == "dev"
58
+ Requires-Dist: ruff==0.5.0; extra == "dev"
59
59
  Provides-Extra: mypy
60
- Requires-Dist: mypy==1.10.0; extra == "mypy"
61
- Requires-Dist: types-requests~=2.31.0; extra == "mypy"
60
+ Requires-Dist: mypy==1.10.1; extra == "mypy"
61
+ Requires-Dist: types-requests~=2.32.0; extra == "mypy"
62
62
 
63
63
  Python Semantic Release
64
64
  ***********************
@@ -107,7 +107,7 @@ If a setting is not provided, than PSR will fill in the value with the default v
107
107
  Python Semantic Release expects a root level key to start the configuration definition. Make
108
108
  sure to use the correct root key dependending on the configuration format you are using.
109
109
 
110
- .. note:: If you are using ``pyproject.toml``, this heading should include the `tool`` prefix
110
+ .. note:: If you are using ``pyproject.toml``, this heading should include the ``tool`` prefix
111
111
  as specified within PEP 517, resulting in ``[tool.semantic_release]``.
112
112
 
113
113
  .. note:: If you are using a ``releaserc.toml``, use ``[semantic_release]`` as the root key
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "python-semantic-release"
9
- version = "9.8.3"
9
+ version = "9.8.5"
10
10
  description = "Automatic Semantic Versioning for Python projects"
11
11
  requires-python = ">=3.8"
12
12
  license = { text = "MIT" }
@@ -37,8 +37,8 @@ dependencies = [
37
37
  ]
38
38
 
39
39
  [project.scripts]
40
- semantic-release = "semantic_release.cli:main"
41
- psr = "semantic_release.cli:main"
40
+ semantic-release = "semantic_release.cli.commands.main:main"
41
+ psr = "semantic_release.cli.commands.main:main"
42
42
 
43
43
  [project.urls]
44
44
  changelog = "https://github.com/python-semantic-release/python-semantic-release/blob/master/CHANGELOG.md"
@@ -74,11 +74,11 @@ test = [
74
74
  dev = [
75
75
  "pre-commit ~= 3.5",
76
76
  "tox ~= 4.11",
77
- "ruff == 0.4.9"
77
+ "ruff == 0.5.0"
78
78
  ]
79
79
  mypy = [
80
- "mypy == 1.10.0",
81
- "types-requests ~= 2.31.0"
80
+ "mypy == 1.10.1",
81
+ "types-requests ~= 2.32.0",
82
82
  ]
83
83
 
84
84
  [tool.pytest.ini_options]
@@ -156,6 +156,7 @@ show_error_context = true
156
156
  pretty = true
157
157
  error_summary = true
158
158
  follow_imports = "normal"
159
+ enable_error_code = ["ignore-without-code"]
159
160
  ignore_missing_imports = true # gitpython is very dynamic
160
161
  disallow_untyped_calls = true
161
162
  # warn_return_any = true
@@ -222,6 +223,8 @@ ignore = [
222
223
  "DTZ",
223
224
  # flake8-errmsg
224
225
  "EM",
226
+ # Some todos and some examples; leave this disabled for now
227
+ "ERA001",
225
228
  # don't compare types, use isinstance()
226
229
  # sometimes using type(x) == y is deliberately chosen to exclude
227
230
  # subclasses
@@ -234,6 +237,8 @@ ignore = [
234
237
  "INP001",
235
238
  # Errors should end with "Error"
236
239
  "N818",
240
+ # mypy prevents blanket-type-ignore
241
+ "PGH003",
237
242
  # Fixtures that do not return a value need an underscore prefix. The rule
238
243
  # does not handle generators.
239
244
  "PT004",
@@ -282,13 +287,13 @@ ignore = [
282
287
  ]
283
288
 
284
289
  external = ["V"]
285
- ignore-init-module-imports = true
286
290
  task-tags = ["NOTE", "TODO", "FIXME", "XXX"]
287
291
 
288
292
  [tool.ruff.format]
289
- quote-style = "double"
293
+ docstring-code-format = true
290
294
  indent-style = "space"
291
295
  line-ending = "lf"
296
+ quote-style = "double"
292
297
 
293
298
  [tool.ruff.lint.per-file-ignores]
294
299
  # Imported but unused
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-semantic-release
3
- Version: 9.8.3
3
+ Version: 9.8.5
4
4
  Summary: Automatic Semantic Versioning for Python projects
5
5
  Author-email: Rolf Erik Lekang <me@rolflekang.com>
6
6
  License: MIT
@@ -55,10 +55,10 @@ Requires-Dist: types-pytest-lazy-fixture~=0.6.3; extra == "test"
55
55
  Provides-Extra: dev
56
56
  Requires-Dist: pre-commit~=3.5; extra == "dev"
57
57
  Requires-Dist: tox~=4.11; extra == "dev"
58
- Requires-Dist: ruff==0.4.9; extra == "dev"
58
+ Requires-Dist: ruff==0.5.0; extra == "dev"
59
59
  Provides-Extra: mypy
60
- Requires-Dist: mypy==1.10.0; extra == "mypy"
61
- Requires-Dist: types-requests~=2.31.0; extra == "mypy"
60
+ Requires-Dist: mypy==1.10.1; extra == "mypy"
61
+ Requires-Dist: types-requests~=2.32.0; extra == "mypy"
62
62
 
63
63
  Python Semantic Release
64
64
  ***********************
@@ -36,13 +36,15 @@ semantic_release/__main__.py
36
36
  semantic_release/const.py
37
37
  semantic_release/enums.py
38
38
  semantic_release/errors.py
39
+ semantic_release/gitproject.py
39
40
  semantic_release/helpers.py
40
41
  semantic_release/changelog/__init__.py
41
42
  semantic_release/changelog/context.py
42
43
  semantic_release/changelog/release_history.py
43
44
  semantic_release/changelog/template.py
44
45
  semantic_release/cli/__init__.py
45
- semantic_release/cli/common.py
46
+ semantic_release/cli/changelog_writer.py
47
+ semantic_release/cli/cli_context.py
46
48
  semantic_release/cli/config.py
47
49
  semantic_release/cli/const.py
48
50
  semantic_release/cli/github_actions_output.py
@@ -50,7 +52,6 @@ semantic_release/cli/masking_filter.py
50
52
  semantic_release/cli/util.py
51
53
  semantic_release/cli/commands/__init__.py
52
54
  semantic_release/cli/commands/changelog.py
53
- semantic_release/cli/commands/cli_context.py
54
55
  semantic_release/cli/commands/generate_config.py
55
56
  semantic_release/cli/commands/main.py
56
57
  semantic_release/cli/commands/publish.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ psr = semantic_release.cli.commands.main:main
3
+ semantic-release = semantic_release.cli.commands.main:main
@@ -17,7 +17,7 @@ build~=1.2
17
17
  [dev]
18
18
  pre-commit~=3.5
19
19
  tox~=4.11
20
- ruff==0.4.9
20
+ ruff==0.5.0
21
21
 
22
22
  [docs]
23
23
  Sphinx~=6.0
@@ -26,8 +26,8 @@ sphinx-autobuild==2024.2.4
26
26
  furo~=2024.1
27
27
 
28
28
  [mypy]
29
- mypy==1.10.0
30
- types-requests~=2.31.0
29
+ mypy==1.10.1
30
+ types-requests~=2.32.0
31
31
 
32
32
  [test]
33
33
  coverage[toml]~=7.0
@@ -24,7 +24,25 @@ from semantic_release.version import (
24
24
  tags_and_versions,
25
25
  )
26
26
 
27
- __version__ = "9.8.3"
27
+ __version__ = "9.8.5"
28
+
29
+ __all__ = [
30
+ "CommitParser",
31
+ "ParsedCommit",
32
+ "ParseError",
33
+ "ParseResult",
34
+ "ParseResultType",
35
+ "ParserOptions",
36
+ "LevelBump",
37
+ "SemanticReleaseBaseError",
38
+ "CommitParseError",
39
+ "InvalidConfiguration",
40
+ "InvalidVersion",
41
+ "Version",
42
+ "VersionTranslator",
43
+ "next_version",
44
+ "tags_and_versions",
45
+ ]
28
46
 
29
47
 
30
48
  def setup_hook(argv: list[str]) -> None:
@@ -36,6 +54,6 @@ def setup_hook(argv: list[str]) -> None:
36
54
  if len(argv) > 1 and any(
37
55
  cmd in argv for cmd in ["version", "publish", "changelog"]
38
56
  ):
39
- from semantic_release.cli import main
57
+ from semantic_release.cli.commands.main import main
40
58
 
41
59
  main()
@@ -1,6 +1,6 @@
1
1
  import sys
2
2
 
3
- from semantic_release.cli import main
3
+ from semantic_release.cli.commands.main import main
4
4
 
5
5
  if __name__ == "__main__":
6
6
  main(args=sys.argv[1:])
@@ -6,8 +6,32 @@ from typing import TYPE_CHECKING, Any, Callable
6
6
  if TYPE_CHECKING:
7
7
  from jinja2 import Environment
8
8
 
9
- from semantic_release.changelog.release_history import ReleaseHistory
9
+ from semantic_release.changelog.release_history import Release, ReleaseHistory
10
10
  from semantic_release.hvcs._base import HvcsBase
11
+ from semantic_release.version.version import Version
12
+
13
+
14
+ @dataclass
15
+ class ReleaseNotesContext:
16
+ repo_name: str
17
+ repo_owner: str
18
+ hvcs_type: str
19
+ version: Version
20
+ release: Release
21
+ filters: tuple[Callable[..., Any], ...] = ()
22
+
23
+ def bind_to_environment(self, env: Environment) -> Environment:
24
+ env_globals = dict(
25
+ filter(lambda k_v: k_v[0] != "filters", self.__dict__.items())
26
+ )
27
+
28
+ for g, v in env_globals.items():
29
+ env.globals[g] = v
30
+
31
+ for f in self.filters:
32
+ env.filters[f.__name__] = f
33
+
34
+ return env
11
35
 
12
36
 
13
37
  @dataclass
@@ -41,6 +41,13 @@ class ReleaseHistory:
41
41
  unreleased: dict[str, list[ParseResult]] = defaultdict(list)
42
42
  released: dict[Version, Release] = {}
43
43
 
44
+ # Performance optimization: create a mapping of tag sha to version
45
+ # so we can quickly look up the version for a given commit based on sha
46
+ tag_sha_2_version_lookup = {
47
+ tag.commit.hexsha: (tag, version)
48
+ for tag, version in all_git_tags_and_versions
49
+ }
50
+
44
51
  # Strategy:
45
52
  # Loop through commits in history, parsing as we go.
46
53
  # Add these commits to `unreleased` as a key-value mapping
@@ -54,7 +61,7 @@ class ReleaseHistory:
54
61
  is_commit_released = False
55
62
  the_version: Version | None = None
56
63
 
57
- for commit in repo.iter_commits():
64
+ for commit in repo.iter_commits("HEAD", topo_order=True):
58
65
  # mypy will be happy if we make this an explicit string
59
66
  commit_message = str(commit.message)
60
67
 
@@ -64,45 +71,44 @@ class ReleaseHistory:
64
71
  )
65
72
  log.debug("commit has type %s", commit_type)
66
73
 
67
- for tag, version in all_git_tags_and_versions:
68
- if tag.commit == commit:
69
- # we have found the latest commit introduced by this tag
70
- # so we create a new Release entry
71
- log.debug("found commit %s for tag %s", commit.hexsha, tag.name)
72
- is_commit_released = True
73
- the_version = version
74
-
75
- # tag.object is a Commit if the tag is lightweight, otherwise
76
- # it is a TagObject with additional metadata about the tag
77
- if isinstance(tag.object, TagObject):
78
- tagger = tag.object.tagger
79
- committer = tag.object.tagger.committer()
80
- _tz = timezone(
81
- timedelta(seconds=-1 * tag.object.tagger_tz_offset)
82
- )
83
- tagged_date = datetime.fromtimestamp(
84
- tag.object.tagged_date, tz=_tz
85
- )
86
- else:
87
- # For some reason, sometimes tag.object is a Commit
88
- tagger = tag.object.author
89
- committer = tag.object.author
90
- _tz = timezone(
91
- timedelta(seconds=-1 * tag.object.author_tz_offset)
92
- )
93
- tagged_date = datetime.fromtimestamp(
94
- tag.object.committed_date, tz=_tz
95
- )
96
-
97
- release = Release(
98
- tagger=tagger,
99
- committer=committer,
100
- tagged_date=tagged_date,
101
- elements=defaultdict(list),
74
+ log.debug("checking if commit %s matches any tags", commit.hexsha)
75
+ t_v = tag_sha_2_version_lookup.get(commit.hexsha, None)
76
+
77
+ if t_v is None:
78
+ log.debug("no tags correspond to commit %s", commit.hexsha)
79
+ else:
80
+ # Unpack the tuple (overriding the current version)
81
+ tag, the_version = t_v
82
+ # we have found the latest commit introduced by this tag
83
+ # so we create a new Release entry
84
+ log.debug("found commit %s for tag %s", commit.hexsha, tag.name)
85
+ is_commit_released = True
86
+
87
+ # tag.object is a Commit if the tag is lightweight, otherwise
88
+ # it is a TagObject with additional metadata about the tag
89
+ if isinstance(tag.object, TagObject):
90
+ tagger = tag.object.tagger
91
+ committer = tag.object.tagger.committer()
92
+ _tz = timezone(timedelta(seconds=-1 * tag.object.tagger_tz_offset))
93
+ tagged_date = datetime.fromtimestamp(tag.object.tagged_date, tz=_tz)
94
+ else:
95
+ # For some reason, sometimes tag.object is a Commit
96
+ tagger = tag.object.author
97
+ committer = tag.object.author
98
+ _tz = timezone(timedelta(seconds=-1 * tag.object.author_tz_offset))
99
+ tagged_date = datetime.fromtimestamp(
100
+ tag.object.committed_date, tz=_tz
102
101
  )
103
102
 
104
- released.setdefault(the_version, release)
105
- break
103
+ release = Release(
104
+ tagger=tagger,
105
+ committer=committer,
106
+ tagged_date=tagged_date,
107
+ elements=defaultdict(list),
108
+ version=the_version,
109
+ )
110
+
111
+ released.setdefault(the_version, release)
106
112
 
107
113
  if any(pat.match(commit_message) for pat in exclude_commit_patterns):
108
114
  log.debug(
@@ -165,6 +171,7 @@ class ReleaseHistory:
165
171
  "committer": committer,
166
172
  "tagged_date": tagged_date,
167
173
  "elements": self.unreleased,
174
+ "version": version,
168
175
  },
169
176
  **self.released,
170
177
  },
@@ -183,3 +190,4 @@ class Release(TypedDict):
183
190
  committer: Actor
184
191
  tagged_date: datetime
185
192
  elements: dict[str, list[ParseResult]]
193
+ version: Version
@@ -0,0 +1,169 @@
1
+ from __future__ import annotations
2
+
3
+ from logging import getLogger
4
+ from os import listdir
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING
7
+
8
+ # NOTE: use backport with newer API than stdlib
9
+ from importlib_resources import files
10
+
11
+ from semantic_release.changelog.context import (
12
+ ReleaseNotesContext,
13
+ make_changelog_context,
14
+ )
15
+ from semantic_release.changelog.template import environment, recursive_render
16
+ from semantic_release.cli.util import noop_report
17
+
18
+ if TYPE_CHECKING:
19
+ from jinja2 import Environment
20
+
21
+ from semantic_release.changelog.release_history import Release, ReleaseHistory
22
+ from semantic_release.cli.config import RuntimeContext
23
+ from semantic_release.hvcs._base import HvcsBase
24
+
25
+
26
+ log = getLogger(__name__)
27
+
28
+
29
+ def get_release_notes_template(template_dir: Path) -> str:
30
+ """Read the project's template for release notes, falling back to the default."""
31
+ fname = template_dir / ".release_notes.md.j2"
32
+ try:
33
+ return fname.read_text(encoding="utf-8")
34
+ except FileNotFoundError:
35
+ return (
36
+ files("semantic_release")
37
+ .joinpath("data/templates/release_notes.md.j2")
38
+ .read_text(encoding="utf-8")
39
+ )
40
+
41
+
42
+ def render_default_changelog_file(template_env: Environment) -> str:
43
+ changelog_text = (
44
+ files("semantic_release")
45
+ .joinpath("data/templates/CHANGELOG.md.j2")
46
+ .read_text(encoding="utf-8")
47
+ )
48
+ template = template_env.from_string(changelog_text)
49
+ return template.render().rstrip()
50
+
51
+
52
+ def render_release_notes(
53
+ release_notes_template: str,
54
+ template_env: Environment,
55
+ ) -> str:
56
+ template = template_env.from_string(release_notes_template)
57
+ return template.render().rstrip()
58
+
59
+
60
+ def apply_user_changelog_template_directory(
61
+ template_dir: Path,
62
+ environment: Environment,
63
+ destination_dir: Path,
64
+ noop: bool = False,
65
+ ) -> list[str]:
66
+ if noop:
67
+ noop_report(
68
+ str.join(
69
+ " ",
70
+ [
71
+ "would have recursively rendered the template directory",
72
+ f"{template_dir!r} relative to {destination_dir!r}.",
73
+ "Paths which would be modified by this operation cannot be",
74
+ "determined in no-op mode.",
75
+ ],
76
+ )
77
+ )
78
+ return []
79
+
80
+ return recursive_render(
81
+ template_dir, environment=environment, _root_dir=destination_dir
82
+ )
83
+
84
+
85
+ def write_default_changelog(
86
+ changelog_file: Path,
87
+ destination_dir: Path,
88
+ environment: Environment,
89
+ noop: bool = False,
90
+ ) -> str:
91
+ if noop:
92
+ noop_report(
93
+ str.join(
94
+ " ",
95
+ [
96
+ "would have written your changelog to",
97
+ str(changelog_file.relative_to(destination_dir)),
98
+ ],
99
+ )
100
+ )
101
+ else:
102
+ changelog_text = render_default_changelog_file(environment)
103
+ changelog_file.write_text(f"{changelog_text}\n", encoding="utf-8")
104
+
105
+ return str(changelog_file)
106
+
107
+
108
+ def write_changelog_files(
109
+ runtime_ctx: RuntimeContext,
110
+ release_history: ReleaseHistory,
111
+ hvcs_client: HvcsBase,
112
+ noop: bool = False,
113
+ ) -> list[str]:
114
+ project_dir = Path(runtime_ctx.repo_dir)
115
+ template_dir = runtime_ctx.template_dir
116
+
117
+ changelog_context = make_changelog_context(
118
+ hvcs_client=hvcs_client,
119
+ release_history=release_history,
120
+ )
121
+
122
+ changelog_context.bind_to_environment(runtime_ctx.template_environment)
123
+
124
+ use_user_template_dir = bool(
125
+ # Directory exists and directory is not empty
126
+ template_dir.exists() and template_dir.is_dir() and listdir(template_dir)
127
+ )
128
+
129
+ if use_user_template_dir:
130
+ return apply_user_changelog_template_directory(
131
+ template_dir=template_dir,
132
+ environment=runtime_ctx.template_environment,
133
+ destination_dir=project_dir,
134
+ noop=noop,
135
+ )
136
+
137
+ log.info("No contents found in %r, using default changelog template", template_dir)
138
+ return [
139
+ write_default_changelog(
140
+ changelog_file=runtime_ctx.changelog_file,
141
+ destination_dir=project_dir,
142
+ environment=runtime_ctx.template_environment,
143
+ noop=noop,
144
+ )
145
+ ]
146
+
147
+
148
+ def generate_release_notes(
149
+ hvcs_client: HvcsBase,
150
+ release: Release,
151
+ template_dir: Path,
152
+ ) -> str:
153
+ release_notes_env = ReleaseNotesContext(
154
+ repo_name=hvcs_client.repo_name,
155
+ repo_owner=hvcs_client.owner,
156
+ hvcs_type=hvcs_client.__class__.__name__.lower(),
157
+ version=release["version"],
158
+ release=release,
159
+ filters=(*hvcs_client.get_changelog_context_filters(),),
160
+ ).bind_to_environment(
161
+ # Use a new, non-configurable environment for release notes -
162
+ # not user-configurable at the moment
163
+ environment(template_dir=template_dir)
164
+ )
165
+
166
+ return render_release_notes(
167
+ release_notes_template=get_release_notes_template(template_dir),
168
+ template_env=release_notes_env,
169
+ )
@@ -14,7 +14,11 @@ from semantic_release.cli.config import (
14
14
  RuntimeContext,
15
15
  )
16
16
  from semantic_release.cli.util import load_raw_config_file, rprint
17
- from semantic_release.errors import InvalidConfiguration, NotAReleaseBranch
17
+ from semantic_release.errors import (
18
+ DetachedHeadGitError,
19
+ InvalidConfiguration,
20
+ NotAReleaseBranch,
21
+ )
18
22
 
19
23
  if TYPE_CHECKING:
20
24
  from semantic_release.cli.config import GlobalCommandLineOptions
@@ -30,10 +34,17 @@ class CliContextObj:
30
34
  logger: logging.Logger,
31
35
  global_opts: GlobalCommandLineOptions,
32
36
  ) -> None:
33
- self._runtime_ctx: RuntimeContext | None = None
34
37
  self.ctx = ctx
35
38
  self.logger = logger
36
39
  self.global_opts = global_opts
40
+ self._raw_config: RawConfig | None = None
41
+ self._runtime_ctx: RuntimeContext | None = None
42
+
43
+ @property
44
+ def raw_config(self) -> RawConfig:
45
+ if self._raw_config is None:
46
+ self._raw_config = self._init_raw_config()
47
+ return self._raw_config
37
48
 
38
49
  @property
39
50
  def runtime_ctx(self) -> RuntimeContext:
@@ -45,7 +56,7 @@ class CliContextObj:
45
56
  self._runtime_ctx = self._init_runtime_ctx()
46
57
  return self._runtime_ctx
47
58
 
48
- def _init_runtime_ctx(self) -> RuntimeContext:
59
+ def _init_raw_config(self) -> RawConfig:
49
60
  config_path = Path(self.global_opts.config_file)
50
61
  conf_file_exists = config_path.exists()
51
62
  was_conf_file_user_provided = bool(
@@ -56,9 +67,10 @@ class CliContextObj:
56
67
  )
57
68
  )
58
69
 
70
+ # TODO: Evaluate Exeception catches
59
71
  try:
60
72
  if was_conf_file_user_provided and not conf_file_exists:
61
- raise FileNotFoundError(
73
+ raise FileNotFoundError( # noqa: TRY301
62
74
  f"File {self.global_opts.config_file} does not exist"
63
75
  )
64
76
 
@@ -70,9 +82,23 @@ class CliContextObj:
70
82
  "configuration empty, falling back to default configuration"
71
83
  )
72
84
 
73
- raw_config = RawConfig.model_validate(config_obj)
85
+ return RawConfig.model_validate(config_obj)
86
+ except FileNotFoundError as exc:
87
+ click.echo(str(exc), err=True)
88
+ self.ctx.exit(2)
89
+ except (
90
+ ValidationError,
91
+ InvalidConfiguration,
92
+ InvalidGitRepositoryError,
93
+ ) as exc:
94
+ click.echo(str(exc), err=True)
95
+ self.ctx.exit(1)
96
+
97
+ def _init_runtime_ctx(self) -> RuntimeContext:
98
+ # TODO: Evaluate Exception catches
99
+ try:
74
100
  runtime = RuntimeContext.from_raw_config(
75
- raw_config,
101
+ self.raw_config,
76
102
  global_cli_options=self.global_opts,
77
103
  )
78
104
  except NotAReleaseBranch as exc:
@@ -81,13 +107,11 @@ class CliContextObj:
81
107
  # multibranch CI it might be desirable to run a non-release branch's pipeline
82
108
  # without specifying conditional execution of PSR based on branch name
83
109
  self.ctx.exit(2 if self.global_opts.strict else 0)
84
- except FileNotFoundError as exc:
85
- click.echo(str(exc), err=True)
86
- self.ctx.exit(2)
87
110
  except (
88
- ValidationError,
111
+ DetachedHeadGitError,
89
112
  InvalidConfiguration,
90
113
  InvalidGitRepositoryError,
114
+ ValidationError,
91
115
  ) as exc:
92
116
  click.echo(str(exc), err=True)
93
117
  self.ctx.exit(1)