diff --git a/docs/manpages/gbp-rpm-ch.xml b/docs/manpages/gbp-rpm-ch.xml
index e0f0d9d7..b7cb47ce 100644
--- a/docs/manpages/gbp-rpm-ch.xml
+++ b/docs/manpages/gbp-rpm-ch.xml
@@ -28,7 +28,12 @@
DIRECTORY
FILEPATH
FILEPATH
- COMMITISH
+
+
+ MESSAGE
+ COMMITISH
+
+ META_TAGS
@@ -38,6 +43,13 @@
GIT-LOG-OPTIONS
EDITOR
+
+ MSG-FORMAT
+
+
+ MSG-FORMAT
+
+ GPG-KEYID
CUSTOMIZATION-FILE
[PATH1 PATH2]
@@ -151,6 +163,16 @@
+
+
+
+
+
+ Use all commits from the Git history, overrides
+ .
+
+
+
COMMITTISH
@@ -161,6 +183,19 @@
+
+ META_TAGS
+
+
+
+ Meta tags in the commit messages that are interpreted as bug tracking
+ system related references. The recognized bts references are added in
+ the generated changelog entries. See the META TAGS section below for
+ more information. The bts meta tag tracking feature can be disabled
+ by defining an empty string.
+
+
+
@@ -263,6 +298,91 @@
+
+
+
+
+
+ Text to use for new changelog entries. Git history and the commit
+ messages, including and
+ options are ignored in this case.
+
+
+
+
+
+
+
+
+ Commit changes to git after modifying changelog. Importantly, in
+ addition to the changelog modifications all other staged changes are
+ committed, too, making it possible to update other files in the same
+ commit.
+
+
+
+
+ MSG-FORMAT
+
+
+
+ Format string for the commit message when committing changes
+ (when is given).
+
+
+
+
+
+
+
+
+ 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
@@ -310,6 +430,8 @@
Indicate in the changelog entry that bug
BUGNUMBER was addressed in this commit.
+ The bts meta tags recognized by &gbp-rpm-ch; is actually defined by
+ the option.
diff --git a/gbp/config.py b/gbp/config.py
index 76a850de..b062248d 100644
--- a/gbp/config.py
+++ b/gbp/config.py
@@ -798,6 +798,7 @@ class GbpOptionParserRpm(GbpOptionParser):
'changelog-revision': '',
'spawn-editor': 'always',
'editor-cmd': 'vim',
+ 'meta-bts': '(Close|Closes|Fixes|Fix)',
'spec-vcs-tag': '',
})
@@ -860,6 +861,8 @@ class GbpOptionParserRpm(GbpOptionParser):
'git-author':
"Use name and email from git-config for the changelog header, "
"default is '%(git-author)s'",
+ 'meta-bts':
+ "Meta tags for the bts commands, default is '%(meta-bts)s'",
'spec-vcs-tag':
"Set/update the 'VCS:' tag in the spec file, empty value "
"removes the tag entirely, default is '%(spec-vcs-tag)s'",
diff --git a/gbp/git/repository.py b/gbp/git/repository.py
index 6cc3cd9f..ae62b5cb 100644
--- a/gbp/git/repository.py
+++ b/gbp/git/repository.py
@@ -171,7 +171,7 @@ def _git_getoutput(self, command, args=[], extra_env=None, cwd=None):
return output, popen.returncode
def _git_inout(self, command, args, input=None, extra_env=None, cwd=None,
- capture_stderr=False, config_args=None):
+ capture_stderr=False, capture_stdout=True, config_args=None):
"""
Run a git command with input and return output
@@ -192,10 +192,12 @@ def _git_inout(self, command, args, input=None, extra_env=None, cwd=None,
"""
if not cwd:
cwd = self.path
- return self.__git_inout(command, args, input, extra_env, cwd, capture_stderr, config_args)
+ return self.__git_inout(command, args, input, extra_env, cwd, capture_stderr,
+ capture_stdout, config_args)
@classmethod
- def __git_inout(cls, command, args, input, extra_env, cwd, capture_stderr, config_args=None):
+ def __git_inout(cls, command, args, input, extra_env, cwd, capture_stderr,
+ capture_stdout, config_args=None):
"""
As _git_inout but can be used without an instance
"""
@@ -206,13 +208,14 @@ def __git_inout(cls, command, args, input, extra_env, cwd, capture_stderr, confi
cmd = ['git'] + config_opts + [command] + args
env = cls.__build_env(extra_env)
+ stdout_arg = subprocess.PIPE if capture_stdout else None
stderr_arg = subprocess.PIPE if capture_stderr else None
stdin_arg = subprocess.PIPE if input is not None else None
log.debug(cmd)
popen = subprocess.Popen(cmd,
stdin=stdin_arg,
- stdout=subprocess.PIPE,
+ stdout=stdout_arg,
stderr=stderr_arg,
env=env,
close_fds=True,
@@ -220,7 +223,7 @@ def __git_inout(cls, command, args, input, extra_env, cwd, capture_stderr, confi
(stdout, stderr) = popen.communicate(input)
return stdout, stderr, popen.returncode
- def _git_command(self, command, args=[], extra_env=None):
+ def _git_command(self, command, args=[], extra_env=None, interactive=False):
"""
Execute git command with arguments args and environment env
at path.
@@ -232,12 +235,14 @@ def _git_command(self, command, args=[], extra_env=None):
@param extra_env: extra environment variables to set when running command
@type extra_env: C{dict}
"""
+ capture_stdout = not interactive
try:
stdout, stderr, ret = self._git_inout(command=command,
args=args,
input=None,
extra_env=extra_env,
- capture_stderr=True)
+ capture_stderr=True,
+ capture_stdout=capture_stdout)
except Exception as excobj:
raise GitRepositoryError("Error running git %s: %s" % (command, excobj))
if ret:
@@ -1450,11 +1455,17 @@ def rename_file(self, old, new):
#{ Comitting
- def _commit(self, msg, args=[], author_info=None):
+ def _commit(self, msg, args=[], author_info=None,
+ committer_info=None, edit=False):
extra_env = author_info.get_author_env() if author_info else None
- self._git_command("commit", ['-q', '-m', msg] + args, extra_env=extra_env)
+ if committer_info:
+ extra_env.update(committer_info.get_committer_env())
+ default_args = ['-q', '-m', msg] + (['--edit'] if edit else [])
+ self._git_command("commit", default_args + args, extra_env=extra_env,
+ interactive=edit)
- def commit_staged(self, msg, author_info=None, edit=False):
+ def commit_staged(self, msg, author_info=None, edit=False,
+ committer_info=None):
"""
Commit currently staged files to the repository
@@ -1464,10 +1475,11 @@ def commit_staged(self, msg, author_info=None, edit=False):
@type author_info: L{GitModifier}
@param edit: whether to spawn an editor to edit the commit info
@type edit: C{bool}
+ @param committer_info: committer information
+ @type committer_info: L{GitModifier}
"""
- args = GitArgs()
- args.add_true(edit, '--edit')
- self._commit(msg=msg, args=args.args, author_info=author_info)
+ self._commit(msg=msg, author_info=author_info,
+ committer_info=committer_info, edit=edit)
def commit_all(self, msg, author_info=None, edit=False):
"""
@@ -1477,11 +1489,9 @@ def commit_all(self, msg, author_info=None, edit=False):
@param author_info: authorship information
@type author_info: L{GitModifier}
"""
- args = GitArgs('-a')
- args.add_true(edit, '--edit')
- self._commit(msg=msg, args=args.args, author_info=author_info)
+ self._commit(msg=msg, args=['-a'], author_info=author_info, edit=edit)
- def commit_files(self, files, msg, author_info=None):
+ def commit_files(self, files, msg, author_info=None, committer_info=None):
"""
Commit the given files to the repository
@@ -1491,10 +1501,13 @@ def commit_files(self, files, msg, author_info=None):
@type msg: C{str}
@param author_info: authorship information
@type author_info: L{GitModifier}
+ @param committer_info: committer information
+ @type committer_info: L{GitModifier}
"""
if isinstance(files, str):
files = [files]
- self._commit(msg=msg, args=files, author_info=author_info)
+ self._commit(msg=msg, args=files, author_info=author_info,
+ committer_info=committer_info)
def commit_dir(self, unpack_dir, msg, branch, other_parents=None,
author={}, committer={}, create_missing_branch=False):
@@ -2007,7 +2020,8 @@ def create(cls, path, description=None, bare=False):
input=None,
extra_env=None,
cwd=abspath,
- capture_stderr=True)
+ capture_stderr=True,
+ capture_stdout=True)
except Exception as excobj:
raise GitRepositoryError("Error running git init: %s" % excobj)
if ret:
@@ -2073,7 +2087,8 @@ def clone(cls, path, remote, depth=0, recursive=False, mirror=False,
input=None,
extra_env=None,
cwd=abspath,
- capture_stderr=True)
+ capture_stderr=True,
+ capture_stdout=True)
except Exception as excobj:
raise GitRepositoryError("Error running git clone: %s" % excobj)
if ret:
diff --git a/gbp/rpm/policy.py b/gbp/rpm/policy.py
index a027ed99..791b25b1 100644
--- a/gbp/rpm/policy.py
+++ b/gbp/rpm/policy.py
@@ -94,8 +94,6 @@ class ChangelogEntryFormatter(object):
# Maximum length for a changelog entry line
max_entry_line_length = 76
- # Bug tracking system related meta tags recognized from git commit msg
- bts_meta_tags = ("Close", "Closes", "Fixes", "Fix")
# Regexp for matching bug tracking system ids (e.g. "bgo#123")
bug_id_re = r'[A-Za-z0-9#_\-]+'
@@ -107,15 +105,18 @@ def _parse_bts_tags(cls, lines, meta_tags):
@param lines: commit message
@type lines: C{list} of C{str}
- @param meta_tags: meta tags to look for
- @type meta_tags: C{tuple} of C{str}
+ @param meta_tags: meta tags (regexp) to look for
+ @type meta_tags: C{str}
@return: bts-ids per meta tag and the non-mathced lines
@rtype: (C{dict}, C{list} of C{str})
"""
+ if not meta_tags:
+ return ({}, lines[:])
+
tags = {}
other_lines = []
- bts_re = re.compile(r'^(?P%s):\s*(?P.*)' %
- ('|'.join(meta_tags)), re.I)
+ bts_re = re.compile(r'^(?P%s):\s*(?P.*)' % meta_tags,
+ re.I)
bug_id_re = re.compile(cls.bug_id_re)
for line in lines:
match = bts_re.match(line)
@@ -172,7 +173,7 @@ def compose(cls, commit_info, **kwargs):
return None
# Parse and filter out bts-related meta-tags
- bts_tags, body = cls._parse_bts_tags(body, cls.bts_meta_tags)
+ bts_tags, body = cls._parse_bts_tags(body, kwargs['meta_bts'])
# Additional filtering
body = cls._extra_filter(body, kwargs['ignore_re'])
@@ -191,7 +192,7 @@ def compose(cls, commit_info, **kwargs):
text.extend([" " + line for line in body if line.strip()])
# Add bts tags and ids in the end
- for tag, ids in bts_tags.items():
+ for tag, ids in sorted(bts_tags.items()):
bts_msg = " (%s: %s)" % (tag, ', '.join(ids))
if len(text[-1]) + len(bts_msg) >= cls.max_entry_line_length:
text.append(" ")
diff --git a/gbp/scripts/rpm_ch.py b/gbp/scripts/rpm_ch.py
index 9212f717..a60ba96f 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
@@ -122,8 +124,9 @@ def determine_editor(options):
return 'vi'
-def check_branch(repo, options):
- """Check the current git branch"""
+def check_repo_state(repo, options):
+ """Check that the repository is in good state"""
+ # Check branch
try:
branch = repo.get_branch()
except GitRepositoryError:
@@ -133,6 +136,18 @@ def check_branch(repo, options):
(options.packaging_branch, branch))
raise GbpError("Use --ignore-branch to ignore or "
"--packaging-branch to set the branch name.")
+ # Check unstaged changes
+ if options.commit:
+ unstaged = []
+ status = repo.status()
+ for group, files in status.items():
+ if group != '??' and group[1] != ' ':
+ unstaged.extend([f.decode() for f in files])
+ if unstaged:
+ gbp.log.err("Unstaged changes in:\n %s" %
+ '\n '.join(unstaged))
+ raise GbpError("Please commit or stage your changes before using "
+ "the --commit or --tag option")
def parse_spec_file(repo, options):
@@ -223,7 +238,9 @@ def guess_commit(section, repo, options):
def get_start_commit(changelog, repo, options):
"""Get the start commit from which to generate new entries"""
- if options.since:
+ if options.all:
+ since = None
+ elif options.since:
since = options.since
else:
if changelog.sections:
@@ -232,7 +249,7 @@ def get_start_commit(changelog, repo, options):
since = None
if not since:
raise GbpError("Couldn't determine starting point from "
- "changelog, please use the '--since' option")
+ "changelog, please use the '--since' or '--all'")
gbp.log.info("Continuing from commit '%s'" % since)
return since
@@ -269,23 +286,65 @@ def entries_from_commits(changelog, repo, commits, options):
info = repo.get_commit_info(commit)
entry_text = ChangelogEntryFormatter.compose(info, full=options.full,
ignore_re=options.ignore_regex,
- id_len=options.idlen)
+ id_len=options.idlen,
+ meta_bts=options.meta_bts)
if entry_text:
entries.append(changelog.create_entry(author=info['author'].name,
text=entry_text))
return entries
+def entries_from_text(changelog, text, author):
+ """Generate a list of changelog entries from a string"""
+ entries = []
+ # Use current user as the author for all entries
+ for line in text.splitlines():
+ if line.strip():
+ entry_text = "- %s" % line.strip()
+ entries.append(changelog.create_entry(author=author,
+ text=entry_text))
+ return entries
+
+
+def generate_new_entries(changelog, repo, options, args):
+ """Generate new entries to be appended to changelog"""
+ if options.message:
+ author = get_author(repo, options.git_author)[0]
+ entries = entries_from_text(changelog, options.message, author)
+ else:
+ # Get range of commits from where to generate changes
+ since = get_start_commit(changelog, repo, options)
+ if args:
+ gbp.log.info("Only looking for changes in '%s'" % ", ".join(args))
+ commits = repo.get_commits(since=since, until='HEAD', paths=args,
+ options=options.git_log.split(" "))
+ commits.reverse()
+ if not commits:
+ gbp.log.info("No changes detected from %s to %s." % (since, 'HEAD'))
+ entries = entries_from_commits(changelog, repo, commits, options)
+ return entries
+
+
def update_changelog(changelog, entries, repo, spec, options):
"""Update the changelog with a range of commits"""
# 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:
@@ -305,6 +364,27 @@ 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"""
+ fields = spec.version
+ fields['version'] = compose_version_str(spec.version)
+ fields['vendor'] = options.vendor
+ fields['pkg'] = spec.name
+ try:
+ return options.commit_msg % fields
+ except KeyError as err:
+ raise GbpError("Unknown key %s in commit-msg string, "
+ "only %s are accepted" % (err, fields.keys()))
+
+
+def commit_changelog(repo, changelog, message, author, committer, edit):
+ """Commit changelog to Git"""
+ repo.add_files(changelog.path)
+ repo.commit_staged(message, author_info=author, committer_info=committer,
+ edit=edit)
def build_parser(name):
@@ -322,9 +402,12 @@ def build_parser(name):
"how to format the changelog entries")
naming_grp = GbpOptionGroup(parser, "naming",
"branch names, tag formats, directory and file naming")
+ commit_grp = GbpOptionGroup(parser, "commit",
+ "automatic committing and tagging")
parser.add_option_group(range_grp)
parser.add_option_group(format_grp)
parser.add_option_group(naming_grp)
+ parser.add_option_group(commit_grp)
# Non-grouped options
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
@@ -351,6 +434,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",
@@ -359,7 +444,11 @@ def build_parser(name):
# Range group options
range_grp.add_option("-s", "--since", dest="since",
help="commit to start from (e.g. HEAD^^^, release/0.1.2)")
+ range_grp.add_option("--all", action="store_true",
+ help="use all commits from the Git history, overrides "
+ "--since")
# Formatting group options
+ format_grp.add_config_file_option(option_name="meta-bts", dest="meta_bts")
format_grp.add_option("--no-release", action="store_false", default=True,
dest="release",
help="no release, just update the last changelog section")
@@ -380,6 +469,22 @@ def build_parser(name):
dest="spawn_editor")
format_grp.add_config_file_option(option_name="editor-cmd",
dest="editor_cmd")
+ format_grp.add_option("-m", '--message',
+ help="text to use as new changelog entries - git commit "
+ "messages and the --since are ignored in this case")
+ # 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
@@ -391,6 +496,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
@@ -412,35 +519,37 @@ def main(argv):
editor_cmd = determine_editor(options)
repo = RpmGitRepository('.')
- check_branch(repo, options)
+ check_repo_state(repo, options)
# Find and parse spec file
spec = parse_spec_file(repo, options)
# Find and parse changelog file
ch_file = parse_changelog_file(repo, spec, options)
- since = get_start_commit(ch_file.changelog, repo, options)
- # Get range of commits from where to generate changes
- if args:
- gbp.log.info("Only looking for changes in '%s'" % ", ".join(args))
- commits = repo.get_commits(since=since, until='HEAD', paths=args,
- options=options.git_log.split(" "))
- commits.reverse()
- if not commits:
- gbp.log.info("No changes detected from %s to %s." % (since, 'HEAD'))
+ # Get new entries
+ entries = generate_new_entries(ch_file.changelog, repo, options, args)
# 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()
- if editor_cmd:
+ if editor_cmd and not options.message:
gbpc.Command(editor_cmd, [ch_file.path])()
+ if options.commit:
+ edit = True if editor_cmd else False
+ msg = create_commit_message(spec, options)
+ 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__()):
gbp.log.err(err)
diff --git a/tests/component/rpm/test_rpm_ch.py b/tests/component/rpm/test_rpm_ch.py
index 97f5d7e6..197f6db9 100644
--- a/tests/component/rpm/test_rpm_ch.py
+++ b/tests/component/rpm/test_rpm_ch.py
@@ -109,6 +109,16 @@ def test_create_changes_file(self):
# Should contain 3 lines (header, 1 entry and an empty line)
eq_(len(content), 3)
+ def test_option_all(self):
+ """Test the --all cmdline option"""
+ repo = self.init_test_repo('gbp-test2')
+
+ eq_(mock_ch(['--changelog-file=CHANGES', '--all']), 0)
+ content = self.read_file('packaging/gbp-test2.changes')
+ # Should contain N+2 lines (header, N commits and an empty line)
+ commit_cnt = len(repo.get_commits(since=None, until='master'))
+ eq_(len(content), commit_cnt + 2)
+
def test_option_changelog_file(self):
"""Test the --changelog-file cmdline option"""
repo = self.init_test_repo('gbp-test-native')
@@ -163,6 +173,26 @@ def test_branch_options(self):
eq_(mock_ch(['--packaging-branch=foo', '--ignore-branch']), 0)
+ def test_option_meta_bts(self):
+ """Test parsing of the bts meta tags"""
+ repo = self.init_test_repo('gbp-test-native')
+
+ # Create a dummy commit that references bts
+ with open('new-file', 'w') as fobj:
+ fobj.write('foobar\n')
+ repo.add_files('new-file')
+ repo.commit_all('Fix\n\nCloses: #123\nFixes: #456\n Fixes: #789')
+
+ eq_(mock_ch(['--since=HEAD^']), 0)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # rpm-ch shouldn't have picked the ref with leading whitespace
+ eq_(content[1], '- Fix (Closes: #123) (Fixes: #456)\n')
+
+ # Check the --meta-bts option
+ eq_(mock_ch(['--since=HEAD^', '--meta-bts=Fixes']), 0)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ eq_(content[1], '- Fix (Fixes: #456)\n')
+
def test_option_no_release(self):
"""Test the --no-release cmdline option"""
self.init_test_repo('gbp-test-native')
@@ -255,6 +285,81 @@ def test_option_changelog_revision(self):
header = self.read_file('packaging/gbp-test-native.changes')[0]
ok_(re.match(r'.+ foobar$', header))
+ def test_option_commit(self):
+ """Test the --commit cmdline option"""
+ repo = self.init_test_repo('gbp-test')
+
+ # Check unclean repo
+ with open('untracked-file', 'w') as fobj:
+ fobj.write('this file is not tracked\n')
+ with open('foo.txt', 'a') as fobj:
+ fobj.write('new stuff\n')
+
+ # Unstaged file (foo.txt) -> failure
+ eq_(mock_ch(['--commit', '--since=HEAD^']), 1)
+ self._check_log(-1, 'gbp:error: Please commit or stage your changes')
+
+ # Add file, update and commit, untracked file should be ignored
+ repo.add_files('foo.txt')
+ sha = repo.rev_parse('HEAD')
+ eq_(mock_ch(['--commit', '--since=HEAD^']), 0)
+ eq_(sha, repo.rev_parse('HEAD^'))
+ eq_(repo.get_commit_info('HEAD')['files'],
+ {'M': [b'foo.txt', b'gbp-test.spec']})
+
+ def test_option_commit_msg(self):
+ """Test the --commit-msg cmdline option"""
+ repo = self.init_test_repo('gbp-test2')
+
+ eq_(mock_ch(['--commit', '--since=HEAD^', '--commit-msg=Foo']), 0)
+ eq_(repo.get_commit_info('HEAD')['subject'], 'Foo')
+
+ # Unknown key in format string causes failure
+ 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')
@@ -268,6 +373,17 @@ def test_option_editor_cmd(self):
eq_(mock_ch(['--spawn-editor=always', '--editor-cmd=']),
0)
+ def test_option_message(self):
+ """Test the --message cmdline option"""
+ self.init_test_repo('gbp-test-native')
+ orig_content = self.read_file('packaging/gbp-test-native.changes')
+
+ eq_(mock_ch(['--message', 'my entry\nanother entry']), 0)
+ content = self.read_file('packaging/gbp-test-native.changes')
+ # Added header, two entries and a blank line
+ eq_(len(content), len(orig_content) + 4)
+ eq_(content[2], '- another entry\n')
+
def test_user_customizations(self):
"""Test the user customizations"""
repo = self.init_test_repo('gbp-test-native')