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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tinysemver
3
- Version: 2.0.6
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.6"
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
- def get_commits_since_tag(repository_path: PathLike, tag: str) -> Tuple[List[str], List[str]]:
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
- commits = [line.partition(":")[2] for line in lines if line.strip()]
86
- return hashes, commits
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[str],
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[str], List[str], List[str]]:
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
- commits_hashes, commits_messages = get_commits_since_tag(repository_path, last_tag)
406
- assert len(commits_hashes), f"No new commits since the last {last_tag} tag, aborting."
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(commits_hashes)}")
410
- for hash, commit in zip(commits_hashes, commits_messages):
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(commits_messages, major_verbs, minor_verbs, patch_verbs)
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(commits_messages)
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
- if len(major_commits):
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.6
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