Skip to content

Refactor #125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions commitizen/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from packaging.version import Version

from commitizen.git import GitCommit
from commitizen.defaults import (
MAJOR,
MINOR,
Expand All @@ -17,7 +18,7 @@


def find_increment(
messages: List[str], regex: str = bump_pattern, increments_map: dict = bump_map
commits: List[GitCommit], regex: str = bump_pattern, increments_map: dict = bump_map
) -> Optional[str]:

# Most important cases are major and minor.
Expand All @@ -26,18 +27,19 @@ def find_increment(
pattern = re.compile(regex)
increment = None

for message in messages:
result = pattern.search(message)
if not result:
continue
found_keyword = result.group(0)
new_increment = increments_map_default[found_keyword]
if new_increment == "MAJOR":
for commit in commits:
for message in commit.message.split("\n"):
result = pattern.search(message)
if not result:
continue
found_keyword = result.group(0)
new_increment = increments_map_default[found_keyword]
if new_increment == "MAJOR":
increment = new_increment
break
elif increment == "MINOR" and new_increment == "PATCH":
continue
increment = new_increment
break
elif increment == "MINOR" and new_increment == "PATCH":
continue
increment = new_increment

return increment

Expand Down
7 changes: 5 additions & 2 deletions commitizen/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ class Command(NamedTuple):


def run(cmd: str) -> Command:
cmd.split()
process = subprocess.Popen(
cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE
cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
)
stdout, stderr = process.communicate()
return Command(stdout.decode(), stderr.decode(), stdout, stderr)
49 changes: 25 additions & 24 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, List

import questionary
from packaging.version import Version
Expand All @@ -20,17 +20,11 @@ class Bump:
def __init__(self, config: BaseConfig, arguments: dict):
self.config: BaseConfig = config
self.arguments: dict = arguments
self.parameters: dict = {
self.bump_settings: dict = {
**config.settings,
**{
key: arguments[key]
for key in [
"dry_run",
"tag_format",
"prerelease",
"increment",
"bump_message",
]
for key in ["tag_format", "prerelease", "increment", "bump_message"]
if arguments[key] is not None
},
}
Expand All @@ -54,7 +48,7 @@ def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool
is_initial = questionary.confirm("Is this the first tag created?").ask()
return is_initial

def find_increment(self, commits: list) -> Optional[str]:
def find_increment(self, commits: List[git.GitCommit]) -> Optional[str]:
bump_pattern = self.cz.bump_pattern
bump_map = self.cz.bump_map
if not bump_map or not bump_pattern:
Expand All @@ -65,10 +59,10 @@ def find_increment(self, commits: list) -> Optional[str]:
)
return increment

def __call__(self):
def __call__(self): # noqa: C901
"""Steps executed to bump."""
try:
current_version_instance: Version = Version(self.parameters["version"])
current_version_instance: Version = Version(self.bump_settings["version"])
except TypeError:
out.error(
"[NO_VERSION_SPECIFIED]\n"
Expand All @@ -79,21 +73,26 @@ def __call__(self):

# Initialize values from sources (conf)
current_version: str = self.config.settings["version"]
tag_format: str = self.parameters["tag_format"]
bump_commit_message: str = self.parameters["bump_message"]
current_tag_version: str = bump.create_tag(
current_version, tag_format=tag_format
)
version_files: list = self.parameters["version_files"]
dry_run: bool = self.parameters["dry_run"]

tag_format: str = self.bump_settings["tag_format"]
bump_commit_message: str = self.bump_settings["bump_message"]
version_files: list = self.bump_settings["version_files"]

dry_run: bool = self.arguments["dry_run"]
is_yes: bool = self.arguments["yes"]
prerelease: str = self.arguments["prerelease"]
increment: Optional[str] = self.arguments["increment"]
prerelease: str = self.arguments["prerelease"]
is_files_only: Optional[bool] = self.arguments["files_only"]

current_tag_version: str = bump.create_tag(
current_version, tag_format=tag_format
)

is_initial = self.is_initial_tag(current_tag_version, is_yes)
commits = git.get_commits(current_tag_version, from_beginning=is_initial)
if is_initial:
commits = git.get_commits()
else:
commits = git.get_commits(current_tag_version)

# No commits, there is no need to create an empty tag.
# Unless we previously had a prerelease.
Expand All @@ -118,9 +117,11 @@ def __call__(self):
)

# Report found information
out.write(message)
out.write(f"tag to create: {new_tag_version}")
out.write(f"increment detected: {increment}")
out.write(
f"message\n"
f"tag to create: {new_tag_version}\n"
f"increment detected: {increment}\n"
)

# Do not perform operations over files or git.
if dry_run:
Expand Down
8 changes: 4 additions & 4 deletions commitizen/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from commitizen import factory, out
from commitizen.cz import registry
from commitizen.config import BaseConfig, TomlConfig, IniConfig
from commitizen.git import get_latest_tag, get_all_tags
from commitizen.git import get_latest_tag_name, get_tag_names
from commitizen.defaults import config_files


Expand Down Expand Up @@ -57,7 +57,7 @@ def _ask_name(self) -> str:
return name

def _ask_tag(self) -> str:
latest_tag = get_latest_tag()
latest_tag = get_latest_tag_name()
if not latest_tag:
out.error("No Existing Tag. Set tag to v0.0.1")
return "0.0.1"
Expand All @@ -66,14 +66,14 @@ def _ask_tag(self) -> str:
f"Is {latest_tag} the latest tag?", style=self.cz.style, default=False
).ask()
if not is_correct_tag:
tags = get_all_tags()
tags = get_tag_names()
if not tags:
out.error("No Existing Tag. Set tag to v0.0.1")
return "0.0.1"

latest_tag = questionary.select(
"Please choose the latest tag: ",
choices=get_all_tags(),
choices=get_tag_names(),
style=self.cz.style,
).ask()

Expand Down
99 changes: 84 additions & 15 deletions commitizen/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@
from commitizen import cmd


class GitObject:
def __eq__(self, other):
if not isinstance(other, GitObject):
return False
return self.rev == other.rev


class GitCommit(GitObject):
def __init__(self, rev, title, body=""):
self.rev = rev.strip()
self.title = title.strip()
self.body = body.strip()

@property
def message(self):
return f"{self.title}\n\n{self.body}"

def __repr__(self):
return f"{self.title} ({self.rev})"


class GitTag(GitObject):
def __init__(self, name, rev, date):
self.rev = rev.strip()
self.name = name.strip()
self.date = date.strip()

def __repr__(self):
return f"{self.name} ({self.rev})"


def tag(tag: str):
c = cmd.run(f"git tag {tag}")
return c
Expand All @@ -20,38 +51,69 @@ def commit(message: str, args=""):
return c


def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> list:
def get_commits(
start: Optional[str] = None,
end: str = "HEAD",
*,
log_format: str = "%H%n%s%n%b",
delimiter: str = "----------commit-delimiter----------",
) -> List[GitCommit]:
"""
Get the commits betweeen start and end
"""
git_log_cmd = f"git log --pretty={log_format}{delimiter}"

c = cmd.run(f"git log --pretty=format:%s%n%b {start}...{end}")

if from_beginning:
c = cmd.run(f"git log --pretty=format:%s%n%b {end}")
if start:
c = cmd.run(f"{git_log_cmd} {start}...{end}")
else:
c = cmd.run(f"{git_log_cmd} {end}")

if not c.out:
return []
return c.out.split("\n")

git_commits = []
for rev_and_commit in c.out.split(delimiter):
rev_and_commit = rev_and_commit.strip()
if not rev_and_commit:
continue
rev, title, *body_list = rev_and_commit.split("\n")

if rev_and_commit:
git_commit = GitCommit(
rev=rev.strip(), title=title.strip(), body="\n".join(body_list).strip()
)
git_commits.append(git_commit)
return git_commits


def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]:
inner_delimiter = "---inner_delimiter---"
formatter = (
f"'%(refname:lstrip=2){inner_delimiter}"
f"%(objectname){inner_delimiter}"
f"%(committerdate:format:{dateformat})'"
)
c = cmd.run(f"git tag --format={formatter} --sort=-committerdate")
if c.err or not c.out:
return []

