diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index ee1894d3a4..928d525e16 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -77,12 +77,12 @@ def __call__(self): current_version, increment, prerelease=prerelease ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) - message = f"Bump version {current_version} → {new_version}" + message = f"bump: version {current_version} → {new_version}" # Report found information out.write(message) - out.write(f"Tag to create: {new_tag_version}") - out.write(f"Increment detected: {increment}") + out.write(f"tag to create: {new_tag_version}") + out.write(f"increment detected: {increment}") # Do not perform operations over files or git. if dry_run: diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 3b4c7195ca..b84a24707d 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -1,4 +1,9 @@ -from commitizen import factory +import questionary +from commitizen import factory, out, git + + +NO_ANSWERS = 5 +COMMIT_ERROR = 6 class Commit: @@ -9,4 +14,23 @@ def __init__(self, config: dict, *args): self.cz = factory.commiter_factory(self.config) def __call__(self): - self.cz.run() + cz = self.cz + questions = cz.questions() + answers = questionary.prompt(questions) + if not answers: + raise SystemExit(NO_ANSWERS) + m = cz.message(answers) + + c = git.commit(m) + + if c.err: + out.error(c.err) + raise SystemExit(COMMIT_ERROR) + + if "nothing added" in c.out or "no changes added to commit" in c.out: + out.error(c.out) + elif c.err: + out.error(c.err) + else: + out.write(c.out) + out.success("Commit successful!") diff --git a/commitizen/commands/example.py b/commitizen/commands/example.py index 61cdb41bef..66246d4f55 100644 --- a/commitizen/commands/example.py +++ b/commitizen/commands/example.py @@ -1,4 +1,4 @@ -from commitizen import factory +from commitizen import factory, out class Example: @@ -9,4 +9,4 @@ def __init__(self, config: dict, *args): self.cz = factory.commiter_factory(self.config) def __call__(self): - self.cz.show_example() + out.write(self.cz.example()) diff --git a/commitizen/commands/info.py b/commitizen/commands/info.py index bd11c45278..f8450e6b0d 100644 --- a/commitizen/commands/info.py +++ b/commitizen/commands/info.py @@ -1,4 +1,4 @@ -from commitizen import factory +from commitizen import factory, out class Info: @@ -9,4 +9,4 @@ def __init__(self, config: dict, *args): self.cz = factory.commiter_factory(self.config) def __call__(self): - self.cz.show_info() + out.write(self.cz.info()) diff --git a/commitizen/commands/schema.py b/commitizen/commands/schema.py index d4bbbd0a4c..fdb488295b 100644 --- a/commitizen/commands/schema.py +++ b/commitizen/commands/schema.py @@ -1,4 +1,4 @@ -from commitizen import factory +from commitizen import factory, out class Schema: @@ -9,4 +9,4 @@ def __init__(self, config: dict, *args): self.cz = factory.commiter_factory(self.config) def __call__(self): - self.cz.show_schema() + out.write(self.cz.schema()) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 3cc00e5752..4dbaa21ab3 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -1,11 +1,4 @@ -import sys -import logging - -from commitizen import out, git from abc import ABCMeta, abstractmethod -from questionary import prompt - -logger = logging.getLogger(__name__) class BaseCommitizen(metaclass=ABCMeta): @@ -13,84 +6,21 @@ def __init__(self, config: dict): self.config = config @abstractmethod - def questions(self): - """Questions regarding the commit message. - - Must have 'whaaaaat' format. - More info: https://github.com/finklabs/whaaaaat/ - - :rtype: list - """ + def questions(self) -> list: + """Questions regarding the commit message.""" @abstractmethod - def message(self, answers): - """Format your git message. - - :param answers: Use answers - :type answers: dict + def message(self, answers: dict) -> str: + """Format your git message.""" - :rtype: string - """ - - def commit(self, message: str): - c = git.commit(message) - # f = NamedTemporaryFile("wb", delete=False) - # f.write(message.encode("utf-8")) - # f.close() - - # c = cmd.run(f"git commit -F {f.name}") - # os.unlink(f.name) - return c - - def example(self): - """Example of the commit message. - - :rtype: string - """ + def example(self) -> str: + """Example of the commit message.""" raise NotImplementedError("Not Implemented yet") - def schema(self): - """Schema definition of the commit message. - - :rtype: string - """ + def schema(self) -> str: + """Schema definition of the commit message.""" raise NotImplementedError("Not Implemented yet") - def info(self): - """Information about the standardized commit message. - - :rtype: string - """ + def info(self) -> str: + """Information about the standardized commit message.""" raise NotImplementedError("Not Implemented yet") - - def show_example(self, *args, **kwargs): - out.write(self.example()) - - def show_schema(self, *args, **kwargs): - out.write(self.schema()) - - def show_info(self, *args, **kwargs): - out.write(self.info()) - - def run(self, *args, **kwargs): - questions = self.questions() - answers = prompt(questions) - logger.debug("Answers:\n %s", answers) - m = self.message(answers) - logger.debug("Commit message generated:\n %s", m) - - c = self.commit(m) - - if c.err: - logger.warning(c.err) - sys.exit(1) - - if "nothing added" in c.out or "no changes added to commit" in c.out: - out.error(c.out) - elif c.err: - out.error(c.err) - else: - out.write(c.out) - out.success("Commit successful!") - - sys.exit(0) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 6b79ffa061..6fe9ff4672 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -30,7 +30,7 @@ def parse_subject(text): class ConventionalCommitsCz(BaseCommitizen): - def questions(self): + def questions(self) -> list: questions = [ { "type": "list", @@ -45,13 +45,6 @@ def questions(self): "value": "feat", "name": "feat: A new feature. Correlates with MINOR in SemVer", }, - { - "value": "BREAKING CHANGE", - "name": ( - "BREAKING CHANGE: introduces a breaking API change. " - "Correlates with MAJOR in SemVer" - ), - }, {"value": "docs", "name": "docs: Documentation only changes"}, { "value": "style", @@ -112,6 +105,12 @@ def questions(self): "Imperative, lower case and no final dot:\n" ), }, + { + "type": "confirm", + "message": "Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer", + "name": "is_breaking_change", + "default": False, + }, { "type": "input", "name": "body", @@ -131,46 +130,46 @@ def questions(self): ] return questions - def message(self, answers): + def message(self, answers: dict) -> str: prefix = answers["prefix"] scope = answers["scope"] subject = answers["subject"] body = answers["body"] footer = answers["footer"] - message = "" - - if prefix: - message += "{0}".format(prefix) - if scope: - message += "({0})".format(scope) - message += ": " - if subject: - message += "{0}".format(subject) + is_breaking_change = answers["is_breaking_change"] + + if scope: + scope = f"({scope})" + if is_breaking_change: + body = f"BREAKING CHANGE: {body}" if body: - message += "\n\n{0}".format(body) + body = f"\n\n{body}" if footer: - message += "\n\n{0}".format(footer) + footer = f"\n\n{footer}" + + message = f"{prefix}{scope}: {subject}{body}{footer}" + return message - def example(self): + def example(self) -> str: return ( - "feat($injector): ability to load new modules after bootstrapping\n" - "\nThe new method `$injector.loadNewModules(modules)` will add " - "each of the\ninjectables to the injector and execute all of the " - "config and run blocks\nfor each module passed to the method.\n" - "\nCloses #324" + "fix: correct minor typos in code\n" + "\n" + "see the issue for details on the typos fixed\n" + "\n" + "closes issue #12" ) - def schema(self): + def schema(self) -> str: return ( "(): \n" "\n" - "
\n" + "(BREAKING CHANGE: )\n" "\n" "
" ) - def info(self): + def info(self) -> str: dir_path = os.path.dirname(os.path.realpath(__file__)) filepath = os.path.join(dir_path, "conventional_commits_info.txt") with open(filepath, "r") as f: diff --git a/commitizen/cz/conventional_commits/conventional_commits_info.txt b/commitizen/cz/conventional_commits/conventional_commits_info.txt index 2191c04f04..f1b5633e07 100644 --- a/commitizen/cz/conventional_commits/conventional_commits_info.txt +++ b/commitizen/cz/conventional_commits/conventional_commits_info.txt @@ -1,20 +1,31 @@ -Commit Message Format +The commit contains the following structural elements, to communicate +intent to the consumers of your library: -Each commit message consists of a header, a body and a footer. The header has a special format that -includes a type, a scope and a subject: +fix: a commit of the type fix patches a bug in your codebase +(this correlates with PATCH in semantic versioning). -(): - - - -
+feat: a commit of the type feat introduces a new feature to the codebase +(this correlates with MINOR in semantic versioning). -The header is mandatory and the scope of the header is optional. +BREAKING CHANGE: a commit that has the text BREAKING CHANGE: at the beginning of +its optional body or footer section introduces a breaking API change +(correlating with MAJOR in semantic versioning). +A BREAKING CHANGE can be part of commits of any type. -Any line of the commit message cannot be longer 100 characters! This allows the message to be easier -to read on GitHub as well as in various git tools. +Others: commit types other than fix: and feat: are allowed, +like chore:, docs:, style:, refactor:, perf:, test:, and others. -Footer should contain a closing reference to an issue if any. +We also recommend improvement for commits that improve a current +implementation without adding a new feature or fixing a bug. -This leads to more readable messages that are easy to follow when looking through the project history. -But also, the git commit messages can be used to generate the changelog. +Notice these types are not mandated by the conventional commits specification, +and have no implicit effect in semantic versioning (unless they include a BREAKING CHANGE). + +A scope may be provided to a commit’s type, to provide additional contextual +information and is contained within parenthesis, e.g., feat(parser): add ability to parse arrays. + +[optional scope]: + +[optional body] + +[optional footer] \ No newline at end of file diff --git a/commitizen/git.py b/commitizen/git.py index acfd428758..ba6eb456cb 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -19,14 +19,14 @@ def commit(message: str, args=""): def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> list: - c = cmd.run(f"git log --pretty=format:%s {start}...{end}") + 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 {end}") + c = cmd.run(f"git log --pretty=format:%s%n%b {end}") if not c.out: return [] - + print(c.out) return c.out.split("\n") diff --git a/docs/images/commit.yml b/docs/images/commit.yml new file mode 100644 index 0000000000..a239bc3aab --- /dev/null +++ b/docs/images/commit.yml @@ -0,0 +1,187 @@ +# The configurations that used for the recording, feel free to edit them +config: + + # Specify a command to be executed + # like `/bin/bash -l`, `ls`, or any other commands + # the default is bash for Linux + # or powershell.exe for Windows + command: bash -l + + # Specify the current working directory path + # the default is the current working directory path + cwd: ~/my-project + + # Export additional ENV variables + env: + recording: true + + # Explicitly set the number of columns + # or use `auto` to take the current + # number of columns of your shell + cols: 101 + + # Explicitly set the number of rows + # or use `auto` to take the current + # number of rows of your shell + rows: 22 + + # Amount of times to repeat GIF + # If value is -1, play once + # If value is 0, loop indefinitely + # If value is a positive number, loop n times + repeat: 0 + + # Quality + # 1 - 100 + quality: 85 + + # Delay between frames in ms + # If the value is `auto` use the actual recording delays + frameDelay: auto + + # Maximum delay between frames in ms + # Ignored if the `frameDelay` isn't set to `auto` + # Set to `auto` to prevent limiting the max idle time + maxIdleTime: 2000 + + # The surrounding frame box + # The `type` can be null, window, floating, or solid` + # To hide the title use the value null + # Don't forget to add a backgroundColor style with a null as type + frameBox: + type: floating + title: Commitizen + style: + border: 0px black solid + # boxShadow: none + # margin: 0px + + # Add a watermark image to the rendered gif + # You need to specify an absolute path for + # the image on your machine or a URL, and you can also + # add your own CSS styles + watermark: + imagePath: null + style: + position: absolute + right: 15px + bottom: 15px + width: 100px + opacity: 0.9 + + # Cursor style can be one of + # `block`, `underline`, or `bar` + cursorStyle: block + + # Font family + # You can use any font that is installed on your machine + # in CSS-like syntax + fontFamily: "Monaco, Lucida Console, Ubuntu Mono, Monospace" + + # The size of the font + fontSize: 12 + + # The height of lines + lineHeight: 1 + + # The spacing between letters + letterSpacing: 0 + + # Theme + theme: + background: "transparent" + foreground: "#afafaf" + cursor: "#c7c7c7" + black: "#232628" + red: "#fc4384" + green: "#b3e33b" + yellow: "#ffa727" + blue: "#75dff2" + magenta: "#ae89fe" + cyan: "#708387" + white: "#d5d5d0" + brightBlack: "#626566" + brightRed: "#ff7fac" + brightGreen: "#c8ed71" + brightYellow: "#ebdf86" + brightBlue: "#75dff2" + brightMagenta: "#ae89fe" + brightCyan: "#b1c6ca" + brightWhite: "#f9f9f4" + +# Records, feel free to edit them +records: + - delay: 987 + content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master #|\e[1;32m\r\r\n\e[1;32m$\e[00m " + - delay: 731 + content: c + - delay: 345 + content: z + - delay: 135 + content: ' ' + - delay: 118 + content: c + - delay: 116 + content: o + - delay: 200 + content: m + - delay: 135 + content: m + - delay: 199 + content: i + - delay: 406 + content: t + - delay: 144 + content: "\r\n" + - delay: 209 + content: "\e[?1l\e[6n" + - delay: 7 + content: "\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Select the type of change you are committing \e[0m (Use arrow keys) \r\e[100C \e[0m\r\r\n\e[0m » fix: A bug fix. Correlates with PATCH in SemVer\e[0m\r\r\n\e[0m feat: A new feature. Correlates with MINOR in SemVer\e[0m\r\r\n\e[0m docs: Documentation only changes\e[0m\r\r\n\e[0m style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-\r\e[100Cc\e[0m\r\r\n\e[0m refactor: A code change that neither fixes a bug nor adds a feature\e[0m\r\r\n\e[0m perf: A code change that improves performance\e[0m\r\r\n\e[0m test: Adding missing or correcting existing tests\e[0m\r\r\n\e[0m build: Changes that affect the build system or external dependencies (example scopes: pip, docker\r\e[100C,\e[0m\r\r\n\e[0m ci: Changes to our CI configuration files and scripts (example scopes: GitLabCI) \r\e[100C \r\e[9A\e[64C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 17 + content: "\e[?25l\e[?7l\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m ci: Changes to our CI configuration files and scripts (example scopes: GitLabCI)\e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[19A\e[64C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 647 + content: "\e[?25l\e[?7l\e[0m\r\r\n\e[0m \e[0m\r\r\n\e[0m » \e[2A\e[61C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 574 + content: "\e[?25l\e[?7l\e[64D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Select the type of change you are committing \e[0;38;5;214;1m feat: A new feature. Correlates with MINOR in SemVer\r\e[100C\e[0m \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" + - delay: 20 + content: "\e[?1l\e[6n\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Scope. Could be anything specifying place of the commit change (users, db, poll):\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 11 + content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[17A\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 1388 + content: "\e[?25l\e[?7l\e[A\b\e[0m\e[J\e[0;38;5;67m?\e[0;1m Scope. Could be anything specifying place of the commit change (users, db, poll):\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" + - delay: 12 + content: "\e[?1l\e[6n" + - delay: 5 + content: "\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Subject. Concise description of the changes. Imperative, lower case and no final dot:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 24 + content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[15A\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 925 + content: "\e[?25l\e[?7l\e[0mallow provided config object to extend other configs \b\e[?7h\e[0m\e[?12l\e[?25h\e[?25l\e[?7l\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 2880 + content: "\e[?25l\e[?7l\e[A\e[53D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Subject. Concise description of the changes. Imperative, lower case and no final dot:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0mallow provided config object to extend other configs \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" + - delay: 13 + content: "\e[?1l\e[6n\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer \e[0m (y/N) \r\e[100C \r\e[67C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 19 + content: "\e[?25l\e[?7l\e[67D\e[0;38;5;67m?\e[0;1m Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer \e[0m (y/N) \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[14A\e[67C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 1521 + content: "\e[?25l\e[?7l\e[67D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer \e[0;38;5;214;1m Yes\e[0m \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" + - delay: 15 + content: "\e[?1l\e[6n\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Body. Motivation for the change and contrast this with previous behavior:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 16 + content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[12A\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 5659 + content: "\e[?25l\e[?7l\e[0mextends key in config file is now used for extending other config files \b\e[?7h\e[0m\e[?12l\e[?25h\e[?25l\e[?7l\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 647 + content: "\e[?25l\e[?7l\e[A\e[72D\e[0m\e[J\e[0;38;5;67m?\e[0;1m Body. Motivation for the change and contrast this with previous behavior:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0mextends key in config file is now used for extending other config files \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" + - delay: 10 + content: "\e[?1l\e[6n" + - delay: 5 + content: "\e[?2004h\e[?25l\e[0m\e[?7l\e[0m\e[J\e[0;38;5;67m?\e[0;1m Footer. Information about Breaking Changes and reference issues that this commit closes:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 22 + content: "\e[?25l\e[?7l\b\e[0;1m \e[0m \e[0m\e[K\e[0m\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\r\r\n\e[0m \r\e[100C \r\e[10A\e[C\e[?7h\e[0m\e[?12l\e[?25h" + - delay: 1583 + content: "\e[?25l\e[?7l\e[A\b\e[0m\e[J\e[0;38;5;67m?\e[0;1m Footer. Information about Breaking Changes and reference issues that this commit closes:\e[0m \r\e[100C \e[0m\r\r\n\e[0;1m \e[0m \r\e[100C \r\e[0m\r\r\n\e[J\e[?7h\e[0m\e[?12l\e[?25h\e[?2004l" + - delay: 6 + content: "[master (root-commit) 76d9660] feat: allow provided config object to extend other configs\r\n 1 file changed, 0 insertions(+), 0 deletions(-)\r\n create mode 100644 fil.py\r\n\r\n\e[32mCommit successful!\e[0m\r\n\e[0m" + - delay: 102 + content: "\e[1;33m\e[0;32m\e[1;34m\e[1;32msantiago\e[1;34m@\e[1;31mhome\e[1;37m in \e[1;34m~/my-project\e[0;36m |master|\e[1;32m\r\r\n\e[1;32m$\e[00m " diff --git a/docs/images/demo.gif b/docs/images/demo.gif index d1653fa1c0..0f2b9f2487 100644 Binary files a/docs/images/demo.gif and b/docs/images/demo.gif differ diff --git a/docs/index.md b/docs/index.md index 1812d15b0c..fbd06922b1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -36,7 +36,7 @@ the version or a changelog. Python 3.6+ -[Git][gitscm] +[Git][gitscm] `1.8.5.2`+ ## Installation diff --git a/tests/test_commands.py b/tests/test_commands.py index 1d925a14a1..9ef0fe1421 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,48 +1,45 @@ # import pytest from unittest import mock -from commitizen import defaults, commands +from commitizen import defaults, commands, cmd config = {"name": defaults.name} -def test_commit(): - with mock.patch("commitizen.factory.commiter_factory") as mocked_factory: - mock_cz = mock.Mock() - mocked_factory.return_value = mock_cz - commands.Commit(config)() +def test_commit(mocker): + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "", + "footer": "", + } - mocked_factory.assert_called_once() - mock_cz.run.assert_called_once() + commit_mock = mocker.patch("commitizen.git.commit") + commit_mock.return_value = cmd.Command("success", "", "", "") + success_mock = mocker.patch("commitizen.out.success") + + commands.Commit(config)() + success_mock.assert_called_once() def test_example(): - with mock.patch("commitizen.factory.commiter_factory") as mocked_factory: - mock_cz = mock.Mock() - mocked_factory.return_value = mock_cz + with mock.patch("commitizen.out.write") as write_mock: commands.Example(config)() - - mocked_factory.assert_called_once() - mock_cz.show_example.assert_called_once() + write_mock.assert_called_once() def test_info(): - with mock.patch("commitizen.factory.commiter_factory") as mocked_factory: - mock_cz = mock.Mock() - mocked_factory.return_value = mock_cz + with mock.patch("commitizen.out.write") as write_mock: commands.Info(config)() - - mocked_factory.assert_called_once() - mock_cz.show_info.assert_called_once() + write_mock.assert_called_once() def test_schema(): - with mock.patch("commitizen.factory.commiter_factory") as mocked_factory: - mock_cz = mock.Mock() - mocked_factory.return_value = mock_cz + with mock.patch("commitizen.out.write") as write_mock: commands.Schema(config)() - - mocked_factory.assert_called_once() - mock_cz.show_schema.assert_called_once() + write_mock.assert_called_once() def test_list_cz(): diff --git a/tests/test_cz_base.py b/tests/test_cz_base.py index 801a4033ab..7aab7a6a59 100644 --- a/tests/test_cz_base.py +++ b/tests/test_cz_base.py @@ -44,34 +44,3 @@ def test_info(): cz = DummyCz(config) with pytest.raises(NotImplementedError): cz.info() - - -def test_show_example(): - cz = DummyCz(config) - with pytest.raises(NotImplementedError): - cz.show_example() - - -def test_show_schema(): - cz = DummyCz(config) - with pytest.raises(NotImplementedError): - cz.show_schema() - - -def test_show_info(): - cz = DummyCz(config) - with pytest.raises(NotImplementedError): - cz.show_info() - - -def test_commit(mocker): - process_mock = mocker.Mock() - attrs = {"communicate.return_value": (b"commit done", b"")} - process_mock.configure_mock(**attrs) - - m = mocker.patch("subprocess.Popen") - m.return_value = process_mock - - cz = DummyCz(config) - c = cz.commit("test: run test") - assert c.out == "commit done" diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 5eb2d7e260..210102afe8 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -61,6 +61,7 @@ def test_small_answer(): "prefix": "fix", "scope": "users", "subject": "email pattern corrected", + "is_breaking_change": False, "body": "", "footer": "", } @@ -74,13 +75,14 @@ def test_long_answer(): "prefix": "fix", "scope": "users", "subject": "email pattern corrected", + "is_breaking_change": True, "body": "complete content", "footer": "closes #24", } message = conventional_commits.message(answers) assert ( message - == "fix(users): email pattern corrected\n\ncomplete content\n\ncloses #24" + == "fix(users): email pattern corrected\n\nBREAKING CHANGE: complete content\n\ncloses #24" )

AltStyle によって変換されたページ (->オリジナル) /