bump-py-version 2.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.
@@ -0,0 +1 @@
1
+ __version__ = "2.1.0"
bump_py_version/cli.py ADDED
@@ -0,0 +1,245 @@
1
+ import sys
2
+ import argparse
3
+ import shlex
4
+ import shutil
5
+ import tomlkit
6
+ import subprocess
7
+ from bump_py_version import __version__
8
+
9
+
10
+ def parse_version_tag(tag):
11
+ """
12
+ Remove leading 'v' if it exists
13
+ """
14
+ if tag.startswith("v"):
15
+ return tag[1:]
16
+ return tag
17
+
18
+
19
+ def alter_pyproject(doc, version):
20
+ """
21
+ Changes the project version and the poetry version
22
+ in the pyproject.toml file, preserving formatting.
23
+ """
24
+ version = parse_version_tag(version)
25
+
26
+ if "project" in doc:
27
+ doc["project"]["version"] = version
28
+
29
+ with open("pyproject.toml", "w", encoding="utf-8") as f:
30
+ f.write(tomlkit.dumps(doc))
31
+
32
+
33
+ def alter_init(path, version):
34
+ """
35
+ Changes the version in the __init__.py file
36
+ """
37
+ version = parse_version_tag(version)
38
+ with open(path, "r") as f:
39
+ lines = f.readlines()
40
+ with open(path, "w") as f:
41
+ for line in lines:
42
+ if line.startswith("__version__ ="):
43
+ f.write(f'__version__ = "{version}"\n')
44
+ else:
45
+ f.write(line)
46
+
47
+
48
+ def alter_text_file(file, str_search, replace):
49
+ """
50
+ Changes the version in a text file by replacing
51
+ the line after the line matching str_search.
52
+ """
53
+ dynamic_next_line = False
54
+ with open(file, "r") as f:
55
+ lines = f.readlines()
56
+ with open(file, "w") as f:
57
+ for line in lines:
58
+ if dynamic_next_line:
59
+ f.write(replace)
60
+ dynamic_next_line = False
61
+ elif line.startswith(str_search):
62
+ f.write(line)
63
+ dynamic_next_line = True
64
+ else:
65
+ f.write(line)
66
+
67
+
68
+ def alter_version(version):
69
+ try:
70
+ with open("pyproject.toml", "r", encoding="utf-8") as f:
71
+ content = f.read()
72
+ doc = tomlkit.parse(content)
73
+ except FileNotFoundError:
74
+ doc = None
75
+
76
+ # Alter pyproject.toml
77
+ if doc:
78
+ alter_pyproject(doc, version)
79
+
80
+ # Alter __init__.py
81
+ try:
82
+ version_file = doc["tool"]["bump_version"]["version_file"]
83
+ alter_init(version_file, version)
84
+ except KeyError:
85
+ pass
86
+
87
+ # Alter text files
88
+ try:
89
+ replace_patterns = doc["tool"]["bump_version"]["replace_patterns"]
90
+ for _, pattern in replace_patterns.items():
91
+ pattern["replace"] = pattern["replace"].replace("{version}", version)
92
+ alter_text_file(
93
+ pattern["file"],
94
+ pattern["search"],
95
+ pattern["replace"],
96
+ )
97
+ except KeyError:
98
+ pass
99
+
100
+
101
+ def run_command_check_untracked():
102
+ """
103
+ Checks if there are untracked files.
104
+ """
105
+ status_message = """There are untracked files.
106
+ Use `git status` to see the files.
107
+ Please remove or commit the files before running the command."""
108
+
109
+ result = subprocess.run(
110
+ "git ls-files --others --exclude-standard",
111
+ check=True,
112
+ shell=True,
113
+ stdout=subprocess.PIPE,
114
+ stderr=subprocess.PIPE,
115
+ text=True,
116
+ )
117
+
118
+ if result.stdout.strip():
119
+ print(status_message)
120
+ sys.exit(1)
121
+
122
+
123
+ def run_command_check_uncommited():
124
+ """
125
+ Checks if there are uncommited changes.
126
+ """
127
+ status_message = (
128
+ "There are uncommited changes. " "Use `git status` to see the changes.\n" "Please commit the changes before running the command."
129
+ )
130
+
131
+ try:
132
+ subprocess.run(
133
+ "git diff-index --quiet HEAD --",
134
+ check=True,
135
+ shell=True,
136
+ stdout=subprocess.PIPE,
137
+ stderr=subprocess.PIPE,
138
+ text=True,
139
+ )
140
+ except Exception:
141
+ print(status_message)
142
+ sys.exit(1)
143
+
144
+
145
+ def run_command(command):
146
+ try:
147
+ subprocess.run(command, check=True, shell=True)
148
+ except subprocess.CalledProcessError as e:
149
+ error_message = "Command execution failed: " + str(e)
150
+ print(error_message)
151
+ sys.exit(1)
152
+
153
+
154
+ def check_uv_lock():
155
+ """Read the opt-in setting and check prerequisites before editing files."""
156
+ try:
157
+ with open("pyproject.toml", "r", encoding="utf-8") as f:
158
+ doc = tomlkit.parse(f.read())
159
+ except FileNotFoundError:
160
+ return False
161
+
162
+ enabled = doc.get("tool", {}).get("bump_version", {}).get("uv_lock", False)
163
+ if not isinstance(enabled, bool):
164
+ print("tool.bump_version.uv_lock must be true or false.")
165
+ sys.exit(1)
166
+ if not enabled:
167
+ return False
168
+
169
+ result = subprocess.run(["git", "check-ignore", "--quiet", "uv.lock"])
170
+ if result.returncode == 0:
171
+ print(
172
+ "uv.lock is ignored by Git. Remove uv.lock from .gitignore "
173
+ "(or the applicable Git ignore rules) before using uv_lock = true."
174
+ )
175
+ sys.exit(1)
176
+ if result.returncode != 1:
177
+ print("Could not check whether uv.lock is ignored by Git.")
178
+ sys.exit(1)
179
+ if shutil.which("uv") is None:
180
+ print("uv_lock = true requires uv to be installed and available on PATH.")
181
+ sys.exit(1)
182
+ return True
183
+
184
+
185
+ def bump_version(version, message=None):
186
+ uv_lock = check_uv_lock()
187
+
188
+ # Check if there are files that are not tracked. If there are, exit
189
+ run_command_check_untracked()
190
+
191
+ # Check if there are uncommited changes
192
+ run_command_check_uncommited()
193
+
194
+ # Alter the version in the files
195
+ alter_version(version)
196
+
197
+ if uv_lock:
198
+ run_command("uv lock")
199
+
200
+ # Add the changes
201
+ run_command("git add .")
202
+
203
+ # Commit the changes
204
+ run_command(f'git commit -m "bump version to {version}"')
205
+
206
+ # Push the changes
207
+ run_command("git push")
208
+
209
+ # Create a tag
210
+ tag_message = message if message else f"bump version to {version}"
211
+ run_command(f"git tag -a {shlex.quote(version)} -m {shlex.quote(tag_message)}")
212
+
213
+ # Push the tag
214
+ run_command("git push --tags")
215
+
216
+
217
+ def get_version():
218
+ """Reads version from pyproject.toml at runtime, only when needed."""
219
+ with open("pyproject.toml", "r", encoding="utf-8") as f:
220
+ content = f.read()
221
+ doc = tomlkit.parse(content)
222
+ return doc["project"]["version"]
223
+
224
+
225
+ def cli():
226
+ parser = argparse.ArgumentParser(
227
+ prog="bump-py-version",
228
+ description=f"Bump the version of a git-enabled python package. Version ({__version__}).",
229
+ epilog="""Example:
230
+
231
+ bump-py-version v1.2.3
232
+ """,
233
+ formatter_class=argparse.RawDescriptionHelpFormatter,
234
+ )
235
+ parser.add_argument("version", help="Version to bump to, e.g. v1.2.3 or 1.2.3")
236
+ parser.add_argument(
237
+ "--message",
238
+ help="Custom git tag message. Overrides the default tag message.",
239
+ )
240
+ args = parser.parse_args()
241
+ bump_version(args.version, message=args.message)
242
+
243
+
244
+ if __name__ == "__main__":
245
+ cli()
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: bump-py-version
3
+ Version: 2.1.0
4
+ Summary: Bump a python version in python files. Create a new tag and push it to git repository.
5
+ Author-email: Dennis Iversen <dennis.iversen@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/diversen/bump-py-version
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Environment :: Console
10
+ Classifier: Topic :: Utilities
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Natural Language :: English
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.12
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: tomlkit==0.13.3
19
+ Dynamic: license-file
20
+
21
+ # bump-py-version
22
+
23
+ This is a simple and opinionated python `tool` to bump the of a python package.
24
+
25
+ 1. The script will check for any changes in the current `git` repository and abort if there are any.
26
+
27
+ 2. If there are no changes, it will check for a `version` field in `pyproject.toml`. If the `project.version` exist it is altered to the specified version. Other options are specified below.
28
+
29
+ 3. The script commits and pushes the changes.
30
+ 4. Then a new tag is created using the new `version` specified to the script.
31
+ 5. Finally the script pushes the new tag to the remote repository.
32
+
33
+ ## Installation
34
+
35
+ Install latest version:
36
+
37
+ <!-- LATEST-VERSION-UV -->
38
+ uv tool install git+https://github.com/diversen/bump-py-version@v2.1.0
39
+
40
+ ## Configuration
41
+
42
+ You may also bump the python version `__version__` in e.g. `__init__.py` file (or similar) using a `pyproject.toml` setting like the following:
43
+
44
+ ```toml
45
+ [tool.bump_version]
46
+ version_file = "bump_py_version/__init__.py"
47
+ ```
48
+
49
+ You may configure the script to alter text files (e.g. `README.md`) by setting the section `tool.bump_version.replace_patterns` in the `pyproject.toml` file. Example:
50
+
51
+ ```toml
52
+ [tool.bump_version.replace_patterns.pipx]
53
+ file = "README.md"
54
+ search = "<!-- LATEST-VERSION-UV -->"
55
+ replace = "\tuv tool install git+https://github.com/diversen/bump-py-version@{version}\n"
56
+
57
+ ```
58
+
59
+ The above will cause the line below the `search` string to be replaced with the `replace` string. Then it is easy to show the latest version of the package in a `README.md` file.
60
+
61
+ ### Updating uv.lock
62
+
63
+ To update `uv.lock` as part of each version bump, enable:
64
+
65
+ ```toml
66
+ [tool.bump_version]
67
+ uv_lock = true
68
+ ```
69
+
70
+ This runs `uv lock` after updating the version files and before staging changes,
71
+ so the lockfile is included in the release commit and tag. It does not request
72
+ dependency upgrades. If the lockfile does not exist, `uv lock` creates it.
73
+
74
+ `uv` must be installed and available on `PATH`. The command checks these
75
+ prerequisites before modifying files and rejects an ignored `uv.lock`, explaining
76
+ that it must be removed from `.gitignore` or the applicable Git ignore rules.
77
+ An existing, untracked lockfile must be committed before bumping, just like any
78
+ other non-ignored untracked file.
79
+
80
+ If `uv lock` fails, the command stops before committing, pushing, or tagging;
81
+ local edits remain available for inspection. The setting defaults to `false`,
82
+ which preserves the existing behavior without running `uv`.
83
+
84
+ ## Usage example
85
+
86
+ Example:
87
+
88
+ ```bash
89
+ bump-py-version v1.2.3
90
+ ```
91
+
92
+ # License
93
+
94
+ MIT © [Dennis Iversen](https://github.com/diversen)
@@ -0,0 +1,8 @@
1
+ bump_py_version/__init__.py,sha256=Xybt2skBZamGMNlLuOX1IG-h4uIxqUDGAO8MIGWrJac,22
2
+ bump_py_version/cli.py,sha256=olHbFQQvZGRppY2jjVci7JxLyqKY-N4etipRdeVHD1Q,6774
3
+ bump_py_version-2.1.0.dist-info/licenses/LICENSE,sha256=RhJa9n3MJadQpolKbuGOiundPNs_9pqw2rNV4GaONmw,1071
4
+ bump_py_version-2.1.0.dist-info/METADATA,sha256=4VAgfAo7tSoLYMUngdY8QFr377UR_NAESGGDeKVrHGk,3327
5
+ bump_py_version-2.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
6
+ bump_py_version-2.1.0.dist-info/entry_points.txt,sha256=GDJqphGw3wBeNi7wmy3lA9CAuw9VvAMLERK36CVS_D0,60
7
+ bump_py_version-2.1.0.dist-info/top_level.txt,sha256=T6wmloAit2RKV2sN--qTdH2dJPlv40t2Juea_1Q5GcU,16
8
+ bump_py_version-2.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ bump-py-version = bump_py_version.cli:cli
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Dennis Iversen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ bump_py_version