{"action":"created","comment":{"url":"https://api.github.com/repos/inveniosoftware/workflow/pulls/comments/29651594","id":29651594,"diff_hunk":"@@ -0,0 +1,338 @@\n+# -*- coding: utf-8 -*-\n+#\n+# This file is part of Workflow.\n+# Copyright (C) 2011, 2012, 2014, 2015 CERN.\n+#\n+# Workflow is free software; you can redistribute it and/or modify it\n+# under the terms of the Revised BSD License; see LICENSE file for\n+# more details.\n+\n+\n+\"\"\"The workflow engine extension of GenericWorkflowEngine.\"\"\"\n+\n+from __future__ import absolute_import\n+\n+import sys\n+\n+import traceback\n+from collections import OrderedDict\n+\n+from .engine import (\n+    GenericWorkflowEngine,\n+    TransitionActions,\n+    ProcessingFactory,\n+    Break,\n+    Continue,\n+)\n+from .errors import AbortProcessing, SkipToken, WorkflowError\n+from .logger import deprecated\n+from .utils import staticproperty\n+\n+\n+class WorkflowStatus(object):\n+    \"\"\"Define the known workflow statuses.\n+\n+       ================  =============\n+       Attribute         Internal repr\n+       ================  =============\n+       NEW               0\n+       RUNNING           1\n+       HALTED            2\n+       COMPLETED         3\n+       ================  =============\n+    \"\"\"\n+\n+    NEW = 0\n+    RUNNING = 1\n+    HALTED = 2\n+    ERROR = 3\n+    COMPLETED = 4\n+\n+\n+# enum34 lib is not used here is because comparisons against non-enumeration\n+# values will always compare not equal (in other words, `0 in ObjectStatus`\n+# would always return `False`.\n+class _ObjectStatus(object):\n+    \"\"\"Specify the known object statuses.\n+\n+       ================ =================== =============\n+       Attribute        Human-friendly name Internal repr\n+       ================ =================== =============\n+       INTIAL           New                 0\n+       COMPLETED        Done                1\n+       HALTED           Need action         2\n+       RUNNING          In process          3\n+       WAITING          Waiting             4\n+       ERROR            Error               5\n+       ================ =================== =============\n+\n+    \"\"\"\n+    def __init__(self):\n+        self._statuses = OrderedDict((\n+            ('INITIAL', \"New\"),         # 0\n+            ('COMPLETED', \"Done\"),      # 1\n+            ('HALTED', \"Need action\"),  # 2\n+            ('RUNNING', \"In process\"),  # 3\n+            ('WAITING', \"Waiting\"),     # 4\n+            ('ERROR', \"Error\"),         # 5\n+        ))\n+        for idx, key in enumerate(self._statuses.keys()):\n+            setattr(self, key, idx)\n+\n+    @property\n+    @deprecated(\"Please use ObjectStatus.COMPLETED \"\n+                \"instead of ObjectStatus.FINAL\")\n+    def FINAL(self):\n+        \"\"\"Return cls.COMPLETED, although this is deprecated.\"\"\"\n+        return self.COMPLETED  # pylint: disable=no-member\n+\n+    def name(self, version):\n+        \"\"\"Human readable name from the integer state representation.\"\"\"\n+        return self._statuses.values()[version]\n+\n+    def __contains__(self, val):\n+        return val in range(len(self._statuses))\n+\n+# Required in order to be able to implement `__contains__`.\n+ObjectStatus = _ObjectStatus()\n+\n+\n+class DbWorkflowEngine(GenericWorkflowEngine):\n+    \"\"\"GenericWorkflowEngine with DB persistence.\n+\n+    Adds a SQLAlchemy database model to save workflow states and\n+    workflow data.\n+\n+    Overrides key functions in GenericWorkflowEngine to implement\n+    logging and certain workarounds for storing data before/after\n+    task calls (This part will be revisited in the future).\n+    \"\"\"\n+\n+    def __init__(self, db_obj):\n+        \"\"\"Instantiate a new BibWorkflowEngine object.\n+\n+        :param db_obj: the workflow engine\n+        :type db_obj: Workflow\n+\n+        This object is needed to run a workflow and control the workflow,\n+        like at which step of the workflow execution is currently at, as well\n+        as control object manipulation inside the workflow.\n+\n+        You can pass several parameters to personalize your engine,\n+        but most of the time you will not need to create this object yourself\n+        as the :py:mod:`.api` is there to do it for you.\n+\n+        :param db_obj: instance of a Workflow object.\n+        :type db_obj: Workflow\n+        \"\"\"\n+        self.db_obj = db_obj\n+        self.save()\n+        # To initialize the logger, `db_obj` must be first set. For this we\n+        # must have saved at least once before calling `__init__`.\n+        super(DbWorkflowEngine, self).__init__()\n+\n+    @staticproperty\n+    def processing_factory():  # pylint: disable=no-method-argument\n+        \"\"\"Provide a proccessing factory.\"\"\"\n+        return DbProcessingFactory\n+\n+    ############################################################################\n+    #                                                                          #\n+    # Deprecated\n+    @property\n+    def counter_object(self):\n+        \"\"\"Return the number of object.\"\"\"\n+        raise NotImplementedError\n+\n+    @property\n+    def name(self):\n+        \"\"\"Return the name.\"\"\"\n+        return self.db_obj.name\n+\n+    @property\n+    def status(self):\n+        \"\"\"Return the status.\"\"\"\n+        return self.db_obj.status\n+\n+    # XXX renamed recently from 'objects'\n+    @property\n+    def database_objects(self):\n+        \"\"\"Return the objects associated with this workflow.\"\"\"\n+        return self.db_obj.objects\n+\n+    @property\n+    def final_objects(self):\n+        \"\"\"Return the objects associated with this workflow.\"\"\"\n+        return [obj for obj in self.database_objects\n+                if obj.version in [ObjectStatus.COMPLETED]]  #  pylint: disable=no-member\n+\n+    @property\n+    def halted_objects(self):\n+        \"\"\"Return the objects associated with this workflow.\"\"\"\n+        return [obj for obj in self.database_objects\n+                if obj.version in [ObjectStatus.HALTED]]  #  pylint: disable=no-member\n+\n+    @property\n+    def running_objects(self):\n+        \"\"\"Return the objects associated with this workflow.\"\"\"\n+        return [obj for obj in self.database_objects\n+                if obj.version in [ObjectStatus.RUNNING]]  #  pylint: disable=no-member\n+    #                                                                          #\n+    ############################################################################\n+\n+    def __repr__(self):\n+        \"\"\"Allow to represent the DbWorkflowEngine.\"\"\"\n+        return \"<DbWorkflow_engine(%s)>\" % (self.name,)\n+\n+    def __str__(self, log=False):\n+        \"\"\"Allow to print the DbWorkflowEngine.\"\"\"\n+        return \"\"\"-------------------------------\n+DbWorkflowEngine\n+-------------------------------\n+    %s\n+-------------------------------\n+\"\"\" % (self.db_obj.__str__(),)\n+\n+    def save(self, status=None):\n+        \"\"\"Save the workflow instance to database.\"\"\"\n+        # This workflow continues a previous execution.\n+        self.db_obj.save(status)\n+\n+    ############################################################################\n+    #                                                                          #\n+\n+    # TODO: Modify the counters via signals instead\n+    def set_counter_initial(self, obj_count):\n+        \"\"\"Initiate the counters of object states.\n+\n+        :param obj_count: Number of objects to process.\n+        :type obj_count: int\n+        \"\"\"\n+        self.db_obj.counter_initial = obj_count\n+        self.db_obj.counter_halted = 0\n+        self.db_obj.counter_error = 0\n+        self.db_obj.counter_finished = 0\n+\n+    def increase_counter_halted(self):\n+        \"\"\"Indicate we halted the processing of one object.\"\"\"\n+        self.db_obj.counter_halted += 1\n+\n+    def increase_counter_error(self):\n+        \"\"\"Indicate we crashed the processing of one object.\"\"\"\n+        self.db_obj.counter_error += 1\n+\n+    def increase_counter_finished(self):\n+        \"\"\"Indicate we finished the processing of one object.\"\"\"\n+        self.db_obj.counter_finished += 1\n+\n+    #                                                                          #\n+    ############################################################################\n+\n+    def abortProcessing(self):\n+        \"\"\"Abort current workflow execution without saving object.\"\"\"\n+        raise AbortProcessing\n+\n+    def skipToken(self):\n+        \"\"\"Skip current workflow object without saving it.\"\"\"\n+        raise SkipToken\n+\n+\n+class DbTransitionAction(TransitionActions):\n+    \"\"\"Transition actions on engine exceptions for persistence object.\"\"\"\n+\n+    @staticmethod\n+    def SkipToken(obj, eng, callbacks, e):\n+        \"\"\"Action to take when SkipToken is raised.\"\"\"\n+        msg = \"Skipped running this object: '%s' (object: %s)\" % \\\n+            (str(callbacks), repr(obj))\n+        eng.log.debug(msg)\n+        obj.log.debug(msg)\n+        raise Continue\n+\n+    @staticmethod\n+    def AbortProcessing(obj, eng, callbacks, e):\n+        \"\"\"Action to take when AbortProcessing is raised.\"\"\"\n+        msg = \"Processing was aborted: '%s' (object: %s)\" % \\\n+            (str(callbacks), repr(obj))\n+        eng.log.debug(msg)\n+        obj.log.debug(msg)\n+        raise Break\n+\n+    @staticmethod\n+    def HaltProcessing(obj, eng, callbacks, e):\n+        \"\"\"Action to take when HaltProcessing is raised.\"\"\"\n+        eng.increase_counter_halted()\n+        if e.action:","path":"workflow/engine_db.py","position":265,"original_position":265,"commit_id":"759b23a57d94919240d6e532b5490c2118ed90ba","original_commit_id":"759b23a57d94919240d6e532b5490c2118ed90ba","user":{"login":"jalavik","id":633680,"avatar_url":"https://avatars.githubusercontent.com/u/633680?v=3","gravatar_id":"","url":"https://api.github.com/users/jalavik","html_url":"https://github.com/jalavik","followers_url":"https://api.github.com/users/jalavik/followers","following_url":"https://api.github.com/users/jalavik/following{/other_user}","gists_url":"https://api.github.com/users/jalavik/gists{/gist_id}","starred_url":"https://api.github.com/users/jalavik/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jalavik/subscriptions","organizations_url":"https://api.github.com/users/jalavik/orgs","repos_url":"https://api.github.com/users/jalavik/repos","events_url":"https://api.github.com/users/jalavik/events{/privacy}","received_events_url":"https://api.github.com/users/jalavik/received_events","type":"User","site_admin":false},"body":"The concept of `action` here is really a Holding Pen thing, where halting with an action is HALTED and halting without an action is WAITING. Honestly this distinction should probably only be in Invenio, but I understand if that can be difficult to pull off easily with different `ObjectStatus` enums..","created_at":"2015-05-05T08:46:18Z","updated_at":"2015-05-05T08:46:18Z","html_url":"https://github.com/inveniosoftware/workflow/pull/29#discussion_r29651594","pull_request_url":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29","_links":{"self":{"href":"https://api.github.com/repos/inveniosoftware/workflow/pulls/comments/29651594"},"html":{"href":"https://github.com/inveniosoftware/workflow/pull/29#discussion_r29651594"},"pull_request":{"href":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29"}}},"pull_request":{"url":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29","id":26064529,"html_url":"https://github.com/inveniosoftware/workflow/pull/29","diff_url":"https://github.com/inveniosoftware/workflow/pull/29.diff","patch_url":"https://github.com/inveniosoftware/workflow/pull/29.patch","issue_url":"https://api.github.com/repos/inveniosoftware/workflow/issues/29","number":29,"state":"open","locked":false,"title":"WIP engine: Support user-defined processing actions","user":{"login":"dset0x","id":8993055,"avatar_url":"https://avatars.githubusercontent.com/u/8993055?v=3","gravatar_id":"","url":"https://api.github.com/users/dset0x","html_url":"https://github.com/dset0x","followers_url":"https://api.github.com/users/dset0x/followers","following_url":"https://api.github.com/users/dset0x/following{/other_user}","gists_url":"https://api.github.com/users/dset0x/gists{/gist_id}","starred_url":"https://api.github.com/users/dset0x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dset0x/subscriptions","organizations_url":"https://api.github.com/users/dset0x/orgs","repos_url":"https://api.github.com/users/dset0x/repos","events_url":"https://api.github.com/users/dset0x/events{/privacy}","received_events_url":"https://api.github.com/users/dset0x/received_events","type":"User","site_admin":false},"body":"* Move `processing_factory` out of the `WorkflowEngine` and into its own\r\n  class. The majority of its operations can now be overridden by means\r\n  of subclassing `WorkflowEngine` and the new, complementing\r\n  `ActionMapper` and `TransitionActions` classes and defining\r\n  properties. This way `super` can be used safely while retaining the\r\n  ability to `continue` or `break` out of the main loop.\r\n\r\n* The notion of defining bits of functionality as properties, takes away\r\n  the need for tediously duplicating the class by making assumptions of\r\n  what methods may have been overriden by the user. Only overriding by\r\n  subclassing is now supported. Therefore `duplicate_engine_instance`\r\n  was renamed to `duplicate`, which is now almost a stub.\r\n\r\n* Introduce `eng.reset_callbacks_pointer()`.\r\n\r\nFirst bit of work towards moving handling of storage to workflow.","created_at":"2014-12-15T12:05:36Z","updated_at":"2015-05-05T08:46:18Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d1edb2c6e0c6ec4cbfbf8848293749ced35f52a0","assignee":{"login":"dset0x","id":8993055,"avatar_url":"https://avatars.githubusercontent.com/u/8993055?v=3","gravatar_id":"","url":"https://api.github.com/users/dset0x","html_url":"https://github.com/dset0x","followers_url":"https://api.github.com/users/dset0x/followers","following_url":"https://api.github.com/users/dset0x/following{/other_user}","gists_url":"https://api.github.com/users/dset0x/gists{/gist_id}","starred_url":"https://api.github.com/users/dset0x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dset0x/subscriptions","organizations_url":"https://api.github.com/users/dset0x/orgs","repos_url":"https://api.github.com/users/dset0x/repos","events_url":"https://api.github.com/users/dset0x/events{/privacy}","received_events_url":"https://api.github.com/users/dset0x/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/inveniosoftware/workflow/milestones/3","html_url":"https://github.com/inveniosoftware/workflow/milestones/v2.0.0","labels_url":"https://api.github.com/repos/inveniosoftware/workflow/milestones/3/labels","id":904527,"number":3,"title":"v2.0.0","description":"","creator":{"login":"jirikuncar","id":189798,"avatar_url":"https://avatars.githubusercontent.com/u/189798?v=3","gravatar_id":"","url":"https://api.github.com/users/jirikuncar","html_url":"https://github.com/jirikuncar","followers_url":"https://api.github.com/users/jirikuncar/followers","following_url":"https://api.github.com/users/jirikuncar/following{/other_user}","gists_url":"https://api.github.com/users/jirikuncar/gists{/gist_id}","starred_url":"https://api.github.com/users/jirikuncar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jirikuncar/subscriptions","organizations_url":"https://api.github.com/users/jirikuncar/orgs","repos_url":"https://api.github.com/users/jirikuncar/repos","events_url":"https://api.github.com/users/jirikuncar/events{/privacy}","received_events_url":"https://api.github.com/users/jirikuncar/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":0,"state":"open","created_at":"2014-12-15T16:41:41Z","updated_at":"2014-12-15T16:49:37Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29/commits","review_comments_url":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29/comments","review_comment_url":"https://api.github.com/repos/inveniosoftware/workflow/pulls/comments{/number}","comments_url":"https://api.github.com/repos/inveniosoftware/workflow/issues/29/comments","statuses_url":"https://api.github.com/repos/inveniosoftware/workflow/statuses/759b23a57d94919240d6e532b5490c2118ed90ba","head":{"label":"dset0x:delegate-storage","ref":"delegate-storage","sha":"759b23a57d94919240d6e532b5490c2118ed90ba","user":{"login":"dset0x","id":8993055,"avatar_url":"https://avatars.githubusercontent.com/u/8993055?v=3","gravatar_id":"","url":"https://api.github.com/users/dset0x","html_url":"https://github.com/dset0x","followers_url":"https://api.github.com/users/dset0x/followers","following_url":"https://api.github.com/users/dset0x/following{/other_user}","gists_url":"https://api.github.com/users/dset0x/gists{/gist_id}","starred_url":"https://api.github.com/users/dset0x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dset0x/subscriptions","organizations_url":"https://api.github.com/users/dset0x/orgs","repos_url":"https://api.github.com/users/dset0x/repos","events_url":"https://api.github.com/users/dset0x/events{/privacy}","received_events_url":"https://api.github.com/users/dset0x/received_events","type":"User","site_admin":false},"repo":{"id":28032532,"name":"workflow","full_name":"dset0x/workflow","owner":{"login":"dset0x","id":8993055,"avatar_url":"https://avatars.githubusercontent.com/u/8993055?v=3","gravatar_id":"","url":"https://api.github.com/users/dset0x","html_url":"https://github.com/dset0x","followers_url":"https://api.github.com/users/dset0x/followers","following_url":"https://api.github.com/users/dset0x/following{/other_user}","gists_url":"https://api.github.com/users/dset0x/gists{/gist_id}","starred_url":"https://api.github.com/users/dset0x/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dset0x/subscriptions","organizations_url":"https://api.github.com/users/dset0x/orgs","repos_url":"https://api.github.com/users/dset0x/repos","events_url":"https://api.github.com/users/dset0x/events{/privacy}","received_events_url":"https://api.github.com/users/dset0x/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dset0x/workflow","description":"Simple Pythonic Workflows","fork":true,"url":"https://api.github.com/repos/dset0x/workflow","forks_url":"https://api.github.com/repos/dset0x/workflow/forks","keys_url":"https://api.github.com/repos/dset0x/workflow/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dset0x/workflow/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dset0x/workflow/teams","hooks_url":"https://api.github.com/repos/dset0x/workflow/hooks","issue_events_url":"https://api.github.com/repos/dset0x/workflow/issues/events{/number}","events_url":"https://api.github.com/repos/dset0x/workflow/events","assignees_url":"https://api.github.com/repos/dset0x/workflow/assignees{/user}","branches_url":"https://api.github.com/repos/dset0x/workflow/branches{/branch}","tags_url":"https://api.github.com/repos/dset0x/workflow/tags","blobs_url":"https://api.github.com/repos/dset0x/workflow/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dset0x/workflow/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dset0x/workflow/git/refs{/sha}","trees_url":"https://api.github.com/repos/dset0x/workflow/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dset0x/workflow/statuses/{sha}","languages_url":"https://api.github.com/repos/dset0x/workflow/languages","stargazers_url":"https://api.github.com/repos/dset0x/workflow/stargazers","contributors_url":"https://api.github.com/repos/dset0x/workflow/contributors","subscribers_url":"https://api.github.com/repos/dset0x/workflow/subscribers","subscription_url":"https://api.github.com/repos/dset0x/workflow/subscription","commits_url":"https://api.github.com/repos/dset0x/workflow/commits{/sha}","git_commits_url":"https://api.github.com/repos/dset0x/workflow/git/commits{/sha}","comments_url":"https://api.github.com/repos/dset0x/workflow/comments{/number}","issue_comment_url":"https://api.github.com/repos/dset0x/workflow/issues/comments{/number}","contents_url":"https://api.github.com/repos/dset0x/workflow/contents/{+path}","compare_url":"https://api.github.com/repos/dset0x/workflow/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dset0x/workflow/merges","archive_url":"https://api.github.com/repos/dset0x/workflow/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dset0x/workflow/downloads","issues_url":"https://api.github.com/repos/dset0x/workflow/issues{/number}","pulls_url":"https://api.github.com/repos/dset0x/workflow/pulls{/number}","milestones_url":"https://api.github.com/repos/dset0x/workflow/milestones{/number}","notifications_url":"https://api.github.com/repos/dset0x/workflow/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dset0x/workflow/labels{/name}","releases_url":"https://api.github.com/repos/dset0x/workflow/releases{/id}","created_at":"2014-12-15T10:49:53Z","updated_at":"2014-12-15T10:49:53Z","pushed_at":"2015-05-05T08:22:08Z","git_url":"git://github.com/dset0x/workflow.git","ssh_url":"git@github.com:dset0x/workflow.git","clone_url":"https://github.com/dset0x/workflow.git","svn_url":"https://github.com/dset0x/workflow","homepage":"","size":568,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"inveniosoftware:master","ref":"master","sha":"79b5e68fe46036ee617f2065e535485b771bf8fa","user":{"login":"inveniosoftware","id":1157480,"avatar_url":"https://avatars.githubusercontent.com/u/1157480?v=3","gravatar_id":"","url":"https://api.github.com/users/inveniosoftware","html_url":"https://github.com/inveniosoftware","followers_url":"https://api.github.com/users/inveniosoftware/followers","following_url":"https://api.github.com/users/inveniosoftware/following{/other_user}","gists_url":"https://api.github.com/users/inveniosoftware/gists{/gist_id}","starred_url":"https://api.github.com/users/inveniosoftware/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inveniosoftware/subscriptions","organizations_url":"https://api.github.com/users/inveniosoftware/orgs","repos_url":"https://api.github.com/users/inveniosoftware/repos","events_url":"https://api.github.com/users/inveniosoftware/events{/privacy}","received_events_url":"https://api.github.com/users/inveniosoftware/received_events","type":"Organization","site_admin":false},"repo":{"id":2018739,"name":"workflow","full_name":"inveniosoftware/workflow","owner":{"login":"inveniosoftware","id":1157480,"avatar_url":"https://avatars.githubusercontent.com/u/1157480?v=3","gravatar_id":"","url":"https://api.github.com/users/inveniosoftware","html_url":"https://github.com/inveniosoftware","followers_url":"https://api.github.com/users/inveniosoftware/followers","following_url":"https://api.github.com/users/inveniosoftware/following{/other_user}","gists_url":"https://api.github.com/users/inveniosoftware/gists{/gist_id}","starred_url":"https://api.github.com/users/inveniosoftware/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inveniosoftware/subscriptions","organizations_url":"https://api.github.com/users/inveniosoftware/orgs","repos_url":"https://api.github.com/users/inveniosoftware/repos","events_url":"https://api.github.com/users/inveniosoftware/events{/privacy}","received_events_url":"https://api.github.com/users/inveniosoftware/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/inveniosoftware/workflow","description":"Simple Pythonic Workflows","fork":false,"url":"https://api.github.com/repos/inveniosoftware/workflow","forks_url":"https://api.github.com/repos/inveniosoftware/workflow/forks","keys_url":"https://api.github.com/repos/inveniosoftware/workflow/keys{/key_id}","collaborators_url":"https://api.github.com/repos/inveniosoftware/workflow/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/inveniosoftware/workflow/teams","hooks_url":"https://api.github.com/repos/inveniosoftware/workflow/hooks","issue_events_url":"https://api.github.com/repos/inveniosoftware/workflow/issues/events{/number}","events_url":"https://api.github.com/repos/inveniosoftware/workflow/events","assignees_url":"https://api.github.com/repos/inveniosoftware/workflow/assignees{/user}","branches_url":"https://api.github.com/repos/inveniosoftware/workflow/branches{/branch}","tags_url":"https://api.github.com/repos/inveniosoftware/workflow/tags","blobs_url":"https://api.github.com/repos/inveniosoftware/workflow/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/inveniosoftware/workflow/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/inveniosoftware/workflow/git/refs{/sha}","trees_url":"https://api.github.com/repos/inveniosoftware/workflow/git/trees{/sha}","statuses_url":"https://api.github.com/repos/inveniosoftware/workflow/statuses/{sha}","languages_url":"https://api.github.com/repos/inveniosoftware/workflow/languages","stargazers_url":"https://api.github.com/repos/inveniosoftware/workflow/stargazers","contributors_url":"https://api.github.com/repos/inveniosoftware/workflow/contributors","subscribers_url":"https://api.github.com/repos/inveniosoftware/workflow/subscribers","subscription_url":"https://api.github.com/repos/inveniosoftware/workflow/subscription","commits_url":"https://api.github.com/repos/inveniosoftware/workflow/commits{/sha}","git_commits_url":"https://api.github.com/repos/inveniosoftware/workflow/git/commits{/sha}","comments_url":"https://api.github.com/repos/inveniosoftware/workflow/comments{/number}","issue_comment_url":"https://api.github.com/repos/inveniosoftware/workflow/issues/comments{/number}","contents_url":"https://api.github.com/repos/inveniosoftware/workflow/contents/{+path}","compare_url":"https://api.github.com/repos/inveniosoftware/workflow/compare/{base}...{head}","merges_url":"https://api.github.com/repos/inveniosoftware/workflow/merges","archive_url":"https://api.github.com/repos/inveniosoftware/workflow/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/inveniosoftware/workflow/downloads","issues_url":"https://api.github.com/repos/inveniosoftware/workflow/issues{/number}","pulls_url":"https://api.github.com/repos/inveniosoftware/workflow/pulls{/number}","milestones_url":"https://api.github.com/repos/inveniosoftware/workflow/milestones{/number}","notifications_url":"https://api.github.com/repos/inveniosoftware/workflow/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/inveniosoftware/workflow/labels{/name}","releases_url":"https://api.github.com/repos/inveniosoftware/workflow/releases{/id}","created_at":"2011-07-08T16:28:36Z","updated_at":"2015-04-25T08:15:20Z","pushed_at":"2015-05-05T08:22:08Z","git_url":"git://github.com/inveniosoftware/workflow.git","ssh_url":"git@github.com:inveniosoftware/workflow.git","clone_url":"https://github.com/inveniosoftware/workflow.git","svn_url":"https://github.com/inveniosoftware/workflow","homepage":"","size":1023,"stargazers_count":41,"watchers_count":41,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":12,"mirror_url":null,"open_issues_count":4,"forks":12,"open_issues":4,"watchers":41,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29"},"html":{"href":"https://github.com/inveniosoftware/workflow/pull/29"},"issue":{"href":"https://api.github.com/repos/inveniosoftware/workflow/issues/29"},"comments":{"href":"https://api.github.com/repos/inveniosoftware/workflow/issues/29/comments"},"review_comments":{"href":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29/comments"},"review_comment":{"href":"https://api.github.com/repos/inveniosoftware/workflow/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/inveniosoftware/workflow/pulls/29/commits"},"statuses":{"href":"https://api.github.com/repos/inveniosoftware/workflow/statuses/759b23a57d94919240d6e532b5490c2118ed90ba"}}}}