git_tags = [GitTag(*line.split(inner_delimiter)) for line in c.out.split("\n")[:-1]]
return git_tags


def tag_exist(tag: str) -> bool:
c = cmd.run(f"git tag --list {tag}")
return tag in c.out


def is_staging_clean() -> bool:
"""Check if staing is clean"""
c = cmd.run("git diff --no-ext-diff --name-only")
c_cached = cmd.run("git diff --no-ext-diff --cached --name-only")
return not (bool(c.out) or bool(c_cached.out))


def get_latest_tag() -> Optional[str]:
def get_latest_tag_name() -> Optional[str]:
c = cmd.run("git describe --abbrev=0 --tags")
if c.err:
return None
return c.out.strip()


def get_all_tags() -> Optional[List[str]]:
def get_tag_names() -> Optional[List[str]]:
c = cmd.run("git tag --list")
if c.err:
return []
Expand All @@ -63,3 +125,10 @@ def find_git_project_root() -> Optional[Path]:
if not c.err:
return Path(c.out.strip())
return None


def is_staging_clean() -> bool:
"""Check if staing is clean"""
c = cmd.run("git diff --no-ext-diff --name-only")
c_cached = cmd.run("git diff --no-ext-diff --cached --name-only")
return not (bool(c.out) or bool(c_cached.out))
22 changes: 6 additions & 16 deletions tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,6 @@
from commitizen import cli, cmd, git


@pytest.fixture(scope="function")
def tmp_git_project(tmpdir):
with tmpdir.as_cwd():
with open("pyproject.toml", "w") as f:
f.write("[tool.commitizen]\n" 'version="0.1.0"')

cmd.run("git init")

yield


def create_file_and_commit(message: str, filename: Optional[str] = None):
if not filename:
filename = str(uuid.uuid4())
Expand All @@ -28,7 +17,7 @@ def create_file_and_commit(message: str, filename: Optional[str] = None):
git.commit(message)


@pytest.mark.usefixtures("tmp_git_project")
@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_command(mocker):
# MINOR
create_file_and_commit("feat: new file")
Expand Down Expand Up @@ -101,12 +90,12 @@ def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir):
assert "'cz_jira' rule does not support bump" in err


def test_bump_is_not_specify(mocker, capsys, tmpdir):
@pytest.mark.usefixtures("tmp_git_project")
def test_bump_is_not_specify(mocker, capsys):
mocker.patch.object(sys, "argv", ["cz", "bump"])

with pytest.raises(SystemExit):
with tmpdir.as_cwd():
cli.main()
cli.main()

expected_error_message = (
"[NO_VERSION_SPECIFIED]\n"
Expand All @@ -118,7 +107,8 @@ def test_bump_is_not_specify(mocker, capsys, tmpdir):
assert expected_error_message in err


def test_bump_when_not_new_commit(mocker, capsys, tmp_git_project):
@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_when_not_new_commit(mocker, capsys):
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)

Expand Down
Loading