changelog: utilize rpm-ch from git-buildpackage
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Thu, 27 Mar 2014 09:20:43 +0000 (11:20 +0200)
committerQiang Z Zhang <qiang.z.zhang@intel.com>
Mon, 21 Apr 2014 09:04:42 +0000 (12:04 +0300)
Start to use the gbp changelog tool as backend as it is more
feature-rich. For example, it automatically parses bug-tracking-system
meta-tags from the commit messages (i.e. "Closes: XYZ" etc) and has a
lot more intelligent start-commit guessing.

Later on, additional features from gbp can be enabled in gbs, too.

Creating a new changelog from scratch now requires giving the --since
option. Previously gbs would take the whole git history to the changelog
which is problematic - e.g. creating a new changelog for linux kernel
would take every commit from the linux git history which is *very* long.

Also, the order of entries (i.e. commits) in the new changelog section
is now reversed: the oldest commit will be first (topmost) in the list
and the newest commit will be at the bottom of the list. This should
make the changelog a better chronological read.

Change-Id: Ib4f02f9be95f869b2161d16f8b68f828c5c1deda
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gitbuildsys/cmd_changelog.py
gitbuildsys/utils.py
tests/test_changelog.py

index a1f17fd8b0776d4d0c04bf353bc3a650b5c26623..7cb588bb6bab66d2797e6340da79f3aff7018141 100644 (file)
 """Implementation of subcmd: changelog
 """
 
-import os
-import datetime
 import glob
 
-from gitbuildsys.utils import guess_spec, edit_file
+from gitbuildsys.utils import guess_spec, get_editor_cmd
 from gitbuildsys.cmd_export import get_packaging_dir
 from gitbuildsys.errors import GbsError
 from gitbuildsys.log import LOGGER as log
 
 from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+from gbp.scripts.rpm_changelog import main as gbp_rpm_ch
 
 
 
-def get_all_entries(changesfile, new_entries):
-    """return all entries including old in changesfile and new_entries"""
-    lines = ["%s%s" % (line, os.linesep) for line in new_entries]
-    lines.append(os.linesep)
-
-    if os.path.exists(changesfile):
-        with open(changesfile) as chlog:
-            lines.extend(chlog.readlines())
-    return ''.join(lines)
-
-
-def get_latest_rev(changesfile):
-    """Get latest git revision from the changelog."""
-    if os.path.exists(changesfile):
-        with open(changesfile) as chlog:
-            line = chlog.readline()
-            return line.strip().split(" ")[-1].split("@")[-1]
-    return ''
-
-def get_version(git_repo, commit):
-    """
-    Construct version from commit using rev-parse.
-    Set version to <tag>@<sha1> or <sha1> if tag is not found.
-    """
-    version = git_repo.rev_parse(commit, short=7)
-    try:
-        version = "%s@%s" % (git_repo.find_tag(commit), version)
-    except GitRepositoryError:
-        pass
-
-    return version
-
-def make_log_entries(commits, git_repo):
-    """Make changelog entries from the set of git commits."""
-    entries = []
-    # Add header
-    author = git_repo.get_author_info()
-    entries.append("* %s %s <%s> %s" % \
-                   (datetime.datetime.now().strftime("%a %b %d %Y"),
-                    author.name, author.email, get_version(git_repo,
-                                                           commits[0])))
-    for commit in commits:
-        commit_info = git_repo.get_commit_info(commit)
-        entries.append("- %s" % commit_info["subject"])
-    return entries
-
-def get_first_commit(repo, changes, since):
-    """
-    Get first commit considering since parameter and latest
-    git revision mentioned in .changes file.
-    """
-    if since:
-        first = since
-    else:
-        first = get_latest_rev(changes)
-
-    if first:
-        try:
-            return repo.rev_parse(first)
-        except GitRepositoryError:
-            if since:
-                raise GbsError("Invalid commit: %s" % (first))
-            else:
-                raise GbsError("Can't find last commit ID in the log, "\
-                               "please specify it by '--since'")
-
-
 def main(args):
     """gbs changelog entry point."""
 
@@ -108,43 +40,36 @@ def main(args):
         raise GbsError(str(err))
 
     packaging_dir = get_packaging_dir(args)
+    specfile = guess_spec(repo.path, packaging_dir, args.spec)[0]
     changes_file_list = glob.glob("%s/%s/*.changes" % (repo.path,
                                                        packaging_dir))
-
-    if args.spec or not changes_file_list:
-        # Create .changes file with the same name as a spec
-        specfile = os.path.basename(guess_spec(repo.path,
-                                               packaging_dir, args.spec)[0])
-        fn_changes = os.path.splitext(specfile)[0] + ".changes"
-        fn_changes = os.path.join(repo.path, packaging_dir, fn_changes)
-    else:
+    if changes_file_list:
         fn_changes = changes_file_list[0]
         if len(changes_file_list) > 1:
             log.warning("Found more than one changes files, %s is taken "
                            % (changes_file_list[0]))
-
-    # get the commit start from the args.since
-    commitid_since = get_first_commit(repo, fn_changes, args.since)
-
-    commits = repo.get_commits(commitid_since, 'HEAD')
-    if not commits:
-        raise GbsError("Nothing found between %s and HEAD" % commitid_since)
-
-    if args.message:
-        author = repo.get_author_info()
-        lines = ["- %s" % line for line in args.message.split(os.linesep) \
-                               if line.strip()]
-        new_entries = ["* %s %s <%s> %s" % \
-                       (datetime.datetime.now().strftime("%a %b %d %Y"),
-                        author.name, author.email,
-                        get_version(repo, commits[0]))]
-        new_entries.extend(lines)
     else:
