]> Frank Brehm's Git Trees - profitbricks/jenkins-build-scripts.git/commitdiff
gentoo_build: Add --auto-version feature.
authorBenjamin Drung <benjamin.drung@profitbricks.com>
Tue, 28 Jan 2014 21:21:50 +0000 (22:21 +0100)
committerBenjamin Drung <benjamin.drung@profitbricks.com>
Tue, 28 Jan 2014 21:21:50 +0000 (22:21 +0100)
gentoo_build

index cb8d5ebd79ed5bc6cc83386b44ab789f90824378..ccc096261af062bd916465b0e7648eaffcd6d1cc 100755 (executable)
@@ -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),