rpm-ch: implement tagging options
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Thu, 6 Feb 2014 09:35:42 +0000 (11:35 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 3 Mar 2015 08:07:47 +0000 (10:07 +0200)
Implement '--tag' command line option (and other related options for
e.g. signing) for creating and tagging a release. These correspond the
tagging options in git-buildpackage-rpm.

The git-buildpackage-rpm tool does not commit anything to git. However,
in rpm-ch the '--tag' option automatically enables --commit which causes
the changelog modifications (and, all other staged changes) to be
committed to git before creating the tag. This makes it possible to
create a release and document the packaging/release tag name in the rpm
changelog.

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gbp/scripts/buildpackage_rpm.py
gbp/scripts/rpm_ch.py
tests/component/rpm/test_rpm_ch.py

index 63db6eb785f2191583ca08002889bd754db5d92c..9bbec9f1185bc6616af18efd20f41b12a8ea46c3 100755 (executable)
@@ -327,10 +327,9 @@ def packaging_tag_time_fields(repo, commit, tag_format_str, other_fields):
     return fields
 
 
-def create_packaging_tag(repo, commit, spec, options):
-    """Create a packaging/release Git tag"""
-    version_dict = dict(spec.version,
-                        version=rpm.compose_version_str(spec.version))
+def packaging_tag_data(repo, commit, name, version, options):
+    """Compose packaging tag name and msg"""
+    version_dict = dict(version, version=rpm.compose_version_str(version))
 
     # Compose tag name and message
     tag_name_fields = dict(version_dict, vendor=options.vendor.lower())
@@ -340,10 +339,16 @@ def create_packaging_tag(repo, commit, spec, options):
     tag_name = repo.version_to_tag(options.packaging_tag, tag_name_fields)
 
     tag_msg = format_str(options.packaging_tag_msg,
-                         dict(version_dict, pkg=spec.name,
+                         dict(version_dict, pkg=name,
                               vendor=options.vendor))
+    return (tag_name, tag_msg)
+
+
+def create_packaging_tag(repo, commit, spec, options):
+    """Create a packaging/release Git tag"""
+    tag_name, tag_msg = packaging_tag_data(repo, commit, spec.name,
+                                           spec.version, options)
 
-    # (Re-)create Git tag
     if options.retag and repo.has_tag(tag_name):
         repo.delete_tag(tag_name)
     repo.create_tag(name=tag_name, msg=tag_msg, sign=options.sign_tags,
index 3ceb81ee3059b30ce418263899751b69c73d1cee..7a6c2bbe403f5668372b122850f5fe05d1754cdd 100755 (executable)
@@ -30,11 +30,14 @@ import gbp.command_wrappers as gbpc
 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,
+                                          create_packaging_tag)
 from gbp.tmpfile import init_tmpdir, del_tmpdir
 
 
@@ -143,7 +146,7 @@ def check_repo_state(repo, options):
             gbp.log.error("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):
@@ -291,11 +294,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:
@@ -315,6 +328,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):
     """Generate commit message"""
@@ -381,6 +395,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",
@@ -410,11 +426,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
 
 def parse_args(argv):
@@ -425,6 +449,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
 
@@ -466,7 +492,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()
 
@@ -476,7 +504,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__()):
index 59ce39bcd821a3165f1f235da6bdc46d52a30bc2..177851c54691b78a91c6433871b4ee85e5edb8d2 100644 (file)
@@ -288,6 +288,48 @@ class TestRpmCh(RpmRepoTestBase):
         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')