diff --git a/commitizen/bump.py b/commitizen/bump.py index 7b621a6e1c..d6a1684ea5 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -146,7 +146,12 @@ def generate_version( def update_version_in_files( - current_version: str, new_version: str, files: List[str], *, check_consistency=False + current_version: str, + new_version: str, + files: List[str], + encoding: str, + *, + check_consistency=False, ) -> None: """Change old version to the new one in every file given. @@ -163,7 +168,11 @@ def update_version_in_files( regex = _version_to_regex(current_version) current_version_found, version_file = _bump_with_regex( - filepath, current_version, new_version, regex + filepath, + current_version, + new_version, + regex, + encoding, ) if check_consistency and not current_version_found: @@ -174,17 +183,21 @@ def update_version_in_files( ) # Write the file out again - with smart_open(filepath, "w") as file: + with smart_open(filepath, "w", encoding=encoding) as file: file.write(version_file) def _bump_with_regex( - version_filepath: str, current_version: str, new_version: str, regex: str + version_filepath: str, + current_version: str, + new_version: str, + regex: str, + encoding: str, ) -> Tuple[bool, str]: current_version_found = False lines = [] pattern = re.compile(regex) - with open(version_filepath, "r") as f: + with open(version_filepath, "r", encoding=encoding) as f: for line in f: if pattern.search(line): bumped_line = line.replace(current_version, new_version) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index ead80ab775..63d19d8baa 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -164,7 +164,7 @@ def parse_title_type_of_line(value: str) -> Optional[str]: return m.groupdict().get("title") -def get_metadata(filepath: str) -> Dict: +def get_metadata(filepath: str, encoding: str) -> Dict: unreleased_start: Optional[int] = None unreleased_end: Optional[int] = None unreleased_title: Optional[str] = None @@ -178,7 +178,7 @@ def get_metadata(filepath: str) -> Dict: "latest_version_position": None, } - with open(filepath, "r") as changelog_file: + with open(filepath, "r", encoding=encoding) as changelog_file: for index, line in enumerate(changelog_file): line = line.strip().lower() diff --git a/commitizen/changelog_parser.py b/commitizen/changelog_parser.py index e53c52893a..f3a33798c9 100644 --- a/commitizen/changelog_parser.py +++ b/commitizen/changelog_parser.py @@ -34,7 +34,7 @@ ] -def find_version_blocks(filepath: str) -> Generator: +def find_version_blocks(filepath: str, encoding: str) -> Generator: """Find version block (version block: contains all the information about a version.) E.g: @@ -51,7 +51,7 @@ def find_version_blocks(filepath: str) -> Generator: ``` """ - with open(filepath, "r") as f: + with open(filepath, "r", encoding=encoding) as f: block: list = [] for line in f: line = line.strip("\n") diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 14e339c669..088a14ea25 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -33,6 +33,7 @@ def __init__(self, config: BaseConfig, arguments: dict): raise NotAGitProjectError() self.config: BaseConfig = config + self.encoding = config.settings["encoding"] self.arguments: dict = arguments self.bump_settings: dict = { **config.settings, @@ -267,6 +268,7 @@ def __call__(self): # noqa: C901 current_version, str(new_version), version_files, + self.encoding, check_consistency=self.check_consistency, ) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index aab613fffc..d95aa2d7bf 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -24,6 +24,7 @@ def __init__(self, config: BaseConfig, args): raise NotAGitProjectError() self.config: BaseConfig = config + self.encoding = self.config.settings["encoding"] self.cz = factory.commiter_factory(self.config) self.start_rev = args.get("start_rev") or self.config.settings.get( @@ -87,7 +88,7 @@ def write_changelog( ) changelog_hook: Optional[Callable] = self.cz.changelog_hook - with smart_open(self.file_name, "w") as changelog_file: + with smart_open(self.file_name, "w", encoding=self.encoding) as changelog_file: partial_changelog: Optional[str] = None if self.incremental: new_lines = changelog.incremental_build( @@ -129,7 +130,7 @@ def __call__(self): end_rev = "" if self.incremental: - changelog_meta = changelog.get_metadata(self.file_name) + changelog_meta = changelog.get_metadata(self.file_name, self.encoding) latest_version = changelog_meta.get("latest_version") if latest_version: latest_tag_version: str = bump.normalize_tag( @@ -170,7 +171,7 @@ def __call__(self): lines = [] if self.incremental and os.path.isfile(self.file_name): - with open(self.file_name, "r") as changelog_file: + with open(self.file_name, "r", encoding=self.encoding) as changelog_file: lines = changelog_file.readlines() self.write_changelog(changelog_out, lines, changelog_meta) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 2ce8ed4d64..9c2f23cc94 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -33,6 +33,7 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( self._valid_command_argument() self.config: BaseConfig = config + self.encoding = config.settings["encoding"] self.cz = factory.commiter_factory(self.config) def _valid_command_argument(self): @@ -86,7 +87,7 @@ def _get_commits(self): # Get commit message from file (--commit-msg-file) if self.commit_msg_file is not None: # Enter this branch if commit_msg_file is "". - with open(self.commit_msg_file, "r", encoding="utf-8") as commit_file: + with open(self.commit_msg_file, "r", encoding=self.encoding) as commit_file: msg = commit_file.read() # Get commit message from command line (--message) elif self.commit_msg is not None: diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 13e61abe6d..b3479379a9 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -27,6 +27,7 @@ def __init__(self, config: BaseConfig, arguments: dict): raise NotAGitProjectError() self.config: BaseConfig = config + self.encoding = config.settings["encoding"] self.cz = factory.commiter_factory(self.config) self.arguments = arguments self.temp_file: str = os.path.join( @@ -40,7 +41,7 @@ def read_backup_message(self) -> str: raise NoCommitBackupError() # Read commit message from backup - with open(self.temp_file, "r") as f: + with open(self.temp_file, "r", encoding=self.encoding) as f: return f.read().strip() def prompt_commit_questions(self) -> str: @@ -90,7 +91,7 @@ def __call__(self): out.error(c.err) # Create commit backup - with smart_open(self.temp_file, "w") as f: + with smart_open(self.temp_file, "w", encoding=self.encoding) as f: f.write(m) raise CommitError() diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 3b10a58230..c85f519567 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -16,6 +16,7 @@ class Init: def __init__(self, config: BaseConfig, *args): self.config: BaseConfig = config + self.encoding = config.settings["encoding"] self.cz = factory.commiter_factory(self.config) def __call__(self): @@ -122,7 +123,9 @@ def _install_pre_commit_hook(self): # .pre-commit-config does not exist config_data["repos"] = [cz_hook_config] else: - with open(pre_commit_config_filename) as config_file: + with open( + pre_commit_config_filename, encoding=self.encoding + ) as config_file: yaml_data = yaml.safe_load(config_file) if yaml_data: config_data = yaml_data @@ -138,7 +141,9 @@ def _install_pre_commit_hook(self): # .pre-commit-config exists but there's no "repos" key config_data["repos"] = [cz_hook_config] - with smart_open(pre_commit_config_filename, "w") as config_file: + with smart_open( + pre_commit_config_filename, "w", encoding=self.encoding + ) as config_file: yaml.safe_dump(config_data, stream=config_file) c = cmd.run("pre-commit install --hook-type commit-msg") diff --git a/commitizen/config/json_config.py b/commitizen/config/json_config.py index 34a81a9ef7..0a8327b6d2 100644 --- a/commitizen/config/json_config.py +++ b/commitizen/config/json_config.py @@ -10,12 +10,13 @@ class JsonConfig(BaseConfig): def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): super(JsonConfig, self).__init__() + self.encoding = self.settings["encoding"] self.is_empty_config = False self._parse_setting(data) self.add_path(path) def init_empty_config_content(self): - with smart_open(self.path, "a") as json_file: + with smart_open(self.path, "a", encoding=self.encoding) as json_file: json.dump({"commitizen": {}}, json_file) def set_key(self, key, value): @@ -28,7 +29,7 @@ def set_key(self, key, value): parser = json.load(f) parser["commitizen"][key] = value - with smart_open(self.path, "w") as f: + with smart_open(self.path, "w", encoding=self.encoding) as f: json.dump(parser, f, indent=2) return self @@ -44,6 +45,7 @@ def _parse_setting(self, data: Union[bytes, str]) -> None: ``` """ doc = json.loads(data) + try: self.settings.update(doc["commitizen"]) except KeyError: diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index 0d09c90796..29b4572e0d 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -10,6 +10,7 @@ class TomlConfig(BaseConfig): def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): super(TomlConfig, self).__init__() + self.encoding = self.settings["encoding"] self.is_empty_config = False self._parse_setting(data) self.add_path(path) @@ -25,7 +26,7 @@ def init_empty_config_content(self): if parser.get("tool") is None: parser["tool"] = table() parser["tool"]["commitizen"] = table() - output_toml_file.write(parser.as_string().encode("utf-8")) + output_toml_file.write(parser.as_string().encode(self.encoding)) def set_key(self, key, value): """Set or update a key in the conf. @@ -38,7 +39,7 @@ def set_key(self, key, value): parser["tool"]["commitizen"][key] = value with open(self.path, "wb") as f: - f.write(parser.as_string().encode("utf-8")) + f.write(parser.as_string().encode(self.encoding)) return self def _parse_setting(self, data: Union[bytes, str]) -> None: diff --git a/commitizen/config/yaml_config.py b/commitizen/config/yaml_config.py index 503b32ce06..405b94637b 100644 --- a/commitizen/config/yaml_config.py +++ b/commitizen/config/yaml_config.py @@ -11,12 +11,13 @@ class YAMLConfig(BaseConfig): def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): super(YAMLConfig, self).__init__() + self.encoding = self.settings["encoding"] self.is_empty_config = False self._parse_setting(data) self.add_path(path) def init_empty_config_content(self): - with smart_open(self.path, "a") as json_file: + with smart_open(self.path, "a", encoding=self.encoding) as json_file: yaml.dump({"commitizen": {}}, json_file) def _parse_setting(self, data: Union[bytes, str]) -> None: @@ -43,7 +44,7 @@ def set_key(self, key, value): parser = yaml.load(yaml_file, Loader=yaml.FullLoader) parser["commitizen"][key] = value - with smart_open(self.path, "w") as yaml_file: + with smart_open(self.path, "w", encoding=self.encoding) as yaml_file: yaml.dump(parser, yaml_file) return self diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 7989a17122..a5caf31e4a 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -202,7 +202,7 @@ def schema_pattern(self) -> str: def info(self) -> str: dir_path = os.path.dirname(os.path.realpath(__file__)) filepath = os.path.join(dir_path, "conventional_commits_info.txt") - with open(filepath, "r") as f: + with open(filepath, "r", encoding=self.config.settings["encoding"]) as f: content = f.read() return content diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 994c21c714..e0fb86dd8a 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -73,7 +73,7 @@ def info(self) -> Optional[str]: info_path = self.custom_settings.get("info_path") info = self.custom_settings.get("info") if info_path: - with open(info_path, "r") as f: + with open(info_path, "r", encoding=self.config.settings["encoding"]) as f: content = f.read() return content elif info: diff --git a/commitizen/cz/jira/jira.py b/commitizen/cz/jira/jira.py index bd3cd3c7ee..cc33cd791a 100644 --- a/commitizen/cz/jira/jira.py +++ b/commitizen/cz/jira/jira.py @@ -76,6 +76,6 @@ def schema_pattern(self) -> str: def info(self) -> str: dir_path = os.path.dirname(os.path.realpath(__file__)) filepath = os.path.join(dir_path, "jira_info.txt") - with open(filepath, "r") as f: + with open(filepath, "r", encoding=self.config.settings["encoding"]) as f: content = f.read() return content diff --git a/commitizen/defaults.py b/commitizen/defaults.py index bdc853e1eb..be11146e98 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -40,6 +40,8 @@ class Settings(TypedDict, total=False): style: Optional[List[Tuple[str, str]]] customize: CzSettings major_version_zero: bool + encoding: str + major_version_zero: bool name: str = "cz_conventional_commits" @@ -51,6 +53,7 @@ class Settings(TypedDict, total=False): ".cz.yaml", "cz.yaml", ] +encoding: str = "utf-8" DEFAULT_SETTINGS: Settings = { "name": "cz_conventional_commits", @@ -64,6 +67,9 @@ class Settings(TypedDict, total=False): "changelog_start_rev": None, "update_changelog_on_bump": False, "use_shortcuts": False, + "encoding": "utf-8", + "major_version_zero": False, + "encoding": "utf-8", "major_version_zero": False, } diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index b79c73e7d7..7888d503d0 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -222,7 +222,7 @@ def test_bump_command_prelease(mocker): def test_bump_on_git_with_hooks_no_verify_disabled(mocker): """Bump commit without --no-verify""" cmd.run("mkdir .git/hooks") - with open(".git/hooks/pre-commit", "w") as f: + with open(".git/hooks/pre-commit", "w", encoding="utf-8") as f: f.write("#!/usr/bin/env bash\n" 'echo "0.1.0"') cmd.run("chmod +x .git/hooks/pre-commit") @@ -241,7 +241,7 @@ def test_bump_on_git_with_hooks_no_verify_disabled(mocker): @pytest.mark.usefixtures("tmp_commitizen_project") def test_bump_tag_exists_raises_exception(mocker): cmd.run("mkdir .git/hooks") - with open(".git/hooks/post-commit", "w") as f: + with open(".git/hooks/post-commit", "w", encoding="utf-8") as f: f.write("#!/usr/bin/env bash\n" "exit 9") cmd.run("chmod +x .git/hooks/post-commit") @@ -260,7 +260,7 @@ def test_bump_tag_exists_raises_exception(mocker): @pytest.mark.usefixtures("tmp_commitizen_project") def test_bump_on_git_with_hooks_no_verify_enabled(mocker): cmd.run("mkdir .git/hooks") - with open(".git/hooks/pre-commit", "w") as f: + with open(".git/hooks/pre-commit", "w", encoding="utf-8") as f: f.write("#!/usr/bin/env bash\n" 'echo "0.1.0"') cmd.run("chmod +x .git/hooks/pre-commit") @@ -400,10 +400,10 @@ def test_bump_files_only(mocker, tmp_commitizen_project): tag_exists = git.tag_exist("0.3.0") assert tag_exists is False - with open(tmp_version_file, "r") as f: + with open(tmp_version_file, "r", encoding="utf-8") as f: assert "0.3.0" in f.read() - with open(tmp_commitizen_cfg_file, "r") as f: + with open(tmp_commitizen_cfg_file, "r", encoding="utf-8") as f: assert "0.3.0" in f.read() @@ -425,7 +425,7 @@ def test_bump_local_version(mocker, tmp_commitizen_project): tag_exists = git.tag_exist("4.5.1+0.2.0") assert tag_exists is True - with open(tmp_version_file, "r") as f: + with open(tmp_version_file, "r", encoding="utf-8") as f: assert "4.5.1+0.2.0" in f.read() @@ -504,7 +504,7 @@ def test_bump_with_changelog_arg(mocker, changelog_path): tag_exists = git.tag_exist("0.2.0") assert tag_exists is True - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() assert out.startswith("#") assert "0.2.0" in out @@ -513,7 +513,7 @@ def test_bump_with_changelog_arg(mocker, changelog_path): @pytest.mark.usefixtures("tmp_commitizen_project") def test_bump_with_changelog_config(mocker, changelog_path, config_path): create_file_and_commit("feat(user): new file") - with open(config_path, "a") as fp: + with open(config_path, "a", encoding="utf-8") as fp: fp.write("update_changelog_on_bump = true\n") testargs = ["cz", "bump", "--yes"] @@ -522,7 +522,7 @@ def test_bump_with_changelog_config(mocker, changelog_path, config_path): tag_exists = git.tag_exist("0.2.0") assert tag_exists is True - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() assert out.startswith("#") assert "0.2.0" in out @@ -566,7 +566,7 @@ def test_bump_with_changelog_to_stdout_arg(mocker, capsys, changelog_path): tag_exists = git.tag_exist("0.2.0") assert tag_exists is True - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() assert out.startswith("#") assert "0.2.0" in out @@ -658,11 +658,13 @@ def test_bump_changelog_command_commits_untracked_changelog_and_version_files( """ with tmp_commitizen_project.join("pyproject.toml").open( - mode="a" + mode="a", encoding="utf-8" ) as commitizen_config: commitizen_config.write(f"version_files = [\n" f"'{version_regex}'\n]") - with tmp_commitizen_project.join(version_filepath).open(mode="a+") as version_file: + with tmp_commitizen_project.join(version_filepath).open( + mode="a+", encoding="utf-8" + ) as version_file: version_file.write(version_file_content) create_file_and_commit("fix: some test commit") diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index c2fafd4552..006997b160 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -62,7 +62,7 @@ def test_changelog_from_start(mocker, capsys, changelog_path, file_regression): mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -91,7 +91,7 @@ def test_changelog_replacing_unreleased_using_incremental( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read().replace( datetime.strftime(datetime.now(), "%Y-%m-%d"), "2022-08-14" ) @@ -116,7 +116,7 @@ def test_changelog_is_persisted_using_incremental( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "a") as f: + with open(changelog_path, "a", encoding="utf-8") as f: f.write("\nnote: this should be persisted using increment\n") create_file_and_commit("fix: mama gotta work") @@ -128,7 +128,7 @@ def test_changelog_is_persisted_using_incremental( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read().replace( datetime.strftime(datetime.now(), "%Y-%m-%d"), "2022-08-14" ) @@ -140,7 +140,7 @@ def test_changelog_is_persisted_using_incremental( def test_changelog_incremental_angular_sample( mocker, capsys, changelog_path, file_regression ): - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write( "# [10.0.0-rc.3](https://github.com/angular/angular/compare/10.0.0-rc.2...10.0.0-rc.3) (2020-04-22)\n" "\n" @@ -162,7 +162,7 @@ def test_changelog_incremental_angular_sample( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -197,7 +197,7 @@ def test_changelog_incremental_angular_sample( def test_changelog_incremental_keep_a_changelog_sample( mocker, capsys, changelog_path, file_regression ): - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") git.tag("1.0.0") @@ -213,7 +213,7 @@ def test_changelog_incremental_keep_a_changelog_sample( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -292,7 +292,7 @@ def test_changelog_multiple_incremental_do_not_add_new_lines( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -303,7 +303,7 @@ def test_changelog_incremental_newline_separates_new_content_from_old( mocker, changelog_path ): """Test for https://github.com/commitizen-tools/commitizen/issues/509""" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write("Pre-existing content that should be kept\n") create_file_and_commit("feat: add more cat videos") @@ -313,7 +313,7 @@ def test_changelog_incremental_newline_separates_new_content_from_old( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() assert ( @@ -436,9 +436,9 @@ def test_changelog_config_flag_increment( mocker, changelog_path, config_path, file_regression ): - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write("changelog_incremental = true\n") - with open(changelog_path, "a") as f: + with open(changelog_path, "a", encoding="utf-8") as f: f.write("\nnote: this should be persisted using increment\n") create_file_and_commit("feat: add new output") @@ -447,7 +447,7 @@ def test_changelog_config_flag_increment( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() assert "this should be persisted using increment" in out @@ -469,7 +469,7 @@ def test_changelog_config_start_rev_option( create_file_and_commit("feat: after 0.2.0") create_file_and_commit("feat: after 0.2") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('changelog_start_rev = "0.2.0"\n') testargs = ["cz", "changelog", "--dry-run"] @@ -486,7 +486,7 @@ def test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag( mocker, capsys, changelog_path, file_regression ): """Fix #378""" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") git.tag("1.0.0", annotated=True) @@ -502,7 +502,7 @@ def test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -515,7 +515,7 @@ def test_changelog_incremental_with_release_candidate_version( mocker, changelog_path, file_regression, test_input ): """Fix #357""" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") git.tag("1.0.0", annotated=True) @@ -536,7 +536,7 @@ def test_changelog_incremental_with_release_candidate_version( mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -545,7 +545,7 @@ def test_changelog_incremental_with_release_candidate_version( @pytest.mark.usefixtures("tmp_commitizen_project") def test_changelog_with_filename_as_empty_string(mocker, changelog_path, config_path): - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write("changelog_file = true\n") create_file_and_commit("feat: add new output") @@ -563,7 +563,7 @@ def test_changelog_from_rev_first_version_from_arg( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -584,7 +584,7 @@ def test_changelog_from_rev_first_version_from_arg( testargs = ["cz", "changelog", "0.2.0"] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -597,7 +597,7 @@ def test_changelog_from_rev_latest_version_from_arg( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -632,7 +632,7 @@ def test_changelog_from_rev_single_version_not_found( mocker, config_path, changelog_path ): """Provides an invalid revision ID to changelog command""" - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -694,7 +694,7 @@ def test_changelog_from_rev_range_default_tag_format( @pytest.mark.freeze_time("2022-02-13") def test_changelog_from_rev_range_version_not_found(mocker, config_path): """Provides an invalid end revision ID to changelog command""" - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -725,7 +725,7 @@ def test_changelog_from_rev_version_range_including_first_tag( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -744,7 +744,7 @@ def test_changelog_from_rev_version_range_including_first_tag( testargs = ["cz", "changelog", "0.2.0..0.3.0"] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -757,7 +757,7 @@ def test_changelog_from_rev_version_range_from_arg( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -784,7 +784,7 @@ def test_changelog_from_rev_version_range_from_arg( testargs = ["cz", "changelog", "0.3.0..0.4.0"] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -797,7 +797,7 @@ def test_changelog_from_rev_version_with_big_range_from_arg( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -844,7 +844,7 @@ def test_changelog_from_rev_version_with_big_range_from_arg( testargs = ["cz", "changelog", "0.3.0..0.5.0"] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") @@ -857,7 +857,7 @@ def test_changelog_from_rev_latest_version_dry_run( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') # create commit and tag @@ -911,7 +911,7 @@ def test_changelog_with_customized_change_type_order( ): mocker.patch("commitizen.git.GitTag.date", "2022-02-13") - with open(config_path, "a") as f: + with open(config_path, "a", encoding="utf-8") as f: f.write('tag_format = "$version"\n') f.write( 'change_type_order = ["BREAKING CHANGE", "Perf", "Fix", "Feat", "Refactor"]\n' @@ -943,7 +943,7 @@ def test_changelog_with_customized_change_type_order( testargs = ["cz", "changelog", "0.3.0..0.4.0"] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: out = f.read() file_regression.check(out, extension=".md") diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 4b59665b8e..d25f063e68 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -55,7 +55,7 @@ def test_init_without_setup_pre_commit_hook(tmpdir, mocker, config): with tmpdir.as_cwd(): commands.Init(config)() - with open("pyproject.toml", "r") as toml_file: + with open("pyproject.toml", "r", encoding="utf-8") as toml_file: config_data = toml_file.read() assert config_data == expected_config @@ -112,7 +112,7 @@ def test_no_existing_pre_commit_conifg(_, default_choice, tmpdir, config): with tmpdir.as_cwd(): commands.Init(config)() - with open(default_choice, "r") as file: + with open(default_choice, "r", encoding="utf-8") as file: if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: @@ -123,7 +123,9 @@ def test_no_existing_pre_commit_conifg(_, default_choice, tmpdir, config): config_data = file.read() assert config_data == expected_config - with open(pre_commit_config_filename, "r") as pre_commit_file: + with open( + pre_commit_config_filename, "r", encoding="utf-8" + ) as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) assert pre_commit_config_data == {"repos": [cz_hook_config]} @@ -134,7 +136,7 @@ def test_empty_pre_commit_config(_, default_choice, tmpdir, config): commands.Init(config)() - with open(default_choice, "r") as file: + with open(default_choice, "r", encoding="utf-8") as file: if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: @@ -145,7 +147,9 @@ def test_empty_pre_commit_config(_, default_choice, tmpdir, config): config_data = file.read() assert config_data == expected_config - with open(pre_commit_config_filename, "r") as pre_commit_file: + with open( + pre_commit_config_filename, "r", encoding="utf-8" + ) as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) assert pre_commit_config_data == {"repos": [cz_hook_config]} @@ -162,7 +166,7 @@ def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config): commands.Init(config)() - with open(default_choice, "r") as file: + with open(default_choice, "r", encoding="utf-8") as file: if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: @@ -173,7 +177,9 @@ def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config): config_data = file.read() assert config_data == expected_config - with open(pre_commit_config_filename, "r") as pre_commit_file: + with open( + pre_commit_config_filename, "r", encoding="utf-8" + ) as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) assert pre_commit_config_data == { "repos": [existing_hook_config, cz_hook_config] @@ -186,7 +192,7 @@ def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config): commands.Init(config)() - with open(default_choice, "r") as file: + with open(default_choice, "r", encoding="utf-8") as file: if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: @@ -197,7 +203,9 @@ def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config): config_data = file.read() assert config_data == expected_config - with open(pre_commit_config_filename, "r") as pre_commit_file: + with open( + pre_commit_config_filename, "r", encoding="utf-8" + ) as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) # check that config is not duplicated diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 0c37bf538c..c15425e459 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -102,11 +102,11 @@ def version_files( def test_update_version_in_files(version_files, file_regression): old_version = "1.2.3" new_version = "2.0.0" - bump.update_version_in_files(old_version, new_version, version_files) + bump.update_version_in_files(old_version, new_version, version_files, "utf-8") file_contents = "" for filepath in version_files: - with open(filepath, "r") as f: + with open(filepath, "r", encoding="utf-8") as f: file_contents += f.read() file_regression.check(file_contents, extension=".txt") @@ -117,8 +117,8 @@ def test_partial_update_of_file(version_repeated_file, file_regression): regex = "version" location = f"{version_repeated_file}:{regex}" - bump.update_version_in_files(old_version, new_version, [location]) - with open(version_repeated_file, "r") as f: + bump.update_version_in_files(old_version, new_version, [location], "utf-8") + with open(version_repeated_file, "r", encoding="utf-8") as f: file_regression.check(f.read(), extension=".json") @@ -127,7 +127,7 @@ def test_random_location(random_location_version_file, file_regression): new_version = "2.0.0" location = f"{random_location_version_file}:version.+Commitizen" - bump.update_version_in_files(old_version, new_version, [location]) + bump.update_version_in_files(old_version, new_version, [location], "utf-8") with open(random_location_version_file, "r") as f: file_regression.check(f.read(), extension=".lock") @@ -139,8 +139,8 @@ def test_duplicates_are_change_with_no_regex( new_version = "2.0.0" location = f"{random_location_version_file}:version" - bump.update_version_in_files(old_version, new_version, [location]) - with open(random_location_version_file, "r") as f: + bump.update_version_in_files(old_version, new_version, [location], "utf-8") + with open(random_location_version_file, "r", encoding="utf-8") as f: file_regression.check(f.read(), extension=".lock") @@ -151,7 +151,7 @@ def test_version_bump_increase_string_length( new_version = "1.2.10" location = f"{multiple_versions_increase_string}:version" - bump.update_version_in_files(old_version, new_version, [location]) + bump.update_version_in_files(old_version, new_version, [location], "utf-8") with open(multiple_versions_increase_string, "r") as f: file_regression.check(f.read(), extension=".txt") @@ -163,8 +163,8 @@ def test_version_bump_reduce_string_length( new_version = "2.0.0" location = f"{multiple_versions_reduce_string}:version" - bump.update_version_in_files(old_version, new_version, [location]) - with open(multiple_versions_reduce_string, "r") as f: + bump.update_version_in_files(old_version, new_version, [location], "utf-8") + with open(multiple_versions_reduce_string, "r", encoding="utf-8") as f: file_regression.check(f.read(), extension=".txt") @@ -180,7 +180,7 @@ def test_file_version_inconsistent_error( new_version = "2.0.0" with pytest.raises(CurrentVersionNotFoundError) as excinfo: bump.update_version_in_files( - old_version, new_version, version_files, check_consistency=True + old_version, new_version, version_files, "utf-8", check_consistency=True ) expected_msg = ( @@ -191,13 +191,13 @@ def test_file_version_inconsistent_error( assert expected_msg in str(excinfo.value) -def test_multiplt_versions_to_bump( +def test_multiple_versions_to_bump( multiple_versions_to_update_poetry_lock, file_regression ): old_version = "1.2.9" new_version = "1.2.10" location = f"{multiple_versions_to_update_poetry_lock}:version" - bump.update_version_in_files(old_version, new_version, [location]) - with open(multiple_versions_to_update_poetry_lock, "r") as f: + bump.update_version_in_files(old_version, new_version, [location], "utf-8") + with open(multiple_versions_to_update_poetry_lock, "r", encoding="utf-8") as f: file_regression.check(f.read(), extension=".toml") diff --git a/tests/test_bump_update_version_in_files/test_multiple_versions_to_bump_with_eol_.toml b/tests/test_bump_update_version_in_files/test_multiple_versions_to_bump_with_eol_.toml new file mode 100644 index 0000000000..f279eb4d61 --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_multiple_versions_to_bump_with_eol_.toml @@ -0,0 +1,27 @@ +[[package]] +name = "to-update-1" +version = "1.2.10" + +[[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.10" diff --git a/tests/test_bump_update_version_in_files/test_multiple_versions_to_bump_without_eol_.toml b/tests/test_bump_update_version_in_files/test_multiple_versions_to_bump_without_eol_.toml new file mode 100644 index 0000000000..47092b958b --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_multiple_versions_to_bump_without_eol_.toml @@ -0,0 +1,27 @@ +[[package]] +name = "to-update-1" +version = "1.2.10" + +[[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.10" \ No newline at end of file diff --git a/tests/test_changelog.py b/tests/test_changelog.py index e68a3abdcf..9d7efcc659 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -496,7 +496,7 @@ def tags() -> list: @pytest.fixture def changelog_content() -> str: changelog_path = "tests/CHANGELOG_FOR_TEST.md" - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: return f.read() diff --git a/tests/test_changelog_meta.py b/tests/test_changelog_meta.py index 505daefb83..0f06ab58c9 100644 --- a/tests/test_changelog_meta.py +++ b/tests/test_changelog_meta.py @@ -44,7 +44,7 @@ def changelog_a_file(): changelog_path = "tests/CHANGELOG.md" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(CHANGELOG_A) yield changelog_path @@ -56,7 +56,7 @@ def changelog_a_file(): def changelog_b_file(): changelog_path = "tests/CHANGELOG.md" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(CHANGELOG_B) yield changelog_path @@ -68,7 +68,7 @@ def changelog_b_file(): def changelog_c_file(): changelog_path = "tests/CHANGELOG.md" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(CHANGELOG_C) yield changelog_path @@ -80,7 +80,7 @@ def changelog_c_file(): def changelog_d_file(): changelog_path = "tests/CHANGELOG.md" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(CHANGELOG_D) yield changelog_path @@ -126,7 +126,7 @@ def test_parse_title_type_of_line(line_from_changelog, output_title): def test_get_metadata_from_a(changelog_a_file): - meta = changelog.get_metadata(changelog_a_file) + meta = changelog.get_metadata(changelog_a_file, "utf-8") assert meta == { "latest_version": "1.0.0", "latest_version_position": 10, @@ -136,7 +136,7 @@ def test_get_metadata_from_a(changelog_a_file): def test_get_metadata_from_b(changelog_b_file): - meta = changelog.get_metadata(changelog_b_file) + meta = changelog.get_metadata(changelog_b_file, "utf-8") assert meta == { "latest_version": "1.2.0", "latest_version_position": 3, @@ -146,7 +146,7 @@ def test_get_metadata_from_b(changelog_b_file): def test_get_metadata_from_c(changelog_c_file): - meta = changelog.get_metadata(changelog_c_file) + meta = changelog.get_metadata(changelog_c_file, "utf-8") assert meta == { "latest_version": "1.0.0", "latest_version_position": 3, @@ -156,7 +156,7 @@ def test_get_metadata_from_c(changelog_c_file): def test_get_metadata_from_d(changelog_d_file): - meta = changelog.get_metadata(changelog_d_file) + meta = changelog.get_metadata(changelog_d_file, "utf-8") assert meta == { "latest_version": None, "latest_version_position": None, diff --git a/tests/test_changelog_parser.py b/tests/test_changelog_parser.py index 540f62fd19..75f6788a8d 100644 --- a/tests/test_changelog_parser.py +++ b/tests/test_changelog_parser.py @@ -28,7 +28,7 @@ @pytest.fixture def changelog_content() -> str: changelog_path = "tests/CHANGELOG_FOR_TEST.md" - with open(changelog_path, "r") as f: + with open(changelog_path, "r", encoding="utf-8") as f: return f.read() @@ -38,7 +38,7 @@ def existing_changelog_file(tmpdir): changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") # changelog_path = "tests/CHANGELOG.md" - with open(changelog_path, "w") as f: + with open(changelog_path, "w", encoding="utf-8") as f: f.write(CHANGELOG_TEMPLATE) yield changelog_path @@ -47,7 +47,7 @@ def existing_changelog_file(tmpdir): def test_read_changelog_blocks(existing_changelog_file): - blocks = changelog_parser.find_version_blocks(existing_changelog_file) + blocks = changelog_parser.find_version_blocks(existing_changelog_file, "utf-8") blocks = list(blocks) amount_of_blocks = len(blocks) assert amount_of_blocks == 2 @@ -127,7 +127,7 @@ def test_transform_change_type_fail(): def test_generate_block_tree(existing_changelog_file): - blocks = changelog_parser.find_version_blocks(existing_changelog_file) + blocks = changelog_parser.find_version_blocks(existing_changelog_file, "utf-8") block = next(blocks) tree = changelog_parser.generate_block_tree(block) assert tree == { @@ -157,7 +157,7 @@ def test_generate_block_tree(existing_changelog_file): def test_generate_full_tree(existing_changelog_file): - blocks = changelog_parser.find_version_blocks(existing_changelog_file) + blocks = changelog_parser.find_version_blocks(existing_changelog_file, "utf-8") tree = list(changelog_parser.generate_full_tree(blocks)) assert tree == [ diff --git a/tests/test_cli.py b/tests/test_cli.py index 68a9c04a23..54a2dcd775 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -97,7 +97,7 @@ def test_argcomplete_activation(): Equivalent to run: $ eval "$(register-python-argcomplete pytest)" """ - output = subprocess.run(["register-python-argcomplete", "cz"]) + output = subprocess.run(["py", "-m", "register-python-argcomplete", "cz"]) assert output.returncode == 0 diff --git a/tests/test_conf.py b/tests/test_conf.py index 746cde2401..c5487fe5f7 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -48,6 +48,9 @@ "changelog_start_rev": None, "update_changelog_on_bump": False, "use_shortcuts": False, + "encoding": "utf-8", + "major_version_zero": False, + "encoding": "utf-8", "major_version_zero": False, } @@ -64,6 +67,9 @@ "changelog_start_rev": None, "update_changelog_on_bump": False, "use_shortcuts": False, + "encoding": "utf-8", + "major_version_zero": False, + "encoding": "utf-8", "major_version_zero": False, } @@ -80,7 +86,7 @@ def config_files_manager(request, tmpdir): with tmpdir.as_cwd(): filename = request.param - with open(filename, "w") as f: + with open(filename, "w", encoding="utf-8") as f: if "toml" in filename: f.write(PYPROJECT) elif "json" in filename: @@ -148,7 +154,7 @@ def test_init_empty_config_content_with_existing_content(self, tmpdir): toml_config = config.TomlConfig(data="", path=path) toml_config.init_empty_config_content() - with open(path, "r") as toml_file: + with open(path, "r", encoding="utf-8") as toml_file: assert toml_file.read() == existing_content + "\n[tool.commitizen]\n" @@ -158,5 +164,5 @@ def test_init_empty_config_content(self, tmpdir): json_config = config.JsonConfig(data="{}", path=path) json_config.init_empty_config_content() - with open(path, "r") as json_file: + with open(path, "r", encoding="utf-8") as json_file: assert json.load(json_file) == {"commitizen": {}} diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 84e463cf96..154d15d40d 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -7,7 +7,7 @@ TOML_STR = r""" [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example = "feature: this feature enable customize through config file" + example = "feature: this feature enables customization through a config file" schema = ": " schema_pattern = "(feature|bug fix):(\\s.*)" commit_parser = "^(?Pfeature|bug fix):\\s(?P.*)?" @@ -50,7 +50,7 @@ ], "customize": { "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", - "example": "feature: this feature enable customize through config file", + "example": "feature: this feature enables customization through a config file", "schema": ": ", "schema_pattern": "(feature|bug fix):(\\s.*)", "bump_pattern": "^(break|new|fix|hotfix)", @@ -106,7 +106,7 @@ - pyproject.toml customize: message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example: 'feature: this feature enable customize through config file' + example: 'feature: this feature enables customization through a config file' schema: ": " schema_pattern: "(feature|bug fix):(\\s.*)" bump_pattern: "^(break|new|fix|hotfix)" @@ -134,11 +134,110 @@ message: Do you want to add body message in commit? """ +TOML_WITH_UNICODE = r""" + [tool.commitizen] + name = "cz_customize" + version = "1.0.0" + version_files = [ + "commitizen/__version__.py", + "pyproject.toml:version" + ] + + [tool.commitizen.customize] + message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example = "✨ feature: this feature enables customization through a config file" + schema = ": " + schema_pattern = "(✨ feature|🐛 bug fix):(\\s.*)" + commit_parser = "^(?P✨ feature|🐛 bug fix):\\s(?P.*)?" + changelog_pattern = "^(✨ feature|🐛 bug fix)?(!)?" + change_type_map = {"✨ feature" = "Feat", "🐛 bug fix" = "Fix"} + + bump_pattern = "^(✨ feat|🐛 bug fix)" + bump_map = {"break" = "MAJOR", "✨ feat" = "MINOR", "🐛 bug fix" = "MINOR"} + change_type_order = ["perf", "BREAKING CHANGE", "feat", "fix", "refactor"] + info = "This is a customized cz with emojis 🎉!" + + [[tool.commitizen.customize.questions]] + type = "list" + name = "change_type" + choices = [ + {value = "✨ feature", name = "✨ feature: A new feature."}, + {value = "🐛 bug fix", name = "🐛 bug fix: A bug fix."} + ] + message = "Select the type of change you are committing" + + [[tool.commitizen.customize.questions]] + type = "input" + name = "message" + message = "Body." + + [[tool.commitizen.customize.questions]] + type = "confirm" + name = "show_message" + message = "Do you want to add body message in commit?" +""" + +JSON_WITH_UNICODE = r""" + { + "commitizen": { + "name": "cz_customize", + "version": "1.0.0", + "version_files": [ + "commitizen/__version__.py", + "pyproject.toml:version" + ], + "customize": { + "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", + "example": "✨ feature: this feature enables customization through a config file", + "schema": ": ", + "schema_pattern": "(✨ feature|🐛 bug fix):(\\s.*)", + "bump_pattern": "^(✨ feat|🐛 bug fix)", + "bump_map": { + "break": "MAJOR", + "✨ feat": "MINOR", + "🐛 bug fix": "MINOR" + }, + "commit_parser": "^(?P✨ feature|🐛 bug fix):\\s(?P.*)?", + "changelog_pattern": "^(✨ feature|🐛 bug fix)?(!)?", + "change_type_map": {"✨ feature": "Feat", "🐛 bug fix": "Fix"}, + "change_type_order": ["perf", "BREAKING CHANGE", "feat", "fix", "refactor"], + "info": "This is a customized cz with emojis 🎉!", + "questions": [ + { + "type": "list", + "name": "change_type", + "choices": [ + { + "value": "✨ feature", + "name": "✨ feature: A new feature." + }, + { + "value": "🐛 bug fix", + "name": "🐛 bug fix: A bug fix." + } + ], + "message": "Select the type of change you are committing" + }, + { + "type": "input", + "name": "message", + "message": "Body." + }, + { + "type": "confirm", + "name": "show_message", + "message": "Do you want to add body message in commit?" + } + ] + } + } + } +""" TOML_STR_INFO_PATH = """ [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example = "feature: this feature enable customize through config file" + example = "feature: this feature enables customization through a config file" schema = ": " bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} @@ -150,7 +249,7 @@ "commitizen": { "customize": { "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", - "example": "feature: this feature enable customize through config file", + "example": "feature: this feature enables customization through a config file", "schema": ": ", "bump_pattern": "^(break|new|fix|hotfix)", "bump_map": { @@ -169,7 +268,7 @@ commitizen: customize: message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example: 'feature: this feature enable customize through config file' + example: 'feature: this feature enables customization through a config file' schema: ": " bump_pattern: "^(break|new|fix|hotfix)" bump_map: @@ -183,7 +282,7 @@ TOML_STR_WITHOUT_INFO = """ [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example = "feature: this feature enable customize through config file" + example = "feature: this feature enables customization through a config file" schema = ": " bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} @@ -194,7 +293,7 @@ "commitizen": { "customize": { "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", - "example": "feature: this feature enable customize through config file", + "example": "feature: this feature enables customization through a config file", "schema": ": ", "bump_pattern": "^(break|new|fix|hotfix)", "bump_map": { @@ -212,7 +311,7 @@ commitizen: customize: message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example: 'feature: this feature enable customize through config file' + example: 'feature: this feature enables customization through a config file' schema: ": " bump_pattern: "^(break|new|fix|hotfix)" bump_map: @@ -260,6 +359,16 @@ def config_without_info(request): return request.param +@pytest.fixture( + params=[ + TomlConfig(data=TOML_WITH_UNICODE, path="not_exist.toml"), + JsonConfig(data=JSON_WITH_UNICODE, path="not_exist.json"), + ] +) +def config_with_unicode(request): + return request.param + + def test_initialize_cz_customize_failed(): with pytest.raises(MissingCzCustomizeConfigError) as excinfo: config = BaseConfig() @@ -273,6 +382,11 @@ def test_bump_pattern(config): assert cz.bump_pattern == "^(break|new|fix|hotfix)" +def test_bump_pattern_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert cz.bump_pattern == "^(✨ feat|🐛 bug fix)" + + def test_bump_map(config): cz = CustomizeCommitsCz(config) assert cz.bump_map == { @@ -283,6 +397,15 @@ def test_bump_map(config): } +def test_bump_map_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert cz.bump_map == { + "break": "MAJOR", + "✨ feat": "MINOR", + "🐛 bug fix": "MINOR", + } + + def test_change_type_order(config): cz = CustomizeCommitsCz(config) assert cz.change_type_order == [ @@ -294,6 +417,17 @@ def test_change_type_order(config): ] +def test_change_type_order_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert cz.change_type_order == [ + "perf", + "BREAKING CHANGE", + "feat", + "fix", + "refactor", + ] + + def test_questions(config): cz = CustomizeCommitsCz(config) questions = cz.questions() @@ -317,29 +451,87 @@ def test_questions(config): assert list(questions) == expected_questions +def test_questions_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + questions = cz.questions() + expected_questions = [ + { + "type": "list", + "name": "change_type", + "choices": [ + {"value": "✨ feature", "name": "✨ feature: A new feature."}, + {"value": "🐛 bug fix", "name": "🐛 bug fix: A bug fix."}, + ], + "message": "Select the type of change you are committing", + }, + {"type": "input", "name": "message", "message": "Body."}, + { + "type": "confirm", + "name": "show_message", + "message": "Do you want to add body message in commit?", + }, + ] + assert list(questions) == expected_questions + + def test_answer(config): cz = CustomizeCommitsCz(config) answers = { "change_type": "feature", - "message": "this feature enaable customize through config file", + "message": "this feature enables customization through a config file", "show_message": True, } message = cz.message(answers) - assert message == "feature: this feature enaable customize through config file" + assert ( + message == "feature: this feature enables customization through a config file" + ) cz = CustomizeCommitsCz(config) answers = { "change_type": "feature", - "message": "this feature enaable customize through config file", + "message": "this feature enables customization through a config file", "show_message": False, } message = cz.message(answers) assert message == "feature:" +def test_answer_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + answers = { + "change_type": "✨ feature", + "message": "this feature enables customization through a config file", + "show_message": True, + } + message = cz.message(answers) + assert ( + message == "✨ feature: this feature enables customization through a config file" + ) + + cz = CustomizeCommitsCz(config_with_unicode) + answers = { + "change_type": "✨ feature", + "message": "this feature enables customization through a config file", + "show_message": False, + } + message = cz.message(answers) + assert message == "✨ feature:" + + def test_example(config): cz = CustomizeCommitsCz(config) - assert "feature: this feature enable customize through config file" in cz.example() + assert ( + "feature: this feature enables customization through a config file" + in cz.example() + ) + + +def test_example_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert ( + "✨ feature: this feature enables customization through a config file" + in cz.example() + ) def test_schema(config): @@ -352,11 +544,21 @@ def test_schema_pattern(config): assert r"(feature|bug fix):(\s.*)" in cz.schema_pattern() +def test_schema_pattern_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert r"(✨ feature|🐛 bug fix):(\s.*)" in cz.schema_pattern() + + def test_info(config): cz = CustomizeCommitsCz(config) assert "This is a customized cz." in cz.info() +def test_info_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert "This is a customized cz with emojis 🎉!" in cz.info() + + def test_info_with_info_path(tmpdir, config_info): with tmpdir.as_cwd(): tmpfile = tmpdir.join("info.txt") @@ -376,11 +578,28 @@ def test_commit_parser(config): assert cz.commit_parser == "^(?Pfeature|bug fix):\\s(?P.*)?" +def test_commit_parser_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert ( + cz.commit_parser == "^(?P✨ feature|🐛 bug fix):\\s(?P.*)?" + ) + + def test_changelog_pattern(config): cz = CustomizeCommitsCz(config) assert cz.changelog_pattern == "^(feature|bug fix)?(!)?" +def test_changelog_pattern_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert cz.changelog_pattern == "^(✨ feature|🐛 bug fix)?(!)?" + + def test_change_type_map(config): cz = CustomizeCommitsCz(config) assert cz.change_type_map == {"feature": "Feat", "bug fix": "Fix"} + + +def test_change_type_map_unicode(config_with_unicode): + cz = CustomizeCommitsCz(config_with_unicode) + assert cz.change_type_map == {"✨ feature": "Feat", "🐛 bug fix": "Fix"}