bumpversion-slim 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bumpversion_slim/__init__.py +0 -0
- bumpversion_slim/bump.py +92 -0
- bumpversion_slim/cli.py +141 -0
- bumpversion_slim/config.py +89 -0
- bumpversion_slim/context.py +79 -0
- bumpversion_slim/errors.py +10 -0
- bumpversion_slim/git.py +111 -0
- bumpversion_slim/py.typed +0 -0
- bumpversion_slim-0.1.0.dist-info/METADATA +38 -0
- bumpversion_slim-0.1.0.dist-info/RECORD +12 -0
- bumpversion_slim-0.1.0.dist-info/WHEEL +4 -0
- bumpversion_slim-0.1.0.dist-info/entry_points.txt +2 -0
|
File without changes
|
bumpversion_slim/bump.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import typing as t
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from bumpversion_slim import errors
|
|
9
|
+
|
|
10
|
+
if t.TYPE_CHECKING:
|
|
11
|
+
from bumpversion_slim.config import Config
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
T = t.TypeVar("T", bound="BumpVersion")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ModifyFile:
|
|
20
|
+
"""Configured file for modification."""
|
|
21
|
+
|
|
22
|
+
filename: str
|
|
23
|
+
path: Path
|
|
24
|
+
patterns: list[str]
|
|
25
|
+
|
|
26
|
+
def update(self, current: str, new: str, *, dry_run: bool) -> tuple[Path, Path]:
|
|
27
|
+
"""Update file with configured patterns."""
|
|
28
|
+
try:
|
|
29
|
+
with self.path.open("r") as f:
|
|
30
|
+
contents = f.read()
|
|
31
|
+
except FileNotFoundError as e:
|
|
32
|
+
msg = f"Configured file not found '{self.filename}'."
|
|
33
|
+
raise errors.VersionError(msg) from e
|
|
34
|
+
|
|
35
|
+
for pattern in self.patterns:
|
|
36
|
+
try:
|
|
37
|
+
search, replace = pattern.format(version=current), pattern.format(version=new)
|
|
38
|
+
except KeyError as e:
|
|
39
|
+
msg = f"Incorrect pattern '{pattern}' for '{self.filename}'."
|
|
40
|
+
raise errors.VersionError(msg) from e
|
|
41
|
+
|
|
42
|
+
if search == replace:
|
|
43
|
+
msg = f"Pattern '{pattern}' generated no change for '{self.filename}'."
|
|
44
|
+
raise errors.VersionError(msg)
|
|
45
|
+
|
|
46
|
+
new_contents = contents.replace(search, replace)
|
|
47
|
+
if new_contents == contents:
|
|
48
|
+
msg = f"No change for '{self.filename}', ensure pattern '{pattern}' is correct."
|
|
49
|
+
raise errors.VersionError(msg)
|
|
50
|
+
contents = new_contents
|
|
51
|
+
|
|
52
|
+
backup = Path(f"{self.path}.bak")
|
|
53
|
+
if not dry_run:
|
|
54
|
+
with backup.open("w") as f:
|
|
55
|
+
f.write(contents)
|
|
56
|
+
|
|
57
|
+
return (self.path, backup)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class BumpVersion: # noqa: D101
|
|
61
|
+
def __init__(self, cfg: Config, new: str = "", *, allow_dirty: bool = False, dry_run: bool = False) -> None:
|
|
62
|
+
self.allow_dirty = allow_dirty
|
|
63
|
+
self.dry_run = dry_run
|
|
64
|
+
self.config = cfg
|
|
65
|
+
self.new = new
|
|
66
|
+
|
|
67
|
+
def replace(self, version: str) -> list[str]: # noqa: D102
|
|
68
|
+
cwd = Path.cwd()
|
|
69
|
+
files_to_modify = {
|
|
70
|
+
"pyproject.toml": ModifyFile("pyproject.toml", cwd / "pyproject.toml", ['current_version = "{version}"']),
|
|
71
|
+
}
|
|
72
|
+
for file in self.config.files:
|
|
73
|
+
mf = files_to_modify.get(file["filename"], ModifyFile(file["filename"], cwd / file["filename"], []))
|
|
74
|
+
mf.patterns.append(file.get("pattern", "{version}"))
|
|
75
|
+
files_to_modify[file["filename"]] = mf
|
|
76
|
+
|
|
77
|
+
modified_files = []
|
|
78
|
+
for file in files_to_modify.values():
|
|
79
|
+
try:
|
|
80
|
+
modified_files.append(file.update(self.config.current_version, version, dry_run=self.dry_run))
|
|
81
|
+
except Exception: # noqa: PERF203
|
|
82
|
+
if not self.dry_run:
|
|
83
|
+
for _original, backup in modified_files:
|
|
84
|
+
backup.unlink()
|
|
85
|
+
raise
|
|
86
|
+
|
|
87
|
+
if not self.dry_run:
|
|
88
|
+
for original, backup in modified_files:
|
|
89
|
+
original.write_text(backup.read_text())
|
|
90
|
+
backup.unlink()
|
|
91
|
+
|
|
92
|
+
return sorted({mf.filename for mf in files_to_modify.values()})
|
bumpversion_slim/cli.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import importlib
|
|
5
|
+
import importlib.metadata
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
from bumpversion_slim import (
|
|
10
|
+
config,
|
|
11
|
+
errors,
|
|
12
|
+
)
|
|
13
|
+
from bumpversion_slim.bump import BumpVersion
|
|
14
|
+
from bumpversion_slim.context import Context
|
|
15
|
+
from bumpversion_slim.git import Git
|
|
16
|
+
|
|
17
|
+
version = importlib.metadata.version("bumpversion_slim")
|
|
18
|
+
parser = argparse.ArgumentParser(prog="bumpversion")
|
|
19
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {version}")
|
|
20
|
+
parser.add_argument("version_number", help="The desired version number to bump to.")
|
|
21
|
+
parser.add_argument("--dry-run", action=argparse.BooleanOptionalAction, help="Don't commit changes, check for errors.")
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--allow-dirty",
|
|
24
|
+
action=argparse.BooleanOptionalAction,
|
|
25
|
+
help="Don't abort if branch contains uncommitted changes.",
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"--allow-missing",
|
|
29
|
+
action=argparse.BooleanOptionalAction,
|
|
30
|
+
help="Don't abort if missing commits on origin.",
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--commit",
|
|
34
|
+
action=argparse.BooleanOptionalAction,
|
|
35
|
+
help="Commit changes made to package, and configured files, after writing.",
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument("--tag", action=argparse.BooleanOptionalAction, help="Tag changes made after commit.")
|
|
38
|
+
parser.add_argument("--verbose", "-v", action="count", default=0, help="Set output verbosity.")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def process_info(info: dict, context: Context, cfg: config.Config, *, dry_run: bool) -> None:
|
|
42
|
+
"""Process git info and raise on invalid state."""
|
|
43
|
+
if dry_run:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
if info["dirty"] and not cfg.allow_dirty:
|
|
47
|
+
context.error("Working directory is not clean. Use `allow_dirty` configuration to ignore.")
|
|
48
|
+
sys.exit(1)
|
|
49
|
+
|
|
50
|
+
if info["missing_local"] and not cfg.allow_missing:
|
|
51
|
+
context.error(
|
|
52
|
+
"Current local branch is missing commits from remote %s.\nUse `allow_missing` configuration to ignore.",
|
|
53
|
+
info["branch"],
|
|
54
|
+
)
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
if info["missing_remote"] and not cfg.allow_missing:
|
|
58
|
+
context.error(
|
|
59
|
+
"Current remote branch is missing commits from local %s.\nUse `allow_missing` configuration to ignore.",
|
|
60
|
+
info["branch"],
|
|
61
|
+
)
|
|
62
|
+
sys.exit(1)
|
|
63
|
+
|
|
64
|
+
allowed_branches = cfg.allowed_branches
|
|
65
|
+
if allowed_branches and info["branch"] not in allowed_branches:
|
|
66
|
+
context.error("Current branch not in allowed generation branches.")
|
|
67
|
+
sys.exit(1)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def main() -> None:
|
|
71
|
+
"""Bump package version."""
|
|
72
|
+
parsed = parser.parse_args()
|
|
73
|
+
start = time.time()
|
|
74
|
+
cfg = config.read(
|
|
75
|
+
allow_dirty=parsed.allow_dirty,
|
|
76
|
+
allow_missing=parsed.allow_missing,
|
|
77
|
+
commit=parsed.commit,
|
|
78
|
+
tag=parsed.tag,
|
|
79
|
+
verbose=parsed.verbose,
|
|
80
|
+
)
|
|
81
|
+
context = Context(cfg, parsed.verbose)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
_bump(
|
|
85
|
+
context,
|
|
86
|
+
cfg,
|
|
87
|
+
parsed.version_number,
|
|
88
|
+
dry_run=parsed.dry_run,
|
|
89
|
+
)
|
|
90
|
+
except errors.BumpException as ex:
|
|
91
|
+
context.stacktrace()
|
|
92
|
+
context.debug("Run time (error) %fms", (time.time() - start) * 1000)
|
|
93
|
+
context.error(str(ex))
|
|
94
|
+
sys.exit(1)
|
|
95
|
+
context.debug("Run time %fms", (time.time() - start) * 1000)
|
|
96
|
+
sys.exit(0)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _bump(
|
|
100
|
+
context: Context,
|
|
101
|
+
cfg: config.Config,
|
|
102
|
+
new_version: str,
|
|
103
|
+
*,
|
|
104
|
+
dry_run: bool = False,
|
|
105
|
+
) -> None:
|
|
106
|
+
bv = BumpVersion(cfg, new_version, dry_run=dry_run, allow_dirty=cfg.allow_dirty)
|
|
107
|
+
git = Git(context=context, dry_run=dry_run, commit=cfg.commit, tag=cfg.tag)
|
|
108
|
+
|
|
109
|
+
process_info(git.get_current_info(), context, cfg, dry_run=dry_run)
|
|
110
|
+
|
|
111
|
+
version_tag = cfg.version_string.format(new_version=str(new_version))
|
|
112
|
+
|
|
113
|
+
def release_hook(_context: Context, new_version: str) -> list[str]:
|
|
114
|
+
return bv.replace(new_version)
|
|
115
|
+
|
|
116
|
+
hooks = [release_hook]
|
|
117
|
+
for hook in cfg.hooks:
|
|
118
|
+
try:
|
|
119
|
+
import_path, hook_func = hook.split(":")
|
|
120
|
+
except ValueError:
|
|
121
|
+
context.error("Invalid hook format, expected `path.to.module:hook_func`.")
|
|
122
|
+
sys.exit(1)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
mod = importlib.import_module(import_path)
|
|
126
|
+
except ModuleNotFoundError:
|
|
127
|
+
context.error("Invalid hook module `%s`, not found.", import_path)
|
|
128
|
+
sys.exit(1)
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
hooks.append(getattr(mod, hook_func))
|
|
132
|
+
except AttributeError:
|
|
133
|
+
context.error("Invalid hook func `%s`, not found in hook module.", hook_func)
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
|
|
136
|
+
paths = cfg.commit_extra
|
|
137
|
+
for hook in hooks:
|
|
138
|
+
hook_paths = hook(context, new_version)
|
|
139
|
+
paths.extend(hook_paths)
|
|
140
|
+
|
|
141
|
+
git.commit(cfg.current_version, new_version, version_tag, paths)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import typing
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import rtoml
|
|
8
|
+
|
|
9
|
+
from bumpversion_slim import errors
|
|
10
|
+
|
|
11
|
+
P = typing.ParamSpec("P")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclasses.dataclass
|
|
15
|
+
class Config:
|
|
16
|
+
"""Changelog configuration options."""
|
|
17
|
+
|
|
18
|
+
current_version: str
|
|
19
|
+
allowed_branches: list[str] = dataclasses.field(default_factory=list)
|
|
20
|
+
|
|
21
|
+
# CLI overrides
|
|
22
|
+
verbose: int = 0
|
|
23
|
+
commit: bool = True
|
|
24
|
+
tag: bool = True
|
|
25
|
+
allow_dirty: bool = False
|
|
26
|
+
allow_missing: bool = False
|
|
27
|
+
commit_extra: list[str] = dataclasses.field(default_factory=list)
|
|
28
|
+
|
|
29
|
+
# Version bumping
|
|
30
|
+
files: dict = dataclasses.field(default_factory=dict)
|
|
31
|
+
version_string: str = "v{new_version}"
|
|
32
|
+
|
|
33
|
+
# Hooks
|
|
34
|
+
hooks: list[str] = dataclasses.field(default_factory=list)
|
|
35
|
+
custom: dict = dataclasses.field(default_factory=dict)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _process_overrides(overrides: dict) -> dict:
|
|
39
|
+
"""Process provided overrides.
|
|
40
|
+
|
|
41
|
+
Remove any unsupplied values (None).
|
|
42
|
+
"""
|
|
43
|
+
return {k: v for k, v in overrides.items() if v is not None}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _process_pyproject(pyproject: Path) -> dict:
|
|
47
|
+
cfg = {}
|
|
48
|
+
with pyproject.open() as f:
|
|
49
|
+
data = rtoml.load(f)
|
|
50
|
+
|
|
51
|
+
if "tool" not in data or "bumpversion" not in data["tool"]:
|
|
52
|
+
return cfg
|
|
53
|
+
|
|
54
|
+
return data["tool"]["bumpversion"]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def check_deprecations(cfg: dict) -> None: # noqa: ARG001
|
|
58
|
+
"""Check parsed configuration dict for deprecated features."""
|
|
59
|
+
# No current deprecations
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def read(path: str = "pyproject.toml", *args: P.args, **kwargs: P.kwargs) -> Config: # noqa: ARG001
|
|
64
|
+
"""Read configuration from local environment.
|
|
65
|
+
|
|
66
|
+
Supported configuration locations (checked in order):
|
|
67
|
+
* pyproject.toml
|
|
68
|
+
"""
|
|
69
|
+
overrides = _process_overrides(kwargs)
|
|
70
|
+
cfg = {}
|
|
71
|
+
|
|
72
|
+
pyproject = Path(path)
|
|
73
|
+
|
|
74
|
+
if not pyproject.exists():
|
|
75
|
+
msg = "pyproject.toml configuration missing."
|
|
76
|
+
raise errors.BumpException(msg)
|
|
77
|
+
|
|
78
|
+
# parse pyproject
|
|
79
|
+
cfg = _process_pyproject(pyproject)
|
|
80
|
+
|
|
81
|
+
cfg.update(overrides)
|
|
82
|
+
|
|
83
|
+
check_deprecations(cfg) # pragma: no mutate
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
return Config(**cfg)
|
|
87
|
+
except TypeError as e:
|
|
88
|
+
msg = "Invalid configuration."
|
|
89
|
+
raise errors.BumpException(msg) from e
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import sys
|
|
5
|
+
import traceback
|
|
6
|
+
import typing
|
|
7
|
+
from enum import IntEnum
|
|
8
|
+
|
|
9
|
+
if typing.TYPE_CHECKING:
|
|
10
|
+
from bumpversion_slim.config import Config
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Verbosity(IntEnum):
|
|
14
|
+
"""Verbosity levels."""
|
|
15
|
+
|
|
16
|
+
quiet = 0
|
|
17
|
+
verbose1 = 1
|
|
18
|
+
verbose2 = 2
|
|
19
|
+
verbose3 = 3
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
P = typing.ParamSpec("P")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Context:
|
|
26
|
+
"""Global context class."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, config: Config, verbose: int = 0) -> None:
|
|
29
|
+
self.config = config
|
|
30
|
+
self._verbose = verbose
|
|
31
|
+
self._indent = 0
|
|
32
|
+
|
|
33
|
+
def reset(self) -> None:
|
|
34
|
+
"""Reset context messaging indentation."""
|
|
35
|
+
self._indent = 0
|
|
36
|
+
|
|
37
|
+
def indent(self) -> None:
|
|
38
|
+
"""Indent context messaging."""
|
|
39
|
+
self._indent += 1
|
|
40
|
+
|
|
41
|
+
def dedent(self) -> None:
|
|
42
|
+
"""Dedent context messaging."""
|
|
43
|
+
self._indent = max(0, self._indent - 1)
|
|
44
|
+
|
|
45
|
+
def _echo(self, message: str, *args: P.args, **kwargs: P.kwargs) -> None: # noqa: ARG002
|
|
46
|
+
"""Echo to the console."""
|
|
47
|
+
message = message % args
|
|
48
|
+
print(f"{' ' * self._indent}{message}")
|
|
49
|
+
|
|
50
|
+
def error(self, message: str, *args: P.args, **kwargs: P.kwargs) -> None:
|
|
51
|
+
"""Echo to the console."""
|
|
52
|
+
self._echo(message, *args, **kwargs)
|
|
53
|
+
|
|
54
|
+
def warning(self, message: str, *args: P.args, **kwargs: P.kwargs) -> None:
|
|
55
|
+
"""Echo to the console for -v."""
|
|
56
|
+
if self._verbose > Verbosity.quiet:
|
|
57
|
+
self._echo(message, *args, **kwargs)
|
|
58
|
+
|
|
59
|
+
def info(self, message: str, *args: P.args, **kwargs: P.kwargs) -> None:
|
|
60
|
+
"""Echo to the console for -vv."""
|
|
61
|
+
if self._verbose > Verbosity.verbose1:
|
|
62
|
+
self._echo(message, *args, **kwargs)
|
|
63
|
+
|
|
64
|
+
def debug(self, message: str, *args: P.args, **kwargs: P.kwargs) -> None:
|
|
65
|
+
"""Echo to the console for -vvv."""
|
|
66
|
+
if self._verbose > Verbosity.verbose2:
|
|
67
|
+
self._echo(message, *args, **kwargs)
|
|
68
|
+
|
|
69
|
+
def stacktrace(self) -> None:
|
|
70
|
+
"""Echo exceptions to console for -vvv."""
|
|
71
|
+
if self._verbose > Verbosity.verbose2:
|
|
72
|
+
t, v, tb = sys.exc_info()
|
|
73
|
+
sio = io.StringIO()
|
|
74
|
+
traceback.print_exception(t, v, tb, None, sio)
|
|
75
|
+
s = sio.getvalue()
|
|
76
|
+
# Clean up odd python 3.11, 3.12 formatting on mac
|
|
77
|
+
s = s.replace("\n ^^^^^^^^^^^^^^^^^^^^^^^^^^", "")
|
|
78
|
+
sio.close()
|
|
79
|
+
self._echo(s)
|
bumpversion_slim/git.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing as t
|
|
4
|
+
|
|
5
|
+
import git
|
|
6
|
+
|
|
7
|
+
from bumpversion_slim import errors
|
|
8
|
+
|
|
9
|
+
if t.TYPE_CHECKING:
|
|
10
|
+
from bumpversion_slim.context import Context
|
|
11
|
+
|
|
12
|
+
T = t.TypeVar("T", bound="Git")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Git:
|
|
16
|
+
"""VCS implementation for git repositories."""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
context: Context,
|
|
21
|
+
*,
|
|
22
|
+
commit: bool = True,
|
|
23
|
+
tag: bool = True,
|
|
24
|
+
dry_run: bool = False,
|
|
25
|
+
) -> None:
|
|
26
|
+
self.context = context
|
|
27
|
+
self._commit = commit
|
|
28
|
+
self._tag = tag
|
|
29
|
+
self.dry_run = dry_run
|
|
30
|
+
try:
|
|
31
|
+
self.repo = git.Repo()
|
|
32
|
+
except git.exc.InvalidGitRepositoryError as e:
|
|
33
|
+
msg = "No git repository found, please run git init."
|
|
34
|
+
raise errors.GitError(msg) from e
|
|
35
|
+
|
|
36
|
+
def get_current_info(self) -> dict[str, str | bool]:
|
|
37
|
+
"""Get current state info from git."""
|
|
38
|
+
branch = self.repo.active_branch.name
|
|
39
|
+
try:
|
|
40
|
+
missing_local = list(self.repo.iter_commits(f"HEAD..origin/{branch}"))
|
|
41
|
+
except git.GitCommandError as e:
|
|
42
|
+
if f"bad revision 'HEAD..origin/{branch}'" in str(e):
|
|
43
|
+
missing_local = []
|
|
44
|
+
else:
|
|
45
|
+
msg = f"Unable to determine missing commit status: {e}"
|
|
46
|
+
raise errors.GitError(msg) from e
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
missing_remote = list(self.repo.iter_commits(f"origin/{branch}..HEAD"))
|
|
50
|
+
except git.GitCommandError as e:
|
|
51
|
+
if f"bad revision 'origin/{branch}..HEAD'" in str(e):
|
|
52
|
+
missing_remote = ["missing"]
|
|
53
|
+
else:
|
|
54
|
+
msg = f"Unable to determine missing commit status: {e}"
|
|
55
|
+
raise errors.GitError(msg) from e
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
"missing_local": missing_local != [],
|
|
59
|
+
"missing_remote": missing_remote != [],
|
|
60
|
+
"dirty": self.repo.is_dirty(),
|
|
61
|
+
"branch": branch,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
def add_paths(self, paths: list[str]) -> None:
|
|
65
|
+
"""Add path to git repository."""
|
|
66
|
+
if self.dry_run:
|
|
67
|
+
self.context.warning(" Would add paths '%s' to Git", "', '".join(paths))
|
|
68
|
+
return
|
|
69
|
+
self.repo.git.add(*paths)
|
|
70
|
+
|
|
71
|
+
def commit(self, current: str, new: str, tag: str, paths: list[str] | None = None) -> None:
|
|
72
|
+
"""Commit changes to git repository."""
|
|
73
|
+
self.context.warning("Would prepare Git commit")
|
|
74
|
+
paths = paths or []
|
|
75
|
+
|
|
76
|
+
if paths:
|
|
77
|
+
self.add_paths(paths)
|
|
78
|
+
|
|
79
|
+
msg = [
|
|
80
|
+
f"Update CHANGELOG for {new}",
|
|
81
|
+
f"Bump version: {current} → {new}",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
message = "\n".join(msg).strip()
|
|
85
|
+
if self.dry_run or not self._commit:
|
|
86
|
+
self.context.warning(" Would commit to Git with message '%s", message)
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
self.repo.git.commit(message=message)
|
|
91
|
+
except git.GitCommandError as e:
|
|
92
|
+
msg = f"Unable to commit: {e}"
|
|
93
|
+
raise errors.GitError(msg) from e
|
|
94
|
+
|
|
95
|
+
if not self._tag:
|
|
96
|
+
self.context.warning(" Would tag with version '%s", tag)
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
self.repo.git.tag(tag)
|
|
101
|
+
except git.GitCommandError as e:
|
|
102
|
+
self.revert()
|
|
103
|
+
msg = f"Unable to tag: {e}"
|
|
104
|
+
raise errors.GitError(msg) from e
|
|
105
|
+
|
|
106
|
+
def revert(self) -> None:
|
|
107
|
+
"""Revert a commit."""
|
|
108
|
+
if self.dry_run:
|
|
109
|
+
self.context.warning("Would revert commit in Git")
|
|
110
|
+
return
|
|
111
|
+
self.repo.git.reset("HEAD~1", hard=True)
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bumpversion-slim
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight tool to bump package versions
|
|
5
|
+
Author-email: Daniel Edgecombe <daniel@nrwl.co>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
21
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
22
|
+
Classifier: Topic :: System :: Software Distribution
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: gitpython>=3.1.46
|
|
25
|
+
Requires-Dist: rtoml>=0.13.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: git-cliff>=2.12.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: prek>=0.3.4; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.14.10; extra == 'dev'
|
|
30
|
+
Requires-Dist: ty>=0.0.17; extra == 'dev'
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: freezegun>=1.2.1; extra == 'test'
|
|
33
|
+
Requires-Dist: path<17,>=16; extra == 'test'
|
|
34
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'test'
|
|
35
|
+
Requires-Dist: pytest-git<1.8,>=1.7.0; extra == 'test'
|
|
36
|
+
Requires-Dist: pytest-httpx>=0.36.0; extra == 'test'
|
|
37
|
+
Requires-Dist: pytest-random-order>=1.2.0; extra == 'test'
|
|
38
|
+
Requires-Dist: pytest>=9.0.0; extra == 'test'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
bumpversion_slim/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
bumpversion_slim/bump.py,sha256=kHJMsWAvUf3MkqlHSM13fCrvBz4_ZcthSSZqR7hAV1I,3213
|
|
3
|
+
bumpversion_slim/cli.py,sha256=tysVOK80yCtUaCUDagtAuApiKYIlB-HThtePLbQ0fxY,4636
|
|
4
|
+
bumpversion_slim/config.py,sha256=OeZLnBKzkm8JNveSOJwKioGwbhjK1JlzvPjpwZtT1ow,2206
|
|
5
|
+
bumpversion_slim/context.py,sha256=nXbsP4iTrXexh500NggIqIRizNAWVIg3nmFK2IKS1i0,2355
|
|
6
|
+
bumpversion_slim/errors.py,sha256=e4oUs0DoqZOeV7Uq5DmjbVMgKfDnXVrJ10pASQLPJXY,213
|
|
7
|
+
bumpversion_slim/git.py,sha256=l4g7B-2lSuzdNf6bvfK_q6Q3mdFHuStQATlM9plyfY8,3476
|
|
8
|
+
bumpversion_slim/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
bumpversion_slim-0.1.0.dist-info/METADATA,sha256=QieAreL1C2ljr9fDNZc0OC0m0oLS6zgrfId0P0ToZc0,1660
|
|
10
|
+
bumpversion_slim-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
11
|
+
bumpversion_slim-0.1.0.dist-info/entry_points.txt,sha256=Slc323FHt9s9JUJQ_dRTbGYk_1Jg6hCYR3lhei7Ax5I,58
|
|
12
|
+
bumpversion_slim-0.1.0.dist-info/RECORD,,
|