python-semantic-release 9.2.0__py3-none-any.whl → 9.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {python_semantic_release-9.2.0.dist-info → python_semantic_release-9.2.2.dist-info}/METADATA +2 -2
  2. python_semantic_release-9.2.2.dist-info/RECORD +54 -0
  3. semantic_release/__init__.py +2 -1
  4. semantic_release/changelog/release_history.py +5 -9
  5. semantic_release/changelog/template.py +3 -1
  6. semantic_release/cli/commands/changelog.py +5 -4
  7. semantic_release/cli/commands/cli_context.py +100 -0
  8. semantic_release/cli/commands/generate_config.py +1 -1
  9. semantic_release/cli/commands/main.py +13 -71
  10. semantic_release/cli/commands/publish.py +11 -3
  11. semantic_release/cli/commands/version.py +22 -15
  12. semantic_release/cli/config.py +11 -6
  13. semantic_release/cli/util.py +1 -0
  14. semantic_release/commit_parser/_base.py +1 -2
  15. semantic_release/commit_parser/angular.py +1 -0
  16. semantic_release/commit_parser/emoji.py +1 -0
  17. semantic_release/commit_parser/scipy.py +1 -0
  18. semantic_release/commit_parser/tag.py +1 -0
  19. semantic_release/helpers.py +2 -2
  20. semantic_release/hvcs/_base.py +1 -0
  21. semantic_release/hvcs/bitbucket.py +8 -9
  22. semantic_release/hvcs/gitea.py +1 -0
  23. semantic_release/hvcs/github.py +1 -0
  24. semantic_release/hvcs/gitlab.py +1 -0
  25. semantic_release/version/version.py +2 -4
  26. python_semantic_release-9.2.0.dist-info/RECORD +0 -53
  27. {python_semantic_release-9.2.0.dist-info → python_semantic_release-9.2.2.dist-info}/AUTHORS.rst +0 -0
  28. {python_semantic_release-9.2.0.dist-info → python_semantic_release-9.2.2.dist-info}/LICENSE +0 -0
  29. {python_semantic_release-9.2.0.dist-info → python_semantic_release-9.2.2.dist-info}/WHEEL +0 -0
  30. {python_semantic_release-9.2.0.dist-info → python_semantic_release-9.2.2.dist-info}/entry_points.txt +0 -0
  31. {python_semantic_release-9.2.0.dist-info → python_semantic_release-9.2.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-semantic-release
3
- Version: 9.2.0
3
+ Version: 9.2.2
4
4
  Summary: Automatic Semantic Versioning for Python projects
5
5
  Author-email: Rolf Erik Lekang <me@rolflekang.com>
6
6
  License: MIT
@@ -35,7 +35,7 @@ Requires-Dist: shellingham >=1.5.0.post1
35
35
  Provides-Extra: dev
36
36
  Requires-Dist: pre-commit ; extra == 'dev'
37
37
  Requires-Dist: tox ; extra == 'dev'
38
- Requires-Dist: ruff ==0.1.11 ; extra == 'dev'
38
+ Requires-Dist: ruff ==0.3.2 ; extra == 'dev'
39
39
  Provides-Extra: docs
40
40
  Requires-Dist: Sphinx <=6.0.0 ; extra == 'docs'
41
41
  Requires-Dist: sphinxcontrib-apidoc ==0.3.0 ; extra == 'docs'
@@ -0,0 +1,54 @@
1
+ semantic_release/__init__.py,sha256=UY60uqsKwT97THCS1FDDtGpgKytMBM6Hi3uMAfzJrLI,870
2
+ semantic_release/__main__.py,sha256=vXOARLV7KHeVXgpOMU0Q-8wovpdsOrtTsycxulI5xIE,106
3
+ semantic_release/const.py,sha256=Z1o2QNh60wSLeF-_1TemMBjU3ZXbV0XghnUFsbTVfOs,831
4
+ semantic_release/enums.py,sha256=D5B_reQGGKQQT22HO5PUtvn2Bok3fkht6TfJtXkmAUg,1020
5
+ semantic_release/errors.py,sha256=KKKCV45vvE9tla0sxYDGHkHWvqDn1gEfGIpzujcDbeI,809
6
+ semantic_release/helpers.py,sha256=d1jOX0SNyqPc_3wr14xR25FfpqhMd4Ev7MNBOWlScc0,5581
7
+ semantic_release/changelog/__init__.py,sha256=Bg6Xe5Vt32rWoMscW-hd4sUwiZqzWmsg4CD1EhMesMY,262
8
+ semantic_release/changelog/context.py,sha256=ItSz5Bon2mcJkLxyQZzBTukN0zEdcaVQ4iXvz3jGCLc,986
9
+ semantic_release/changelog/release_history.py,sha256=ShzZpxTjhxka6TMbzOzYzG3EuCH8j3xjUQzll-FKcCo,6675
10
+ semantic_release/changelog/template.py,sha256=JqZcjdozM9-059Sa8PfiHxYNeyZFa0jxk_beyRLv5sU,4640
11
+ semantic_release/cli/__init__.py,sha256=gwAYhZO-4TR0tKCkQ4GqutWsL--0CII2_dcbrElI4M4,419
12
+ semantic_release/cli/common.py,sha256=cVQUI7Uaac_nJ7VEXuJ7Q9pVJpuMVRvE7bBl_i96g20,1439
13
+ semantic_release/cli/config.py,sha256=lBkTlc2x4PkCj7aGJn6DahsF_LH7Fsy-5OiTW61wRzA,16070
14
+ semantic_release/cli/const.py,sha256=S8oNNpSaKdZxcAs7PAKEjQHic0czoJBGd7XHo57FOzw,39
15
+ semantic_release/cli/github_actions_output.py,sha256=stGWcuMtelY0qM2E_-IfofP6UvsQ6czsO7qpMfnRJI4,2102
16
+ semantic_release/cli/masking_filter.py,sha256=DxqjiJyABlzwwwZ1r8JGQpb6QrF00StJFm0-2-s5Fv0,3071
17
+ semantic_release/cli/util.py,sha256=FyXaBkeL7nXKjy3X9rQLEwvn7p46xPekp2V8Z-5MVrk,3755
18
+ semantic_release/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ semantic_release/cli/commands/changelog.py,sha256=Tk9DprnY9mDQXSE1krQd8oILn3W6dKN_stWx9EbLjhU,4087
20
+ semantic_release/cli/commands/cli_context.py,sha256=fOLTUKb4UnZGQ6zVhftuvdfZ7fK7bDDIvj7Ud5yU98c,3443
21
+ semantic_release/cli/commands/generate_config.py,sha256=2xZOu3NpyhBp0pWr7d8ugKl_kjqQgpSsSMHq5wHTfrE,1699
22
+ semantic_release/cli/commands/main.py,sha256=LuL-O0LGonI5fQTZn0AUtYv2Ei_CYyNqYHMF_wN4InI,2900
23
+ semantic_release/cli/commands/publish.py,sha256=_pz7rKx65tCH7J2uyWiBghQ61MmmIbxhF9bE4AkE0N8,1703
24
+ semantic_release/cli/commands/version.py,sha256=1YfdvAkaammmgVRCFcGPujM2fNUvl5DN8xL3utGOzKE,22461
25
+ semantic_release/commit_parser/__init__.py,sha256=cv5HFBdw7OJd4Laj4Ex8ZZ5Tml8GwXgQcXW6Pasr2Ao,615
26
+ semantic_release/commit_parser/_base.py,sha256=aDS0dhFosT5i11tA5Ez8BTeikk6jwXjSEpJnJC5D2cs,2609
27
+ semantic_release/commit_parser/angular.py,sha256=bS7Wrzpg_6zFil5Y4GIZkeGDPhvWQdTlFdWTtGVcpp0,4393
28
+ semantic_release/commit_parser/emoji.py,sha256=6cFnqpvtjtxlwDYc8oB9y41RPqFGGD8PbqiAA53SVac,3289
29
+ semantic_release/commit_parser/scipy.py,sha256=AaAtQYUsG_Y29YIgDVISl5mljBCkG8zyzUkn_3HYGeM,5777
30
+ semantic_release/commit_parser/tag.py,sha256=0Y8GTRclyoLMhyDRrcMU8JKTM4lsbfpJbjqZ7qz5ifE,3194
31
+ semantic_release/commit_parser/token.py,sha256=UxYAwEylPvp4x39RqNA9ITcgkaSRDEH7A5XDDJ3tdiM,1505
32
+ semantic_release/commit_parser/util.py,sha256=vLcVDErZrExM55jMffos0hyMbNVQoJ-PeeVDG1Ej51I,730
33
+ semantic_release/data/templates/CHANGELOG.md.j2,sha256=GB3YJwgVrhlcb-g5ESdEh_Gsysb_Texxv-Ip2LjulC0,1066
34
+ semantic_release/data/templates/release_notes.md.j2,sha256=27uIHgG6iYmqdMaoWFP5LJRZcrO-3paqFzHHHsGpXXE,465
35
+ semantic_release/hvcs/__init__.py,sha256=ulesZslSG4Lu8Iz3YzOrPXpdgvgbADq_MV17B-bSYQA,379
36
+ semantic_release/hvcs/_base.py,sha256=VnsEz01W9t3DQ2QHGnsbuAB9jYfZT3hIXRRsCUnhS0g,5635
37
+ semantic_release/hvcs/bitbucket.py,sha256=pGZksLht66zLJXbPIgRz4hntsa-F1A02xl4JNRCXE0o,4626
38
+ semantic_release/hvcs/gitea.py,sha256=HpaqQQxbUiWLByzceFVkR6o_c60gT6HmFwsq4CPwJKY,8459
39
+ semantic_release/hvcs/github.py,sha256=L29AaUmmtdJTNDJqD6ro3YVcDNr8OMwqTx5ofujOZz8,10710
40
+ semantic_release/hvcs/gitlab.py,sha256=qSvNdQK40QM20-HDh3eIO6Rz8Lo3PEND_4kluugVx4w,6154
41
+ semantic_release/hvcs/token_auth.py,sha256=ZjT56-NIPB4OKIt1qwHCu1TavXnrWFIBl9ARlg56hgU,663
42
+ semantic_release/hvcs/util.py,sha256=PNKXApgL2np9lpnKjAbo77toRgElLPXrbS1q7621waI,2886
43
+ semantic_release/version/__init__.py,sha256=CLhtGQry9dLIij5XyRa9ZevxU_1p8tjMTSQ-K_GMpWM,270
44
+ semantic_release/version/algorithm.py,sha256=K9WkPRur0x5baXsqEi8kvaDfxduG4WNUiALXZRXujJ4,16484
45
+ semantic_release/version/declaration.py,sha256=f6Ld7hIhrqvDrRBapJHr-KDimuyo-4IG8009Zu9BIgU,7357
46
+ semantic_release/version/translator.py,sha256=P1noIsVBn8u6zNOFjG0xKYOWapxqf_PHSMvMeLJ9kXg,3050
47
+ semantic_release/version/version.py,sha256=6PCtSbLP88U1daoxnCwHc--YguZo4waGNLqJ5JfeczE,14175
48
+ python_semantic_release-9.2.2.dist-info/AUTHORS.rst,sha256=XOReVvpymEFUPsS2QPH97jlfJBVrxwS2eu8-jVAe4gk,230
49
+ python_semantic_release-9.2.2.dist-info/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
50
+ python_semantic_release-9.2.2.dist-info/METADATA,sha256=b41gxhINO5-3krE8YC0-_sQSa8G4L5zFuOlMd9Rsd0A,5365
51
+ python_semantic_release-9.2.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
52
+ python_semantic_release-9.2.2.dist-info/entry_points.txt,sha256=qojUBx_Ywf4u7KgP6NWlDaBDymZVUGQ7m5wF2duC2F0,95
53
+ python_semantic_release-9.2.2.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
54
+ python_semantic_release-9.2.2.dist-info/RECORD,,
@@ -1,4 +1,5 @@
1
1
  """Python Semantic Release"""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from semantic_release.commit_parser import (
@@ -23,7 +24,7 @@ from semantic_release.version import (
23
24
  tags_and_versions,
24
25
  )
25
26
 
26
- __version__ = "9.2.0"
27
+ __version__ = "9.2.2"
27
28
 
28
29
 
29
30
  def setup_hook(argv: list[str]) -> None:
@@ -3,20 +3,16 @@ from __future__ import annotations
3
3
  import logging
4
4
  from collections import defaultdict
5
5
  from datetime import datetime, timedelta, timezone
6
- from typing import TYPE_CHECKING, Iterable, Iterator
6
+ from typing import TYPE_CHECKING, TypedDict
7
7
 
8
8
  from git.objects.tag import TagObject
9
9
 
10
- # For Python3.7 compatibility
11
- from typing_extensions import TypedDict
12
-
13
- from semantic_release.commit_parser import (
14
- ParseError,
15
- )
10
+ from semantic_release.commit_parser import ParseError
16
11
  from semantic_release.version.algorithm import tags_and_versions
17
12
 
18
13
  if TYPE_CHECKING:
19
- import re
14
+ from re import Pattern
15
+ from typing import Iterable, Iterator
20
16
 
21
17
  from git.repo.base import Repo
22
18
  from git.util import Actor
@@ -39,7 +35,7 @@ class ReleaseHistory:
39
35
  repo: Repo,
40
36
  translator: VersionTranslator,
41
37
  commit_parser: CommitParser[ParseResult, ParserOptions],
42
- exclude_commit_patterns: Iterable[re.Pattern[str]] = (),
38
+ exclude_commit_patterns: Iterable[Pattern[str]] = (),
43
39
  ) -> ReleaseHistory:
44
40
  all_git_tags_and_versions = tags_and_versions(repo.tags, translator)
45
41
  unreleased: dict[str, list[ParseResult]] = defaultdict(list)
@@ -12,8 +12,10 @@ from jinja2.sandbox import SandboxedEnvironment
12
12
  from semantic_release.helpers import dynamic_import
13
13
 
14
14
  if TYPE_CHECKING:
15
+ from typing import Literal
16
+
15
17
  from jinja2 import Environment
16
- from typing_extensions import Literal
18
+
17
19
 
18
20
  log = logging.getLogger(__name__)
19
21
 
@@ -16,7 +16,7 @@ from semantic_release.cli.common import (
16
16
  from semantic_release.cli.util import noop_report
17
17
 
18
18
  if TYPE_CHECKING:
19
- from semantic_release.cli.config import RuntimeContext
19
+ from semantic_release.cli.commands.cli_context import CliContextObj
20
20
  from semantic_release.version import Version
21
21
 
22
22
  log = logging.getLogger(__name__)
@@ -34,10 +34,11 @@ log = logging.getLogger(__name__)
34
34
  default=None,
35
35
  help="Post the generated release notes to the remote VCS's release for this tag",
36
36
  )
37
- @click.pass_context
38
- def changelog(ctx: click.Context, release_tag: str | None = None) -> None:
37
+ @click.pass_obj
38
+ def changelog(cli_ctx: CliContextObj, release_tag: str | None = None) -> None:
39
39
  """Generate and optionally publish a changelog for your project"""
40
- runtime: RuntimeContext = ctx.obj
40
+ ctx = click.get_current_context()
41
+ runtime = cli_ctx.runtime_ctx
41
42
  repo = runtime.repo
42
43
  parser = runtime.commit_parser
43
44
  translator = runtime.version_translator
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING
6
+
7
+ import click
8
+ from click.core import ParameterSource
9
+ from git import InvalidGitRepositoryError
10
+ from pydantic import ValidationError
11
+
12
+ from semantic_release.cli.config import (
13
+ RawConfig,
14
+ RuntimeContext,
15
+ )
16
+ from semantic_release.cli.util import load_raw_config_file, rprint
17
+ from semantic_release.errors import InvalidConfiguration, NotAReleaseBranch
18
+
19
+ if TYPE_CHECKING:
20
+ from semantic_release.cli.config import GlobalCommandLineOptions
21
+
22
+ class CliContext(click.Context):
23
+ obj: CliContextObj
24
+
25
+
26
+ class CliContextObj:
27
+ def __init__(
28
+ self,
29
+ ctx: click.Context,
30
+ logger: logging.Logger,
31
+ global_opts: GlobalCommandLineOptions,
32
+ ) -> None:
33
+ self._runtime_ctx: RuntimeContext | None = None
34
+ self.ctx = ctx
35
+ self.logger = logger
36
+ self.global_opts = global_opts
37
+
38
+ @property
39
+ def runtime_ctx(self) -> RuntimeContext:
40
+ """
41
+ Lazy load the runtime context. This is done to avoid configuration loading when
42
+ the command is not run. This is useful for commands like `--help` and `--version`
43
+ """
44
+ if self._runtime_ctx is None:
45
+ self._runtime_ctx = self._init_runtime_ctx()
46
+ return self._runtime_ctx
47
+
48
+ def _init_runtime_ctx(self) -> RuntimeContext:
49
+ config_path = Path(self.global_opts.config_file)
50
+ conf_file_exists = config_path.exists()
51
+ was_conf_file_user_provided = bool(
52
+ self.ctx.get_parameter_source("config_file")
53
+ not in (
54
+ ParameterSource.DEFAULT,
55
+ ParameterSource.DEFAULT_MAP,
56
+ )
57
+ )
58
+
59
+ try:
60
+ if was_conf_file_user_provided and not conf_file_exists:
61
+ raise FileNotFoundError(
62
+ f"File {self.global_opts.config_file} does not exist"
63
+ )
64
+
65
+ config_obj = (
66
+ {} if not conf_file_exists else load_raw_config_file(config_path)
67
+ )
68
+ if not config_obj:
69
+ self.logger.info(
70
+ "configuration empty, falling back to default configuration"
71
+ )
72
+
73
+ raw_config = RawConfig.model_validate(config_obj)
74
+ runtime = RuntimeContext.from_raw_config(
75
+ raw_config,
76
+ global_cli_options=self.global_opts,
77
+ )
78
+ except NotAReleaseBranch as exc:
79
+ rprint(f"[bold {'red' if self.global_opts.strict else 'orange1'}]{exc!s}")
80
+ # If not strict, exit 0 so other processes can continue. For example, in
81
+ # multibranch CI it might be desirable to run a non-release branch's pipeline
82
+ # without specifying conditional execution of PSR based on branch name
83
+ 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
+ except (
88
+ ValidationError,
89
+ InvalidConfiguration,
90
+ InvalidGitRepositoryError,
91
+ ) as exc:
92
+ click.echo(str(exc), err=True)
93
+ self.ctx.exit(1)
94
+
95
+ # This allows us to mask secrets in the logging
96
+ # by applying it to all the configured handlers
97
+ for handler in logging.getLogger().handlers:
98
+ handler.addFilter(runtime.masker)
99
+
100
+ return runtime
@@ -38,7 +38,7 @@ def generate_config(fmt: str = "toml", is_pyproject_toml: bool = False) -> None:
38
38
  your needs. For example, to append the default configuration to your pyproject.toml
39
39
  file, you can use the following command:
40
40
 
41
- semantic-release generate-config -f toml >> pyproject.toml
41
+ semantic-release generate-config --pyproject >> pyproject.toml
42
42
  """
43
43
  # due to possible IntEnum values (which are not supported by tomlkit.dumps, see sdispater/tomlkit#237),
44
44
  # we must ensure the transformation of the model to a dict uses json serializable values
@@ -1,26 +1,21 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from pathlib import Path
5
4
 
5
+ # from typing import TYPE_CHECKING
6
6
  import click
7
- from click.core import ParameterSource
8
- from git import InvalidGitRepositoryError
9
- from git.repo.base import Repo
10
- from pydantic import ValidationError
11
7
  from rich.console import Console
12
8
  from rich.logging import RichHandler
13
9
 
14
10
  import semantic_release
15
- from semantic_release.cli.commands.generate_config import generate_config
16
- from semantic_release.cli.config import (
17
- GlobalCommandLineOptions,
18
- RawConfig,
19
- RuntimeContext,
20
- )
11
+ from semantic_release.cli.commands.cli_context import CliContextObj
12
+ from semantic_release.cli.config import GlobalCommandLineOptions
21
13
  from semantic_release.cli.const import DEFAULT_CONFIG_FILE
22
- from semantic_release.cli.util import load_raw_config_file, rprint
23
- from semantic_release.errors import InvalidConfiguration, NotAReleaseBranch
14
+ from semantic_release.cli.util import rprint
15
+
16
+ # if TYPE_CHECKING:
17
+ # pass
18
+
24
19
 
25
20
  FORMAT = "[%(name)s] %(levelname)s %(module)s.%(funcName)s: %(message)s"
26
21
 
@@ -94,19 +89,8 @@ def main(
94
89
  ],
95
90
  )
96
91
 
97
- log = logging.getLogger(__name__)
98
-
99
- if ctx.invoked_subcommand == generate_config.name:
100
- # generate-config doesn't require any of the usual setup,
101
- # so exit out early and delegate to it
102
- log.debug("Forwarding to %s", generate_config.name)
103
- return
104
-
105
- log.debug("logging level set to: %s", logging.getLevelName(log_level))
106
- try:
107
- repo = Repo(".", search_parent_directories=True)
108
- except InvalidGitRepositoryError:
109
- ctx.fail("Not in a valid Git repository")
92
+ logger = logging.getLogger(__name__)
93
+ logger.debug("logging level set to: %s", logging.getLevelName(log_level))
110
94
 
111
95
  if noop:
112
96
  rprint(
@@ -115,51 +99,9 @@ def main(
115
99
  )
116
100
 
117
101
  cli_options = GlobalCommandLineOptions(
118
- noop=noop,
119
- verbosity=verbosity,
120
- config_file=config_file,
121
- strict=strict,
102
+ noop=noop, verbosity=verbosity, config_file=config_file, strict=strict
122
103
  )
123
- log.debug("global cli options: %s", cli_options)
124
-
125
- config_path = Path(config_file)
126
- # default no config loaded
127
- config_text = {}
128
- if not config_path.exists():
129
- if ctx.get_parameter_source("config_file") not in (
130
- ParameterSource.DEFAULT,
131
- ParameterSource.DEFAULT_MAP,
132
- ):
133
- ctx.fail(f"File {config_file} does not exist")
134
-
135
- log.info(
136
- "configuration file %s not found, using default configuration",
137
- config_file,
138
- )
139
104
 
140
- else:
141
- try:
142
- config_text = load_raw_config_file(config_path)
143
- except InvalidConfiguration as exc:
144
- ctx.fail(str(exc))
105
+ logger.debug("global cli options: %s", cli_options)
145
106
 
146
- try:
147
- raw_config = RawConfig.model_validate(config_text)
148
- runtime = RuntimeContext.from_raw_config(
149
- raw_config, repo=repo, global_cli_options=cli_options
150
- )
151
- except NotAReleaseBranch as exc:
152
- rprint(f"[bold {'red' if strict else 'orange1'}]{exc!s}")
153
- # If not strict, exit 0 so other processes can continue. For example, in
154
- # multibranch CI it might be desirable to run a non-release branch's pipeline
155
- # without specifying conditional execution of PSR based on branch name
156
- ctx.exit(2 if strict else 0)
157
- except (ValidationError, InvalidConfiguration) as exc:
158
- click.echo(str(exc), err=True)
159
- ctx.exit(1)
160
- ctx.obj = runtime
161
-
162
- # This allows us to mask secrets in the logging
163
- # by applying it to all the configured handlers
164
- for handler in logging.getLogger().handlers:
165
- handler.addFilter(runtime.masker)
107
+ ctx.obj = CliContextObj(ctx, logger, cli_options)
@@ -1,10 +1,17 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
4
+ from typing import TYPE_CHECKING
2
5
 
3
6
  import click
4
7
 
5
8
  from semantic_release.cli.util import noop_report
6
9
  from semantic_release.version import tags_and_versions
7
10
 
11
+ if TYPE_CHECKING:
12
+ from semantic_release.cli.commands.cli_context import CliContextObj
13
+
14
+
8
15
  log = logging.getLogger(__name__)
9
16
 
10
17
 
@@ -20,10 +27,11 @@ log = logging.getLogger(__name__)
20
27
  help="The tag associated with the release to publish to",
21
28
  default="latest",
22
29
  )
23
- @click.pass_context
24
- def publish(ctx: click.Context, tag: str = "latest") -> None:
30
+ @click.pass_obj
31
+ def publish(cli_ctx: CliContextObj, tag: str = "latest") -> None:
25
32
  """Build and publish a distribution to a VCS release."""
26
- runtime = ctx.obj
33
+ ctx = click.get_current_context()
34
+ runtime = cli_ctx.runtime_ctx
27
35
  repo = runtime.repo
28
36
  hvcs_client = runtime.hvcs_client
29
37
  translator = runtime.version_translator
@@ -5,7 +5,7 @@ import os
5
5
  import subprocess
6
6
  from contextlib import nullcontext
7
7
  from datetime import datetime
8
- from typing import TYPE_CHECKING, ContextManager, Iterable
8
+ from typing import TYPE_CHECKING
9
9
 
10
10
  import click
11
11
  import shellingham # type: ignore[import]
@@ -28,10 +28,12 @@ from semantic_release.version import Version, next_version, tags_and_versions
28
28
  log = logging.getLogger(__name__)
29
29
 
30
30
  if TYPE_CHECKING: # pragma: no cover
31
+ from typing import ContextManager, Iterable
32
+
31
33
  from git import Repo
32
34
  from git.refs.tag import Tag
33
35
 
34
- from semantic_release.cli.config import RuntimeContext
36
+ from semantic_release.cli.commands.cli_context import CliContextObj
35
37
  from semantic_release.version import VersionTranslator
36
38
  from semantic_release.version.declaration import VersionDeclarationABC
37
39
 
@@ -213,9 +215,9 @@ def shell(cmd: str, *, check: bool = True) -> subprocess.CompletedProcess:
213
215
  is_flag=True,
214
216
  help="Skip building the current project",
215
217
  )
216
- @click.pass_context
218
+ @click.pass_obj
217
219
  def version( # noqa: C901
218
- ctx: click.Context,
220
+ cli_ctx: CliContextObj,
219
221
  print_only: bool = False,
220
222
  print_only_tag: bool = False,
221
223
  print_last_released: bool = False,
@@ -231,22 +233,27 @@ def version( # noqa: C901
231
233
  build_metadata: str | None = None,
232
234
  skip_build: bool = False,
233
235
  ) -> str:
234
- r"""
236
+ """
235
237
  Detect the semantically correct next version that should be applied to your
236
238
  project.
237
239
 
238
- \b
239
240
  By default:
240
- * Write this new version to the project metadata locations
241
- specified in the configuration file
242
- * Create a new commit with these locations and any other assets configured
243
- to be included in a release
244
- * Tag this commit according the configured format, with a tag that uniquely
245
- identifies the version being released.
246
- * Push the new tag and commit to the remote for the repository
247
- * Create a release (if supported) in the remote VCS for this tag
241
+
242
+ * Write this new version to the project metadata locations specified
243
+ in the configuration file
244
+
245
+ * Create a new commit with these locations and any other assets configured
246
+ to be included in a release
247
+
248
+ * Tag this commit according the configured format, with a tag that uniquely
249
+ identifies the version being released.
250
+
251
+ * Push the new tag and commit to the remote for the repository
252
+
253
+ * Create a release (if supported) in the remote VCS for this tag
248
254
  """
249
- runtime: RuntimeContext = ctx.obj
255
+ ctx = click.get_current_context()
256
+ runtime = cli_ctx.runtime_ctx
250
257
  repo = runtime.repo
251
258
  translator = runtime.version_translator
252
259
 
@@ -7,13 +7,15 @@ from collections.abc import Mapping
7
7
  from dataclasses import dataclass, is_dataclass
8
8
  from enum import Enum
9
9
  from pathlib import Path
10
- from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union
10
+ from typing import Any, ClassVar, Dict, List, Literal, Optional, Tuple, Type, Union
11
11
 
12
- from git import Actor
12
+ from git import Actor, InvalidGitRepositoryError
13
13
  from git.repo.base import Repo
14
14
  from jinja2 import Environment
15
15
  from pydantic import BaseModel, Field, RootModel, ValidationError, model_validator
16
- from typing_extensions import Annotated, Literal
16
+
17
+ # For Python 3.8, 3.9, 3.10 compatibility
18
+ from typing_extensions import Annotated, Self
17
19
 
18
20
  from semantic_release import hvcs
19
21
  from semantic_release.changelog import environment
@@ -117,7 +119,7 @@ class RemoteConfig(BaseModel):
117
119
  ignore_token_for_push: bool = False
118
120
 
119
121
  @model_validator(mode="after")
120
- def set_default_token(self) -> RemoteConfig:
122
+ def set_default_token(self) -> Self:
121
123
  # Set the default token name for the given VCS when no user input is given
122
124
  if not self.token and self.type in _known_hvcs:
123
125
  default_token_name = _known_hvcs[self.type].DEFAULT_ENV_TOKEN_NAME
@@ -153,7 +155,7 @@ class RawConfig(BaseModel):
153
155
  version_variables: Optional[Tuple[str, ...]] = None
154
156
 
155
157
  @model_validator(mode="after")
156
- def set_default_opts(self) -> RawConfig:
158
+ def set_default_opts(self) -> Self:
157
159
  # Set the default parser options for the given commit parser when no user input is given
158
160
  if not self.commit_parser_options and self.commit_parser:
159
161
  parser_opts_type = None
@@ -289,14 +291,17 @@ class RuntimeContext:
289
291
 
290
292
  @classmethod
291
293
  def from_raw_config(
292
- cls, raw: RawConfig, repo: Repo, global_cli_options: GlobalCommandLineOptions
294
+ cls, raw: RawConfig, global_cli_options: GlobalCommandLineOptions
293
295
  ) -> RuntimeContext:
294
296
  ##
295
297
  # credentials masking for logging
296
298
  masker = MaskingFilter(_use_named_masks=raw.logging_use_named_masks)
297
299
 
298
300
  try:
301
+ repo = Repo(".", search_parent_directories=True)
299
302
  active_branch = repo.active_branch.name
303
+ except InvalidGitRepositoryError as err:
304
+ raise InvalidGitRepositoryError("No valid git repository found!") from err
300
305
  except TypeError as err:
301
306
  raise NotAReleaseBranch(
302
307
  "Detached HEAD state cannot match any release groups; "
@@ -1,4 +1,5 @@
1
1
  """Utilities for command-line functionality"""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import json
@@ -71,5 +71,4 @@ class CommitParser(ABC, Generic[_TT, _OPTS]):
71
71
  self.options = options
72
72
 
73
73
  @abstractmethod
74
- def parse(self, commit: Commit) -> _TT:
75
- ...
74
+ def parse(self, commit: Commit) -> _TT: ...
@@ -2,6 +2,7 @@
2
2
  Angular commit style parser
3
3
  https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines
4
4
  """
5
+
5
6
  from __future__ import annotations
6
7
 
7
8
  import logging
@@ -1,4 +1,5 @@
1
1
  """Commit parser which looks for emojis to determine the type of commit"""
2
+
2
3
  import logging
3
4
  from typing import Tuple
4
5
 
@@ -34,6 +34,7 @@ Supported Changelog Sections::
34
34
 
35
35
  .. _`scipy-style`: https://docs.scipy.org/doc/scipy/reference/dev/contributor/development_workflow.html#writing-the-commit-message
36
36
  """
37
+
37
38
  from __future__ import annotations
38
39
 
39
40
  import logging
@@ -1,4 +1,5 @@
1
1
  """Legacy commit parser from Python Semantic Release 1.0"""
2
+
2
3
  import logging
3
4
  import re
4
5
 
@@ -114,12 +114,12 @@ def parse_git_url(url: str) -> ParsedGitUrl:
114
114
  # Normalizers are a list of tuples of (pattern, replacement)
115
115
  normalizers = [
116
116
  # normalize implicit ssh urls to explicit ssh://
117
- (r"^(\w+@)", r"ssh://\1"),
117
+ (r"^([\w._-]+@)", r"ssh://\1"),
118
118
  # normalize git+ssh:// urls to ssh://
119
119
  (r"^git\+ssh://", "ssh://"),
120
120
  # normalize an scp like syntax to URL compatible syntax
121
121
  # excluding port definitions (:#####) & including numeric usernames
122
- (r"(ssh://(?:\w+@)?[\w.-]+):(?!\d{1,5}/\w+/)(.*)$", r"\1/\2"),
122
+ (r"(ssh://(?:[\w._-]+@)?[\w.-]+):(?!\d{1,5}/\w+/)(.*)$", r"\1/\2"),
123
123
  # normalize implicit file (windows || posix) urls to explicit file:// urls
124
124
  (r"^([C-Z]:/)|^/(\w)", r"file:///\1\2"),
125
125
  ]
@@ -1,4 +1,5 @@
1
1
  """Common functionality and interface for interacting with Git remote VCS"""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import logging
@@ -37,7 +37,7 @@ class Bitbucket(HvcsBase):
37
37
  API_VERSION = "2.0"
38
38
  DEFAULT_DOMAIN = "bitbucket.org"
39
39
  DEFAULT_API_DOMAIN = "api.bitbucket.org"
40
- DEFAULT_ENV_TOKEN_NAME = "BITBUCKET_TOKEN"
40
+ DEFAULT_ENV_TOKEN_NAME = "BITBUCKET_TOKEN" # noqa: S105
41
41
 
42
42
  def __init__(
43
43
  self,
@@ -93,14 +93,13 @@ class Bitbucket(HvcsBase):
93
93
  f"https://{user}:{self.token}@"
94
94
  f"{self.hvcs_domain}/{self.owner}/{self.repo_name}.git"
95
95
  )
96
- else:
97
- # Note: Assume the token is a repository token which will only work on the
98
- # repository it was created for.
99
- # https://support.atlassian.com/bitbucket-cloud/docs/using-access-tokens
100
- return (
101
- f"https://x-token-auth:{self.token}@"
102
- f"{self.hvcs_domain}/{self.owner}/{self.repo_name}.git"
103
- )
96
+ # Note: Assume the token is a repository token which will only work on the
97
+ # repository it was created for.
98
+ # https://support.atlassian.com/bitbucket-cloud/docs/using-access-tokens
99
+ return (
100
+ f"https://x-token-auth:{self.token}@"
101
+ f"{self.hvcs_domain}/{self.owner}/{self.repo_name}.git"
102
+ )
104
103
 
105
104
  def commit_hash_url(self, commit_hash: str) -> str:
106
105
  return (
@@ -1,4 +1,5 @@
1
1
  """Helper code for interacting with a Gitea remote VCS"""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import glob
@@ -1,4 +1,5 @@
1
1
  """Helper code for interacting with a GitHub remote VCS"""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import glob
@@ -1,4 +1,5 @@
1
1
  """Helper code for interacting with a Gitlab remote VCS"""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import logging
@@ -25,15 +25,13 @@ VersionComparator = Callable[["Version", "Version"], bool]
25
25
  def _comparator(
26
26
  *,
27
27
  type_guard: bool,
28
- ) -> Callable[[VersionComparator], VersionComparator]:
29
- ...
28
+ ) -> Callable[[VersionComparator], VersionComparator]: ...
30
29
 
31
30
 
32
31
  @overload
33
32
  def _comparator(
34
33
  method: VersionComparator, *, type_guard: bool = True
35
- ) -> VersionComparator:
36
- ...
34
+ ) -> VersionComparator: ...
37
35
 
38
36
 
39
37
  def _comparator(
@@ -1,53 +0,0 @@
1
- semantic_release/__init__.py,sha256=VAvwW3w5b39fdfZha1JYL-fk_yvUuSj9aP7DihEURSE,869
2
- semantic_release/__main__.py,sha256=vXOARLV7KHeVXgpOMU0Q-8wovpdsOrtTsycxulI5xIE,106
3
- semantic_release/const.py,sha256=Z1o2QNh60wSLeF-_1TemMBjU3ZXbV0XghnUFsbTVfOs,831
4
- semantic_release/enums.py,sha256=D5B_reQGGKQQT22HO5PUtvn2Bok3fkht6TfJtXkmAUg,1020
5
- semantic_release/errors.py,sha256=KKKCV45vvE9tla0sxYDGHkHWvqDn1gEfGIpzujcDbeI,809
6
- semantic_release/helpers.py,sha256=JYsAVmqF46VLONkT5t_0M5cq4zs6gNC3vzQhW3WlbN8,5571
7
- semantic_release/changelog/__init__.py,sha256=Bg6Xe5Vt32rWoMscW-hd4sUwiZqzWmsg4CD1EhMesMY,262
8
- semantic_release/changelog/context.py,sha256=ItSz5Bon2mcJkLxyQZzBTukN0zEdcaVQ4iXvz3jGCLc,986
9
- semantic_release/changelog/release_history.py,sha256=GpJ1aQDq46ymBUBCILInfJ4sVuZoexiEfUBqAB9FN0o,6712
10
- semantic_release/changelog/template.py,sha256=Vzsc2dN4_6RuykELN8lqEc4L9Gw6ibpiq4oB36kUoOU,4649
11
- semantic_release/cli/__init__.py,sha256=gwAYhZO-4TR0tKCkQ4GqutWsL--0CII2_dcbrElI4M4,419
12
- semantic_release/cli/common.py,sha256=cVQUI7Uaac_nJ7VEXuJ7Q9pVJpuMVRvE7bBl_i96g20,1439
13
- semantic_release/cli/config.py,sha256=9k0ms8H-A7Idpww3dDqrcuIGFFhBFHZzk-T_vx9QGmM,15822
14
- semantic_release/cli/const.py,sha256=S8oNNpSaKdZxcAs7PAKEjQHic0czoJBGd7XHo57FOzw,39
15
- semantic_release/cli/github_actions_output.py,sha256=stGWcuMtelY0qM2E_-IfofP6UvsQ6czsO7qpMfnRJI4,2102
16
- semantic_release/cli/masking_filter.py,sha256=DxqjiJyABlzwwwZ1r8JGQpb6QrF00StJFm0-2-s5Fv0,3071
17
- semantic_release/cli/util.py,sha256=toWIrjKhnuU66giiLD5anpHGg1OuVbhnPigIDt4byxA,3754
18
- semantic_release/cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- semantic_release/cli/commands/changelog.py,sha256=vIJKTy8vPh7xGzJ3jEz-1z9evuJrHVg-Wqmms-c6G_k,4040
20
- semantic_release/cli/commands/generate_config.py,sha256=BwtwFhh80bkOUUNnR2ArC51YfPKI_y4HMD7C1oAFREA,1695
21
- semantic_release/cli/commands/main.py,sha256=LBbHbDNIctb35bUQsklefXVPN9bhY-LlrQFF1nNTMLg,5049
22
- semantic_release/cli/commands/publish.py,sha256=CvhZ4Z8CTPS-4f7kWH-xJ5JTk3jlJ-p8Mg7y2KC4SnY,1492
23
- semantic_release/cli/commands/version.py,sha256=lFXRUPM-amJaRNSaneV5olrf6UEYN_mCeBN_y7jGssk,22416
24
- semantic_release/commit_parser/__init__.py,sha256=cv5HFBdw7OJd4Laj4Ex8ZZ5Tml8GwXgQcXW6Pasr2Ao,615
25
- semantic_release/commit_parser/_base.py,sha256=d7-sOgKn44-IG_fpJhSPZuOvkrVrMVTihfH395i3qtE,2617
26
- semantic_release/commit_parser/angular.py,sha256=7kp-vo3hpShHC3X3TZKHiOyXI_grLHn1hZ8L8bI3gC8,4392
27
- semantic_release/commit_parser/emoji.py,sha256=alZL8BgMfdOQYTFwWPn9JtWD2HAoYNeHigFYjxxLqy8,3288
28
- semantic_release/commit_parser/scipy.py,sha256=YOO5SaE0d3R6nCg5WBCBe6Zd0hoPjBZrdRr7IHVsdSw,5776
29
- semantic_release/commit_parser/tag.py,sha256=Ue_XYc-Y_BWda4uMcYcOY9wU_12aw_brySMHekX4EX4,3193
30
- semantic_release/commit_parser/token.py,sha256=UxYAwEylPvp4x39RqNA9ITcgkaSRDEH7A5XDDJ3tdiM,1505
31
- semantic_release/commit_parser/util.py,sha256=vLcVDErZrExM55jMffos0hyMbNVQoJ-PeeVDG1Ej51I,730
32
- semantic_release/data/templates/CHANGELOG.md.j2,sha256=GB3YJwgVrhlcb-g5ESdEh_Gsysb_Texxv-Ip2LjulC0,1066
33
- semantic_release/data/templates/release_notes.md.j2,sha256=27uIHgG6iYmqdMaoWFP5LJRZcrO-3paqFzHHHsGpXXE,465
34
- semantic_release/hvcs/__init__.py,sha256=ulesZslSG4Lu8Iz3YzOrPXpdgvgbADq_MV17B-bSYQA,379
35
- semantic_release/hvcs/_base.py,sha256=CXE-yI1zDgOybSnd7oMQJ_GVyiIA7HrltqoO8I1N1hc,5634
36
- semantic_release/hvcs/bitbucket.py,sha256=jqWWxVOrtrK-Yk9yLzQySb4G41G7yGDkGDUhHW4KuMQ,4654
37
- semantic_release/hvcs/gitea.py,sha256=xQ6sm04YNk30t8ieCNY61DtcDPygppvcvF_meI17Des,8458
38
- semantic_release/hvcs/github.py,sha256=IfBtKSXXoT-H-cKdwmiB-xRGYrvzC5hJN6cf1Ekylgk,10709
39
- semantic_release/hvcs/gitlab.py,sha256=hJCTv4QC9y1iABiqJeSc0V5H8R1HZ8TRTd6ZFIKj4Es,6153
40
- semantic_release/hvcs/token_auth.py,sha256=ZjT56-NIPB4OKIt1qwHCu1TavXnrWFIBl9ARlg56hgU,663
41
- semantic_release/hvcs/util.py,sha256=PNKXApgL2np9lpnKjAbo77toRgElLPXrbS1q7621waI,2886
42
- semantic_release/version/__init__.py,sha256=CLhtGQry9dLIij5XyRa9ZevxU_1p8tjMTSQ-K_GMpWM,270
43
- semantic_release/version/algorithm.py,sha256=K9WkPRur0x5baXsqEi8kvaDfxduG4WNUiALXZRXujJ4,16484
44
- semantic_release/version/declaration.py,sha256=f6Ld7hIhrqvDrRBapJHr-KDimuyo-4IG8009Zu9BIgU,7357
45
- semantic_release/version/translator.py,sha256=P1noIsVBn8u6zNOFjG0xKYOWapxqf_PHSMvMeLJ9kXg,3050
46
- semantic_release/version/version.py,sha256=siyX3Cl_qhw9dTIUpafFX8-wHKW2RILVm8u6i519Pck,14183
47
- python_semantic_release-9.2.0.dist-info/AUTHORS.rst,sha256=XOReVvpymEFUPsS2QPH97jlfJBVrxwS2eu8-jVAe4gk,230
48
- python_semantic_release-9.2.0.dist-info/LICENSE,sha256=NE85nszX252sdQdu0xgS9qwfYES0k8qS6gW3uO4jRGE,1083
49
- python_semantic_release-9.2.0.dist-info/METADATA,sha256=AmbbiVLWcUVLNNwMJflgWhScEq_w5eNbn8rgAPk5ZX4,5366
50
- python_semantic_release-9.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
51
- python_semantic_release-9.2.0.dist-info/entry_points.txt,sha256=qojUBx_Ywf4u7KgP6NWlDaBDymZVUGQ7m5wF2duC2F0,95
52
- python_semantic_release-9.2.0.dist-info/top_level.txt,sha256=qYA24nyg3eP-ti5UW7Vuj2aXVmM0wqVHx4mREdRZNAA,17
53
- python_semantic_release-9.2.0.dist-info/RECORD,,