tgit 0.1.0__tar.gz → 0.2.2__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.
- tgit-0.2.2/PKG-INFO +19 -0
- tgit-0.2.2/README.md +0 -0
- tgit-0.2.2/pyproject.toml +29 -0
- tgit-0.2.2/tgit/__init__.py +0 -0
- tgit-0.2.2/tgit/changelog.py +25 -0
- tgit-0.2.2/tgit/cli.py +43 -0
- tgit-0.2.2/tgit/commit.py +52 -0
- tgit-0.2.2/tgit/settings.py +32 -0
- tgit-0.2.2/tgit/utils.py +82 -0
- tgit-0.2.2/tgit/version.py +385 -0
- tgit-0.2.2/tgit.egg-info/PKG-INFO +19 -0
- tgit-0.2.2/tgit.egg-info/SOURCES.txt +15 -0
- tgit-0.2.2/tgit.egg-info/entry_points.txt +2 -0
- tgit-0.2.2/tgit.egg-info/requires.txt +3 -0
- tgit-0.2.2/tgit.egg-info/top_level.txt +1 -0
- tgit-0.1.0/PKG-INFO +0 -3
- tgit-0.1.0/setup.py +0 -8
- tgit-0.1.0/tgit.egg-info/PKG-INFO +0 -3
- tgit-0.1.0/tgit.egg-info/SOURCES.txt +0 -6
- tgit-0.1.0/tgit.egg-info/entry_points.txt +0 -2
- tgit-0.1.0/tgit.egg-info/top_level.txt +0 -1
- {tgit-0.1.0 → tgit-0.2.2}/setup.cfg +0 -0
- {tgit-0.1.0 → tgit-0.2.2}/tgit.egg-info/dependency_links.txt +0 -0
tgit-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tgit
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Tool for Git Interaction Temptation (tgit): An elegant CLI tool that simplifies and streamlines your Git workflow, making version control a breeze.
|
|
5
|
+
Author-email: Jannchie <jannchie@gmail.com>
|
|
6
|
+
Maintainer-email: Jannchie <jannchie@gmail.com>
|
|
7
|
+
Keywords: git,tool,changelog,version,commit
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
13
|
+
Classifier: Topic :: Utilities
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: rich
|
|
18
|
+
Requires-Dist: PyYAML
|
|
19
|
+
Requires-Dist: inquirer
|
tgit-0.2.2/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = ["setuptools", "wheel"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "tgit"
|
|
9
|
+
version = "0.2.2"
|
|
10
|
+
description = "Tool for Git Interaction Temptation (tgit): An elegant CLI tool that simplifies and streamlines your Git workflow, making version control a breeze."
|
|
11
|
+
requires-python = ">=3.6"
|
|
12
|
+
keywords = ["git", "tool", "changelog", "version", "commit"]
|
|
13
|
+
dependencies = ["rich", "PyYAML", "inquirer"]
|
|
14
|
+
license = { file = "LICENSE" }
|
|
15
|
+
authors = [{ name = "Jannchie", email = "jannchie@gmail.com" }]
|
|
16
|
+
maintainers = [{ name = "Jannchie", email = "jannchie@gmail.com" }]
|
|
17
|
+
readme = "README.md"
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Topic :: Software Development :: Version Control",
|
|
24
|
+
"Topic :: Utilities",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
tgit = "tgit.cli:main"
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from tgit.utils import console
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def define_changelog_parser(subparsers):
|
|
7
|
+
parser_changelog = subparsers.add_parser("changelog", help="generate changelogs")
|
|
8
|
+
parser_changelog.add_argument("-f", "--from", help="From hash/tag", type=str, dest="from_raw")
|
|
9
|
+
parser_changelog.add_argument("-t", "--to", help="To hash/tag", type=str, dest="to_raw")
|
|
10
|
+
parser_changelog.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
|
|
11
|
+
parser_changelog.set_defaults(func=handle_changelog)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class ChangelogArgs:
|
|
16
|
+
from_raw: str
|
|
17
|
+
to_raw: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def handle_changelog(args: ChangelogArgs):
|
|
21
|
+
from_raw = args.from_raw
|
|
22
|
+
to_raw = args.to_raw
|
|
23
|
+
console.log(f"{from_raw} -> {to_raw}")
|
|
24
|
+
console.log(args)
|
|
25
|
+
console.log("WIP")
|
tgit-0.2.2/tgit/cli.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import importlib.metadata
|
|
3
|
+
|
|
4
|
+
import rich
|
|
5
|
+
import rich.traceback
|
|
6
|
+
|
|
7
|
+
from tgit.changelog import define_changelog_parser
|
|
8
|
+
from tgit.commit import define_commit_parser
|
|
9
|
+
from tgit.utils import console
|
|
10
|
+
from tgit.version import define_version_parser
|
|
11
|
+
|
|
12
|
+
rich.traceback.install()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main():
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
description="TGIT cli",
|
|
18
|
+
prog="tgit",
|
|
19
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
20
|
+
)
|
|
21
|
+
parser.add_argument("--version", action="store_true", help="show version")
|
|
22
|
+
subparsers = parser.add_subparsers(title="Subcommands")
|
|
23
|
+
|
|
24
|
+
define_commit_parser(subparsers)
|
|
25
|
+
define_version_parser(subparsers)
|
|
26
|
+
define_changelog_parser(subparsers)
|
|
27
|
+
|
|
28
|
+
args = parser.parse_args()
|
|
29
|
+
handle(parser, args)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def handle(parser, args):
|
|
33
|
+
if hasattr(args, "func"):
|
|
34
|
+
args.func(args)
|
|
35
|
+
elif args.version:
|
|
36
|
+
version = importlib.metadata.version("tgit")
|
|
37
|
+
console.print(f"TGIT - ver.{version}", highlight=False)
|
|
38
|
+
else:
|
|
39
|
+
parser.print_help()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from tgit.settings import settings
|
|
6
|
+
from tgit.utils import get_commit_command, run_command, type_emojis
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def define_commit_parser(subparsers):
|
|
10
|
+
commit_type = ["feat", "fix", "chore", "docs", "style", "refactor", "perf"]
|
|
11
|
+
prefix = ["!", ""]
|
|
12
|
+
commit_settings = settings.get("commit", {})
|
|
13
|
+
types_settings = commit_settings.get("types", [])
|
|
14
|
+
for data in types_settings:
|
|
15
|
+
type_emojis[data.get("type")] = data.get("emoji")
|
|
16
|
+
commit_type.append(data.get("type"))
|
|
17
|
+
|
|
18
|
+
choices = ["".join(data) for data in itertools.product(commit_type, prefix)] + ["ci", "test", "version"]
|
|
19
|
+
parser_commit = subparsers.add_parser("commit", help="commit changes following the conventional commit format")
|
|
20
|
+
parser_commit.add_argument(
|
|
21
|
+
"type",
|
|
22
|
+
help="commit type",
|
|
23
|
+
choices=choices,
|
|
24
|
+
)
|
|
25
|
+
parser_commit.add_argument("scope", help="commit scope", type=str, nargs="?")
|
|
26
|
+
parser_commit.add_argument("message", help="commit message", type=str)
|
|
27
|
+
parser_commit.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
|
|
28
|
+
parser_commit.add_argument("-e", "--emoji", action="store_true", help="use emojis")
|
|
29
|
+
parser_commit.add_argument("-b", "--breaking", action="store_true", help="breaking change")
|
|
30
|
+
parser_commit.set_defaults(func=handle_commit)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class CommitArgs:
|
|
35
|
+
type: str
|
|
36
|
+
scope: Optional[str]
|
|
37
|
+
message: str
|
|
38
|
+
emoji: bool
|
|
39
|
+
breaking: bool
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def handle_commit(args: CommitArgs):
|
|
43
|
+
|
|
44
|
+
commit_type = args.type
|
|
45
|
+
commit_scope = args.scope
|
|
46
|
+
commit_msg = args.message
|
|
47
|
+
use_emoji = args.emoji
|
|
48
|
+
if use_emoji == False:
|
|
49
|
+
use_emoji = settings.get("commit", {}).get("emoji", False)
|
|
50
|
+
is_breaking = args.breaking
|
|
51
|
+
command = get_commit_command(commit_type, commit_scope, commit_msg, use_emoji, is_breaking)
|
|
52
|
+
run_command(command)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import yaml
|
|
4
|
+
|
|
5
|
+
settings = {}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load_global_settings():
|
|
9
|
+
global_settings_path = [Path.home() / ".tgit.yaml", Path.home() / ".tgit.yml"]
|
|
10
|
+
return next(
|
|
11
|
+
(yaml.safe_load(path.read_text()) for path in global_settings_path if path.exists()),
|
|
12
|
+
None,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_workspace_settings():
|
|
17
|
+
workspace_settings_path = [Path.cwd() / ".tgit.yaml", Path.cwd() / ".tgit.yml"]
|
|
18
|
+
return next(
|
|
19
|
+
(yaml.safe_load(path.read_text()) for path in workspace_settings_path if path.exists()),
|
|
20
|
+
None,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def load_settings():
|
|
25
|
+
global_settings = load_global_settings()
|
|
26
|
+
workspace_settings = load_workspace_settings()
|
|
27
|
+
settings.update(global_settings or {})
|
|
28
|
+
settings.update(workspace_settings or {})
|
|
29
|
+
return settings
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
load_settings()
|
tgit-0.2.2/tgit/utils.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import inquirer
|
|
6
|
+
import rich
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.syntax import Syntax
|
|
9
|
+
|
|
10
|
+
from tgit.settings import settings
|
|
11
|
+
|
|
12
|
+
console = rich.get_console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
type_emojis = {
|
|
16
|
+
"feat": ":sparkles:",
|
|
17
|
+
"fix": ":adhesive_bandage:",
|
|
18
|
+
"chore": ":wrench:",
|
|
19
|
+
"docs": ":page_with_curl:",
|
|
20
|
+
"style": ":lipstick:",
|
|
21
|
+
"refactor": ":hammer:",
|
|
22
|
+
"perf": ":zap:",
|
|
23
|
+
"test": ":rotating_light:",
|
|
24
|
+
"version": ":bookmark:",
|
|
25
|
+
"ci": ":construction_worker:",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_commit_command(commit_type: str, commit_scope: Optional[str], commit_msg: str, use_emoji=False, is_breaking=False):
|
|
30
|
+
if commit_type.endswith("!"):
|
|
31
|
+
commit_type = commit_type[:-1]
|
|
32
|
+
is_breaking = True
|
|
33
|
+
breaking_str = "!"
|
|
34
|
+
else:
|
|
35
|
+
breaking_str = "!" if is_breaking else ""
|
|
36
|
+
if commit_scope is None:
|
|
37
|
+
msg = f"{commit_type}{breaking_str}: {commit_msg}"
|
|
38
|
+
else:
|
|
39
|
+
msg = f"{commit_type}{breaking_str}({commit_scope}): {commit_msg}"
|
|
40
|
+
if use_emoji:
|
|
41
|
+
msg = f"{type_emojis.get(commit_type, ':wrench:' )} {msg}"
|
|
42
|
+
return f'git commit -m "{msg}"'
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def run_command(command: str):
|
|
46
|
+
if settings.get("show_command", True):
|
|
47
|
+
panel = Panel.fit(
|
|
48
|
+
Syntax(command, "bash", line_numbers=False, theme="github-dark", background_color="default", word_wrap=True),
|
|
49
|
+
title="The following command will be executed:",
|
|
50
|
+
border_style="cyan",
|
|
51
|
+
highlight=True,
|
|
52
|
+
padding=(1, 4),
|
|
53
|
+
title_align="left",
|
|
54
|
+
subtitle_align="right",
|
|
55
|
+
)
|
|
56
|
+
print()
|
|
57
|
+
console.print(panel)
|
|
58
|
+
|
|
59
|
+
if not settings.get("skip_confirm", False):
|
|
60
|
+
ok = inquirer.prompt([inquirer.Confirm("continue", message="Do you want to continue?", default=True)])
|
|
61
|
+
if not ok or not ok["continue"]:
|
|
62
|
+
return
|
|
63
|
+
console.print()
|
|
64
|
+
|
|
65
|
+
with console.status("[bold green]Executing...") as status:
|
|
66
|
+
# use subprocess to run the command
|
|
67
|
+
commands = command.split("\n")
|
|
68
|
+
for command in commands:
|
|
69
|
+
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
70
|
+
status.update(f"[bold green]Executing: {command}[/bold green]")
|
|
71
|
+
|
|
72
|
+
# get the output and error
|
|
73
|
+
stdout, stderr = process.communicate()
|
|
74
|
+
|
|
75
|
+
if process.returncode != 0:
|
|
76
|
+
status.update("[bold red]Error[/bold red]")
|
|
77
|
+
else:
|
|
78
|
+
status.update("[bold green]Execute successful[/bold green]")
|
|
79
|
+
if stderr != b"" and process.returncode != 0:
|
|
80
|
+
sys.stderr.write(stderr.decode())
|
|
81
|
+
if stdout != b"":
|
|
82
|
+
sys.stdout.write(stdout.decode())
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import difflib
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
import subprocess
|
|
5
|
+
import tomllib
|
|
6
|
+
from copy import deepcopy
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
import inquirer
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
|
|
13
|
+
from tgit.settings import settings
|
|
14
|
+
from tgit.utils import console, get_commit_command, run_command
|
|
15
|
+
|
|
16
|
+
semver_regex = re.compile(
|
|
17
|
+
r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class Version:
|
|
23
|
+
major: int
|
|
24
|
+
minor: int
|
|
25
|
+
patch: int
|
|
26
|
+
release: Optional[str] = None
|
|
27
|
+
build: Optional[str] = None
|
|
28
|
+
|
|
29
|
+
def __str__(self):
|
|
30
|
+
if self.release:
|
|
31
|
+
if self.build:
|
|
32
|
+
return f"{self.major}.{self.minor}.{self.patch}-{self.release}+{self.build}"
|
|
33
|
+
return f"{self.major}.{self.minor}.{self.patch}-{self.release}"
|
|
34
|
+
if self.build:
|
|
35
|
+
return f"{self.major}.{self.minor}.{self.patch}+{self.build}"
|
|
36
|
+
|
|
37
|
+
return f"{self.major}.{self.minor}.{self.patch}"
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def from_str(cls, version: str):
|
|
41
|
+
res = semver_regex.match(version)
|
|
42
|
+
if not res:
|
|
43
|
+
raise ValueError("Invalid version format")
|
|
44
|
+
groups = res.groups()
|
|
45
|
+
major, minor, patch = map(int, groups[:3])
|
|
46
|
+
release = groups[3]
|
|
47
|
+
build = groups[4]
|
|
48
|
+
return cls(major, minor, patch, release, build)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class VersionArgs:
|
|
53
|
+
version: str
|
|
54
|
+
verbose: int
|
|
55
|
+
no_commit: bool
|
|
56
|
+
no_tag: bool
|
|
57
|
+
no_push: bool
|
|
58
|
+
patch: bool
|
|
59
|
+
minor: bool
|
|
60
|
+
major: bool
|
|
61
|
+
prepatch: str
|
|
62
|
+
preminor: str
|
|
63
|
+
premajor: str
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_prev_version():
|
|
67
|
+
# first, check if there is a file with the version, such as a package.json, pyproject.toml, etc.
|
|
68
|
+
|
|
69
|
+
# for nodejs
|
|
70
|
+
if os.path.exists("package.json"):
|
|
71
|
+
import json
|
|
72
|
+
|
|
73
|
+
with open("package.json") as f:
|
|
74
|
+
json_data = json.load(f)
|
|
75
|
+
if version := json_data.get("version"):
|
|
76
|
+
return Version.from_str(version)
|
|
77
|
+
elif os.path.exists("pyproject.toml"):
|
|
78
|
+
|
|
79
|
+
with open("pyproject.toml", "rb") as f:
|
|
80
|
+
toml_data = tomllib.load(f)
|
|
81
|
+
if version := toml_data.get("project", {}).get("version"):
|
|
82
|
+
return Version.from_str(version)
|
|
83
|
+
if version := toml_data.get("tool", {}).get("poetry", {}).get("version"):
|
|
84
|
+
return Version.from_str(version)
|
|
85
|
+
if version := toml_data.get("tool", {}).get("flit", {}).get("metadata", {}).get("version"):
|
|
86
|
+
return Version.from_str(version)
|
|
87
|
+
if version := toml_data.get("tool", {}).get("setuptools", {}).get("setup_requires", {}).get("version"):
|
|
88
|
+
return Version.from_str(version)
|
|
89
|
+
|
|
90
|
+
elif os.path.exists("setup.py"):
|
|
91
|
+
with open("setup.py") as f:
|
|
92
|
+
setup_data = f.read()
|
|
93
|
+
if res := re.search(r"version=['\"]([^'\"]+)['\"]", setup_data):
|
|
94
|
+
return Version.from_str(res[1])
|
|
95
|
+
|
|
96
|
+
elif os.path.exists(
|
|
97
|
+
"Cargo.toml",
|
|
98
|
+
):
|
|
99
|
+
with open("Cargo.toml", "rb") as f:
|
|
100
|
+
cargo_data = tomllib.load(f)
|
|
101
|
+
if version := cargo_data.get("package", {}).get("version"):
|
|
102
|
+
return Version.from_str(version)
|
|
103
|
+
|
|
104
|
+
elif os.path.exists("VERSION"):
|
|
105
|
+
with open("VERSION") as f:
|
|
106
|
+
version = f.read().strip()
|
|
107
|
+
return Version.from_str(version)
|
|
108
|
+
elif os.path.exists("VERSION.txt"):
|
|
109
|
+
with open("VERSION.txt") as f:
|
|
110
|
+
version = f.read().strip()
|
|
111
|
+
return Version.from_str(version)
|
|
112
|
+
|
|
113
|
+
# if not, check if there is a git tag with the version
|
|
114
|
+
status = subprocess.run(["git", "tag"], capture_output=True)
|
|
115
|
+
if status.returncode == 0:
|
|
116
|
+
tags = status.stdout.decode().split("\n")
|
|
117
|
+
for tag in tags:
|
|
118
|
+
if tag.startswith("v"):
|
|
119
|
+
return Version.from_str(tag[1:])
|
|
120
|
+
|
|
121
|
+
# if not, return 0.0.0
|
|
122
|
+
return Version(major=0, minor=0, patch=0)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def handle_version(args: VersionArgs):
|
|
126
|
+
verbose = args.verbose
|
|
127
|
+
|
|
128
|
+
# check if there is uncommitted changes
|
|
129
|
+
# status = subprocess.run(["git", "status", "--porcelain"], capture_output=True)
|
|
130
|
+
# if status.returncode != 0:
|
|
131
|
+
# console.print("Error getting git status")
|
|
132
|
+
# return
|
|
133
|
+
# if status.stdout:
|
|
134
|
+
# console.print("There are uncommitted changes, please commit or stash them first")
|
|
135
|
+
# return
|
|
136
|
+
|
|
137
|
+
if verbose > 0:
|
|
138
|
+
console.print("Bumping version...")
|
|
139
|
+
console.print("Getting current version...")
|
|
140
|
+
with console.status("[bold green]Getting current version..."):
|
|
141
|
+
prev_version = get_prev_version()
|
|
142
|
+
|
|
143
|
+
console.print(f"Previous version: [cyan bold]{prev_version}")
|
|
144
|
+
# get next version
|
|
145
|
+
next_version = deepcopy(prev_version)
|
|
146
|
+
if not any([args.version, args.patch, args.minor, args.major, args.prepatch, args.preminor, args.premajor]):
|
|
147
|
+
ans = inquirer.prompt(
|
|
148
|
+
[
|
|
149
|
+
inquirer.List(
|
|
150
|
+
"target",
|
|
151
|
+
message="Select the version to bump to",
|
|
152
|
+
choices=[
|
|
153
|
+
VersionChoice(prev_version, bump) for bump in ["patch", "minor", "major", "prepatch", "preminor", "premajor", "previous", "custom"]
|
|
154
|
+
],
|
|
155
|
+
carousel=True,
|
|
156
|
+
),
|
|
157
|
+
]
|
|
158
|
+
)
|
|
159
|
+
if not ans:
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
target = ans["target"]
|
|
163
|
+
assert isinstance(target, VersionChoice)
|
|
164
|
+
if verbose > 0:
|
|
165
|
+
console.print(f"Selected target: [cyan bold]{target}")
|
|
166
|
+
|
|
167
|
+
# bump the version
|
|
168
|
+
if target.bump in ["patch", "prepatch"]:
|
|
169
|
+
next_version.patch += 1
|
|
170
|
+
elif target.bump in ["minor", "preminor"]:
|
|
171
|
+
next_version.minor += 1
|
|
172
|
+
next_version.patch = 0
|
|
173
|
+
elif target.bump in ["major", "premajor"]:
|
|
174
|
+
next_version.major += 1
|
|
175
|
+
next_version.minor = 0
|
|
176
|
+
next_version.patch = 0
|
|
177
|
+
|
|
178
|
+
if target.bump in ["prepatch", "preminor", "premajor"]:
|
|
179
|
+
ans = inquirer.prompt(
|
|
180
|
+
[
|
|
181
|
+
inquirer.Text(
|
|
182
|
+
"identifier",
|
|
183
|
+
message="Enter the pre-release identifier",
|
|
184
|
+
default="alpha",
|
|
185
|
+
validate=lambda _, x: re.match(r"[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*", x).group() == x,
|
|
186
|
+
)
|
|
187
|
+
]
|
|
188
|
+
)
|
|
189
|
+
release = ans["identifier"]
|
|
190
|
+
next_version.release = release
|
|
191
|
+
if target.bump == "custom":
|
|
192
|
+
|
|
193
|
+
def validate_semver(_, x):
|
|
194
|
+
res = semver_regex.match(x)
|
|
195
|
+
return res and res.group() == x
|
|
196
|
+
|
|
197
|
+
ans = inquirer.prompt(
|
|
198
|
+
[
|
|
199
|
+
inquirer.Text(
|
|
200
|
+
"version",
|
|
201
|
+
message="Enter the version",
|
|
202
|
+
validate=validate_semver,
|
|
203
|
+
)
|
|
204
|
+
]
|
|
205
|
+
)
|
|
206
|
+
version = ans["version"]
|
|
207
|
+
next_version = Version.from_str(version)
|
|
208
|
+
next_version_str = str(next_version)
|
|
209
|
+
|
|
210
|
+
# edit files
|
|
211
|
+
|
|
212
|
+
if verbose > 0:
|
|
213
|
+
current_path = os.getcwd()
|
|
214
|
+
console.print(f"Current path: [cyan bold]{current_path}")
|
|
215
|
+
|
|
216
|
+
# check package.json
|
|
217
|
+
if os.path.exists("package.json"):
|
|
218
|
+
if verbose > 0:
|
|
219
|
+
console.print("Updating package.json")
|
|
220
|
+
with open("package.json", "r") as f:
|
|
221
|
+
package_json = f.read()
|
|
222
|
+
package_json = re.sub(r'"version":\s*".*?"', f'"version": "{next_version_str}"', package_json)
|
|
223
|
+
|
|
224
|
+
with open("package.json", "w") as f:
|
|
225
|
+
f.write(package_json)
|
|
226
|
+
|
|
227
|
+
if os.path.exists("pyproject.toml"):
|
|
228
|
+
if verbose > 0:
|
|
229
|
+
console.print("Updating pyproject.toml")
|
|
230
|
+
with open("pyproject.toml", "r") as f:
|
|
231
|
+
pyproject_toml = f.read()
|
|
232
|
+
new_pyproject_toml = re.sub(r'version\s*=\s*".*?"', f'version = "{next_version_str}"', pyproject_toml)
|
|
233
|
+
# print diff between the two files
|
|
234
|
+
old_lines = pyproject_toml.splitlines()
|
|
235
|
+
new_lines = new_pyproject_toml.splitlines()
|
|
236
|
+
diff = list(difflib.Differ().compare(old_lines, new_lines))
|
|
237
|
+
print_lines = {}
|
|
238
|
+
for i, line in enumerate(diff):
|
|
239
|
+
if line.startswith("+") or line.startswith("-"):
|
|
240
|
+
# console.print(f"[green]{line}")
|
|
241
|
+
for j in range(i - 3, i + 3):
|
|
242
|
+
if j >= 0 and j < len(diff):
|
|
243
|
+
print_lines[j] = diff[j][0]
|
|
244
|
+
|
|
245
|
+
diffs = []
|
|
246
|
+
for i, line in enumerate(diff):
|
|
247
|
+
line = line.replace("[", "\\[")
|
|
248
|
+
line = line.strip()
|
|
249
|
+
if i in print_lines:
|
|
250
|
+
if print_lines[i] == "+":
|
|
251
|
+
diffs.append(f"[green]{line}[/green]")
|
|
252
|
+
elif print_lines[i] == "-":
|
|
253
|
+
diffs.append(f"[red]{line}[/red]")
|
|
254
|
+
elif print_lines[i] == "?":
|
|
255
|
+
# replace the ? with a space
|
|
256
|
+
line = line.replace("?", " ")
|
|
257
|
+
diffs.append(f"[yellow]{line}[/yellow]")
|
|
258
|
+
else:
|
|
259
|
+
diffs.append(line)
|
|
260
|
+
if diffs:
|
|
261
|
+
console.print(
|
|
262
|
+
Panel.fit(
|
|
263
|
+
"\n".join(diffs),
|
|
264
|
+
border_style="cyan",
|
|
265
|
+
title="Diff for pyproject.toml",
|
|
266
|
+
title_align="left",
|
|
267
|
+
padding=(1, 4),
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
ok = inquirer.prompt([inquirer.Confirm("continue", message="Do you want to continue?", default=True)])
|
|
272
|
+
if not ok or not ok["continue"]:
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
with open("pyproject.toml", "w") as f:
|
|
276
|
+
f.write(new_pyproject_toml)
|
|
277
|
+
|
|
278
|
+
git_tag = f"v{next_version_str}"
|
|
279
|
+
|
|
280
|
+
commands = []
|
|
281
|
+
if args.no_commit:
|
|
282
|
+
if verbose > 0:
|
|
283
|
+
console.print("Skipping commit")
|
|
284
|
+
else:
|
|
285
|
+
commands.append("git add .")
|
|
286
|
+
use_emoji = settings.get("commit", {}).get("emoji", False)
|
|
287
|
+
commands.append(get_commit_command("version", None, f"{git_tag}", use_emoji=use_emoji))
|
|
288
|
+
|
|
289
|
+
if args.no_tag:
|
|
290
|
+
if verbose > 0:
|
|
291
|
+
console.print("Skipping tag")
|
|
292
|
+
else:
|
|
293
|
+
commands.append(f"git tag {git_tag}")
|
|
294
|
+
|
|
295
|
+
if args.no_push:
|
|
296
|
+
if verbose > 0:
|
|
297
|
+
console.print("Skipping push")
|
|
298
|
+
else:
|
|
299
|
+
commands.append("git push")
|
|
300
|
+
commands.append("git push --tag")
|
|
301
|
+
commands_str = "\n".join(commands)
|
|
302
|
+
run_command(commands_str)
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class VersionChoice:
|
|
307
|
+
def __init__(self, previous_version: Version, bump: str):
|
|
308
|
+
self.previous_version = previous_version
|
|
309
|
+
self.bump = bump
|
|
310
|
+
if bump == "major":
|
|
311
|
+
self.next_version = Version(
|
|
312
|
+
major=previous_version.major + 1,
|
|
313
|
+
minor=0,
|
|
314
|
+
patch=0,
|
|
315
|
+
)
|
|
316
|
+
elif bump == "minor":
|
|
317
|
+
self.next_version = Version(
|
|
318
|
+
major=previous_version.major,
|
|
319
|
+
minor=previous_version.minor + 1,
|
|
320
|
+
patch=0,
|
|
321
|
+
)
|
|
322
|
+
elif bump == "patch":
|
|
323
|
+
self.next_version = Version(
|
|
324
|
+
major=previous_version.major,
|
|
325
|
+
minor=previous_version.minor,
|
|
326
|
+
patch=previous_version.patch + 1,
|
|
327
|
+
)
|
|
328
|
+
elif bump == "premajor":
|
|
329
|
+
self.next_version = Version(
|
|
330
|
+
major=previous_version.major + 1,
|
|
331
|
+
minor=0,
|
|
332
|
+
patch=0,
|
|
333
|
+
release="RELEASE",
|
|
334
|
+
)
|
|
335
|
+
elif bump == "preminor":
|
|
336
|
+
self.next_version = Version(
|
|
337
|
+
major=previous_version.major,
|
|
338
|
+
minor=previous_version.minor + 1,
|
|
339
|
+
patch=0,
|
|
340
|
+
release="RELEASE",
|
|
341
|
+
)
|
|
342
|
+
elif bump == "prepatch":
|
|
343
|
+
self.next_version = Version(
|
|
344
|
+
major=previous_version.major,
|
|
345
|
+
minor=previous_version.minor,
|
|
346
|
+
patch=previous_version.patch + 1,
|
|
347
|
+
release="RELEASE",
|
|
348
|
+
)
|
|
349
|
+
elif bump == "previous":
|
|
350
|
+
self.next_version = previous_version
|
|
351
|
+
|
|
352
|
+
def __str__(self):
|
|
353
|
+
if "next_version" in self.__dict__:
|
|
354
|
+
return f"{self.bump} -> {self.next_version}"
|
|
355
|
+
else:
|
|
356
|
+
return self.bump
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def define_version_parser(subparsers):
|
|
360
|
+
parser_version = subparsers.add_parser("version", help="bump version of the project")
|
|
361
|
+
parser_version.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
|
|
362
|
+
parser_version.add_argument("--no-commit", action="store_true", help="do not commit the changes")
|
|
363
|
+
parser_version.add_argument("--no-tag", action="store_true", help="do not create a tag")
|
|
364
|
+
parser_version.add_argument("--no-push", action="store_true", help="do not push the changes")
|
|
365
|
+
|
|
366
|
+
# TODO: add option to bump all packages in the monorepo
|
|
367
|
+
# parser_version.add_argument("-r", "--recursive", action="store_true", help="bump all packages in the monorepo")
|
|
368
|
+
|
|
369
|
+
# create a mutually exclusive group
|
|
370
|
+
version_group = parser_version.add_mutually_exclusive_group()
|
|
371
|
+
|
|
372
|
+
# add arguments to the group
|
|
373
|
+
version_group.add_argument("-p", "--patch", help="patch version", action="store_true")
|
|
374
|
+
version_group.add_argument("-m", "--minor", help="minor version", action="store_true")
|
|
375
|
+
version_group.add_argument("-M", "--major", help="major version", action="store_true")
|
|
376
|
+
version_group.add_argument("-pp", "--prepatch", help="prepatch version", type=str)
|
|
377
|
+
version_group.add_argument("-pm", "--preminor", help="preminor version", type=str)
|
|
378
|
+
version_group.add_argument("-pM", "--premajor", help="premajor version", type=str)
|
|
379
|
+
version_group.add_argument("version", help="version to bump to", type=str, nargs="?")
|
|
380
|
+
parser_version.set_defaults(func=handle_version)
|
|
381
|
+
parser_version.set_defaults(func=handle_version)
|
|
382
|
+
parser_version.set_defaults(func=handle_version)
|
|
383
|
+
parser_version.set_defaults(func=handle_version)
|
|
384
|
+
parser_version.set_defaults(func=handle_version)
|
|
385
|
+
parser_version.set_defaults(func=handle_version)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tgit
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Tool for Git Interaction Temptation (tgit): An elegant CLI tool that simplifies and streamlines your Git workflow, making version control a breeze.
|
|
5
|
+
Author-email: Jannchie <jannchie@gmail.com>
|
|
6
|
+
Maintainer-email: Jannchie <jannchie@gmail.com>
|
|
7
|
+
Keywords: git,tool,changelog,version,commit
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
13
|
+
Classifier: Topic :: Utilities
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.6
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: rich
|
|
18
|
+
Requires-Dist: PyYAML
|
|
19
|
+
Requires-Dist: inquirer
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
tgit/__init__.py
|
|
4
|
+
tgit/changelog.py
|
|
5
|
+
tgit/cli.py
|
|
6
|
+
tgit/commit.py
|
|
7
|
+
tgit/settings.py
|
|
8
|
+
tgit/utils.py
|
|
9
|
+
tgit/version.py
|
|
10
|
+
tgit.egg-info/PKG-INFO
|
|
11
|
+
tgit.egg-info/SOURCES.txt
|
|
12
|
+
tgit.egg-info/dependency_links.txt
|
|
13
|
+
tgit.egg-info/entry_points.txt
|
|
14
|
+
tgit.egg-info/requires.txt
|
|
15
|
+
tgit.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tgit
|
tgit-0.1.0/PKG-INFO
DELETED
tgit-0.1.0/setup.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
File without changes
|
|
File without changes
|