def test_changelog_incremental_keep_a_changelog_sample(mocker, capsys, changelog_path): with open(changelog_path, "w") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") git.tag("1.0.0") create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") create_file_and_commit("fix: mama gotta work") create_file_and_commit("feat: add more stuff") create_file_and_commit("Merge into master") testargs = ["cz", "changelog", "--incremental"] mocker.patch.object(sys, "argv", testargs) cli.main() with open(changelog_path, "r") as f: out = f.read() assert ( out == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" )
def test_changelog_incremental_angular_sample(mocker, capsys, changelog_path): with open(changelog_path, "w") as f: f.write( "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n" "\n" "### Bug Fixes" "\n" "* **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)\n" ) create_file_and_commit("irrelevant commit") git.tag("10.0.0-next.3") create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") create_file_and_commit("fix: mama gotta work") create_file_and_commit("feat: add more stuff") create_file_and_commit("Merge into master") testargs = ["cz", "changelog", "--incremental"] mocker.patch.object(sys, "argv", testargs) cli.main() with open(changelog_path, "r") as f: out = f.read() assert ( out == "## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n\n### Bug Fixes\n* **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)\n" )
def test_changelog_incremental_with_release_candidate_version( mocker, changelog_path, file_regression, test_input): """Fix #357""" with open(changelog_path, "w") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") git.tag("1.0.0", annotated=True) create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") testargs = [ "cz", "bump", "--changelog", "--prerelease", test_input, "--yes" ] mocker.patch.object(sys, "argv", testargs) cli.main() create_file_and_commit("fix: mama gotta work") create_file_and_commit("feat: add more stuff") create_file_and_commit("Merge into master") testargs = ["cz", "changelog", "--incremental"] mocker.patch.object(sys, "argv", testargs) cli.main() with open(changelog_path, "r") as f: out = f.read() file_regression.check(out, extension=".md")
def test_bump_tag_exists_raises_exception(mocker): cmd.run("mkdir .git/hooks") with open(".git/hooks/post-commit", "w") as f: f.write("#!/usr/bin/env bash\n" "exit 9") cmd.run("chmod +x .git/hooks/post-commit") # MINOR create_file_and_commit("feat: new file") git.tag("0.2.0") testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) with pytest.raises(BumpTagFailedError) as excinfo: cli.main() assert "0.2.0" in str(excinfo.value) # This should be a fatal error
def test_changelog_with_different_tag_name_and_changelog_content( mocker, tmp_commitizen_project): changelog_file = tmp_commitizen_project.join("CHANGELOG.md") changelog_file.write(""" # Unreleased ## v1.0.0 """) create_file_and_commit("feat: new file") git.tag("2.0.0") # create_file_and_commit("feat: new file") testargs = ["cz", "changelog", "--incremental"] mocker.patch.object(sys, "argv", testargs) with pytest.raises(NoRevisionError): cli.main()
def test_none_increment_should_not_call_git_tag(mocker, tmp_commitizen_project): create_file_and_commit("test(test_get_all_droplets): fix bad comparison test") testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) # stash git.tag for later restore stashed_git_tag = git.tag dummy_value = git.tag("0.0.2") git.tag = MagicMock(return_value=dummy_value) with pytest.raises(NoneIncrementExit): cli.main() git.tag.assert_not_called() # restore pop stashed git.tag = stashed_git_tag
def __call__(self): """Steps executed to bump.""" try: current_version_instance: Version = Version(self.parameters["version"]) except TypeError: out.error("[NO_VERSION_SPECIFIED]") out.error("Check if current version is specified in config file, like:") out.error("version = 0.4.3") raise SystemExit(NO_VERSION_SPECIFIED) # Initialize values from sources (conf) current_version: str = self.config["version"] tag_format: str = self.parameters["tag_format"] bump_commit_message: str = self.parameters["bump_message"] current_tag_version: str = bump.create_tag( current_version, tag_format=tag_format ) files: list = self.parameters["files"] dry_run: bool = self.parameters["dry_run"] is_yes: bool = self.arguments["yes"] prerelease: str = self.arguments["prerelease"] increment: Optional[str] = self.arguments["increment"] is_initial = self.is_initial_tag(current_tag_version, is_yes) commits = git.get_commits(current_tag_version, from_beginning=is_initial) # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: out.error("[NO_COMMITS_FOUND]") out.error("No new commits found.") raise SystemExit(NO_COMMITS_FOUND) if increment is None: bump_pattern = self.cz.bump_pattern bump_map = self.cz.bump_map if not bump_map or not bump_pattern: out.error(f"'{self.config['name']}' rule does not support bump") raise SystemExit(NO_PATTERN_MAP) increment = bump.find_increment( commits, regex=bump_pattern, increments_map=bump_map ) # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: increment = None new_version = bump.generate_version( current_version, increment, prerelease=prerelease ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) message = bump.create_commit_message( current_version, new_version, bump_commit_message ) # Report found information out.write(message) out.write(f"tag to create: {new_tag_version}") out.write(f"increment detected: {increment}") # Do not perform operations over files or git. if dry_run: raise SystemExit() config.set_key("version", new_version.public) bump.update_version_in_files(current_version, new_version.public, files) c = git.commit(message, args="-a") if c.err: out.error(c.err) raise SystemExit(COMMIT_FAILED) c = git.tag(new_tag_version) if c.err: out.error(c.err) raise SystemExit(TAG_FAILED) out.success("Done!")
def __call__(self): # noqa: C901 """Steps executed to bump.""" try: current_version_instance: Version = Version(self.bump_settings["version"]) except TypeError: raise NoVersionSpecifiedError() # Initialize values from sources (conf) current_version: str = self.config.settings["version"] tag_format: str = self.bump_settings["tag_format"] bump_commit_message: str = self.bump_settings["bump_message"] version_files: List[str] = self.bump_settings["version_files"] dry_run: bool = self.arguments["dry_run"] is_yes: bool = self.arguments["yes"] increment: Optional[str] = self.arguments["increment"] prerelease: str = self.arguments["prerelease"] is_files_only: Optional[bool] = self.arguments["files_only"] is_local_version: Optional[bool] = self.arguments["local_version"] current_tag_version: str = bump.create_tag( current_version, tag_format=tag_format ) is_initial = self.is_initial_tag(current_tag_version, is_yes) if is_initial: commits = git.get_commits() else: commits = git.get_commits(current_tag_version) # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: raise NoCommitsFoundError("[NO_COMMITS_FOUND]\n" "No new commits found.") if increment is None: increment = self.find_increment(commits) # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: increment = None new_version = bump.generate_version( current_version, increment, prerelease=prerelease, is_local_version=is_local_version, ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) message = bump.create_commit_message( current_version, new_version, bump_commit_message ) # Report found information out.write( f"{message}\n" f"tag to create: {new_tag_version}\n" f"increment detected: {increment}\n" ) if increment is None and new_tag_version == current_tag_version: raise NoneIncrementExit() # Do not perform operations over files or git. if dry_run: raise DryRunExit() bump.update_version_in_files( current_version, str(new_version), version_files, check_consistency=self.check_consistency, ) if self.changelog: changelog_cmd = Changelog( self.config, { "unreleased_version": new_tag_version, "incremental": True, "dry_run": dry_run, }, ) changelog_cmd() c = cmd.run(f"git add {changelog_cmd.file_name}") self.config.set_key("version", str(new_version)) if is_files_only: raise ExpectedExit() c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') c = git.tag(new_tag_version) if c.return_code != 0: raise BumpTagFailedError(c.err) out.success("Done!")
def __call__(self): # noqa: C901 """Steps executed to bump.""" try: current_version_instance: Version = Version( self.bump_settings["version"]) except TypeError: raise NoVersionSpecifiedError() # Initialize values from sources (conf) current_version: str = self.config.settings["version"] tag_format: str = self.bump_settings["tag_format"] bump_commit_message: str = self.bump_settings["bump_message"] version_files: List[str] = self.bump_settings["version_files"] dry_run: bool = self.arguments["dry_run"] is_yes: bool = self.arguments["yes"] increment: Optional[str] = self.arguments["increment"] prerelease: str = self.arguments["prerelease"] is_files_only: Optional[bool] = self.arguments["files_only"] is_local_version: Optional[bool] = self.arguments["local_version"] current_tag_version: str = bump.normalize_tag(current_version, tag_format=tag_format) is_initial = self.is_initial_tag(current_tag_version, is_yes) if is_initial: commits = git.get_commits() else: commits = git.get_commits(current_tag_version) # If user specified changelog_to_stdout, they probably want the # changelog to be generated as well, this is the most intuitive solution if not self.changelog and self.changelog_to_stdout: self.changelog = True # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: raise NoCommitsFoundError("[NO_COMMITS_FOUND]\n" "No new commits found.") if increment is None: increment = self.find_increment(commits) # It may happen that there are commits, but they are not elegible # for an increment, this generates a problem when using prerelease (#281) if (prerelease and increment is None and not current_version_instance.is_prerelease): raise NoCommitsFoundError( "[NO_COMMITS_FOUND]\n" "No commits found to generate a pre-release.\n" "To avoid this error, manually specify the type of increment with `--increment`" ) # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: increment = None new_version = bump.generate_version( current_version, increment, prerelease=prerelease, is_local_version=is_local_version, ) new_tag_version = bump.normalize_tag(new_version, tag_format=tag_format) message = bump.create_commit_message(current_version, new_version, bump_commit_message) # Report found information information = (f"{message}\n" f"tag to create: {new_tag_version}\n" f"increment detected: {increment}\n") if self.changelog_to_stdout: # When the changelog goes to stdout, we want to send # the bump information to stderr, this way the # changelog output can be captured out.diagnostic(information) else: out.write(information) if increment is None and new_tag_version == current_tag_version: raise NoneIncrementExit( "[NO_COMMITS_TO_BUMP]\n" "The commits found are not elegible to be bumped") # Do not perform operations over files or git. if dry_run: raise DryRunExit() bump.update_version_in_files( current_version, str(new_version), version_files, check_consistency=self.check_consistency, ) if self.changelog: if self.changelog_to_stdout: changelog_cmd = Changelog( self.config, { "unreleased_version": new_tag_version, "incremental": True, "dry_run": True, }, ) try: changelog_cmd() except DryRunExit: pass changelog_cmd = Changelog( self.config, { "unreleased_version": new_tag_version, "incremental": True, "dry_run": dry_run, }, ) changelog_cmd() c = cmd.run( f"git add {changelog_cmd.file_name} {' '.join(version_files)}") self.config.set_key("version", str(new_version)) if is_files_only: raise ExpectedExit() c = git.commit(message, args=self._get_commit_args()) if self.retry and c.return_code != 0 and self.changelog: # Maybe pre-commit reformatted some files? Retry once logger.debug("1st git.commit error: %s", c.err) logger.info("1st commit attempt failed; retrying once") cmd.run( f"git add {changelog_cmd.file_name} {' '.join(version_files)}") c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError( f'2nd git.commit error: "{c.err.strip()}"') c = git.tag( new_tag_version, annotated=self.bump_settings.get("annotated_tag", False) or bool(self.config.settings.get("annotated_tag", False)), ) if c.return_code != 0: raise BumpTagFailedError(c.err) # TODO: For v3 output this only as diagnostic and remove this if if self.changelog_to_stdout: out.diagnostic("Done!") else: out.success("Done!")
def __call__(self): # noqa: C901 """Steps executed to bump.""" try: current_version_instance: Version = Version(self.bump_settings["version"]) except TypeError: out.error( "[NO_VERSION_SPECIFIED]\n" "Check if current version is specified in config file, like:\n" "version = 0.4.3\n" ) raise SystemExit(NO_VERSION_SPECIFIED) # Initialize values from sources (conf) current_version: str = self.config.settings["version"] tag_format: str = self.bump_settings["tag_format"] bump_commit_message: str = self.bump_settings["bump_message"] version_files: List[str] = self.bump_settings["version_files"] dry_run: bool = self.arguments["dry_run"] is_yes: bool = self.arguments["yes"] increment: Optional[str] = self.arguments["increment"] prerelease: str = self.arguments["prerelease"] is_files_only: Optional[bool] = self.arguments["files_only"] current_tag_version: str = bump.create_tag( current_version, tag_format=tag_format ) is_initial = self.is_initial_tag(current_tag_version, is_yes) if is_initial: commits = git.get_commits() else: commits = git.get_commits(current_tag_version) # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: out.error("[NO_COMMITS_FOUND]\n" "No new commits found.") raise SystemExit(NO_COMMITS_FOUND) if increment is None: increment = self.find_increment(commits) # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: increment = None new_version = bump.generate_version( current_version, increment, prerelease=prerelease ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) message = bump.create_commit_message( current_version, new_version, bump_commit_message ) # Report found information out.write( f"message\n" f"tag to create: {new_tag_version}\n" f"increment detected: {increment}\n" ) # Do not perform operations over files or git. if dry_run: raise SystemExit() bump.update_version_in_files( current_version, new_version.public, version_files, check_consistency=self.check_consistency, ) if is_files_only: raise SystemExit() if self.changelog: changelog = Changelog( self.config, { "unreleased_version": new_tag_version, "incremental": True, "dry_run": dry_run, }, ) changelog() self.config.set_key("version", new_version.public) c = git.commit(message, args=self._get_commit_args()) if c.err: out.error('git.commit error: "{}"'.format(c.err.strip())) raise SystemExit(COMMIT_FAILED) c = git.tag(new_tag_version) if c.err: out.error(c.err) raise SystemExit(TAG_FAILED) out.success("Done!")