tinysemver 2.0.6__tar.gz → 2.0.8__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.
- {tinysemver-2.0.6/tinysemver.egg-info → tinysemver-2.0.8}/PKG-INFO +1 -1
- {tinysemver-2.0.6 → tinysemver-2.0.8}/pyproject.toml +1 -1
- {tinysemver-2.0.6 → tinysemver-2.0.8}/tinysemver/tinysemver.py +56 -21
- {tinysemver-2.0.6 → tinysemver-2.0.8/tinysemver.egg-info}/PKG-INFO +1 -1
- {tinysemver-2.0.6 → tinysemver-2.0.8}/LICENSE +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/README.md +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/setup.cfg +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/tinysemver/__init__.py +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/tinysemver.egg-info/SOURCES.txt +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/tinysemver.egg-info/dependency_links.txt +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/tinysemver.egg-info/entry_points.txt +0 -0
- {tinysemver-2.0.6 → tinysemver-2.0.8}/tinysemver.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinysemver
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.8
|
|
4
4
|
Summary: Tiny Semantic Versioning (SemVer) library, that doesn't depend on 300K lines of JavaScript
|
|
5
5
|
Author-email: Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>, Guillaume de Rouville <31691250+grouville@users.noreply.github.com>
|
|
6
6
|
License: Apache License
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tinysemver"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.8"
|
|
8
8
|
description = "Tiny Semantic Versioning (SemVer) library, that doesn't depend on 300K lines of JavaScript"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -47,13 +47,19 @@ import argparse
|
|
|
47
47
|
import subprocess
|
|
48
48
|
import re
|
|
49
49
|
import os
|
|
50
|
-
from typing import List, Tuple, Literal, Union, Optional
|
|
50
|
+
from typing import List, Tuple, Literal, Union, Optional, NamedTuple
|
|
51
51
|
from datetime import datetime
|
|
52
52
|
import traceback
|
|
53
53
|
|
|
54
54
|
SemVer = Tuple[int, int, int]
|
|
55
55
|
BumpType = Literal["major", "minor", "patch"]
|
|
56
56
|
PathLike = Union[str, os.PathLike]
|
|
57
|
+
Commit = NamedTuple("Commit", [("hash", str), ("message", str)])
|
|
58
|
+
|
|
59
|
+
class NoNewCommitsError(Exception):
|
|
60
|
+
"""Raised when no new commits are found since the last tag."""
|
|
61
|
+
|
|
62
|
+
pass
|
|
57
63
|
|
|
58
64
|
|
|
59
65
|
def get_last_tag(repository_path: PathLike) -> str:
|
|
@@ -69,7 +75,8 @@ def get_last_tag(repository_path: PathLike) -> str:
|
|
|
69
75
|
return result.stdout.strip().decode("utf-8")
|
|
70
76
|
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
|
|
79
|
+
def get_commits_since_tag(repository_path: PathLike, tag: str) -> List[Commit]:
|
|
73
80
|
"""Get commit hashes and messages since the specified Git tag."""
|
|
74
81
|
result = subprocess.run(
|
|
75
82
|
["git", "log", f"{tag}..HEAD", "--no-merges", "--pretty=format:%h:%s"],
|
|
@@ -82,8 +89,8 @@ def get_commits_since_tag(repository_path: PathLike, tag: str) -> Tuple[List[str
|
|
|
82
89
|
|
|
83
90
|
lines = result.stdout.strip().decode("utf-8").split("\n")
|
|
84
91
|
hashes = [line.partition(":")[0] for line in lines if line.strip()]
|
|
85
|
-
|
|
86
|
-
return hashes,
|
|
92
|
+
messages = [line.partition(":")[2] for line in lines if line.strip()]
|
|
93
|
+
return [Commit(h, m) for h, m in zip(hashes, messages)]
|
|
87
94
|
|
|
88
95
|
|
|
89
96
|
def parse_version(tag: str) -> SemVer:
|
|
@@ -113,27 +120,45 @@ def normalize_verbs(verbs: Union[str, List[str]], defaults: List[str]) -> List[s
|
|
|
113
120
|
|
|
114
121
|
|
|
115
122
|
def group_commits(
|
|
116
|
-
commits: List[
|
|
123
|
+
commits: List[Commit],
|
|
117
124
|
major_verbs: List[str],
|
|
118
125
|
minor_verbs: List[str],
|
|
119
126
|
patch_verbs: List[str],
|
|
120
|
-
) -> Tuple[List[
|
|
127
|
+
) -> Tuple[List[Commit], List[Commit], List[Commit]]:
|
|
121
128
|
"""Group commits into major, minor, and patch categories based on keywords to simplify future `BumpType` resolution."""
|
|
122
129
|
major_commits = []
|
|
123
130
|
minor_commits = []
|
|
124
131
|
patch_commits = []
|
|
125
132
|
|
|
126
133
|
for commit in commits:
|
|
127
|
-
if any(commit_starts_with_verb(commit, verb) for verb in major_verbs):
|
|
134
|
+
if any(commit_starts_with_verb(commit.message, verb) for verb in major_verbs):
|
|
128
135
|
major_commits.append(commit)
|
|
129
|
-
if any(commit_starts_with_verb(commit, verb) for verb in minor_verbs):
|
|
136
|
+
if any(commit_starts_with_verb(commit.message, verb) for verb in minor_verbs):
|
|
130
137
|
minor_commits.append(commit)
|
|
131
|
-
if any(commit_starts_with_verb(commit, verb) for verb in patch_verbs):
|
|
138
|
+
if any(commit_starts_with_verb(commit.message, verb) for verb in patch_verbs):
|
|
132
139
|
patch_commits.append(commit)
|
|
133
140
|
|
|
134
141
|
return major_commits, minor_commits, patch_commits
|
|
135
142
|
|
|
136
143
|
|
|
144
|
+
def convert_commits_to_message(
|
|
145
|
+
major_commits: List[Commit],
|
|
146
|
+
minor_commits: List[Commit],
|
|
147
|
+
patch_commits: List[Commit],
|
|
148
|
+
) -> str:
|
|
149
|
+
"""Turns the different commits (major, minor, patch) into a single message."""
|
|
150
|
+
message = ""
|
|
151
|
+
|
|
152
|
+
if len(major_commits):
|
|
153
|
+
message += f"\n### Major\n\n" + "\n".join(f"- {c.message} ({c.hash})" for c in major_commits) + "\n"
|
|
154
|
+
if len(minor_commits):
|
|
155
|
+
message += f"\n### Minor\n\n" + "\n".join(f"- {c.message} ({c.hash})" for c in minor_commits) + "\n"
|
|
156
|
+
if len(patch_commits):
|
|
157
|
+
message += f"\n### Patch\n\n" + "\n".join(f"- {c.message} ({c.hash})" for c in patch_commits) + "\n"
|
|
158
|
+
|
|
159
|
+
return message
|
|
160
|
+
|
|
161
|
+
|
|
137
162
|
def bump_version(version: SemVer, bump_type: BumpType) -> SemVer:
|
|
138
163
|
"""Bump the version based on the specified bump type (major, minor, patch)."""
|
|
139
164
|
major, minor, patch = version
|
|
@@ -156,6 +181,9 @@ def create_tag(
|
|
|
156
181
|
github_repository: Optional[str] = None,
|
|
157
182
|
push: bool = False,
|
|
158
183
|
create_release: bool = False,
|
|
184
|
+
major_commits: List[Commit] = None,
|
|
185
|
+
minor_commits: List[Commit] = None,
|
|
186
|
+
patch_commits: List[Commit] = None,
|
|
159
187
|
) -> None:
|
|
160
188
|
"""Create a new Git tag and optionally push it to a remote GitHub repository."""
|
|
161
189
|
|
|
@@ -166,7 +194,10 @@ def create_tag(
|
|
|
166
194
|
env["GIT_AUTHOR_NAME"] = user_name
|
|
167
195
|
env["GIT_AUTHOR_EMAIL"] = user_email
|
|
168
196
|
env["GITHUB_TOKEN"] = github_token
|
|
197
|
+
|
|
169
198
|
message = f"Release: {tag} [skip ci]"
|
|
199
|
+
message += convert_commits_to_message(major_commits or [], minor_commits or [], patch_commits or [])
|
|
200
|
+
|
|
170
201
|
subprocess.run(["git", "add", "-A"], cwd=repository_path)
|
|
171
202
|
subprocess.run(["git", "commit", "-m", message], cwd=repository_path, env=env)
|
|
172
203
|
|
|
@@ -402,18 +433,19 @@ def bump(
|
|
|
402
433
|
if verbose:
|
|
403
434
|
print(f"Current version: {current_version[0]}.{current_version[1]}.{current_version[2]}")
|
|
404
435
|
|
|
405
|
-
|
|
406
|
-
|
|
436
|
+
commits = get_commits_since_tag(repository_path, last_tag)
|
|
437
|
+
if not len(commits):
|
|
438
|
+
raise NoNewCommitsError(f"No new commits since the last {last_tag} tag")
|
|
407
439
|
|
|
408
440
|
if verbose:
|
|
409
|
-
print(f"? Commits since last tag: {len(
|
|
410
|
-
for hash, commit in
|
|
441
|
+
print(f"? Commits since last tag: {len(commits)}")
|
|
442
|
+
for hash, commit in commits:
|
|
411
443
|
print(f"# {hash}: {commit}")
|
|
412
444
|
|
|
413
|
-
major_commits, minor_commits, patch_commits = group_commits(
|
|
445
|
+
major_commits, minor_commits, patch_commits = group_commits(commits, major_verbs, minor_verbs, patch_verbs)
|
|
414
446
|
assert (
|
|
415
447
|
len(major_commits) + len(minor_commits) + len(patch_commits)
|
|
416
|
-
), "No commit categories found to bump the version: " + ", ".join(
|
|
448
|
+
), "No commit categories found to bump the version: " + ", ".join(map(lambda c: c[1], commits))
|
|
417
449
|
|
|
418
450
|
if len(major_commits):
|
|
419
451
|
bump_type = "major"
|
|
@@ -432,17 +464,14 @@ def bump(
|
|
|
432
464
|
if changelog_file:
|
|
433
465
|
now = datetime.now()
|
|
434
466
|
changes = f"\n## {now:%B %d, %Y}: v{new_version_str}\n"
|
|
435
|
-
|
|
436
|
-
changes += f"\n### Major\n\n" + "\n".join(f"- {c}" for c in major_commits) + "\n"
|
|
437
|
-
if len(minor_commits):
|
|
438
|
-
changes += f"\n### Minor\n\n" + "\n".join(f"- {c}" for c in minor_commits) + "\n"
|
|
439
|
-
if len(patch_commits):
|
|
440
|
-
changes += f"\n### Patch\n\n" + "\n".join(f"- {c}" for c in patch_commits) + "\n"
|
|
467
|
+
changes += convert_commits_to_message(major_commits, minor_commits, patch_commits)
|
|
441
468
|
|
|
442
469
|
print(f"Will update file: {changelog_file}")
|
|
443
470
|
if verbose:
|
|
444
471
|
changes_lines = changes.count("\n") + 1
|
|
445
472
|
print(f"? Appending {changes_lines} lines")
|
|
473
|
+
for line in changes.split("\n"):
|
|
474
|
+
print(f"+ {line}")
|
|
446
475
|
|
|
447
476
|
if not dry_run:
|
|
448
477
|
with open(changelog_file, "a") as file:
|
|
@@ -472,6 +501,9 @@ def bump(
|
|
|
472
501
|
github_repository=github_repository,
|
|
473
502
|
push=push,
|
|
474
503
|
create_release=create_release,
|
|
504
|
+
major_commits=major_commits,
|
|
505
|
+
minor_commits=minor_commits,
|
|
506
|
+
patch_commits=patch_commits,
|
|
475
507
|
)
|
|
476
508
|
|
|
477
509
|
|
|
@@ -653,6 +685,9 @@ def main():
|
|
|
653
685
|
push=args.push,
|
|
654
686
|
create_release=args.create_release,
|
|
655
687
|
)
|
|
688
|
+
except NoNewCommitsError as e:
|
|
689
|
+
print(f"! {e}")
|
|
690
|
+
exit(0)
|
|
656
691
|
except AssertionError as e:
|
|
657
692
|
print(f"! {e}")
|
|
658
693
|
exit(1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tinysemver
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.8
|
|
4
4
|
Summary: Tiny Semantic Versioning (SemVer) library, that doesn't depend on 300K lines of JavaScript
|
|
5
5
|
Author-email: Ash Vardanian <1983160+ashvardanian@users.noreply.github.com>, Guillaume de Rouville <31691250+grouville@users.noreply.github.com>
|
|
6
6
|
License: Apache License
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|