rpm: support squashing commits in patch generation
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Wed, 25 Feb 2015 14:06:18 +0000 (16:06 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 3 Mar 2015 08:07:46 +0000 (10:07 +0200)
Implements an option for git-buildpackage-rpm and gbp-pq to squash
commits (from upstream) up to certain tree-ish into one monolithic diff.
Useful e.g. if you wan't to auto-generate a stable update patch.

The new format of the cmdline option filename is commit-ish followed by
(optionally) a colon and the desired diff filename base. Suffix '.diff'
is added by GBP.

Magic word 'HEAD' translates to the end-commit when given as the
squash-point.  This allows one to configure gbp to always squash all
commits into one monolithic diff.

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gbp-rpm.conf
gbp/config.py
gbp/scripts/buildpackage_rpm.py
gbp/scripts/pq_rpm.py

index 622ab02fd38b1a4f8fdcd4d1781eb8a43b119331..6a4c3dc4d9d8e610e4b7a90c8d6a7955fb75c06d 100644 (file)
@@ -26,6 +26,8 @@
 #spec-file = gbp.spec
 # Compress auto-generated patches
 #patch-compress=100k
+# Squash commits until certain tree-ish into one diff
+#patch-squash = stable-updates:stable
 # Export patches with numbering in filenames
 #patch-numbers = False
 
 ###
 [gbp-pq-rpm]
 # Name of the patch-queue / development branch
-pq-branch = %(branch)s-devel
+#pq-branch = %(branch)s-devel
 
 ###
 ### Options only affecting gbp-clone
index 24444d500d8bd5f61a1da6284664a0527f3b292a..f9a1aac0b031d924db7bf83a0a7486ddecc9fd8d 100644 (file)
@@ -621,6 +621,7 @@ class GbpOptionParserRpm(GbpOptionParser):
             'spec-vcs-tag'              : '',
             'patch-export'              : 'False',
             'patch-compress'            : '0',
+            'patch-squash'              : '',
             'patch-import'              : 'True',
             'import-files'              : ['.gbp.conf',
                                            'debian/gbp.conf'],
@@ -671,6 +672,10 @@ class GbpOptionParserRpm(GbpOptionParser):
                 "Compress (auto-generated) patches larger than given number of "
                 "bytes, 0 never compresses, default is "
                 "'%(patch-compress)s'",
+            'patch-squash':
+                "Squash commits (from upstream) until given tree-ish into one "
+                "big diff, format is '<commit_ish>[:<filename_base>]'. "
+                "Default is '%(patch-squash)s'",
             'patch-import':
                 "Import patches to the packaging branch, default is "
                 "'%(patch-import)s'",
index a259f9a077a829b65498cfdfb8c672a246601d99..30d365bd7794ebace5b53a9e6a55bdd0bd6ba4f6 100755 (executable)
@@ -477,6 +477,7 @@ def build_parser(name, prefix=None, git_treeish=None):
     export_group.add_boolean_config_file_option(option_name="patch-numbers",
                     dest="patch_numbers")
     export_group.add_config_file_option("patch-compress", dest="patch_compress")
+    export_group.add_config_file_option("patch-squash", dest="patch_squash")
     return parser
 
 
index 77df2ca32faed1003dfdd2da65fbd18e344e3690..74f23c2d68212acadf47cc0334e6f285bdd62e47 100755 (executable)
@@ -32,7 +32,7 @@ import gbp.log
 from gbp.tmpfile import init_tmpdir, del_tmpdir, tempfile
 from gbp.config import GbpOptionParserRpm, optparse_split_cb
 from gbp.rpm.git import GitRepositoryError, RpmGitRepository
-from gbp.git.modifier import GitModifier
+from gbp.git.modifier import GitModifier, GitTz
 from gbp.command_wrappers import GitCommand, CommandExecFailed
 from gbp.errors import GbpError
 from gbp.patch_series import PatchSeries, Patch
@@ -73,7 +73,7 @@ def compress_patches(patches, compress_size=0):
     return ret_patches
 
 
-def generate_patches(repo, start, end, outdir, options):
+def generate_patches(repo, start, squash, end, outdir, options):
     """
     Generate patch files from git
     """
@@ -98,6 +98,26 @@ def generate_patches(repo, start, end, outdir, options):
     if not is_ancestor(repo, start_sha1, end_commit_sha1):
         raise GbpError("Start commit '%s' not an ancestor of end commit "
                        "'%s'" % (start, end_commit))
+    # Squash commits, if requested
+    if squash[0]:
+        if squash[0] == 'HEAD':
+            squash[0] = end_commit
+        squash_sha1 = repo.rev_parse("%s^0" % squash[0])
+        if start_sha1 != squash_sha1:
+            if not squash_sha1 in repo.get_commits(start, end_commit):
+                raise GbpError("Given squash point '%s' not in the history "
+                               "of end commit '%s'" % (squash[0], end_commit))
+            # Shorten SHA1s
+            squash_sha1 = repo.rev_parse(squash_sha1, short=7)
+            start_sha1 = repo.rev_parse(start_sha1, short=7)
+            gbp.log.info("Squashing commits %s..%s into one monolithic diff" %
+                         (start_sha1, squash_sha1))
+            patch_fn = format_diff(outdir, squash[1], repo,
+                                   start_sha1, squash_sha1)
+            if patch_fn:
+                patches.append(patch_fn)
+                start = squash_sha1
+
     # Check for merge commits, squash if merges found
     merges = repo.get_commits(start, end_commit, options=['--merges'])
     if merges:
@@ -168,10 +188,16 @@ def update_patch_series(repo, spec, start, end, options):
     """
     Export patches to packaging directory and update spec file accordingly.
     """
+    squash = options.patch_squash.split(':', 1)
+    if len(squash) == 1:
+        squash.append(None)
+    else:
+        squash[1] += '.diff'
+
     # Unlink old patch files and generate new patches
     rm_patch_files(spec)
 
-    patches, commands = generate_patches(repo, start, end,
+    patches, commands = generate_patches(repo, start, squash, end,
                                          spec.specdir, options)
     spec.update_patches(patches, commands)
     spec.write_spec_file()
@@ -497,6 +523,7 @@ switch         Switch to patch-queue branch and vice versa.""")
             callback=optparse_split_cb)
     parser.add_config_file_option("patch-compress",
                                   dest="patch_compress")
+    parser.add_config_file_option("patch-squash", dest="patch_squash")
 
     return parser