From: Benjamin Drung Date: Tue, 28 Jan 2014 21:21:50 +0000 (+0100) Subject: gentoo_build: Add --auto-version feature. X-Git-Url: https://git.uhu-banane.de/?a=commitdiff_plain;h=d01460efa6a18ec755d411acf0fc62efd789bb77;p=profitbricks%2Fjenkins-build-scripts.git gentoo_build: Add --auto-version feature. --- diff --git a/gentoo_build b/gentoo_build index cb8d5eb..ccc0962 100755 --- a/gentoo_build +++ b/gentoo_build @@ -17,6 +17,7 @@ """Do a source release for Gentoo (release a versioned ebuild file)""" +import datetime import glob import logging import optparse @@ -39,12 +40,16 @@ DEFAULT_CHROOT_USER = "root" GITWEB_RE = r'^((file://|git\+ssh://[A-Za-z.:@]+)?/srv/git|git://[A-Za-z.:@]+)' GITWEB_URL = 'http://git' +ENV_AUTODECREMENT = "AUTODECREMENT" +ENV_AUTOINCREMENT = "AUTOINCREMENT" ENV_CATEGORY = "CATEGORY" ENV_CHROOT = "CHROOT_NAME" ENV_CHROOT_USER = "CHROOT_USER" ENV_RELEASE_BRANCH = "RELEASE_BRANCH" ENV_RELEASE_REPO = "RELEASE_REPO" ENV_VARIABLES = [ + ENV_AUTODECREMENT, + ENV_AUTOINCREMENT, ENV_CATEGORY, ENV_CHROOT, ENV_CHROOT_USER, @@ -55,6 +60,19 @@ ENV_VARIABLES = [ CATEGORY_VARIABLE = "PB_CATEGORY" CATEGORY_RE = r'^\s*' + CATEGORY_VARIABLE + r'=\s*"?([^"]*)"?\s*$' +SUBST_HELP = """ +Auto increment/decrement substitition variables: + +{time} Replaced by the date and time (UTC) when the package was built. + You can specify a format like {time:%Y%m%d+%H%M} +{debversion} Replaced with the version in the changelog +{debupstream} Replaced by the upstream portion of the version number taken + from debian/changelog. For example: if the version is 1.0-1, + this would evaluate to 1.0. +{git-commit} Replaced with the last 7 characters of the git commit that was + built +""" + class Ebuild(object): """This class represents an .ebuild file.""" @@ -167,6 +185,55 @@ class Ebuild(object): version=self.version)) +class MyOptionParser(optparse.OptionParser): + """Derive the OptionParser class to override the format_epilog method""" + + def format_epilog(self, formatter): + """Return the epilog including the pre-formatted auto in-/decrement""" + return formatter.format_epilog(self.epilog) + SUBST_HELP + + +def version_substitution(logger, pattern, git_commit=None): + """Return a version string with the pattern substituted. + + Following substitution variables are supported: + {debupstream} Replaced by the upstream portion of the version number + taken from debian/changelog. For example: if the version + is 1.0-1, this would evaluate to 1.0. + {debversion} Replaced with the version in the changelog + {git-commit} Replaced with the last 7 characters of the git commit that + was built + {time} Replaced by the date and time (UTC) when the package was + built. You can specify a format like {time:%Y%m%d+%H%M} + """ + subst = dict() + if git_commit: + subst['git-commit'] = git_commit.hexsha[0:7] + subst['time'] = datetime.datetime.utcnow() + if os.path.isfile('debian/changelog'): + changelog_file = open('debian/changelog') + changelog = debian.changelog.Changelog(changelog_file, max_blocks=1) + subst['debupstream'] = changelog.upstream_version + subst['debversion'] = changelog.full_version + try: + version = pattern.format(**subst) + except KeyError as error: + key = error.args[0] + allowed_keys = ["{debupstream}", "{debversion}", "{git-commit}", + "{time}"] + if key in ('debupstream', 'debversion'): + msg = ("Cannot substitude {{{key}}} in '{pattern}', because " + "debian/changelog is missing. Please add a debian/changelog" + " file or avoid {{{key}}} in the substitution pattern.") + else: + msg = ("Key {{{key}}} from pattern '{pattern}' is not a valid " + "substitution. Please use one of the following allowed " + "substitutions: {allowed_keys}") + logger.error(msg.format(key=key, pattern=pattern, + allowed_keys=", ".join(allowed_keys))) + sys.exit(1) + return version + def debian2gentoo_version(debian_version): """Translate a Debian version into a Gentoo version. @@ -196,7 +263,7 @@ def main(): script_name = os.path.basename(sys.argv[0]) usage = "%s [options] [release repository]" % (script_name) epilog = "Supported environment variables: " + ", ".join(ENV_VARIABLES) - parser = optparse.OptionParser(usage=usage, epilog=epilog) + parser = MyOptionParser(usage=usage, epilog=epilog) env = os.environ used_env = dict((k, v) for (k, v) in env.items() if k in ENV_VARIABLES) @@ -212,6 +279,16 @@ def main(): 'CRITICAL': logging.CRITICAL } + parser.add_option("-a", "--auto-version", dest="auto_version", + action="store_true", + help="create a new version by automatically " + "increment or decrement the current version") + parser.add_option("--autodecrement", dest="autodecrement", + default=env.get(ENV_AUTODECREMENT), + help="pattern for auto-decrementing the version") + parser.add_option("--autoincrement", dest="autoincrement", + default=env.get(ENV_AUTOINCREMENT), + help="pattern for auto-incrementing the version") parser.add_option("-b", "--branch", dest="release_branch", default=env.get(ENV_RELEASE_BRANCH), help="specify a branch for the release repository " @@ -282,8 +359,14 @@ def gentoo_build(script_name, logger, release_repo_uri, options): """Main function that creates a versioned ebuild file and releases it.""" ebuilds = find_ebuilds(logger, options.category) repo = git.Repo() - if options.tag_from_debian: - git_tag = tag_from_debian_changelog(logger, repo) + new_tag = None + if options.auto_version: + new_tag = auto_versioning(logger, repo, options.autodecrement, + options.autoincrement) + git_tag = new_tag + elif options.tag_from_debian: + new_tag = tag_from_debian_changelog(logger, repo) + git_tag = new_tag else: git_tag = get_latest_tag(logger, repo) for ebuild in ebuilds: @@ -317,8 +400,8 @@ def gentoo_build(script_name, logger, release_repo_uri, options): "...".format(branch=branch, repo=release_repo_uri)) release_repo.git.push("origin", branch) - if options.tag_from_debian: - push_tag(logger, repo, git_tag, options.dry_run) + if new_tag: + push_tag(logger, repo, new_tag, options.dry_run) finally: if options.keep: logger.warning("Keeping temporary git clone in {dir} as " @@ -380,6 +463,38 @@ def find_ebuilds(logger, category): ebuild=" ".join(ebuild_files))) return [Ebuild(logger, e, category) for e in ebuild_files] +def auto_versioning(logger, repo, autodecrement, autoincrement): + """Increment or decrement the Debian version.""" + if not os.path.isfile('debian/changelog'): + logger.error("No Debian changelog found. Please add a debian/changelog" + "file or disable the auto-version feature.") + changelog_file = open('debian/changelog') + changelog = debian.changelog.Changelog(changelog_file, max_blocks=1) + if changelog.distributions == "UNRELEASED": + logger.info("The distribution is set to UNRELEASED. Doing an " + "auto-decrement.") + if autodecrement is None: + logger.error("No auto-decrement pattern was specified.\nPlease " + "provide one on the command line or set {env} in " + "the environment.".format(env=ENV_AUTODECREMENT)) + sys.exit(1) + pattern = autodecrement + else: + logger.info("The distribution is set to {distro} and therefore this " + "version was released. Doing an " + "auto-increment.".format(distro=changelog.distributions)) + if autoincrement is None: + logger.error("No auto-increment pattern was specified.\nPlease " + "provide one on the command line or set {env} in " + "the environment.".format(env=ENV_AUTOINCREMENT)) + sys.exit(1) + pattern = autoincrement + new_tag = version_substitution(logger, pattern, repo.head.commit) + logger.info("The pattern '{pattern}' evaluates to the version " + "'{version}'.".format(pattern=pattern, version=new_tag)) + tag_head_commit(logger, repo, new_tag) + return new_tag + def tag_from_debian_changelog(logger, repo): """Create a tag from the version specified in debian/changelog. Returns the name of the created tag. @@ -410,6 +525,7 @@ def tag_head_commit(logger, repo, new_tag, resolve_existing_msg=""): 'to release the ebuild file.') msg = msg.format(commit=format_commit(current_commit), tag=new_tag) else: + # TODO: Fix error message when auto-tagging msg = ('The head commit {commit} is already tagged: {tags}\n' 'The script expects a commit without additional tags.') msg = msg.format(commit=format_commit(current_commit),