Adding upstream version 4.6.0+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
f3ad83a1a5
commit
167a3f8553
275 changed files with 30423 additions and 0 deletions
129
tests/CHANGELOG_FOR_TEST.md
Normal file
129
tests/CHANGELOG_FOR_TEST.md
Normal file
|
@ -0,0 +1,129 @@
|
|||
|
||||
## v1.2.0 (2019-04-19)
|
||||
|
||||
### feat
|
||||
|
||||
- custom cz plugins now support bumping version
|
||||
|
||||
## v1.1.1 (2019-04-18)
|
||||
|
||||
### refactor
|
||||
|
||||
- changed stdout statements
|
||||
- **schema**: command logic removed from commitizen base
|
||||
- **info**: command logic removed from commitizen base
|
||||
- **example**: command logic removed from commitizen base
|
||||
- **commit**: moved most of the commit logic to the commit command
|
||||
|
||||
### fix
|
||||
|
||||
- **bump**: commit message now fits better with semver
|
||||
- conventional commit 'breaking change' in body instead of title
|
||||
|
||||
## v1.1.0 (2019-04-14)
|
||||
|
||||
### feat
|
||||
|
||||
- new working bump command
|
||||
- create version tag
|
||||
- update given files with new version
|
||||
- **config**: new set key, used to set version to cfg
|
||||
- support for pyproject.toml
|
||||
- first semantic version bump implementation
|
||||
|
||||
### fix
|
||||
|
||||
- removed all from commit
|
||||
- fix config file not working
|
||||
|
||||
### refactor
|
||||
|
||||
- added commands folder, better integration with decli
|
||||
|
||||
## v1.0.0 (2019-03-01)
|
||||
|
||||
### refactor
|
||||
|
||||
- removed delegator, added decli and many tests
|
||||
|
||||
### BREAKING CHANGE
|
||||
|
||||
- API is stable
|
||||
|
||||
## 1.0.0b2 (2019-01-18)
|
||||
|
||||
## v1.0.0b1 (2019-01-17)
|
||||
|
||||
### feat
|
||||
|
||||
- py3 only, tests and conventional commits 1.0
|
||||
|
||||
## v0.9.11 (2018-12-17)
|
||||
|
||||
### fix
|
||||
|
||||
- **config**: load config reads in order without failing if there is no commitizen section
|
||||
|
||||
## v0.9.10 (2018-09-22)
|
||||
|
||||
### fix
|
||||
|
||||
- parse scope (this is my punishment for not having tests)
|
||||
|
||||
## v0.9.9 (2018-09-22)
|
||||
|
||||
### fix
|
||||
|
||||
- parse scope empty
|
||||
|
||||
## v0.9.8 (2018-09-22)
|
||||
|
||||
### fix
|
||||
|
||||
- **scope**: parse correctly again
|
||||
|
||||
## v0.9.7 (2018-09-22)
|
||||
|
||||
### fix
|
||||
|
||||
- **scope**: parse correctly
|
||||
|
||||
## v0.9.6 (2018-09-19)
|
||||
|
||||
### refactor
|
||||
|
||||
- **conventionalCommit**: moved filters to questions instead of message
|
||||
|
||||
### fix
|
||||
|
||||
- **manifest**: included missing files
|
||||
|
||||
## v0.9.5 (2018-08-24)
|
||||
|
||||
### fix
|
||||
|
||||
- **config**: home path for python versions between 3.0 and 3.5
|
||||
|
||||
## v0.9.4 (2018-08-02)
|
||||
|
||||
### feat
|
||||
|
||||
- **cli**: added version
|
||||
|
||||
## v0.9.3 (2018-07-28)
|
||||
|
||||
### feat
|
||||
|
||||
- **committer**: conventional commit is a bit more intelligent now
|
||||
|
||||
## v0.9.2 (2017-11-11)
|
||||
|
||||
### refactor
|
||||
|
||||
- renamed conventional_changelog to conventional_commits, not backward compatible
|
||||
|
||||
## v0.9.1 (2017-11-11)
|
||||
|
||||
### fix
|
||||
|
||||
- **setup.py**: future is now required for every python version
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
53
tests/commands/conftest.py
Normal file
53
tests/commands/conftest.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen import defaults
|
||||
from commitizen.config import BaseConfig, JsonConfig
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config():
|
||||
_config = BaseConfig()
|
||||
_config.settings.update({"name": defaults.DEFAULT_SETTINGS["name"]})
|
||||
return _config
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config_customize():
|
||||
json_string = r"""{
|
||||
"commitizen": {
|
||||
"name": "cz_customize",
|
||||
"version": "3.0.0",
|
||||
"changelog_incremental": "true",
|
||||
"customize": {
|
||||
"message_template": "{{prefix}}({{scope}}): {{subject}}\n\n{{body}}{% if is_breaking_change %}\nBREAKING CHANGE: {{footer}}{% endif %}",
|
||||
"schema": "<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n(BREAKING CHANGE: <footer>)",
|
||||
"schema_pattern": "(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)(\\(\\S+\\))?!?:(\\s.*)",
|
||||
"change_type_map": {
|
||||
"feat": "Feat",
|
||||
"fix": "Fix",
|
||||
"refactor": "Refactor",
|
||||
"perf": "Perf"
|
||||
},
|
||||
"change_type_order": ["Refactor", "Feat"],
|
||||
"commit_parser": "^(?P<change_type>feat|fix|refactor|perf|BREAKING CHANGE)(?:\\((?P<scope>[^()\\r\\n]*)\\)|\\()?(?P<breaking>!)?:\\s(?P<message>.*)?",
|
||||
"changelog_pattern": "^(BREAKING[\\-\\ ]CHANGE|feat|fix|refactor|perf)(\\(.+\\))?(!)?",
|
||||
"questions": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
}"""
|
||||
_config = JsonConfig(data=json_string, path="not_exist.json")
|
||||
return _config
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def changelog_path() -> str:
|
||||
return os.path.join(os.getcwd(), "CHANGELOG.md")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config_path() -> str:
|
||||
return os.path.join(os.getcwd(), "pyproject.toml")
|
1658
tests/commands/test_bump_command.py
Normal file
1658
tests/commands/test_bump_command.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,81 @@
|
|||
usage: cz bump [-h] [--dry-run] [--files-only] [--local-version] [--changelog]
|
||||
[--no-verify] [--yes] [--tag-format TAG_FORMAT]
|
||||
[--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}]
|
||||
[--devrelease DEVRELEASE] [--increment {MAJOR,MINOR,PATCH}]
|
||||
[--increment-mode {linear,exact}] [--check-consistency]
|
||||
[--annotated-tag]
|
||||
[--annotated-tag-message ANNOTATED_TAG_MESSAGE] [--gpg-sign]
|
||||
[--changelog-to-stdout] [--git-output-to-stderr] [--retry]
|
||||
[--major-version-zero] [--template TEMPLATE] [--extra EXTRA]
|
||||
[--file-name FILE_NAME] [--prerelease-offset PRERELEASE_OFFSET]
|
||||
[--version-scheme {pep440,semver,semver2}]
|
||||
[--version-type {pep440,semver,semver2}]
|
||||
[--build-metadata BUILD_METADATA] [--get-next]
|
||||
[--allow-no-commit]
|
||||
[MANUAL_VERSION]
|
||||
|
||||
bump semantic version based on the git log
|
||||
|
||||
positional arguments:
|
||||
MANUAL_VERSION bump to the given version (e.g: 1.5.3)
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--dry-run show output to stdout, no commit, no modified files
|
||||
--files-only bump version in the files from the config
|
||||
--local-version bump only the local version portion
|
||||
--changelog, -ch generate the changelog for the newest version
|
||||
--no-verify this option bypasses the pre-commit and commit-msg
|
||||
hooks
|
||||
--yes accept automatically questions done
|
||||
--tag-format TAG_FORMAT
|
||||
the format used to tag the commit and read it, use it
|
||||
in existing projects, wrap around simple quotes
|
||||
--bump-message BUMP_MESSAGE
|
||||
template used to create the release commit, useful
|
||||
when working with CI
|
||||
--prerelease, -pr {alpha,beta,rc}
|
||||
choose type of prerelease
|
||||
--devrelease, -d DEVRELEASE
|
||||
specify non-negative integer for dev. release
|
||||
--increment {MAJOR,MINOR,PATCH}
|
||||
manually specify the desired increment
|
||||
--increment-mode {linear,exact}
|
||||
set the method by which the new version is chosen.
|
||||
'linear' (default) guesses the next version based on
|
||||
typical linear version progression, such that bumping
|
||||
of a pre-release with lower precedence than the
|
||||
current pre-release phase maintains the current phase
|
||||
of higher precedence. 'exact' applies the changes that
|
||||
have been specified (or determined from the commit
|
||||
log) without interpretation, such that the increment
|
||||
and pre-release are always honored
|
||||
--check-consistency, -cc
|
||||
check consistency among versions defined in commitizen
|
||||
configuration and version_files
|
||||
--annotated-tag, -at create annotated tag instead of lightweight one
|
||||
--annotated-tag-message, -atm ANNOTATED_TAG_MESSAGE
|
||||
create annotated tag message
|
||||
--gpg-sign, -s sign tag instead of lightweight one
|
||||
--changelog-to-stdout
|
||||
Output changelog to the stdout
|
||||
--git-output-to-stderr
|
||||
Redirect git output to stderr
|
||||
--retry retry commit if it fails the 1st time
|
||||
--major-version-zero keep major version at zero, even for breaking changes
|
||||
--template, -t TEMPLATE
|
||||
changelog template file name (relative to the current
|
||||
working directory)
|
||||
--extra, -e EXTRA a changelog extra variable (in the form 'key=value')
|
||||
--file-name FILE_NAME
|
||||
file name of changelog (default: 'CHANGELOG.md')
|
||||
--prerelease-offset PRERELEASE_OFFSET
|
||||
start pre-releases with this offset
|
||||
--version-scheme {pep440,semver,semver2}
|
||||
choose version scheme
|
||||
--version-type {pep440,semver,semver2}
|
||||
Deprecated, use --version-scheme
|
||||
--build-metadata BUILD_METADATA
|
||||
Add additional build-metadata to the version-number
|
||||
--get-next Determine the next version and write to stdout
|
||||
--allow-no-commit bump version without eligible commits
|
1927
tests/commands/test_changelog_command.py
Normal file
1927
tests/commands/test_changelog_command.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,10 @@
|
|||
## Unreleased
|
||||
|
||||
### BREAKING CHANGE
|
||||
|
||||
- migrate by renaming user to users
|
||||
|
||||
### Feat
|
||||
|
||||
- **users**: email pattern corrected
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
## Unreleased
|
||||
|
||||
### BREAKING CHANGE
|
||||
|
||||
- migrate by renaming user to users
|
||||
|
||||
### Feat
|
||||
|
||||
- **users**: email pattern corrected
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
## Unreleased
|
||||
|
||||
### BREAKING CHANGE
|
||||
|
||||
- migrate by renaming user to users.
|
||||
and then connect the thingy with the other thingy
|
||||
|
||||
### Feat
|
||||
|
||||
- **users**: email pattern corrected
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
## Unreleased
|
||||
|
||||
|
||||
- drop support for py36
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- **pipeline**: some text with breaking change
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME]
|
||||
[--unreleased-version UNRELEASED_VERSION] [--incremental]
|
||||
[--start-rev START_REV] [--merge-prerelease]
|
||||
[--version-scheme {pep440,semver,semver2}]
|
||||
[--export-template EXPORT_TEMPLATE] [--template TEMPLATE]
|
||||
[--extra EXTRA]
|
||||
[rev_range]
|
||||
|
||||
generate changelog (note that it will overwrite existing file)
|
||||
|
||||
positional arguments:
|
||||
rev_range generates changelog for the given version (e.g: 1.5.3)
|
||||
or version range (e.g: 1.5.3..1.7.9)
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--dry-run show changelog to stdout
|
||||
--file-name FILE_NAME
|
||||
file name of changelog (default: 'CHANGELOG.md')
|
||||
--unreleased-version UNRELEASED_VERSION
|
||||
set the value for the new version (use the tag value),
|
||||
instead of using unreleased
|
||||
--incremental generates changelog from last created version, useful
|
||||
if the changelog has been manually modified
|
||||
--start-rev START_REV
|
||||
start rev of the changelog. If not set, it will
|
||||
generate changelog from the start
|
||||
--merge-prerelease collect all changes from prereleases into next non-
|
||||
prerelease. If not set, it will include prereleases in
|
||||
the changelog
|
||||
--version-scheme {pep440,semver,semver2}
|
||||
choose version scheme
|
||||
--export-template EXPORT_TEMPLATE
|
||||
Export the changelog template into this file instead
|
||||
of rendering it
|
||||
--template, -t TEMPLATE
|
||||
changelog template file name (relative to the current
|
||||
working directory)
|
||||
--extra, -e EXTRA a changelog extra variable (in the form 'key=value')
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
note: this should be persisted using increment
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
|
@ -0,0 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 1.0.0 (1970-01-01)
|
|
@ -0,0 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 1.0.0 (1970-01-01)
|
|
@ -0,0 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 1.0.0 (1970-01-01)
|
|
@ -0,0 +1,7 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- after 0.2
|
||||
- after 0.2.0
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
## 0.2.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
|
@ -0,0 +1,7 @@
|
|||
## 0.3.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
## 0.3.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
|
@ -0,0 +1,12 @@
|
|||
## 0.4.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- getting ready for this
|
||||
|
||||
## 0.3.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
|
@ -0,0 +1,12 @@
|
|||
## 0.3.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
||||
|
||||
## 0.2.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
|
@ -0,0 +1,17 @@
|
|||
## legacy-0.4.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
||||
|
||||
## legacy-0.3.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
||||
|
||||
## old-0.2.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
|
@ -0,0 +1,24 @@
|
|||
## 0.5.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- new shinny feature
|
||||
|
||||
## 0.4.1 (2022-02-13)
|
||||
|
||||
### Fix
|
||||
|
||||
- small error
|
||||
|
||||
## 0.4.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- getting ready for this
|
||||
|
||||
## 0.3.0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
|
@ -0,0 +1,9 @@
|
|||
== Unreleased
|
||||
|
||||
=== Feat
|
||||
|
||||
* new file
|
||||
|
||||
=== Refactor
|
||||
|
||||
* is in changelog
|
|
@ -0,0 +1,9 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
||||
|
||||
### Refactor
|
||||
|
||||
- is in changelog
|
|
@ -0,0 +1,12 @@
|
|||
Unreleased
|
||||
==========
|
||||
|
||||
Feat
|
||||
----
|
||||
|
||||
- new file
|
||||
|
||||
Refactor
|
||||
--------
|
||||
|
||||
- is in changelog
|
|
@ -0,0 +1,9 @@
|
|||
h2. Unreleased
|
||||
|
||||
h3. Feat
|
||||
|
||||
- new file
|
||||
|
||||
h3. Refactor
|
||||
|
||||
- is in changelog
|
|
@ -0,0 +1,7 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- after 0.2
|
||||
- after 0.2.0
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
# [10.0.0-rc.3](https://github.com/angular/angular/compare/10.0.0-rc.2...10.0.0-rc.3) (2020-04-22)
|
||||
|
||||
### Bug Fixes
|
||||
* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)
|
|
@ -0,0 +1,17 @@
|
|||
## v0.3.0 (2024-11-18)
|
||||
|
||||
### Feat
|
||||
|
||||
- another new file
|
||||
|
||||
## older-0.2.0 (2024-11-18)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
||||
|
||||
## older-0.1.0 (2024-11-18)
|
||||
|
||||
### Feat
|
||||
|
||||
- new file
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,37 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 0.2.0a0 (2023-04-16)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,37 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 0.2.0b0 (2023-04-16)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,37 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 0.2.0rc0 (2023-04-16)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0a1 (2021-06-11)
|
||||
|
||||
## 0.2.0a0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0b0 (2021-06-11)
|
||||
|
||||
## 0.2.0a0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0rc0 (2021-06-11)
|
||||
|
||||
## 0.2.0a0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0b1 (2021-06-11)
|
||||
|
||||
## 0.2.0b0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0b1 (2021-06-11)
|
||||
|
||||
## 0.2.0b0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0rc0 (2021-06-11)
|
||||
|
||||
## 0.2.0b0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0rc1 (2021-06-11)
|
||||
|
||||
## 0.2.0rc0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0rc1 (2021-06-11)
|
||||
|
||||
## 0.2.0rc0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,32 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0rc1 (2021-06-11)
|
||||
|
||||
## 0.2.0rc0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,40 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
|
||||
## 0.2.0a0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,40 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
|
||||
## 0.2.0b0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,40 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
|
||||
## 0.2.0rc0 (2021-06-11)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
## [1.0.0] - 2017-06-20
|
||||
### Added
|
||||
- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).
|
||||
- Version navigation.
|
||||
|
||||
### Changed
|
||||
- Start using "changelog" over "change log" since it's the common usage.
|
||||
|
||||
### Removed
|
||||
- Section about "changelog" vs "CHANGELOG".
|
||||
|
||||
## [0.3.0] - 2015-12-03
|
||||
### Added
|
||||
- RU translation from [@aishek](https://github.com/aishek).
|
|
@ -0,0 +1,21 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
|
||||
## 0.2.0 (2022-08-14)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
||||
|
||||
note: this should be persisted using increment
|
|
@ -0,0 +1,11 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- no more explosions
|
||||
- output glitch
|
|
@ -0,0 +1,7 @@
|
|||
## 0.3.0-a0 (2022-02-13)
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
## 0.3.0-a1 (2022-02-13)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 1.0.0 (1970-01-01)
|
|
@ -0,0 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 1.0.0 (1970-01-01)
|
|
@ -0,0 +1,13 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
- output glitch
|
||||
|
||||
## 1.0.0 (1970-01-01)
|
|
@ -0,0 +1,19 @@
|
|||
== Unreleased
|
||||
|
||||
=== Feat
|
||||
|
||||
* add more stuff
|
||||
|
||||
=== Fix
|
||||
|
||||
* mama gotta work
|
||||
|
||||
== 0.2.0 (2022-08-14)
|
||||
|
||||
=== Feat
|
||||
|
||||
* add new output
|
||||
|
||||
=== Fix
|
||||
|
||||
* output glitch
|
|
@ -0,0 +1,19 @@
|
|||
## Unreleased
|
||||
|
||||
### Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
### Fix
|
||||
|
||||
- mama gotta work
|
||||
|
||||
## 0.2.0 (2022-08-14)
|
||||
|
||||
### Feat
|
||||
|
||||
- add new output
|
||||
|
||||
### Fix
|
||||
|
||||
- output glitch
|
|
@ -0,0 +1,25 @@
|
|||
Unreleased
|
||||
==========
|
||||
|
||||
Feat
|
||||
----
|
||||
|
||||
- add more stuff
|
||||
|
||||
Fix
|
||||
---
|
||||
|
||||
- mama gotta work
|
||||
|
||||
0.2.0 (2022-08-14)
|
||||
==================
|
||||
|
||||
Feat
|
||||
----
|
||||
|
||||
- add new output
|
||||
|
||||
Fix
|
||||
---
|
||||
|
||||
- output glitch
|
|
@ -0,0 +1,19 @@
|
|||
h2. Unreleased
|
||||
|
||||
h3. Feat
|
||||
|
||||
- add more stuff
|
||||
|
||||
h3. Fix
|
||||
|
||||
- mama gotta work
|
||||
|
||||
h2. 0.2.0 (2022-08-14)
|
||||
|
||||
h3. Feat
|
||||
|
||||
- add new output
|
||||
|
||||
h3. Fix
|
||||
|
||||
- output glitch
|
|
@ -0,0 +1,20 @@
|
|||
## 0.4.0 (2022-02-13)
|
||||
|
||||
### Perf
|
||||
|
||||
- perf improvement
|
||||
|
||||
### Feat
|
||||
|
||||
- getting ready for this
|
||||
|
||||
## 0.3.0 (2022-02-13)
|
||||
|
||||
### Fix
|
||||
|
||||
- fix bug
|
||||
|
||||
### Feat
|
||||
|
||||
- another feature
|
||||
- after 0.2.0
|
|
@ -0,0 +1,6 @@
|
|||
## Unreleased
|
||||
|
||||
|
||||
- JRA-35 #time 1w 2d 4h 30m Total work logged
|
||||
- JRA-34 #comment corrected indent issue
|
||||
|
454
tests/commands/test_check_command.py
Normal file
454
tests/commands/test_check_command.py
Normal file
|
@ -0,0 +1,454 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from io import StringIO
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockFixture
|
||||
|
||||
from commitizen import cli, commands, git
|
||||
from commitizen.exceptions import (
|
||||
InvalidCommandArgumentError,
|
||||
InvalidCommitMessageError,
|
||||
NoCommitsFoundError,
|
||||
)
|
||||
from tests.utils import create_file_and_commit, skip_below_py_3_13
|
||||
|
||||
COMMIT_LOG = [
|
||||
"refactor: A code change that neither fixes a bug nor adds a feature",
|
||||
r"refactor(cz/connventional_commit): use \S to check scope",
|
||||
"refactor(git): remove unnecessary dot between git range",
|
||||
"bump: version 1.16.3 → 1.16.4",
|
||||
(
|
||||
"Merge pull request #139 from Lee-W/fix-init-clean-config-file\n\n"
|
||||
"Fix init clean config file"
|
||||
),
|
||||
"ci(pyproject.toml): add configuration for coverage",
|
||||
"fix(commands/init): fix clean up file when initialize commitizen config\n\n#138",
|
||||
"refactor(defaults): split config files into long term support and deprecated ones",
|
||||
"bump: version 1.16.2 → 1.16.3",
|
||||
(
|
||||
"Merge pull request #136 from Lee-W/remove-redundant-readme\n\n"
|
||||
"Remove redundant readme"
|
||||
),
|
||||
"fix: replace README.rst with docs/README.md in config files",
|
||||
(
|
||||
"refactor(docs): remove README.rst and use docs/README.md\n\n"
|
||||
"By removing README.rst, we no longer need to maintain "
|
||||
"two document with almost the same content\n"
|
||||
"Github can read docs/README.md as README for the project."
|
||||
),
|
||||
"docs(check): pin pre-commit to v1.16.2",
|
||||
"docs(check): fix pre-commit setup",
|
||||
"bump: version 1.16.1 → 1.16.2",
|
||||
"Merge pull request #135 from Lee-W/fix-pre-commit-hook\n\nFix pre commit hook",
|
||||
"docs(check): enforce cz check only when committing",
|
||||
(
|
||||
'Revert "fix(pre-commit): set pre-commit check stage to commit-msg"\n\n'
|
||||
"This reverts commit afc70133e4a81344928561fbf3bb20738dfc8a0b."
|
||||
),
|
||||
"feat!: add user stuff",
|
||||
"fixup! test(commands): ignore fixup! prefix",
|
||||
"fixup! test(commands): ignore squash! prefix",
|
||||
]
|
||||
|
||||
|
||||
def _build_fake_git_commits(commit_msgs: list[str]) -> list[git.GitCommit]:
|
||||
return [git.GitCommit("test_rev", commit_msg) for commit_msg in commit_msgs]
|
||||
|
||||
|
||||
def test_check_jira_fails(mocker: MockFixture):
|
||||
testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data="random message for J-2 #fake_command blah"),
|
||||
)
|
||||
with pytest.raises(InvalidCommitMessageError) as excinfo:
|
||||
cli.main()
|
||||
assert "commit validation: failed!" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_check_jira_command_after_issue_one_space(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data="JR-23 #command some arguments etc"),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
def test_check_jira_command_after_issue_two_spaces(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data="JR-2 #command some arguments etc"),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
def test_check_jira_text_between_issue_and_command(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data="JR-234 some text #command some arguments etc"),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
def test_check_jira_multiple_commands(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data="JRA-23 some text #command1 args #command2 args"),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
def test_check_conventional_commit_succeeds(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data="fix(scope): some commit message"),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"commit_msg",
|
||||
(
|
||||
"feat!(lang): removed polish language",
|
||||
"no conventional commit",
|
||||
(
|
||||
"ci: check commit message on merge\n"
|
||||
"testing with more complex commit mes\n\n"
|
||||
"age with error"
|
||||
),
|
||||
),
|
||||
)
|
||||
def test_check_no_conventional_commit(commit_msg, config, mocker: MockFixture, tmpdir):
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
|
||||
tempfile = tmpdir.join("temp_commit_file")
|
||||
tempfile.write(commit_msg)
|
||||
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"commit_msg_file": tempfile}
|
||||
)
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"commit_msg",
|
||||
(
|
||||
"feat(lang)!: removed polish language",
|
||||
"feat(lang): added polish language",
|
||||
"feat: add polish language",
|
||||
"bump: 0.0.1 -> 1.0.0",
|
||||
),
|
||||
)
|
||||
def test_check_conventional_commit(commit_msg, config, mocker: MockFixture, tmpdir):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
tempfile = tmpdir.join("temp_commit_file")
|
||||
tempfile.write(commit_msg)
|
||||
|
||||
check_cmd = commands.Check(config=config, arguments={"commit_msg_file": tempfile})
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_when_commit_file_not_found(config):
|
||||
with pytest.raises(FileNotFoundError):
|
||||
commands.Check(config=config, arguments={"commit_msg_file": "no_such_file"})()
|
||||
|
||||
|
||||
def test_check_a_range_of_git_commits(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
mocker.patch(
|
||||
"commitizen.git.get_commits", return_value=_build_fake_git_commits(COMMIT_LOG)
|
||||
)
|
||||
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"rev_range": "HEAD~10..master"}
|
||||
)
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_a_range_of_git_commits_and_failed(config, mocker: MockFixture):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
mocker.patch(
|
||||
"commitizen.git.get_commits",
|
||||
return_value=_build_fake_git_commits(["This commit does not follow rule"]),
|
||||
)
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"rev_range": "HEAD~10..master"}
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_invalid_argument(config):
|
||||
with pytest.raises(InvalidCommandArgumentError) as excinfo:
|
||||
commands.Check(
|
||||
config=config,
|
||||
arguments={"commit_msg_file": "some_file", "rev_range": "HEAD~10..master"},
|
||||
)
|
||||
assert (
|
||||
"Only one of --rev-range, --message, and --commit-msg-file is permitted by check command!"
|
||||
in str(excinfo.value)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_commitizen_project")
|
||||
def test_check_command_with_empty_range(config, mocker: MockFixture):
|
||||
# must initialize git with a commit
|
||||
create_file_and_commit("feat: initial")
|
||||
|
||||
check_cmd = commands.Check(config=config, arguments={"rev_range": "master..master"})
|
||||
with pytest.raises(NoCommitsFoundError) as excinfo:
|
||||
check_cmd()
|
||||
|
||||
assert "No commit found with range: 'master..master'" in str(excinfo)
|
||||
|
||||
|
||||
def test_check_a_range_of_failed_git_commits(config, mocker: MockFixture):
|
||||
ill_formated_commits_msgs = [
|
||||
"First commit does not follow rule",
|
||||
"Second commit does not follow rule",
|
||||
("Third commit does not follow rule\nIll-formatted commit with body"),
|
||||
]
|
||||
mocker.patch(
|
||||
"commitizen.git.get_commits",
|
||||
return_value=_build_fake_git_commits(ill_formated_commits_msgs),
|
||||
)
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"rev_range": "HEAD~10..master"}
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError) as excinfo:
|
||||
check_cmd()
|
||||
assert all([msg in str(excinfo.value) for msg in ill_formated_commits_msgs])
|
||||
|
||||
|
||||
def test_check_command_with_valid_message(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"message": "fix(scope): some commit message"}
|
||||
)
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_invalid_message(config, mocker: MockFixture):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
check_cmd = commands.Check(config=config, arguments={"message": "bad commit"})
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_empty_message(config, mocker: MockFixture):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
check_cmd = commands.Check(config=config, arguments={"message": ""})
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_allow_abort_arg(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"message": "", "allow_abort": True}
|
||||
)
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_allow_abort_config(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
config.settings["allow_abort"] = True
|
||||
check_cmd = commands.Check(config=config, arguments={"message": ""})
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_override_allow_abort_config(config, mocker: MockFixture):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
config.settings["allow_abort"] = True
|
||||
check_cmd = commands.Check(
|
||||
config=config, arguments={"message": "", "allow_abort": False}
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_allowed_prefixes_arg(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
check_cmd = commands.Check(
|
||||
config=config,
|
||||
arguments={"message": "custom! test", "allowed_prefixes": ["custom!"]},
|
||||
)
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_allowed_prefixes_config(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
config.settings["allowed_prefixes"] = ["custom!"]
|
||||
check_cmd = commands.Check(config=config, arguments={"message": "custom! test"})
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_override_allowed_prefixes_config(config, mocker: MockFixture):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
config.settings["allow_abort"] = ["fixup!"]
|
||||
check_cmd = commands.Check(
|
||||
config=config,
|
||||
arguments={"message": "fixup! test", "allowed_prefixes": ["custom!"]},
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_pipe_message(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "check"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch("sys.stdin", StringIO("fix(scope): some commit message"))
|
||||
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
def test_check_command_with_pipe_message_and_failed(mocker: MockFixture):
|
||||
testargs = ["cz", "check"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch("sys.stdin", StringIO("bad commit message"))
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError) as excinfo:
|
||||
cli.main()
|
||||
assert "commit validation: failed!" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_check_command_with_comment_in_messege_file(mocker: MockFixture, capsys):
|
||||
testargs = ["cz", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(
|
||||
read_data="# <type>: (If applied, this commit will...) <subject>\n"
|
||||
"# |<---- Try to Limit to a Max of 50 char ---->|\n"
|
||||
"ci: add commitizen pre-commit hook\n"
|
||||
"\n"
|
||||
"# Explain why this change is being made\n"
|
||||
"# |<---- Try To Limit Each Line to a Max Of 72 Char ---->|\n"
|
||||
"This pre-commit hook will check our commits automatically."
|
||||
),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
def test_check_conventional_commit_succeed_with_git_diff(mocker, capsys):
|
||||
commit_msg = (
|
||||
"feat: This is a test commit\n"
|
||||
"# Please enter the commit message for your changes. Lines starting\n"
|
||||
"# with '#' will be ignored, and an empty message aborts the commit.\n"
|
||||
"#\n"
|
||||
"# On branch ...\n"
|
||||
"# Changes to be committed:\n"
|
||||
"# modified: ...\n"
|
||||
"#\n"
|
||||
"# ------------------------ >8 ------------------------\n"
|
||||
"# Do not modify or remove the line above.\n"
|
||||
"# Everything below it will be ignored.\n"
|
||||
"diff --git a/... b/...\n"
|
||||
"index f1234c..1c5678 1234\n"
|
||||
"--- a/...\n"
|
||||
"+++ b/...\n"
|
||||
"@@ -92,3 +92,4 @@ class Command(BaseCommand):\n"
|
||||
'+ "this is a test"\n'
|
||||
)
|
||||
testargs = ["cz", "check", "--commit-msg-file", "some_file"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
mocker.patch(
|
||||
"commitizen.commands.check.open",
|
||||
mocker.mock_open(read_data=commit_msg),
|
||||
)
|
||||
cli.main()
|
||||
out, _ = capsys.readouterr()
|
||||
assert "Commit validation: successful!" in out
|
||||
|
||||
|
||||
@skip_below_py_3_13
|
||||
def test_check_command_shows_description_when_use_help_option(
|
||||
mocker: MockFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "check", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
||||
|
||||
|
||||
def test_check_command_with_message_length_limit(config, mocker: MockFixture):
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
message = "fix(scope): some commit message"
|
||||
check_cmd = commands.Check(
|
||||
config=config,
|
||||
arguments={"message": message, "message_length_limit": len(message) + 1},
|
||||
)
|
||||
|
||||
check_cmd()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
def test_check_command_with_message_length_limit_exceeded(config, mocker: MockFixture):
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
message = "fix(scope): some commit message"
|
||||
check_cmd = commands.Check(
|
||||
config=config,
|
||||
arguments={"message": message, "message_length_limit": len(message) - 1},
|
||||
)
|
||||
|
||||
with pytest.raises(InvalidCommitMessageError):
|
||||
check_cmd()
|
||||
error_mock.assert_called_once()
|
|
@ -0,0 +1,25 @@
|
|||
usage: cz check [-h] [--commit-msg-file COMMIT_MSG_FILE |
|
||||
--rev-range REV_RANGE | -m MESSAGE] [--allow-abort]
|
||||
[--allowed-prefixes [ALLOWED_PREFIXES ...]]
|
||||
[-l MESSAGE_LENGTH_LIMIT]
|
||||
|
||||
validates that a commit message matches the commitizen schema
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--commit-msg-file COMMIT_MSG_FILE
|
||||
ask for the name of the temporal file that contains
|
||||
the commit message. Using it in a git hook script:
|
||||
MSG_FILE=$1
|
||||
--rev-range REV_RANGE
|
||||
a range of git rev to check. e.g, master..HEAD
|
||||
-m, --message MESSAGE
|
||||
commit message that needs to be checked
|
||||
--allow-abort allow empty commit messages, which typically abort a
|
||||
commit
|
||||
--allowed-prefixes [ALLOWED_PREFIXES ...]
|
||||
allowed commit message prefixes. If the message starts
|
||||
by one of these prefixes, the message won't be checked
|
||||
against the regex
|
||||
-l, --message-length-limit MESSAGE_LENGTH_LIMIT
|
||||
length limit of the commit message; 0 for no limit
|
527
tests/commands/test_commit_command.py
Normal file
527
tests/commands/test_commit_command.py
Normal file
|
@ -0,0 +1,527 @@
|
|||
import os
|
||||
import sys
|
||||
from unittest.mock import ANY
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockFixture
|
||||
|
||||
from commitizen import cli, cmd, commands
|
||||
from commitizen.cz.exceptions import CzException
|
||||
from commitizen.cz.utils import get_backup_file_path
|
||||
from commitizen.exceptions import (
|
||||
CommitError,
|
||||
CommitMessageLengthExceededError,
|
||||
CustomError,
|
||||
DryRunExit,
|
||||
NoAnswersError,
|
||||
NoCommitBackupError,
|
||||
NotAGitProjectError,
|
||||
NotAllowed,
|
||||
NothingToCommitError,
|
||||
)
|
||||
from tests.utils import skip_below_py_3_13
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def staging_is_clean(mocker: MockFixture, tmp_git_project):
|
||||
is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean")
|
||||
is_staging_clean_mock.return_value = False
|
||||
return tmp_git_project
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def backup_file(tmp_git_project):
|
||||
with open(get_backup_file_path(), "w") as backup_file:
|
||||
backup_file.write("backup commit")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {})()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_backup_on_failure(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("", "error", b"", b"", 9)
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
|
||||
with pytest.raises(CommitError):
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
prompt_mock.assert_called_once()
|
||||
error_mock.assert_called_once()
|
||||
assert os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_retry_fails_no_backup(config, mocker: MockFixture):
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
|
||||
with pytest.raises(NoCommitBackupError) as excinfo:
|
||||
commands.Commit(config, {"retry": True})()
|
||||
|
||||
assert NoCommitBackupError.message in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean", "backup_file")
|
||||
def test_commit_retry_works(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commit_cmd = commands.Commit(config, {"retry": True})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
commit_mock.assert_called_with("backup commit", args="")
|
||||
prompt_mock.assert_not_called()
|
||||
success_mock.assert_called_once()
|
||||
assert not os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_retry_after_failure_no_backup(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["retry_after_failure"] = True
|
||||
commands.Commit(config, {})()
|
||||
|
||||
commit_mock.assert_called_with("feat: user created\n\ncloses #21", args="")
|
||||
prompt_mock.assert_called_once()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean", "backup_file")
|
||||
def test_commit_retry_after_failure_works(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["retry_after_failure"] = True
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
commit_mock.assert_called_with("backup commit", args="")
|
||||
prompt_mock.assert_not_called()
|
||||
success_mock.assert_called_once()
|
||||
assert not os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean", "backup_file")
|
||||
def test_commit_retry_after_failure_with_no_retry_works(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["retry_after_failure"] = True
|
||||
commit_cmd = commands.Commit(config, {"no_retry": True})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
commit_mock.assert_called_with("feat: user created\n\ncloses #21", args="")
|
||||
prompt_mock.assert_called_once()
|
||||
success_mock.assert_called_once()
|
||||
assert not os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_dry_run_option(config, mocker: MockFixture):
|
||||
prompt_mock = mocker = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #57",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
with pytest.raises(DryRunExit):
|
||||
commit_cmd = commands.Commit(config, {"dry_run": True})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_write_message_to_file_option(
|
||||
config, tmp_path, mocker: MockFixture
|
||||
):
|
||||
tmp_file = tmp_path / "message"
|
||||
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"write_message_to_file": tmp_file})()
|
||||
success_mock.assert_called_once()
|
||||
assert tmp_file.exists()
|
||||
assert tmp_file.read_text() == "feat: user created"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_invalid_write_message_to_file_option(
|
||||
config, tmp_path, mocker: MockFixture
|
||||
):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
with pytest.raises(NotAllowed):
|
||||
commit_cmd = commands.Commit(config, {"write_message_to_file": tmp_path})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_signoff_option(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"signoff": True})()
|
||||
|
||||
commit_mock.assert_called_once_with(ANY, args="-s")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_always_signoff_enabled(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["always_signoff"] = True
|
||||
commands.Commit(config, {})()
|
||||
|
||||
commit_mock.assert_called_once_with(ANY, args="-s")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_gpgsign_and_always_signoff_enabled(
|
||||
config, mocker: MockFixture
|
||||
):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["always_signoff"] = True
|
||||
commands.Commit(config, {"extra_cli_args": "-S"})()
|
||||
|
||||
commit_mock.assert_called_once_with(ANY, args="-S -s")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_commit_when_nothing_to_commit(config, mocker: MockFixture):
|
||||
is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean")
|
||||
is_staging_clean_mock.return_value = True
|
||||
|
||||
with pytest.raises(NothingToCommitError) as excinfo:
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
assert "No files added to staging!" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_with_allow_empty(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"extra_cli_args": "--allow-empty"})()
|
||||
|
||||
commit_mock.assert_called_with(
|
||||
"feat: user created\n\ncloses #21", args="--allow-empty"
|
||||
)
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_with_signoff_and_allow_empty(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["always_signoff"] = True
|
||||
commands.Commit(config, {"extra_cli_args": "--allow-empty"})()
|
||||
|
||||
commit_mock.assert_called_with(
|
||||
"feat: user created\n\ncloses #21", args="--allow-empty -s"
|
||||
)
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_when_customized_expected_raised(config, mocker: MockFixture, capsys):
|
||||
_err = ValueError()
|
||||
_err.__context__ = CzException("This is the root custom err")
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.side_effect = _err
|
||||
|
||||
with pytest.raises(CustomError) as excinfo:
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
# Assert only the content in the formatted text
|
||||
assert "This is the root custom err" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_when_non_customized_expected_raised(
|
||||
config, mocker: MockFixture, capsys
|
||||
):
|
||||
_err = ValueError()
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.side_effect = _err
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_when_no_user_answer(config, mocker: MockFixture, capsys):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = None
|
||||
|
||||
with pytest.raises(NoAnswersError):
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
def test_commit_in_non_git_project(tmpdir, config):
|
||||
with tmpdir.as_cwd():
|
||||
with pytest.raises(NotAGitProjectError):
|
||||
commands.Commit(config, {})
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_all_option(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
add_mock = mocker.patch("commitizen.git.add")
|
||||
commands.Commit(config, {"all": True})()
|
||||
add_mock.assert_called()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_extra_args(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
commands.Commit(config, {"extra_cli_args": "-- -extra-args1 -extra-arg2"})()
|
||||
commit_mock.assert_called_once_with(ANY, args="-- -extra-args1 -extra-arg2")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_message_length_limit(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prefix = "feat"
|
||||
subject = "random subject"
|
||||
message_length = len(prefix) + len(": ") + len(subject)
|
||||
prompt_mock.return_value = {
|
||||
"prefix": prefix,
|
||||
"subject": subject,
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "random body",
|
||||
"footer": "random footer",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"message_length_limit": message_length})()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
with pytest.raises(CommitMessageLengthExceededError):
|
||||
commands.Commit(config, {"message_length_limit": message_length - 1})()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
@pytest.mark.parametrize("editor", ["vim", None])
|
||||
def test_manual_edit(editor, config, mocker: MockFixture, tmp_path):
|
||||
mocker.patch("commitizen.git.get_core_editor", return_value=editor)
|
||||
subprocess_mock = mocker.patch("subprocess.call")
|
||||
|
||||
mocker.patch("shutil.which", return_value=editor)
|
||||
|
||||
test_message = "Initial commit message"
|
||||
temp_file = tmp_path / "temp_commit_message"
|
||||
temp_file.write_text(test_message)
|
||||
|
||||
mock_temp_file = mocker.patch("tempfile.NamedTemporaryFile")
|
||||
mock_temp_file.return_value.__enter__.return_value.name = str(temp_file)
|
||||
|
||||
commit_cmd = commands.Commit(config, {"edit": True})
|
||||
|
||||
if editor is None:
|
||||
with pytest.raises(RuntimeError):
|
||||
commit_cmd.manual_edit(test_message)
|
||||
else:
|
||||
edited_message = commit_cmd.manual_edit(test_message)
|
||||
|
||||
subprocess_mock.assert_called_once_with(["vim", str(temp_file)])
|
||||
|
||||
assert edited_message == test_message.strip()
|
||||
|
||||
temp_file.unlink()
|
||||
|
||||
|
||||
@skip_below_py_3_13
|
||||
def test_commit_command_shows_description_when_use_help_option(
|
||||
mocker: MockFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "commit", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,22 @@
|
|||
usage: cz commit [-h] [--retry] [--no-retry] [--dry-run]
|
||||
[--write-message-to-file FILE_PATH] [-s] [-a] [-e]
|
||||
[-l MESSAGE_LENGTH_LIMIT] [--]
|
||||
|
||||
create new commit
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--retry retry last commit
|
||||
--no-retry skip retry if retry_after_failure is set to true
|
||||
--dry-run show output to stdout, no commit, no modified files
|
||||
--write-message-to-file FILE_PATH
|
||||
write message to file before committing (can be
|
||||
combined with --dry-run)
|
||||
-s, --signoff sign off the commit
|
||||
-a, --all Tell the command to automatically stage files that
|
||||
have been modified and deleted, but new files you have
|
||||
not told Git about are not affected.
|
||||
-e, --edit edit the commit message before committing
|
||||
-l, --message-length-limit MESSAGE_LENGTH_LIMIT
|
||||
length limit of the commit message; 0 for no limit
|
||||
-- Positional arguments separator (recommended)
|
26
tests/commands/test_example_command.py
Normal file
26
tests/commands/test_example_command.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from commitizen import cli, commands
|
||||
from tests.utils import skip_below_py_3_10
|
||||
|
||||
|
||||
def test_example(config, mocker: MockerFixture):
|
||||
write_mock = mocker.patch("commitizen.out.write")
|
||||
commands.Example(config)()
|
||||
write_mock.assert_called_once()
|
||||
|
||||
|
||||
@skip_below_py_3_10
|
||||
def test_example_command_shows_description_when_use_help_option(
|
||||
mocker: MockerFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "example", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,6 @@
|
|||
usage: cz example [-h]
|
||||
|
||||
show commit example
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
26
tests/commands/test_info_command.py
Normal file
26
tests/commands/test_info_command.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from commitizen import cli, commands
|
||||
from tests.utils import skip_below_py_3_10
|
||||
|
||||
|
||||
def test_info(config, mocker: MockerFixture):
|
||||
write_mock = mocker.patch("commitizen.out.write")
|
||||
commands.Info(config)()
|
||||
write_mock.assert_called_once()
|
||||
|
||||
|
||||
@skip_below_py_3_10
|
||||
def test_info_command_shows_description_when_use_help_option(
|
||||
mocker: MockerFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "info", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,6 @@
|
|||
usage: cz info [-h]
|
||||
|
||||
show information about the cz
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
268
tests/commands/test_init_command.py
Normal file
268
tests/commands/test_init_command.py
Normal file
|
@ -0,0 +1,268 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from pytest_mock import MockFixture
|
||||
|
||||
from commitizen import cli, commands
|
||||
from commitizen.__version__ import __version__
|
||||
from commitizen.exceptions import InitFailedError, NoAnswersError
|
||||
from tests.utils import skip_below_py_3_10
|
||||
|
||||
|
||||
class FakeQuestion:
|
||||
def __init__(self, expected_return):
|
||||
self.expected_return = expected_return
|
||||
|
||||
def ask(self):
|
||||
return self.expected_return
|
||||
|
||||
def unsafe_ask(self):
|
||||
return self.expected_return
|
||||
|
||||
|
||||
pre_commit_config_filename = ".pre-commit-config.yaml"
|
||||
cz_hook_config = {
|
||||
"repo": "https://github.com/commitizen-tools/commitizen",
|
||||
"rev": f"v{__version__}",
|
||||
"hooks": [
|
||||
{"id": "commitizen"},
|
||||
{"id": "commitizen-branch", "stages": ["push"]},
|
||||
],
|
||||
}
|
||||
|
||||
expected_config = (
|
||||
"[tool.commitizen]\n"
|
||||
'name = "cz_conventional_commits"\n'
|
||||
'tag_format = "$version"\n'
|
||||
'version_scheme = "semver"\n'
|
||||
'version = "0.0.1"\n'
|
||||
"update_changelog_on_bump = true\n"
|
||||
"major_version_zero = true\n"
|
||||
)
|
||||
|
||||
EXPECTED_DICT_CONFIG = {
|
||||
"commitizen": {
|
||||
"name": "cz_conventional_commits",
|
||||
"tag_format": "$version",
|
||||
"version_scheme": "semver",
|
||||
"version": "0.0.1",
|
||||
"update_changelog_on_bump": True,
|
||||
"major_version_zero": True,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_init_without_setup_pre_commit_hook(tmpdir, mocker: MockFixture, config):
|
||||
mocker.patch(
|
||||
"questionary.select",
|
||||
side_effect=[
|
||||
FakeQuestion("pyproject.toml"),
|
||||
FakeQuestion("cz_conventional_commits"),
|
||||
FakeQuestion("commitizen"),
|
||||
FakeQuestion("semver"),
|
||||
],
|
||||
)
|
||||
mocker.patch("questionary.confirm", return_value=FakeQuestion(True))
|
||||
mocker.patch("questionary.text", return_value=FakeQuestion("$version"))
|
||||
# Return None to skip hook installation
|
||||
mocker.patch("questionary.checkbox", return_value=FakeQuestion(None))
|
||||
|
||||
with tmpdir.as_cwd():
|
||||
commands.Init(config)()
|
||||
|
||||
with open("pyproject.toml", encoding="utf-8") as toml_file:
|
||||
config_data = toml_file.read()
|
||||
assert config_data == expected_config
|
||||
|
||||
assert not os.path.isfile(pre_commit_config_filename)
|
||||
|
||||
|
||||
def test_init_when_config_already_exists(config, capsys):
|
||||
# Set config path
|
||||
path = os.sep.join(["tests", "pyproject.toml"])
|
||||
config.add_path(path)
|
||||
|
||||
commands.Init(config)()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == f"Config file {path} already exists\n"
|
||||
|
||||
|
||||
def test_init_without_choosing_tag(config, mocker: MockFixture, tmpdir):
|
||||
mocker.patch(
|
||||
"commitizen.commands.init.get_tag_names", return_value=["0.0.2", "0.0.1"]
|
||||
)
|
||||
mocker.patch("commitizen.commands.init.get_latest_tag_name", return_value="0.0.2")
|
||||
mocker.patch(
|
||||
"questionary.select",
|
||||
side_effect=[
|
||||
FakeQuestion("pyproject.toml"),
|
||||
FakeQuestion("cz_conventional_commits"),
|
||||
FakeQuestion("commitizen"),
|
||||
FakeQuestion(""),
|
||||
],
|
||||
)
|
||||
mocker.patch("questionary.confirm", return_value=FakeQuestion(False))
|
||||
mocker.patch("questionary.text", return_value=FakeQuestion("y"))
|
||||
|
||||
with tmpdir.as_cwd():
|
||||
with pytest.raises(NoAnswersError):
|
||||
commands.Init(config)()
|
||||
|
||||
|
||||
def test_executed_pre_commit_command(config):
|
||||
init = commands.Init(config)
|
||||
expected_cmd = "pre-commit install --hook-type commit-msg --hook-type pre-push"
|
||||
assert init._gen_pre_commit_cmd(["commit-msg", "pre-push"]) == expected_cmd
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def pre_commit_installed(mocker: MockFixture):
|
||||
# Assume the `pre-commit` is installed
|
||||
mocker.patch(
|
||||
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
|
||||
return_value=True,
|
||||
)
|
||||
# And installation success (i.e. no exception raised)
|
||||
mocker.patch(
|
||||
"commitizen.commands.init.Init._exec_install_pre_commit_hook",
|
||||
return_value=None,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", params=["pyproject.toml", ".cz.json", ".cz.yaml"])
|
||||
def default_choice(request, mocker: MockFixture):
|
||||
mocker.patch(
|
||||
"questionary.select",
|
||||
side_effect=[
|
||||
FakeQuestion(request.param),
|
||||
FakeQuestion("cz_conventional_commits"),
|
||||
FakeQuestion("commitizen"),
|
||||
FakeQuestion("semver"),
|
||||
],
|
||||
)
|
||||
mocker.patch("questionary.confirm", return_value=FakeQuestion(True))
|
||||
mocker.patch("questionary.text", return_value=FakeQuestion("$version"))
|
||||
mocker.patch(
|
||||
"questionary.checkbox",
|
||||
return_value=FakeQuestion(["commit-msg", "pre-push"]),
|
||||
)
|
||||
yield request.param
|
||||
|
||||
|
||||
def check_cz_config(config: str):
|
||||
"""
|
||||
Check the content of commitizen config is as expected
|
||||
|
||||
Args:
|
||||
config: The config path
|
||||
"""
|
||||
with open(config) as file:
|
||||
if "json" in config:
|
||||
assert json.load(file) == EXPECTED_DICT_CONFIG
|
||||
elif "yaml" in config:
|
||||
assert yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG
|
||||
else:
|
||||
config_data = file.read()
|
||||
assert config_data == expected_config
|
||||
|
||||
|
||||
def check_pre_commit_config(expected: list[dict[str, Any]]):
|
||||
"""
|
||||
Check the content of pre-commit config is as expected
|
||||
"""
|
||||
with open(pre_commit_config_filename) as pre_commit_file:
|
||||
pre_commit_config_data = yaml.safe_load(pre_commit_file.read())
|
||||
assert pre_commit_config_data == {"repos": expected}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("pre_commit_installed")
|
||||
class TestPreCommitCases:
|
||||
def test_no_existing_pre_commit_conifg(_, default_choice, tmpdir, config):
|
||||
with tmpdir.as_cwd():
|
||||
commands.Init(config)()
|
||||
check_cz_config(default_choice)
|
||||
check_pre_commit_config([cz_hook_config])
|
||||
|
||||
def test_empty_pre_commit_config(_, default_choice, tmpdir, config):
|
||||
with tmpdir.as_cwd():
|
||||
p = tmpdir.join(pre_commit_config_filename)
|
||||
p.write("")
|
||||
|
||||
commands.Init(config)()
|
||||
check_cz_config(default_choice)
|
||||
check_pre_commit_config([cz_hook_config])
|
||||
|
||||
def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config):
|
||||
existing_hook_config = {
|
||||
"repo": "https://github.com/pre-commit/pre-commit-hooks",
|
||||
"rev": "v1.2.3",
|
||||
"hooks": [{"id", "trailing-whitespace"}],
|
||||
}
|
||||
|
||||
with tmpdir.as_cwd():
|
||||
p = tmpdir.join(pre_commit_config_filename)
|
||||
p.write(yaml.safe_dump({"repos": [existing_hook_config]}))
|
||||
|
||||
commands.Init(config)()
|
||||
check_cz_config(default_choice)
|
||||
check_pre_commit_config([existing_hook_config, cz_hook_config])
|
||||
|
||||
def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config):
|
||||
with tmpdir.as_cwd():
|
||||
p = tmpdir.join(pre_commit_config_filename)
|
||||
p.write(yaml.safe_dump({"repos": [cz_hook_config]}))
|
||||
|
||||
commands.Init(config)()
|
||||
check_cz_config(default_choice)
|
||||
# check that config is not duplicated
|
||||
check_pre_commit_config([cz_hook_config])
|
||||
|
||||
|
||||
class TestNoPreCommitInstalled:
|
||||
def test_pre_commit_not_installed(
|
||||
_, mocker: MockFixture, config, default_choice, tmpdir
|
||||
):
|
||||
# Assume `pre-commit` is not installed
|
||||
mocker.patch(
|
||||
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
|
||||
return_value=False,
|
||||
)
|
||||
with tmpdir.as_cwd():
|
||||
with pytest.raises(InitFailedError):
|
||||
commands.Init(config)()
|
||||
|
||||
def test_pre_commit_exec_failed(
|
||||
_, mocker: MockFixture, config, default_choice, tmpdir
|
||||
):
|
||||
# Assume `pre-commit` is installed
|
||||
mocker.patch(
|
||||
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
|
||||
return_value=True,
|
||||
)
|
||||
# But pre-commit installation will fail
|
||||
mocker.patch(
|
||||
"commitizen.commands.init.Init._exec_install_pre_commit_hook",
|
||||
side_effect=InitFailedError("Mock init failed error."),
|
||||
)
|
||||
with tmpdir.as_cwd():
|
||||
with pytest.raises(InitFailedError):
|
||||
commands.Init(config)()
|
||||
|
||||
|
||||
@skip_below_py_3_10
|
||||
def test_init_command_shows_description_when_use_help_option(
|
||||
mocker: MockFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "init", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,6 @@
|
|||
usage: cz init [-h]
|
||||
|
||||
init commitizen configuration
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
26
tests/commands/test_ls_command.py
Normal file
26
tests/commands/test_ls_command.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from commitizen import cli, commands
|
||||
from tests.utils import skip_below_py_3_10
|
||||
|
||||
|
||||
def test_list_cz(config, mocker: MockerFixture):
|
||||
write_mock = mocker.patch("commitizen.out.write")
|
||||
commands.ListCz(config)()
|
||||
write_mock.assert_called_once()
|
||||
|
||||
|
||||
@skip_below_py_3_10
|
||||
def test_ls_command_shows_description_when_use_help_option(
|
||||
mocker: MockerFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "ls", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,6 @@
|
|||
usage: cz ls [-h]
|
||||
|
||||
show available commitizens
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
26
tests/commands/test_schema_command.py
Normal file
26
tests/commands/test_schema_command.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from commitizen import cli, commands
|
||||
from tests.utils import skip_below_py_3_10
|
||||
|
||||
|
||||
def test_schema(config, mocker: MockerFixture):
|
||||
write_mock = mocker.patch("commitizen.out.write")
|
||||
commands.Schema(config)()
|
||||
write_mock.assert_called_once()
|
||||
|
||||
|
||||
@skip_below_py_3_10
|
||||
def test_schema_command_shows_description_when_use_help_option(
|
||||
mocker: MockerFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "schema", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,6 @@
|
|||
usage: cz schema [-h]
|
||||
|
||||
show commit schema
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
122
tests/commands/test_version_command.py
Normal file
122
tests/commands/test_version_command.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
import platform
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from commitizen import cli, commands
|
||||
from commitizen.__version__ import __version__
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from tests.utils import skip_below_py_3_10
|
||||
|
||||
|
||||
def test_version_for_showing_project_version(config, capsys):
|
||||
# No version exist
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": False, "project": True, "commitizen": False, "verbose": False},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
assert "No project information in this project." in captured.err
|
||||
|
||||
config.settings["version"] = "v0.0.1"
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": False, "project": True, "commitizen": False, "verbose": False},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
assert "v0.0.1" in captured.out
|
||||
|
||||
|
||||
def test_version_for_showing_commitizen_version(config, capsys):
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": False, "project": False, "commitizen": True, "verbose": False},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
assert f"{__version__}" in captured.out
|
||||
|
||||
# default showing commitizen version
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": False, "project": False, "commitizen": False, "verbose": False},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
assert f"{__version__}" in captured.out
|
||||
|
||||
|
||||
def test_version_for_showing_both_versions(config, capsys):
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": False, "project": False, "commitizen": False, "verbose": True},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
assert f"Installed Commitizen Version: {__version__}" in captured.out
|
||||
assert "No project information in this project." in captured.err
|
||||
|
||||
config.settings["version"] = "v0.0.1"
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": False, "project": False, "commitizen": False, "verbose": True},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
expected_out = (
|
||||
f"Installed Commitizen Version: {__version__}\nProject Version: v0.0.1"
|
||||
)
|
||||
assert expected_out in captured.out
|
||||
|
||||
|
||||
def test_version_for_showing_commitizen_system_info(config, capsys):
|
||||
commands.Version(
|
||||
config,
|
||||
{"report": True, "project": False, "commitizen": False, "verbose": False},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
assert f"Commitizen Version: {__version__}" in captured.out
|
||||
assert f"Python Version: {sys.version}" in captured.out
|
||||
assert f"Operating System: {platform.system()}" in captured.out
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", (True, False))
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_version_use_version_provider(
|
||||
mocker: MockerFixture,
|
||||
config: BaseConfig,
|
||||
capsys: pytest.CaptureFixture,
|
||||
project: bool,
|
||||
):
|
||||
version = "0.0.0"
|
||||
mock = mocker.MagicMock(name="provider")
|
||||
mock.get_version.return_value = version
|
||||
get_provider = mocker.patch(
|
||||
"commitizen.commands.version.get_provider", return_value=mock
|
||||
)
|
||||
|
||||
commands.Version(
|
||||
config,
|
||||
{
|
||||
"report": False,
|
||||
"project": project,
|
||||
"commitizen": False,
|
||||
"verbose": not project,
|
||||
},
|
||||
)()
|
||||
captured = capsys.readouterr()
|
||||
|
||||
assert version in captured.out
|
||||
get_provider.assert_called_once()
|
||||
mock.get_version.assert_called_once()
|
||||
mock.set_version.assert_not_called()
|
||||
|
||||
|
||||
@skip_below_py_3_10
|
||||
def test_version_command_shows_description_when_use_help_option(
|
||||
mocker: MockerFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "version", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
|
@ -0,0 +1,12 @@
|
|||
usage: cz version [-h] [-r | -p | -c | -v]
|
||||
|
||||
get the version of the installed commitizen or the current project (default:
|
||||
installed commitizen)
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-r, --report get system information for reporting bugs
|
||||
-p, --project get the version of the current project
|
||||
-c, --commitizen get the version of the installed commitizen
|
||||
-v, --verbose get the version of both the installed commitizen and the
|
||||
current project
|
260
tests/conftest.py
Normal file
260
tests/conftest.py
Normal file
|
@ -0,0 +1,260 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from commitizen import cmd, defaults
|
||||
from commitizen.changelog_formats import (
|
||||
ChangelogFormat,
|
||||
get_changelog_format,
|
||||
)
|
||||
from commitizen.config import BaseConfig
|
||||
from commitizen.cz import registry
|
||||
from commitizen.cz.base import BaseCommitizen
|
||||
from tests.utils import create_file_and_commit
|
||||
|
||||
SIGNER = "GitHub Action"
|
||||
SIGNER_MAIL = "action@github.com"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def git_sandbox(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
|
||||
"""Ensure git commands are executed without the current user settings"""
|
||||
# Clear any GIT_ prefixed environment variable
|
||||
for var in os.environ:
|
||||
if var.startswith("GIT_"):
|
||||
monkeypatch.delenv(var)
|
||||
|
||||
# Define a dedicated temporary git config
|
||||
gitconfig = tmp_path / ".git" / "config"
|
||||
if not gitconfig.parent.exists():
|
||||
gitconfig.parent.mkdir()
|
||||
|
||||
monkeypatch.setenv("GIT_CONFIG_GLOBAL", str(gitconfig))
|
||||
|
||||
r = cmd.run(f"git config --file {gitconfig} user.name {SIGNER}")
|
||||
assert r.return_code == 0, r.err
|
||||
r = cmd.run(f"git config --file {gitconfig} user.email {SIGNER_MAIL}")
|
||||
assert r.return_code == 0, r.err
|
||||
|
||||
r = cmd.run(f"git config --file {gitconfig} safe.directory '*'")
|
||||
assert r.return_code == 0, r.err
|
||||
|
||||
r = cmd.run("git config --global init.defaultBranch master")
|
||||
assert r.return_code == 0, r.err
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def chdir(tmp_path: Path) -> Iterator[Path]:
|
||||
cwd = os.getcwd()
|
||||
os.chdir(tmp_path)
|
||||
yield tmp_path
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def tmp_git_project(tmpdir):
|
||||
with tmpdir.as_cwd():
|
||||
cmd.run("git init")
|
||||
|
||||
yield tmpdir
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def tmp_commitizen_project(tmp_git_project):
|
||||
tmp_commitizen_cfg_file = tmp_git_project.join("pyproject.toml")
|
||||
tmp_commitizen_cfg_file.write('[tool.commitizen]\nversion="0.1.0"\n')
|
||||
|
||||
yield tmp_git_project
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def tmp_commitizen_project_initial(tmp_git_project):
|
||||
def _initial(
|
||||
config_extra: str | None = None,
|
||||
version="0.1.0",
|
||||
initial_commit="feat: new user interface",
|
||||
):
|
||||
with tmp_git_project.as_cwd():
|
||||
tmp_commitizen_cfg_file = tmp_git_project.join("pyproject.toml")
|
||||
tmp_commitizen_cfg_file.write(f'[tool.commitizen]\nversion="{version}"\n')
|
||||
tmp_version_file = tmp_git_project.join("__version__.py")
|
||||
tmp_version_file.write(version)
|
||||
tmp_commitizen_cfg_file = tmp_git_project.join("pyproject.toml")
|
||||
tmp_version_file_string = str(tmp_version_file).replace("\\", "/")
|
||||
tmp_commitizen_cfg_file.write(
|
||||
f"{tmp_commitizen_cfg_file.read()}\n"
|
||||
f'version_files = ["{tmp_version_file_string}"]\n'
|
||||
)
|
||||
if config_extra:
|
||||
tmp_commitizen_cfg_file.write(config_extra, mode="a")
|
||||
create_file_and_commit(initial_commit)
|
||||
|
||||
return tmp_git_project
|
||||
|
||||
yield _initial
|
||||
|
||||
|
||||
def _get_gpg_keyid(signer_mail):
|
||||
_new_key = cmd.run(f"gpg --list-secret-keys {signer_mail}")
|
||||
_m = re.search(
|
||||
r"[a-zA-Z0-9 \[\]-_]*\n[ ]*([0-9A-Za-z]*)\n[\na-zA-Z0-9 \[\]-_<>@]*",
|
||||
_new_key.out,
|
||||
)
|
||||
return _m.group(1) if _m else None
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def tmp_commitizen_project_with_gpg(tmp_commitizen_project):
|
||||
# create a temporary GPGHOME to store a temporary keyring.
|
||||
# Home path must be less than 104 characters
|
||||
gpg_home = tempfile.TemporaryDirectory(suffix="_cz")
|
||||
if os.name != "nt":
|
||||
os.environ["GNUPGHOME"] = gpg_home.name # tempdir = temp keyring
|
||||
|
||||
# create a key (a keyring will be generated within GPUPGHOME)
|
||||
c = cmd.run(
|
||||
f"gpg --batch --yes --debug-quick-random --passphrase '' --quick-gen-key '{SIGNER} {SIGNER_MAIL}'"
|
||||
)
|
||||
if c.return_code != 0:
|
||||
raise Exception(f"gpg keygen failed with err: '{c.err}'")
|
||||
key_id = _get_gpg_keyid(SIGNER_MAIL)
|
||||
assert key_id
|
||||
|
||||
# configure git to use gpg signing
|
||||
cmd.run("git config commit.gpgsign true")
|
||||
cmd.run(f"git config user.signingkey {key_id}")
|
||||
|
||||
yield tmp_commitizen_project
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config():
|
||||
_config = BaseConfig()
|
||||
_config.settings.update({"name": defaults.DEFAULT_SETTINGS["name"]})
|
||||
return _config
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def config_path() -> str:
|
||||
return os.path.join(os.getcwd(), "pyproject.toml")
|
||||
|
||||
|
||||
class SemverCommitizen(BaseCommitizen):
|
||||
"""A minimal cz rules used to test changelog and bump.
|
||||
|
||||
Samples:
|
||||
```
|
||||
minor(users): add email to user
|
||||
major: removed user profile
|
||||
patch(deps): updated dependency for security
|
||||
```
|
||||
"""
|
||||
|
||||
bump_pattern = r"^(patch|minor|major)"
|
||||
bump_map = {
|
||||
"major": "MAJOR",
|
||||
"minor": "MINOR",
|
||||
"patch": "PATCH",
|
||||
}
|
||||
bump_map_major_version_zero = {
|
||||
"major": "MINOR",
|
||||
"minor": "MINOR",
|
||||
"patch": "PATCH",
|
||||
}
|
||||
changelog_pattern = r"^(patch|minor|major)"
|
||||
commit_parser = r"^(?P<change_type>patch|minor|major)(?:\((?P<scope>[^()\r\n]*)\)|\()?:?\s(?P<message>.+)" # noqa
|
||||
change_type_map = {
|
||||
"major": "Breaking Changes",
|
||||
"minor": "Features",
|
||||
"patch": "Bugs",
|
||||
}
|
||||
|
||||
def questions(self) -> list:
|
||||
return [
|
||||
{
|
||||
"type": "list",
|
||||
"name": "prefix",
|
||||
"message": "Select the type of change you are committing",
|
||||
"choices": [
|
||||
{
|
||||
"value": "patch",
|
||||
"name": "patch: a bug fix",
|
||||
"key": "p",
|
||||
},
|
||||
{
|
||||
"value": "minor",
|
||||
"name": "minor: a new feature, non-breaking",
|
||||
"key": "m",
|
||||
},
|
||||
{
|
||||
"value": "major",
|
||||
"name": "major: a breaking change",
|
||||
"key": "b",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "input",
|
||||
"name": "subject",
|
||||
"message": (
|
||||
"Write a short and imperative summary of the code changes: (lower case and no period)\n"
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
def message(self, answers: dict) -> str:
|
||||
prefix = answers["prefix"]
|
||||
subject = answers.get("subject", "default message").trim()
|
||||
return f"{prefix}: {subject}"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def use_cz_semver(mocker):
|
||||
new_cz = {**registry, "cz_semver": SemverCommitizen}
|
||||
mocker.patch.dict("commitizen.cz.registry", new_cz)
|
||||
|
||||
|
||||
class MockPlugin(BaseCommitizen):
|
||||
def questions(self) -> defaults.Questions:
|
||||
return []
|
||||
|
||||
def message(self, answers: dict) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_plugin(mocker: MockerFixture, config: BaseConfig) -> BaseCommitizen:
|
||||
mock = MockPlugin(config)
|
||||
mocker.patch("commitizen.factory.commiter_factory", return_value=mock)
|
||||
return mock
|
||||
|
||||
|
||||
SUPPORTED_FORMATS = ("markdown", "textile", "asciidoc", "restructuredtext")
|
||||
|
||||
|
||||
@pytest.fixture(params=SUPPORTED_FORMATS)
|
||||
def changelog_format(
|
||||
config: BaseConfig, request: pytest.FixtureRequest
|
||||
) -> ChangelogFormat:
|
||||
"""For tests relying on formats specifics"""
|
||||
format: str = request.param
|
||||
config.settings["changelog_format"] = format
|
||||
if "tmp_commitizen_project" in request.fixturenames:
|
||||
tmp_commitizen_project = request.getfixturevalue("tmp_commitizen_project")
|
||||
pyproject = tmp_commitizen_project / "pyproject.toml"
|
||||
pyproject.write(f'{pyproject.read()}\nchangelog_format = "{format}"\n')
|
||||
return get_changelog_format(config)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def any_changelog_format(config: BaseConfig) -> ChangelogFormat:
|
||||
"""For test not relying on formats specifics, use the default"""
|
||||
config.settings["changelog_format"] = defaults.CHANGELOG_FORMAT
|
||||
return get_changelog_format(config)
|
4
tests/data/inconsistent_version.py
Normal file
4
tests/data/inconsistent_version.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
__title__ = "requests"
|
||||
__description__ = "Python HTTP for Humans."
|
||||
__url__ = "http://python-requests.org"
|
||||
__version__ = "2.10.3"
|
27
tests/data/multiple_versions_to_update_pyproject.toml
Normal file
27
tests/data/multiple_versions_to_update_pyproject.toml
Normal file
|
@ -0,0 +1,27 @@
|
|||
[[package]]
|
||||
name = "to-update-1"
|
||||
version = "1.2.9"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "to-update-2"
|
||||
version = "1.2.9"
|
27
tests/data/multiple_versions_to_update_pyproject_wo_eol.toml
Normal file
27
tests/data/multiple_versions_to_update_pyproject_wo_eol.toml
Normal file
|
@ -0,0 +1,27 @@
|
|||
[[package]]
|
||||
name = "to-update-1"
|
||||
version = "1.2.9"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "not-to-update"
|
||||
version = "1.3.3"
|
||||
|
||||
[[package]]
|
||||
name = "to-update-2"
|
||||
version = "1.2.9"
|
7
tests/data/repeated_version_number.json
Normal file
7
tests/data/repeated_version_number.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "magictool",
|
||||
"version": "1.2.3",
|
||||
"dependencies": {
|
||||
"lodash": "1.2.3"
|
||||
}
|
||||
}
|
11
tests/data/sample_cargo.lock
Normal file
11
tests/data/sample_cargo.lock
Normal file
|
@ -0,0 +1,11 @@
|
|||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "1.2.3"
|
||||
|
||||
[[package]]
|
||||
name = "there-i-fixed-it"
|
||||
version = "1.2.3" # automatically bumped by Commitizen
|
||||
|
||||
[[package]]
|
||||
name = "other-project"
|
||||
version = "1.2.3"
|
6
tests/data/sample_docker_compose.yaml
Normal file
6
tests/data/sample_docker_compose.yaml
Normal file
|
@ -0,0 +1,6 @@
|
|||
version: "3.3"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: my-repo/my-container:v1.2.3
|
||||
command: my-command
|
3
tests/data/sample_pyproject.toml
Normal file
3
tests/data/sample_pyproject.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[tool.poetry]
|
||||
name = "commitizen"
|
||||
version = "1.2.3"
|
4
tests/data/sample_version.py
Normal file
4
tests/data/sample_version.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
__title__ = "requests"
|
||||
__description__ = "Python HTTP for Humans."
|
||||
__url__ = "http://python-requests.org"
|
||||
__version__ = "1.2.3"
|
15
tests/providers/conftest.py
Normal file
15
tests/providers/conftest.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def chdir(tmp_path: Path) -> Iterator[Path]:
|
||||
cwd = Path()
|
||||
os.chdir(tmp_path)
|
||||
yield tmp_path
|
||||
os.chdir(cwd)
|
20
tests/providers/test_base_provider.py
Normal file
20
tests/providers/test_base_provider.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.exceptions import VersionProviderUnknown
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.commitizen_provider import CommitizenProvider
|
||||
|
||||
|
||||
def test_default_version_provider_is_commitizen_config(config: BaseConfig):
|
||||
provider = get_provider(config)
|
||||
|
||||
assert isinstance(provider, CommitizenProvider)
|
||||
|
||||
|
||||
def test_raise_for_unknown_provider(config: BaseConfig):
|
||||
config.settings["version_provider"] = "unknown"
|
||||
with pytest.raises(VersionProviderUnknown):
|
||||
get_provider(config)
|
60
tests/providers/test_cargo_provider.py
Normal file
60
tests/providers/test_cargo_provider.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.cargo_provider import CargoProvider
|
||||
|
||||
CARGO_TOML = """\
|
||||
[package]
|
||||
name = "whatever"
|
||||
version = "0.1.0"
|
||||
"""
|
||||
|
||||
CARGO_EXPECTED = """\
|
||||
[package]
|
||||
name = "whatever"
|
||||
version = "42.1"
|
||||
"""
|
||||
|
||||
CARGO_WORKSPACE_TOML = """\
|
||||
[workspace.package]
|
||||
name = "whatever"
|
||||
version = "0.1.0"
|
||||
"""
|
||||
|
||||
CARGO_WORKSPACE_EXPECTED = """\
|
||||
[workspace.package]
|
||||
name = "whatever"
|
||||
version = "42.1"
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
(
|
||||
(CARGO_TOML, CARGO_EXPECTED),
|
||||
(CARGO_WORKSPACE_TOML, CARGO_WORKSPACE_EXPECTED),
|
||||
),
|
||||
)
|
||||
def test_cargo_provider(
|
||||
config: BaseConfig,
|
||||
chdir: Path,
|
||||
content: str,
|
||||
expected: str,
|
||||
):
|
||||
filename = CargoProvider.filename
|
||||
file = chdir / filename
|
||||
file.write_text(dedent(content))
|
||||
config.settings["version_provider"] = "cargo"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, CargoProvider)
|
||||
assert provider.get_version() == "0.1.0"
|
||||
|
||||
provider.set_version("42.1")
|
||||
assert file.read_text() == dedent(expected)
|
20
tests/providers/test_commitizen_provider.py
Normal file
20
tests/providers/test_commitizen_provider.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers.commitizen_provider import CommitizenProvider
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
|
||||
def test_commitizen_provider(config: BaseConfig, mocker: MockerFixture):
|
||||
config.settings["version"] = "42"
|
||||
mock = mocker.patch.object(config, "set_key")
|
||||
|
||||
provider = CommitizenProvider(config)
|
||||
assert provider.get_version() == "42"
|
||||
|
||||
provider.set_version("43.1")
|
||||
mock.assert_called_once_with("version", "43.1")
|
47
tests/providers/test_composer_provider.py
Normal file
47
tests/providers/test_composer_provider.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.composer_provider import ComposerProvider
|
||||
|
||||
COMPOSER_JSON = """\
|
||||
{
|
||||
"name": "whatever",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
"""
|
||||
|
||||
COMPOSER_EXPECTED = """\
|
||||
{
|
||||
"name": "whatever",
|
||||
"version": "42.1"
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
((COMPOSER_JSON, COMPOSER_EXPECTED),),
|
||||
)
|
||||
def test_composer_provider(
|
||||
config: BaseConfig,
|
||||
chdir: Path,
|
||||
content: str,
|
||||
expected: str,
|
||||
):
|
||||
filename = ComposerProvider.filename
|
||||
file = chdir / filename
|
||||
file.write_text(dedent(content))
|
||||
config.settings["version_provider"] = "composer"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, ComposerProvider)
|
||||
assert provider.get_version() == "0.1.0"
|
||||
|
||||
provider.set_version("42.1")
|
||||
assert file.read_text() == dedent(expected)
|
98
tests/providers/test_npm_provider.py
Normal file
98
tests/providers/test_npm_provider.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.npm_provider import NpmProvider
|
||||
|
||||
NPM_PACKAGE_JSON = """\
|
||||
{
|
||||
"name": "whatever",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
"""
|
||||
|
||||
NPM_PACKAGE_EXPECTED = """\
|
||||
{
|
||||
"name": "whatever",
|
||||
"version": "42.1"
|
||||
}
|
||||
"""
|
||||
|
||||
NPM_LOCKFILE_JSON = """\
|
||||
{
|
||||
"name": "whatever",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "whatever",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"someotherpackage": {
|
||||
"version": "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
NPM_LOCKFILE_EXPECTED = """\
|
||||
{
|
||||
"name": "whatever",
|
||||
"version": "42.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "whatever",
|
||||
"version": "42.1"
|
||||
},
|
||||
"someotherpackage": {
|
||||
"version": "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"pkg_shrinkwrap_content, pkg_shrinkwrap_expected",
|
||||
((NPM_LOCKFILE_JSON, NPM_LOCKFILE_EXPECTED), (None, None)),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"pkg_lock_content, pkg_lock_expected",
|
||||
((NPM_LOCKFILE_JSON, NPM_LOCKFILE_EXPECTED), (None, None)),
|
||||
)
|
||||
def test_npm_provider(
|
||||
config: BaseConfig,
|
||||
chdir: Path,
|
||||
pkg_lock_content: str,
|
||||
pkg_lock_expected: str,
|
||||
pkg_shrinkwrap_content: str,
|
||||
pkg_shrinkwrap_expected: str,
|
||||
):
|
||||
pkg = chdir / NpmProvider.package_filename
|
||||
pkg.write_text(dedent(NPM_PACKAGE_JSON))
|
||||
if pkg_lock_content:
|
||||
pkg_lock = chdir / NpmProvider.lock_filename
|
||||
pkg_lock.write_text(dedent(pkg_lock_content))
|
||||
if pkg_shrinkwrap_content:
|
||||
pkg_shrinkwrap = chdir / NpmProvider.shrinkwrap_filename
|
||||
pkg_shrinkwrap.write_text(dedent(pkg_shrinkwrap_content))
|
||||
config.settings["version_provider"] = "npm"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, NpmProvider)
|
||||
assert provider.get_version() == "0.1.0"
|
||||
|
||||
provider.set_version("42.1")
|
||||
assert pkg.read_text() == dedent(NPM_PACKAGE_EXPECTED)
|
||||
if pkg_lock_content:
|
||||
assert pkg_lock.read_text() == dedent(pkg_lock_expected)
|
||||
if pkg_shrinkwrap_content:
|
||||
assert pkg_shrinkwrap.read_text() == dedent(pkg_shrinkwrap_expected)
|
43
tests/providers/test_pep621_provider.py
Normal file
43
tests/providers/test_pep621_provider.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.pep621_provider import Pep621Provider
|
||||
|
||||
PEP621_TOML = """\
|
||||
[project]
|
||||
version = "0.1.0"
|
||||
"""
|
||||
|
||||
PEP621_EXPECTED = """\
|
||||
[project]
|
||||
version = "42.1"
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
((PEP621_TOML, PEP621_EXPECTED),),
|
||||
)
|
||||
def test_cargo_provider(
|
||||
config: BaseConfig,
|
||||
chdir: Path,
|
||||
content: str,
|
||||
expected: str,
|
||||
):
|
||||
filename = Pep621Provider.filename
|
||||
file = chdir / filename
|
||||
file.write_text(dedent(content))
|
||||
config.settings["version_provider"] = "pep621"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, Pep621Provider)
|
||||
assert provider.get_version() == "0.1.0"
|
||||
|
||||
provider.set_version("42.1")
|
||||
assert file.read_text() == dedent(expected)
|
43
tests/providers/test_poetry_provider.py
Normal file
43
tests/providers/test_poetry_provider.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.poetry_provider import PoetryProvider
|
||||
|
||||
POETRY_TOML = """\
|
||||
[tool.poetry]
|
||||
version = "0.1.0"
|
||||
"""
|
||||
|
||||
POETRY_EXPECTED = """\
|
||||
[tool.poetry]
|
||||
version = "42.1"
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"content, expected",
|
||||
((POETRY_TOML, POETRY_EXPECTED),),
|
||||
)
|
||||
def test_cargo_provider(
|
||||
config: BaseConfig,
|
||||
chdir: Path,
|
||||
content: str,
|
||||
expected: str,
|
||||
):
|
||||
filename = PoetryProvider.filename
|
||||
file = chdir / filename
|
||||
file.write_text(dedent(content))
|
||||
config.settings["version_provider"] = "poetry"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, PoetryProvider)
|
||||
assert provider.get_version() == "0.1.0"
|
||||
|
||||
provider.set_version("42.1")
|
||||
assert file.read_text() == dedent(expected)
|
138
tests/providers/test_scm_provider.py
Normal file
138
tests/providers/test_scm_provider.py
Normal file
|
@ -0,0 +1,138 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.scm_provider import ScmProvider
|
||||
from tests.utils import (
|
||||
create_branch,
|
||||
create_file_and_commit,
|
||||
create_tag,
|
||||
merge_branch,
|
||||
switch_branch,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"tag_format,tag,expected_version",
|
||||
(
|
||||
# If tag_format is $version (the default), version_scheme.parser is used.
|
||||
# Its DEFAULT_VERSION_PARSER allows a v prefix, but matches PEP440 otherwise.
|
||||
("$version", "no-match-because-version-scheme-is-strict", "0.0.0"),
|
||||
("$version", "0.1.0", "0.1.0"),
|
||||
("$version", "v0.1.0", "0.1.0"),
|
||||
("$version", "v-0.1.0", "0.0.0"),
|
||||
# If tag_format is not None or $version, TAG_FORMAT_REGEXS are used, which are
|
||||
# much more lenient but require a v prefix.
|
||||
("v$version", "v0.1.0", "0.1.0"),
|
||||
("v$version", "no-match-because-no-v-prefix", "0.0.0"),
|
||||
# no match because not a valid version
|
||||
("v$version", "v-match-TAG_FORMAT_REGEXS", "0.0.0"),
|
||||
("version-$version", "version-0.1.0", "0.1.0"),
|
||||
("version-$version", "version-0.1", "0.1"),
|
||||
("version-$version", "version-0.1.0rc1", "0.1.0rc1"),
|
||||
("v$minor.$major.$patch", "v1.0.0", "0.1.0"),
|
||||
("version-$major.$minor.$patch", "version-0.1.0", "0.1.0"),
|
||||
("v$major.$minor$prerelease$devrelease", "v1.0rc1", "1.0rc1"),
|
||||
("v$major.$minor.$patch$prerelease$devrelease", "v0.1.0", "0.1.0"),
|
||||
("v$major.$minor.$patch$prerelease$devrelease", "v0.1.0rc1", "0.1.0rc1"),
|
||||
("v$major.$minor.$patch$prerelease$devrelease", "v1.0.0.dev0", "1.0.0.dev0"),
|
||||
),
|
||||
)
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_scm_provider(
|
||||
config: BaseConfig, tag_format: str, tag: str, expected_version: str
|
||||
):
|
||||
create_file_and_commit("test: fake commit")
|
||||
create_tag(tag)
|
||||
create_file_and_commit("test: fake commit")
|
||||
create_tag("should-not-match")
|
||||
|
||||
config.settings["version_provider"] = "scm"
|
||||
config.settings["tag_format"] = tag_format
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, ScmProvider)
|
||||
actual_version = provider.get_version()
|
||||
assert actual_version == expected_version
|
||||
|
||||
# Should not fail on set_version()
|
||||
provider.set_version("43.1")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_scm_provider_default_without_commits_and_tags(config: BaseConfig):
|
||||
config.settings["version_provider"] = "scm"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, ScmProvider)
|
||||
assert provider.get_version() == "0.0.0"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_scm_provider_default_with_commits_and_tags(config: BaseConfig):
|
||||
config.settings["version_provider"] = "scm"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, ScmProvider)
|
||||
assert provider.get_version() == "0.0.0"
|
||||
|
||||
create_file_and_commit("Initial state")
|
||||
create_tag("1.0.0")
|
||||
# create develop
|
||||
create_branch("develop")
|
||||
switch_branch("develop")
|
||||
|
||||
# add a feature to develop
|
||||
create_file_and_commit("develop: add beta feature1")
|
||||
assert provider.get_version() == "1.0.0"
|
||||
create_tag("1.1.0b0")
|
||||
|
||||
# create staging
|
||||
create_branch("staging")
|
||||
switch_branch("staging")
|
||||
create_file_and_commit("staging: Starting release candidate")
|
||||
assert provider.get_version() == "1.1.0b0"
|
||||
create_tag("1.1.0rc0")
|
||||
|
||||
# add another feature to develop
|
||||
switch_branch("develop")
|
||||
create_file_and_commit("develop: add beta feature2")
|
||||
assert provider.get_version() == "1.1.0b0"
|
||||
create_tag("1.2.0b0")
|
||||
|
||||
# add a hotfix to master
|
||||
switch_branch("master")
|
||||
create_file_and_commit("master: add hotfix")
|
||||
assert provider.get_version() == "1.0.0"
|
||||
create_tag("1.0.1")
|
||||
|
||||
# merge the hotfix to staging
|
||||
switch_branch("staging")
|
||||
merge_branch("master")
|
||||
|
||||
assert provider.get_version() == "1.1.0rc0"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_scm_provider_detect_legacy_tags(config: BaseConfig):
|
||||
config.settings["version_provider"] = "scm"
|
||||
config.settings["tag_format"] = "v${version}"
|
||||
config.settings["legacy_tag_formats"] = [
|
||||
"legacy-${version}",
|
||||
"old-${version}",
|
||||
]
|
||||
provider = get_provider(config)
|
||||
|
||||
create_file_and_commit("test: fake commit")
|
||||
create_tag("old-0.4.1")
|
||||
assert provider.get_version() == "0.4.1"
|
||||
|
||||
create_file_and_commit("test: fake commit")
|
||||
create_tag("legacy-0.4.2")
|
||||
assert provider.get_version() == "0.4.2"
|
||||
|
||||
create_file_and_commit("test: fake commit")
|
||||
create_tag("v0.5.0")
|
||||
assert provider.get_version() == "0.5.0"
|
97
tests/providers/test_uv_provider.py
Normal file
97
tests/providers/test_uv_provider.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from commitizen.config.base_config import BaseConfig
|
||||
from commitizen.providers import get_provider
|
||||
from commitizen.providers.uv_provider import UvProvider
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pytest_regressions.file_regression import FileRegressionFixture
|
||||
|
||||
|
||||
PYPROJECT_TOML = """
|
||||
[project]
|
||||
name = "test-uv"
|
||||
version = "4.2.1"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = ["commitizen==4.2.1"]
|
||||
"""
|
||||
|
||||
UV_LOCK_SIMPLIFIED = """
|
||||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "commitizen"
|
||||
version = "4.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "argcomplete" },
|
||||
{ name = "charset-normalizer" },
|
||||
{ name = "colorama" },
|
||||
{ name = "decli" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "questionary" },
|
||||
{ name = "termcolor" },
|
||||
{ name = "tomlkit" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/a3/77ffc9aee014cbf46c84c9f156a1ddef2d4c7cfb87d567decf2541464245/commitizen-4.2.1.tar.gz", hash = "sha256:5255416f6d6071068159f0b97605777f3e25d00927ff157b7a8d01efeda7b952", size = 50645 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/57/ce/2f5d8ebe8376991b5f805e9f33d20c7f4c9ca6155bdbda761117dc41dff1/commitizen-4.2.1-py3-none-any.whl", hash = "sha256:a347889e0fe408c3b920a34130d8f35616be3ea8ac6b7b20c5b9aac19762661b", size = 72646 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "decli"
|
||||
version = "0.6.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/a0/a4658f93ecb589f479037b164dc13c68d108b50bf6594e54c820749f97ac/decli-0.6.2.tar.gz", hash = "sha256:36f71eb55fd0093895efb4f416ec32b7f6e00147dda448e3365cf73ceab42d6f", size = 7424 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/70/3ea48dc9e958d7d66c44c9944809181f1ca79aaef25703c023b5092d34ff/decli-0.6.2-py3-none-any.whl", hash = "sha256:2fc84106ce9a8f523ed501ca543bdb7e416c064917c12a59ebdc7f311a97b7ed", size = 7854 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-uv"
|
||||
version = "4.2.1"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "commitizen" },
|
||||
]
|
||||
"""
|
||||
|
||||
|
||||
def test_uv_provider(
|
||||
config: BaseConfig, tmpdir, file_regression: FileRegressionFixture
|
||||
):
|
||||
with tmpdir.as_cwd():
|
||||
pyproject_toml_file = tmpdir / UvProvider.filename
|
||||
pyproject_toml_file.write_text(PYPROJECT_TOML, encoding="utf-8")
|
||||
|
||||
uv_lock_file = tmpdir / UvProvider.lock_filename
|
||||
uv_lock_file.write_text(UV_LOCK_SIMPLIFIED, encoding="utf-8")
|
||||
|
||||
config.settings["version_provider"] = "uv"
|
||||
|
||||
provider = get_provider(config)
|
||||
assert isinstance(provider, UvProvider)
|
||||
assert provider.get_version() == "4.2.1"
|
||||
|
||||
provider.set_version("100.100.100")
|
||||
assert provider.get_version() == "100.100.100"
|
||||
|
||||
updated_pyproject_toml_content = pyproject_toml_file.read_text(encoding="utf-8")
|
||||
updated_uv_lock_content = uv_lock_file.read_text(encoding="utf-8")
|
||||
|
||||
for content in (updated_pyproject_toml_content, updated_uv_lock_content):
|
||||
# updated project version
|
||||
assert "100.100.100" in content
|
||||
# commitizen version which was the same as project version and should not be affected
|
||||
assert "4.2.1" in content
|
||||
|
||||
file_regression.check(updated_pyproject_toml_content, extension=".toml")
|
||||
file_regression.check(updated_uv_lock_content, extension=".lock")
|
42
tests/providers/test_uv_provider/test_uv_provider.lock
Normal file
42
tests/providers/test_uv_provider/test_uv_provider.lock
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "commitizen"
|
||||
version = "4.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "argcomplete" },
|
||||
{ name = "charset-normalizer" },
|
||||
{ name = "colorama" },
|
||||
{ name = "decli" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pyyaml" },
|
||||
{ name = "questionary" },
|
||||
{ name = "termcolor" },
|
||||
{ name = "tomlkit" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/a3/77ffc9aee014cbf46c84c9f156a1ddef2d4c7cfb87d567decf2541464245/commitizen-4.2.1.tar.gz", hash = "sha256:5255416f6d6071068159f0b97605777f3e25d00927ff157b7a8d01efeda7b952", size = 50645 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/57/ce/2f5d8ebe8376991b5f805e9f33d20c7f4c9ca6155bdbda761117dc41dff1/commitizen-4.2.1-py3-none-any.whl", hash = "sha256:a347889e0fe408c3b920a34130d8f35616be3ea8ac6b7b20c5b9aac19762661b", size = 72646 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "decli"
|
||||
version = "0.6.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/a0/a4658f93ecb589f479037b164dc13c68d108b50bf6594e54c820749f97ac/decli-0.6.2.tar.gz", hash = "sha256:36f71eb55fd0093895efb4f416ec32b7f6e00147dda448e3365cf73ceab42d6f", size = 7424 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/70/3ea48dc9e958d7d66c44c9944809181f1ca79aaef25703c023b5092d34ff/decli-0.6.2-py3-none-any.whl", hash = "sha256:2fc84106ce9a8f523ed501ca543bdb7e416c064917c12a59ebdc7f311a97b7ed", size = 7854 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-uv"
|
||||
version = "100.100.100"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "commitizen" },
|
||||
]
|
8
tests/providers/test_uv_provider/test_uv_provider.toml
Normal file
8
tests/providers/test_uv_provider/test_uv_provider.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
[project]
|
||||
name = "test-uv"
|
||||
version = "100.100.100"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = ["commitizen==4.2.1"]
|
160
tests/test_bump_create_commit_message.py
Normal file
160
tests/test_bump_create_commit_message.py
Normal file
|
@ -0,0 +1,160 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockFixture
|
||||
|
||||
from commitizen import bump, cli, cmd, exceptions
|
||||
|
||||
conversion = [
|
||||
(
|
||||
("1.2.3", "1.3.0", "bump: $current_version -> $new_version [skip ci]"),
|
||||
"bump: 1.2.3 -> 1.3.0 [skip ci]",
|
||||
),
|
||||
(("1.2.3", "1.3.0", None), "bump: version 1.2.3 → 1.3.0"),
|
||||
(("1.2.3", "1.3.0", "release $new_version"), "release 1.3.0"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("test_input,expected", conversion)
|
||||
def test_create_tag(test_input, expected):
|
||||
current_version, new_version, message_template = test_input
|
||||
new_tag = bump.create_commit_message(current_version, new_version, message_template)
|
||||
assert new_tag == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"retry",
|
||||
(
|
||||
pytest.param(
|
||||
True,
|
||||
marks=pytest.mark.skipif(
|
||||
sys.version_info >= (3, 13),
|
||||
reason="mirrors-prettier is not supported with Python 3.13 or higher",
|
||||
),
|
||||
),
|
||||
False,
|
||||
),
|
||||
)
|
||||
@pytest.mark.usefixtures("tmp_commitizen_project")
|
||||
def test_bump_pre_commit_changelog(mocker: MockFixture, freezer, retry):
|
||||
freezer.move_to("2022-04-01")
|
||||
testargs = ["cz", "bump", "--changelog", "--yes"]
|
||||
if retry:
|
||||
testargs.append("--retry")
|
||||
else:
|
||||
pytest.xfail("it will fail because pre-commit will reformat CHANGELOG.md")
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
# Configure prettier as a pre-commit hook
|
||||
Path(".pre-commit-config.yaml").write_text(
|
||||
dedent(
|
||||
"""\
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v3.0.3
|
||||
hooks:
|
||||
- id: prettier
|
||||
stages: [commit]
|
||||
"""
|
||||
)
|
||||
)
|
||||
# Prettier inherits editorconfig
|
||||
Path(".editorconfig").write_text(
|
||||
dedent(
|
||||
"""\
|
||||
[*]
|
||||
indent_size = 4
|
||||
"""
|
||||
)
|
||||
)
|
||||
cmd.run("git add -A")
|
||||
cmd.run('git commit -m "fix: _test"')
|
||||
cmd.run("pre-commit install")
|
||||
cli.main()
|
||||
# Pre-commit fixed last line adding extra indent and "\" char
|
||||
assert Path("CHANGELOG.md").read_text() == dedent(
|
||||
"""\
|
||||
## 0.1.1 (2022-04-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- \\_test
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("retry", (True, False))
|
||||
@pytest.mark.usefixtures("tmp_commitizen_project")
|
||||
def test_bump_pre_commit_changelog_fails_always(mocker: MockFixture, freezer, retry):
|
||||
freezer.move_to("2022-04-01")
|
||||
testargs = ["cz", "bump", "--changelog", "--yes"]
|
||||
if retry:
|
||||
testargs.append("--retry")
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
Path(".pre-commit-config.yaml").write_text(
|
||||
dedent(
|
||||
"""\
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: forbid-changelog
|
||||
name: changelogs are forbidden
|
||||
entry: changelogs are forbidden
|
||||
language: fail
|
||||
files: CHANGELOG.md
|
||||
"""
|
||||
)
|
||||
)
|
||||
cmd.run("git add -A")
|
||||
cmd.run('git commit -m "feat: forbid changelogs"')
|
||||
cmd.run("pre-commit install")
|
||||
with pytest.raises(exceptions.BumpCommitFailedError):
|
||||
cli.main()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_commitizen_project")
|
||||
def test_bump_with_build_metadata(mocker: MockFixture, freezer):
|
||||
def _add_entry(test_str: str, args: list):
|
||||
Path(test_str).write_text("")
|
||||
cmd.run("git add -A")
|
||||
cmd.run(f'git commit -m "fix: test-{test_str}"')
|
||||
cz_args = ["cz", "bump", "--changelog", "--yes"] + args
|
||||
mocker.patch.object(sys, "argv", cz_args)
|
||||
cli.main()
|
||||
|
||||
freezer.move_to("2024-01-01")
|
||||
|
||||
_add_entry("a", ["--build-metadata", "a.b.c"])
|
||||
_add_entry("b", [])
|
||||
_add_entry("c", ["--build-metadata", "alongmetadatastring"])
|
||||
_add_entry("d", [])
|
||||
|
||||
# Pre-commit fixed last line adding extra indent and "\" char
|
||||
assert Path("CHANGELOG.md").read_text() == dedent(
|
||||
"""\
|
||||
## 0.1.4 (2024-01-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- test-d
|
||||
|
||||
## 0.1.3+alongmetadatastring (2024-01-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- test-c
|
||||
|
||||
## 0.1.2 (2024-01-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- test-b
|
||||
|
||||
## 0.1.1+a.b.c (2024-01-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- test-a
|
||||
"""
|
||||
)
|
124
tests/test_bump_find_increment.py
Normal file
124
tests/test_bump_find_increment.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
"""
|
||||
CC: Conventional commits
|
||||
SVE: Semantic version at the end
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from commitizen import bump
|
||||
from commitizen.cz.conventional_commits import ConventionalCommitsCz
|
||||
from commitizen.git import GitCommit
|
||||
|
||||
NONE_INCREMENT_CC = [
|
||||
"docs(README): motivation",
|
||||
"ci: added travis",
|
||||
"performance. Remove or disable the reimplemented linters",
|
||||
"refactor that how this line starts",
|
||||
]
|
||||
|
||||
PATCH_INCREMENTS_CC = [
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
"docs(README): motivation",
|
||||
]
|
||||
|
||||
MINOR_INCREMENTS_CC = [
|
||||
"feat(cli): added version",
|
||||
"docs(README): motivation",
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
"perf: app is much faster",
|
||||
"refactor: app is much faster",
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_BREAKING_CHANGE_CC = [
|
||||
"feat(cli): added version",
|
||||
"docs(README): motivation",
|
||||
"BREAKING CHANGE: `extends` key in config file is now used for extending other config files", # noqa
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_BREAKING_CHANGE_ALT_CC = [
|
||||
"feat(cli): added version",
|
||||
"docs(README): motivation",
|
||||
"BREAKING-CHANGE: `extends` key in config file is now used for extending other config files", # noqa
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_EXCLAMATION_CC = [
|
||||
"feat(cli)!: added version",
|
||||
"docs(README): motivation",
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_EXCLAMATION_CC_SAMPLE_2 = [
|
||||
"feat(pipeline)!: some text with breaking change"
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_EXCLAMATION_OTHER_TYPE_CC = [
|
||||
"chore!: drop support for Python 3.9",
|
||||
"docs(README): motivation",
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_EXCLAMATION_OTHER_TYPE_WITH_SCOPE_CC = [
|
||||
"chore(deps)!: drop support for Python 3.9",
|
||||
"docs(README): motivation",
|
||||
"fix(setup.py): future is now required for every python version",
|
||||
]
|
||||
|
||||
PATCH_INCREMENTS_SVE = ["readme motivation PATCH", "fix setup.py PATCH"]
|
||||
|
||||
MINOR_INCREMENTS_SVE = [
|
||||
"readme motivation PATCH",
|
||||
"fix setup.py PATCH",
|
||||
"added version to cli MINOR",
|
||||
]
|
||||
|
||||
MAJOR_INCREMENTS_SVE = [
|
||||
"readme motivation PATCH",
|
||||
"fix setup.py PATCH",
|
||||
"added version to cli MINOR",
|
||||
"extends key is used for other config files MAJOR",
|
||||
]
|
||||
|
||||
semantic_version_pattern = r"(MAJOR|MINOR|PATCH)"
|
||||
semantic_version_map = {"MAJOR": "MAJOR", "MINOR": "MINOR", "PATCH": "PATCH"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"messages, expected_type",
|
||||
(
|
||||
(PATCH_INCREMENTS_CC, "PATCH"),
|
||||
(MINOR_INCREMENTS_CC, "MINOR"),
|
||||
(MAJOR_INCREMENTS_BREAKING_CHANGE_CC, "MAJOR"),
|
||||
(MAJOR_INCREMENTS_BREAKING_CHANGE_ALT_CC, "MAJOR"),
|
||||
(MAJOR_INCREMENTS_EXCLAMATION_OTHER_TYPE_CC, "MAJOR"),
|
||||
(MAJOR_INCREMENTS_EXCLAMATION_OTHER_TYPE_WITH_SCOPE_CC, "MAJOR"),
|
||||
(MAJOR_INCREMENTS_EXCLAMATION_CC, "MAJOR"),
|
||||
(MAJOR_INCREMENTS_EXCLAMATION_CC_SAMPLE_2, "MAJOR"),
|
||||
(NONE_INCREMENT_CC, None),
|
||||
),
|
||||
)
|
||||
def test_find_increment(messages, expected_type):
|
||||
commits = [GitCommit(rev="test", title=message) for message in messages]
|
||||
increment_type = bump.find_increment(
|
||||
commits,
|
||||
regex=ConventionalCommitsCz.bump_pattern,
|
||||
increments_map=ConventionalCommitsCz.bump_map,
|
||||
)
|
||||
assert increment_type == expected_type
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"messages, expected_type",
|
||||
(
|
||||
(PATCH_INCREMENTS_SVE, "PATCH"),
|
||||
(MINOR_INCREMENTS_SVE, "MINOR"),
|
||||
(MAJOR_INCREMENTS_SVE, "MAJOR"),
|
||||
),
|
||||
)
|
||||
def test_find_increment_sve(messages, expected_type):
|
||||
commits = [GitCommit(rev="test", title=message) for message in messages]
|
||||
increment_type = bump.find_increment(
|
||||
commits, regex=semantic_version_pattern, increments_map=semantic_version_map
|
||||
)
|
||||
assert increment_type == expected_type
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue