{"action":"created","comment":{"url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/comments/36948581","id":36948581,"diff_hunk":"@@ -0,0 +1,263 @@\n+\"\"\"\n+Copyright (c) 2015 Red Hat, Inc\n+All rights reserved.\n+\n+This software may be modified and distributed under the terms\n+of the BSD license. See the LICENSE file for details.\n+\"\"\"\n+\n+from __future__ import unicode_literals\n+\n+import shlex\n+try:\n+    # py3\n+    from shlex import quote\n+except ImportError:\n+    from pipes import quote\n+\n+import os\n+from pygit2 import init_repository, Signature\n+import subprocess\n+\n+from atomic_reactor.plugin import PreBuildPlugin\n+from atomic_reactor.source import GitSource\n+from atomic_reactor.plugins.pre_check_and_set_rebuild import is_rebuild\n+from atomic_reactor.constants import PY2\n+from dockerfile_parse import DockerfileParser\n+\n+\n+def shlex_splits(value):\n+    if PY2 and isinstance(value, unicode):\n+        value = value.encode('utf-8')\n+        splits = shlex.split(value)\n+        return [split.decode('utf-8') for split in splits]\n+    else:\n+        return shlex.split(value)\n+\n+\n+class BumpReleasePlugin(PreBuildPlugin):\n+    \"\"\"\n+    Git branch management plugin\n+\n+    For rebuilds, push a new commit incrementing the Release label.\n+\n+    For initial builds, verify the branch is at the specified commit\n+    hash.\n+\n+    Example configuration:\n+\n+    {\n+      \"name\": \"bump_release\",\n+      \"args\": {\n+        \"git_ref\": \"12345678....\",\n+        \"author_name\": \"OSBS Build System\",\n+        \"author_email\": \"root@example.com\"\n+      }\n+    }\n+\n+    Additional optional arguments:\n+    - committer_name\n+    - committer_email\n+    - commit_message\n+    - push_url\n+    \"\"\"\n+\n+    key = \"bump_release\"\n+    can_fail = False  # We really want to stop the process\n+\n+    commit_message = \"Bumped release for automated rebuild\"\n+\n+    def __init__(self, tasker, workflow,\n+                 git_ref,\n+                 author_name, author_email,\n+                 committer_name=None, committer_email=None,\n+                 commit_message=None,\n+                 push_url=None):\n+        \"\"\"\n+        constructor\n+\n+        :param tasker: DockerTasker instance\n+        :param workflow: DockerBuildWorkflow instance\n+        :param git_ref: str, commit hash expected on first build\n+        :param author_name: str, name to use for git commits\n+        :param author_email: str, email address for git commits\n+        :param committer_name: str, name to use for git commits (else author's)\n+        :param committer_email: str, email address for git commits (else\n+                                     author's)\n+        :param commit_message: str, git commit message\n+        :param push_url: str, URL for push\n+        \"\"\"\n+        # call parent constructor\n+        super(BumpReleasePlugin, self).__init__(tasker, workflow)\n+        self.git_ref = git_ref\n+        self.author_name = author_name\n+        self.author_email = author_email\n+        self.committer_name = committer_name\n+        self.commiter_email = committer_email\n+        if committer_name is None:\n+            self.committer_name = author_name\n+        if committer_email is None:\n+            self.committer_email = author_email\n+\n+        self.push_url = push_url\n+        if commit_message is not None:\n+            self.commit_message = commit_message\n+\n+    def bump_local_file(self, parser, label_key, next_release):\n+        \"\"\"\n+        Rewrite a local Dockerfile with an incremented Release label\n+        \"\"\"\n+\n+        # Find where in the file to put the next release\n+        content = startline = endline = None\n+        cmd = 'LABEL'\n+        for candidate in [insn for insn in parser.structure\n+                          if insn['instruction'] == cmd]:\n+            splits = shlex_splits(candidate['value'])\n+\n+            # LABEL syntax is one of two types:\n+            if '=' not in splits[0]:  # LABEL name value\n+                # remove (double-)quotes\n+                value = candidate['value'].replace(\"'\", \"\").replace('\"', '')\n+                words = value.split(None, 1)\n+                if words[0] == label_key:\n+                    # Adjust label value\n+                    words[1] = next_release\n+\n+                    # Now reconstruct the line\n+                    content = \" \".join([cmd] + words) + '\\n'\n+                    startline = candidate['startline']\n+                    endline = candidate['endline']\n+                    break\n+            else:  # LABEL \"name\"=\"value\"\n+                for token in splits:\n+                    words = token.split(\"=\", 1)\n+                    if words[0] == label_key:\n+                        # Adjust label value\n+                        words[1] = next_release\n+                        n = splits.index(token)\n+                        splits[n] = \"=\".join(map(quote, words))\n+\n+                        # Now reconstruct the line\n+                        content = \" \".join([cmd] + splits) + '\\n'\n+                        startline = candidate['startline']\n+                        endline = candidate['endline']\n+                        break\n+\n+        # We know the label we're looking for is there\n+        assert content and startline and endline\n+\n+        # Re-write the Dockerfile\n+        lines = parser.lines\n+        del lines[startline:endline + 1]\n+        lines.insert(startline, content)\n+        parser.lines = lines\n+\n+    @staticmethod\n+    def get_next_release(current_release):\n+        try:\n+            return str(int(current_release) + 1)\n+        except ValueError:\n+            isdigit = type(current_release).isdigit\n+            first_nondigit = [isdigit(x) for x in current_release].index(False)\n+            n = str(int(current_release[:first_nondigit]) + 1)\n+            return n + current_release[first_nondigit:]\n+\n+    def bump(self, repo, branch):\n+        # Look in the git repository\n+        remote = repo.remotes['origin']\n+        if self.push_url:\n+            repo.config['push.default'] = 'simple'\n+            remote.push_url = self.push_url\n+            remote.save()\n+\n+        # Bump the Release label\n+        label_key = 'Release'","path":"atomic_reactor/plugins/pre_bump_release.py","position":null,"original_position":175,"commit_id":"ba97a46e521c0cd7d44832a4a318252bb296dd93","original_commit_id":"04b2f27afefb15e00f22bf861a0523529cc17880","user":{"login":"bkabrda","id":1050061,"avatar_url":"https://avatars.githubusercontent.com/u/1050061?v=3","gravatar_id":"","url":"https://api.github.com/users/bkabrda","html_url":"https://github.com/bkabrda","followers_url":"https://api.github.com/users/bkabrda/followers","following_url":"https://api.github.com/users/bkabrda/following{/other_user}","gists_url":"https://api.github.com/users/bkabrda/gists{/gist_id}","starred_url":"https://api.github.com/users/bkabrda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bkabrda/subscriptions","organizations_url":"https://api.github.com/users/bkabrda/orgs","repos_url":"https://api.github.com/users/bkabrda/repos","events_url":"https://api.github.com/users/bkabrda/events{/privacy}","received_events_url":"https://api.github.com/users/bkabrda/received_events","type":"User","site_admin":false},"body":"Thinking about this further, we should really expect just `Release`. Label names are case sensitive, so `Release` is a different label than `RELEASE` or `rELELASE` (just tried that).\r\nSo if someone doesn't use `Release` (precisely this way), I'd call it an error in the provided Dockerfile.","created_at":"2015-08-13T07:54:43Z","updated_at":"2015-08-13T07:54:43Z","html_url":"https://github.com/projectatomic/atomic-reactor/pull/266#discussion_r36948581","pull_request_url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266","_links":{"self":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/comments/36948581"},"html":{"href":"https://github.com/projectatomic/atomic-reactor/pull/266#discussion_r36948581"},"pull_request":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266"}}},"pull_request":{"url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266","id":42226292,"html_url":"https://github.com/projectatomic/atomic-reactor/pull/266","diff_url":"https://github.com/projectatomic/atomic-reactor/pull/266.diff","patch_url":"https://github.com/projectatomic/atomic-reactor/pull/266.patch","issue_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/266","number":266,"state":"open","locked":false,"title":"New bump_release pre-build plugin","user":{"login":"twaugh","id":6985468,"avatar_url":"https://avatars.githubusercontent.com/u/6985468?v=3","gravatar_id":"","url":"https://api.github.com/users/twaugh","html_url":"https://github.com/twaugh","followers_url":"https://api.github.com/users/twaugh/followers","following_url":"https://api.github.com/users/twaugh/following{/other_user}","gists_url":"https://api.github.com/users/twaugh/gists{/gist_id}","starred_url":"https://api.github.com/users/twaugh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/twaugh/subscriptions","organizations_url":"https://api.github.com/users/twaugh/orgs","repos_url":"https://api.github.com/users/twaugh/repos","events_url":"https://api.github.com/users/twaugh/events{/privacy}","received_events_url":"https://api.github.com/users/twaugh/received_events","type":"User","site_admin":false},"body":"Here is a plugin for incrementing the Release label on automatic rebuild.\r\n\r\nThe push URL can be configured separately to the fetch URL used for the build. The `GitSource` provider's repository is modified in-place, the push URL set, and 'git push' run.\r\n\r\nFor authentication, currently this is achieved with Kerberos using the kernel keyring's TGT. This works by making sure the gssproxy package is installed and having git call out to an ssh process. I haven't managed to get it to work using the pygit2 `remote.push()` method.\r\n\r\nFor other authentication mechanisms, we would need another secret to be provided. I think that requires having a service account configured, which is out of scope for this pull request.","created_at":"2015-08-12T10:45:51Z","updated_at":"2015-08-13T07:54:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b39d1af5e39c38e282111fe18e5c58db4a71d995","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266/commits","review_comments_url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266/comments","review_comment_url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/comments{/number}","comments_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/266/comments","statuses_url":"https://api.github.com/repos/projectatomic/atomic-reactor/statuses/ba97a46e521c0cd7d44832a4a318252bb296dd93","head":{"label":"projectatomic:bump_release","ref":"bump_release","sha":"ba97a46e521c0cd7d44832a4a318252bb296dd93","user":{"login":"projectatomic","id":6852258,"avatar_url":"https://avatars.githubusercontent.com/u/6852258?v=3","gravatar_id":"","url":"https://api.github.com/users/projectatomic","html_url":"https://github.com/projectatomic","followers_url":"https://api.github.com/users/projectatomic/followers","following_url":"https://api.github.com/users/projectatomic/following{/other_user}","gists_url":"https://api.github.com/users/projectatomic/gists{/gist_id}","starred_url":"https://api.github.com/users/projectatomic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/projectatomic/subscriptions","organizations_url":"https://api.github.com/users/projectatomic/orgs","repos_url":"https://api.github.com/users/projectatomic/repos","events_url":"https://api.github.com/users/projectatomic/events{/privacy}","received_events_url":"https://api.github.com/users/projectatomic/received_events","type":"Organization","site_admin":false},"repo":{"id":25527782,"name":"atomic-reactor","full_name":"projectatomic/atomic-reactor","owner":{"login":"projectatomic","id":6852258,"avatar_url":"https://avatars.githubusercontent.com/u/6852258?v=3","gravatar_id":"","url":"https://api.github.com/users/projectatomic","html_url":"https://github.com/projectatomic","followers_url":"https://api.github.com/users/projectatomic/followers","following_url":"https://api.github.com/users/projectatomic/following{/other_user}","gists_url":"https://api.github.com/users/projectatomic/gists{/gist_id}","starred_url":"https://api.github.com/users/projectatomic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/projectatomic/subscriptions","organizations_url":"https://api.github.com/users/projectatomic/orgs","repos_url":"https://api.github.com/users/projectatomic/repos","events_url":"https://api.github.com/users/projectatomic/events{/privacy}","received_events_url":"https://api.github.com/users/projectatomic/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/projectatomic/atomic-reactor","description":"Simple python library for building docker images.","fork":false,"url":"https://api.github.com/repos/projectatomic/atomic-reactor","forks_url":"https://api.github.com/repos/projectatomic/atomic-reactor/forks","keys_url":"https://api.github.com/repos/projectatomic/atomic-reactor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/projectatomic/atomic-reactor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/projectatomic/atomic-reactor/teams","hooks_url":"https://api.github.com/repos/projectatomic/atomic-reactor/hooks","issue_events_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/events{/number}","events_url":"https://api.github.com/repos/projectatomic/atomic-reactor/events","assignees_url":"https://api.github.com/repos/projectatomic/atomic-reactor/assignees{/user}","branches_url":"https://api.github.com/repos/projectatomic/atomic-reactor/branches{/branch}","tags_url":"https://api.github.com/repos/projectatomic/atomic-reactor/tags","blobs_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/refs{/sha}","trees_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/projectatomic/atomic-reactor/statuses/{sha}","languages_url":"https://api.github.com/repos/projectatomic/atomic-reactor/languages","stargazers_url":"https://api.github.com/repos/projectatomic/atomic-reactor/stargazers","contributors_url":"https://api.github.com/repos/projectatomic/atomic-reactor/contributors","subscribers_url":"https://api.github.com/repos/projectatomic/atomic-reactor/subscribers","subscription_url":"https://api.github.com/repos/projectatomic/atomic-reactor/subscription","commits_url":"https://api.github.com/repos/projectatomic/atomic-reactor/commits{/sha}","git_commits_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/commits{/sha}","comments_url":"https://api.github.com/repos/projectatomic/atomic-reactor/comments{/number}","issue_comment_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/comments{/number}","contents_url":"https://api.github.com/repos/projectatomic/atomic-reactor/contents/{+path}","compare_url":"https://api.github.com/repos/projectatomic/atomic-reactor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/projectatomic/atomic-reactor/merges","archive_url":"https://api.github.com/repos/projectatomic/atomic-reactor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/projectatomic/atomic-reactor/downloads","issues_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues{/number}","pulls_url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls{/number}","milestones_url":"https://api.github.com/repos/projectatomic/atomic-reactor/milestones{/number}","notifications_url":"https://api.github.com/repos/projectatomic/atomic-reactor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/projectatomic/atomic-reactor/labels{/name}","releases_url":"https://api.github.com/repos/projectatomic/atomic-reactor/releases{/id}","created_at":"2014-10-21T14:45:11Z","updated_at":"2015-08-12T13:51:11Z","pushed_at":"2015-08-12T15:30:42Z","git_url":"git://github.com/projectatomic/atomic-reactor.git","ssh_url":"git@github.com:projectatomic/atomic-reactor.git","clone_url":"https://github.com/projectatomic/atomic-reactor.git","svn_url":"https://github.com/projectatomic/atomic-reactor","homepage":"","size":2545,"stargazers_count":17,"watchers_count":17,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":35,"forks":16,"open_issues":35,"watchers":17,"default_branch":"master"}},"base":{"label":"projectatomic:master","ref":"master","sha":"fcad05aed4d33833e0463ef0265ff443f453a338","user":{"login":"projectatomic","id":6852258,"avatar_url":"https://avatars.githubusercontent.com/u/6852258?v=3","gravatar_id":"","url":"https://api.github.com/users/projectatomic","html_url":"https://github.com/projectatomic","followers_url":"https://api.github.com/users/projectatomic/followers","following_url":"https://api.github.com/users/projectatomic/following{/other_user}","gists_url":"https://api.github.com/users/projectatomic/gists{/gist_id}","starred_url":"https://api.github.com/users/projectatomic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/projectatomic/subscriptions","organizations_url":"https://api.github.com/users/projectatomic/orgs","repos_url":"https://api.github.com/users/projectatomic/repos","events_url":"https://api.github.com/users/projectatomic/events{/privacy}","received_events_url":"https://api.github.com/users/projectatomic/received_events","type":"Organization","site_admin":false},"repo":{"id":25527782,"name":"atomic-reactor","full_name":"projectatomic/atomic-reactor","owner":{"login":"projectatomic","id":6852258,"avatar_url":"https://avatars.githubusercontent.com/u/6852258?v=3","gravatar_id":"","url":"https://api.github.com/users/projectatomic","html_url":"https://github.com/projectatomic","followers_url":"https://api.github.com/users/projectatomic/followers","following_url":"https://api.github.com/users/projectatomic/following{/other_user}","gists_url":"https://api.github.com/users/projectatomic/gists{/gist_id}","starred_url":"https://api.github.com/users/projectatomic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/projectatomic/subscriptions","organizations_url":"https://api.github.com/users/projectatomic/orgs","repos_url":"https://api.github.com/users/projectatomic/repos","events_url":"https://api.github.com/users/projectatomic/events{/privacy}","received_events_url":"https://api.github.com/users/projectatomic/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/projectatomic/atomic-reactor","description":"Simple python library for building docker images.","fork":false,"url":"https://api.github.com/repos/projectatomic/atomic-reactor","forks_url":"https://api.github.com/repos/projectatomic/atomic-reactor/forks","keys_url":"https://api.github.com/repos/projectatomic/atomic-reactor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/projectatomic/atomic-reactor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/projectatomic/atomic-reactor/teams","hooks_url":"https://api.github.com/repos/projectatomic/atomic-reactor/hooks","issue_events_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/events{/number}","events_url":"https://api.github.com/repos/projectatomic/atomic-reactor/events","assignees_url":"https://api.github.com/repos/projectatomic/atomic-reactor/assignees{/user}","branches_url":"https://api.github.com/repos/projectatomic/atomic-reactor/branches{/branch}","tags_url":"https://api.github.com/repos/projectatomic/atomic-reactor/tags","blobs_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/refs{/sha}","trees_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/projectatomic/atomic-reactor/statuses/{sha}","languages_url":"https://api.github.com/repos/projectatomic/atomic-reactor/languages","stargazers_url":"https://api.github.com/repos/projectatomic/atomic-reactor/stargazers","contributors_url":"https://api.github.com/repos/projectatomic/atomic-reactor/contributors","subscribers_url":"https://api.github.com/repos/projectatomic/atomic-reactor/subscribers","subscription_url":"https://api.github.com/repos/projectatomic/atomic-reactor/subscription","commits_url":"https://api.github.com/repos/projectatomic/atomic-reactor/commits{/sha}","git_commits_url":"https://api.github.com/repos/projectatomic/atomic-reactor/git/commits{/sha}","comments_url":"https://api.github.com/repos/projectatomic/atomic-reactor/comments{/number}","issue_comment_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/comments{/number}","contents_url":"https://api.github.com/repos/projectatomic/atomic-reactor/contents/{+path}","compare_url":"https://api.github.com/repos/projectatomic/atomic-reactor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/projectatomic/atomic-reactor/merges","archive_url":"https://api.github.com/repos/projectatomic/atomic-reactor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/projectatomic/atomic-reactor/downloads","issues_url":"https://api.github.com/repos/projectatomic/atomic-reactor/issues{/number}","pulls_url":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls{/number}","milestones_url":"https://api.github.com/repos/projectatomic/atomic-reactor/milestones{/number}","notifications_url":"https://api.github.com/repos/projectatomic/atomic-reactor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/projectatomic/atomic-reactor/labels{/name}","releases_url":"https://api.github.com/repos/projectatomic/atomic-reactor/releases{/id}","created_at":"2014-10-21T14:45:11Z","updated_at":"2015-08-12T13:51:11Z","pushed_at":"2015-08-12T15:30:42Z","git_url":"git://github.com/projectatomic/atomic-reactor.git","ssh_url":"git@github.com:projectatomic/atomic-reactor.git","clone_url":"https://github.com/projectatomic/atomic-reactor.git","svn_url":"https://github.com/projectatomic/atomic-reactor","homepage":"","size":2545,"stargazers_count":17,"watchers_count":17,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":35,"forks":16,"open_issues":35,"watchers":17,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266"},"html":{"href":"https://github.com/projectatomic/atomic-reactor/pull/266"},"issue":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/266"},"comments":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/issues/266/comments"},"review_comments":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266/comments"},"review_comment":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/pulls/266/commits"},"statuses":{"href":"https://api.github.com/repos/projectatomic/atomic-reactor/statuses/ba97a46e521c0cd7d44832a4a318252bb296dd93"}}}}