diff --git a/docs/manpages/gbp-rpm-ch.xml b/docs/manpages/gbp-rpm-ch.xml index 53c78f9f..70cc28bf 100644 --- a/docs/manpages/gbp-rpm-ch.xml +++ b/docs/manpages/gbp-rpm-ch.xml @@ -40,6 +40,11 @@ EDITOR MSG-FORMAT + + + MSG-FORMAT + + GPG-KEYID CUSTOMIZATION-FILE [PATH1 PATH2] @@ -287,6 +292,58 @@ + + + + + + Commit the changes and create a packaging (release) tag. Similarly to + , all staged changes are committed to git + before creating the tag. This option makes it possible to create a + release and correctly document the the tag name in the rpm changelog + (by using %(tagname)s in the + string). + + + + + + + + + Don't fail tag operations if a tag with the same version already + exists, but, overwrite the existing tag, instead. + + + + + MSG-FORMAT + + + + Format string for the tag message + (when is given). + + + + + + + + + GPG sign all created tags. + + + + + GPG-KEYID + + + + Use this keyid for gpg signing tags. + + + CUSTOMIZATION-FILE diff --git a/gbp/scripts/rpm_ch.py b/gbp/scripts/rpm_ch.py index db1f8221..d7da0fc9 100644 --- a/gbp/scripts/rpm_ch.py +++ b/gbp/scripts/rpm_ch.py @@ -29,11 +29,13 @@ import gbp.log from gbp.config import GbpOptionParserRpm, GbpOptionGroup from gbp.errors import GbpError +from gbp.git.modifier import GitModifier from gbp.rpm import (guess_spec, NoSpecError, SpecFile, split_version_str, compose_version_str) from gbp.rpm.changelog import Changelog, ChangelogParser, ChangelogError from gbp.rpm.git import GitRepositoryError, RpmGitRepository from gbp.rpm.policy import RpmPkgPolicy +from gbp.scripts.buildpackage_rpm import packaging_tag_data from gbp.scripts.common import ExitCodes from gbp.tmpfile import init_tmpdir, del_tmpdir @@ -145,7 +147,7 @@ def check_repo_state(repo, options): gbp.log.err("Unstaged changes in:\n %s" % '\n '.join(unstaged)) raise GbpError("Please commit or stage your changes before using " - "the --commit option") + "the --commit or --tag option") def parse_spec_file(repo, options): @@ -294,11 +296,21 @@ def update_changelog(changelog, entries, repo, spec, options): # Get info for section header now = datetime.now() name, email = get_author(repo, options.git_author) + author = None + committer = None rev_str_fields = dict(spec.version, version=compose_version_str(spec.version), - vendor=options.vendor, - tagname=repo.describe('HEAD', longfmt=True, - always=True)) + vendor=options.vendor) + if options.tag: + # Get fake information for the to-be-created git commit + author = committer = GitModifier(date=now) + tag, msg = packaging_tag_data(repo, 'HEAD', spec.name, spec.version, + options) + else: + tag = repo.describe('HEAD', longfmt=True, always=True) + msg = None + rev_str_fields['tagname'] = tag + try: revision = options.changelog_revision % rev_str_fields except KeyError as err: @@ -318,6 +330,7 @@ def update_changelog(changelog, entries, repo, spec, options): # Add new entries to the topmost section for entry in entries: top_section.append_entry(entry) + return (tag, msg, author, committer) def create_commit_message(spec, options): @@ -387,6 +400,8 @@ def build_parser(name): dest="packaging_branch") naming_grp.add_config_file_option(option_name="packaging-tag", dest="packaging_tag") + naming_grp.add_config_file_option(option_name="packaging-tag-msg", + dest="packaging_tag_msg") naming_grp.add_config_file_option(option_name="packaging-dir", dest="packaging_dir") naming_grp.add_config_file_option(option_name="changelog-file", @@ -416,11 +431,19 @@ def build_parser(name): dest="spawn_editor") format_grp.add_config_file_option(option_name="editor-cmd", dest="editor_cmd") - # Commit group options + # Commit/tag group options commit_grp.add_option("-c", "--commit", action="store_true", help="commit changes") commit_grp.add_config_file_option(option_name="commit-msg", dest="commit_msg") + commit_grp.add_option("--tag", action="store_true", + help="commit the changes and create a" + "packaging/release tag") + commit_grp.add_option("--retag", action="store_true", + help="Overwrite packaging tag if it already exists") + commit_grp.add_boolean_config_file_option(option_name="sign-tags", + dest="sign_tags") + commit_grp.add_config_file_option(option_name="keyid", dest="keyid") return parser @@ -432,6 +455,8 @@ def parse_args(argv): options, args = parser.parse_args(argv[1:]) + if options.tag: + options.commit = True if not options.changelog_revision: options.changelog_revision = RpmPkgPolicy.Changelog.header_rev_format @@ -474,7 +499,9 @@ def main(argv): # Do the actual update entries = entries_from_commits(ch_file.changelog, repo, commits, options) - update_changelog(ch_file.changelog, entries, repo, spec, options) + tag, tag_msg, author, committer = update_changelog(ch_file.changelog, + entries, repo, spec, + options) # Write to file ch_file.write() @@ -484,7 +511,12 @@ def main(argv): if options.commit: edit = True if editor_cmd else False msg = create_commit_message(spec, options) - commit_changelog(repo, ch_file, msg, None, None, edit) + commit_changelog(repo, ch_file, msg, author, committer, edit) + if options.tag: + if options.retag and repo.has_tag(tag): + repo.delete_tag(tag) + repo.create_tag(tag, tag_msg, 'HEAD', options.sign_tags, + options.keyid) except (GbpError, GitRepositoryError, ChangelogError, NoSpecError) as err: if len(err.__str__()): diff --git a/tests/component/rpm/test_rpm_ch.py b/tests/component/rpm/test_rpm_ch.py index 60b542ab..bc57d8be 100644 --- a/tests/component/rpm/test_rpm_ch.py +++ b/tests/component/rpm/test_rpm_ch.py @@ -288,6 +288,48 @@ def test_option_commit_msg(self): eq_(mock_ch(['--commit', '--since=HEAD^', '--commit-msg=%(foo)s']), 1) self._check_log(-1, "gbp:error: Unknown key 'foo' in commit-msg string") + def test_tagging(self): + """Test commiting/tagging""" + repo = self.init_test_repo('gbp-test-native') + + # Update and commit+tag + eq_(mock_ch(['--tag', '--packaging-tag=new-tag', '--since=HEAD^']), 0) + ok_(repo.has_tag('new-tag')) + sha = repo.rev_parse('HEAD') + eq_(sha, repo.rev_parse('new-tag^0')) + + # Should fail if the tag already exists + eq_(mock_ch(['--tag', '--packaging-tag=new-tag', '--since=HEAD^']), 1) + + # Update and commit+tag + eq_(mock_ch(['--tag', '--packaging-tag=new-tag', '--since=HEAD^', + '--retag']), 0) + ok_(repo.has_tag('new-tag')) + sha2 = repo.rev_parse('HEAD') + ok_(sha2 != sha) + eq_(sha2, repo.rev_parse('new-tag^0')) + + def test_tagging2(self): + """Test commiting/tagging spec file""" + repo = self.init_test_repo('gbp-test2') + + # Check unclean repo + with open('untracked-file', 'w') as fobj: + fobj.write('this file is not tracked\n') + with open('README', 'a') as fobj: + fobj.write('some new content\n') + + # Unstaged file (README) -> failure + eq_(mock_ch(['--tag', '--packaging-tag=new-tag', '--since=HEAD^']), 1) + self._check_log(-1, 'gbp:error: Please commit or stage your changes') + + # Add file, update and commit+tag, untracked file should be ignored + repo.add_files('README') + eq_(mock_ch(['--tag', '--packaging-tag=new-tag', '--since=HEAD^']), 0) + ok_(repo.has_tag('new-tag')) + sha = repo.rev_parse('HEAD') + eq_(sha, repo.rev_parse('new-tag^0')) + def test_option_editor_cmd(self): """Test the --editor-cmd and --spawn-editor cmdline options""" repo = self.init_test_repo('gbp-test-native')