-        new_entries = make_log_entries(commits, repo)
+        fn_changes = 'CHANGES'
+
+    gbp_args = ['dummy argv[0]',
+                '--color-scheme=magenta:green:yellow:red',
+                '--ignore-branch',
+                '--changelog-revision=%(tagname)s',
+                '--spawn-editor=always',
+                '--git-author',
+                '--packaging-dir=%s' % packaging_dir,
+                '--spec-file=%s' % specfile,
+                '--changelog-file=%s' % fn_changes,
+                '--editor-cmd=%s' % get_editor_cmd(),
+                ]
+    if args.since:
+        gbp_args.append('--since=%s' % args.since)
+    if args.message:
+        gbp_args.append('--message=%s' % args.message)
 
-    content = get_all_entries(fn_changes, new_entries)
-    if edit_file(fn_changes, content):
-        log.info("Change log has been updated.")
+    ret = gbp_rpm_ch(gbp_args)
+    if ret:
+        raise GbsError("Change log has not been updated")
     else:
-        log.info("Change log has not been updated")
+        log.info("Change log has been updated.")
 
index e19c9516bfcfdb805f8237eb0045d940bb5c5ac3..3814038af724818a1bb50ac285fe1ef2c5096396 100644 (file)
@@ -642,13 +642,18 @@ def glob_in_rev(git_path, pattern, commit_id):
     return fnmatch.filter(output.splitlines(), pattern)
 
 
+def get_editor_cmd():
+    """Determine the preferred text editor command"""
+    from gitbuildsys.conf import configmgr
+    return configmgr.get('editor') or os.getenv('EDITOR') or 'vi'
+
+
 def edit(initial_content=None):
     """
     Launch an editor to get input from user.
     Returns: content of user input.
     """
-    from gitbuildsys.conf import configmgr
-    editor = configmgr.get('editor') or os.getenv('EDITOR') or 'vi'
+    editor = get_editor_cmd()
 
     temp = TempCopy(initial_content)
     subprocess.call('%s %s' % (editor, temp.name), shell=True)
index a71855174378d65ec2cb7a04cd367cf0627097db..51922bb6cbaef832e555a28b2fc6c02930e04118 100644 (file)
@@ -26,7 +26,7 @@ import imp
 import datetime
 import time
 
-from nose.tools import eq_, raises
+from nose.tools import eq_, ok_, assert_raises, raises
 
 from gbp.git.repository import GitRepository
 
@@ -35,6 +35,16 @@ from gitbuildsys.errors import GbsError
 GBS = imp.load_source("gbs", "./tools/gbs").main
 ENV = {}
 
+TEST_SPEC_CONTENT="""
+Name:           test
+Version:        1.0
+Release:        0
+License:        GPL-2.0
+Summary:        Test spec file
+%description
+Test spec file for changelog testing
+"""
+
 def set_editor(editor):
     '''set editor'''
     os.environ['EDITOR'] = editor
@@ -89,15 +99,20 @@ class TestChangelog(unittest.TestCase):
         # [Re]create packaging/test.spec
         shutil.rmtree('packaging', ignore_errors=True)
         os.mkdir('packaging')
-        open("packaging/test.spec", "w").close()
+        with open("packaging/test.spec", "w") as spec_fp:
+            spec_fp.write(TEST_SPEC_CONTENT)
 
-        set_editor("sleep 1 && touch")
+        set_editor("touch")
 
     def test_new_changes(self):
         """Test generating new .changes."""
-        eq_(GBS(argv=["gbs", "changelog"]), None)
+        with assert_raises(GbsError):
+            eq_(GBS(argv=["gbs", "changelog"]), None)
+        ok_(not os.path.exists(self.changes))
+
+        eq_(GBS(argv=["gbs", "changelog", "--since=HEAD~2"]), None)
         eq_(open(self.changes).read(),
-            "* %s %s <%s> %s\n- change 3\n- change 2\n- change 1\n\n" % \
+            "* %s %s <%s> %s\n- change 2\n- change 3\n\n" % \
             (ENV["date"], ENV["name"], ENV["email"], ENV["commits"][0][:7]))
 
     def test_new_changes_with_content(self):
@@ -116,7 +131,7 @@ class TestChangelog(unittest.TestCase):
             changes.write(init)
 
         eq_(GBS(argv=["gbs", "changelog"]), None)
-        expected = "* %s %s <%s> %s\n- change 3\n- change 2\n\n" % \
+        expected = "* %s %s <%s> %s\n- change 2\n- change 3\n\n" % \
                    (ENV["date"], ENV["name"], ENV["email"],
                     ENV["commits"][0][:7])
         eq_(open(self.changes).read(), expected+init)
@@ -132,7 +147,7 @@ class TestChangelog(unittest.TestCase):
     def test_not_updated():
         """Test normal exit when changelog is not updated."""
         set_editor("true")
-        eq_(GBS(argv=["gbs ", "changelog"]), None)
+        eq_(GBS(argv=["gbs ", "changelog", "-m", "new entry"]), None)
 
     @staticmethod
     @raises(GbsError)