{"action":"created","comment":{"url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/comments/132644634","pull_request_review_id":55564064,"id":132644634,"diff_hunk":"@@ -0,0 +1,358 @@\n+import base64\n+import logging\n+import md5\n+import StringIO\n+import boto3\n+from botocore.exceptions import ClientError\n+import google.protobuf.message\n+import aws_kinesis_agg\n+import aws_kinesis_agg.kpl_pb2 as kpl_pb2\n+from .common import parse_response\n+from .digest_table import MD5DigestTable\n+from .checkpoint_table import CheckpointTable\n+import threading\n+\n+\"\"\"\n+# Easy usage example:\n+\n+from consumer import ShardConsumer\n+import time\n+cons = ShardConsumer(stream_name='orange-peach-gap-raw', shard_id = 'shardId-000000000000',\n+                     shard_iterator_type='TRIM_HORIZON')\n+while True:\n+    records = cons.get_records(10)\n+    recs = []\n+    for rec in records:\n+        # do something to each record 'rec' here ...\n+        print 'reccooooooooooord'\n+        recs.append(rec)\n+    cons.put_items_digests(recs)\n+    time.sleep(10)\n+    # sleep k seconds of each k records count requested to avoid rate limits\n+\"\"\"\n+\n+logger = logging.getLogger(__name__)\n+\n+\n+def get_shards(kinesis_client, stream_name):\n+    '''Returns a list of every shards in the current stream'''\n+    response = parse_response(kinesis_client.describe_stream(StreamName=stream_name))\n+    shards = [x.get('ShardId') for x in response.get('StreamDescription').get('Shards')]\n+    while response.get('HasMoreShards', False):\n+        next_shard = shards[-1]\n+        response = parse_response(kinesis_client.describe_stream(\n+            StreamName=stream_name,\n+            ExclusiveStartShardId=next_shard))\n+        shards.extend([x.get('ShardId') for x in response.get('StreamDescription').get('Shards')])\n+    return list(set(shards))\n+\n+\n+def get_shards_iterators(kinesis_client, stream_name,\n+                         shard_iterator_type='TRIM_HORIZON',\n+                         starting_sequence_number=None):\n+    '''Returns a list of iterators of each shard in the stream'''\n+    iterators = []\n+\n+    if shard_iterator_type in ['AT_SEQUENCE_NUMBER', 'AFTER_SEQUENCE_NUMBER']:\n+        if starting_sequence_number is None:\n+            logger.error('With Shard iterators using sequence number,\\\n+             you must provide a sequence number string')\n+            return []\n+        args = {'StartingSequenceNumber': starting_sequence_number,\n+                'ShardIteratorType': shard_iterator_type}\n+    else:\n+        args = {'ShardIteratorType': shard_iterator_type}\n+\n+    for shard in get_shards(kinesis_client, stream_name):\n+        response = parse_response(kinesis_client.get_shard_iterator(\n+            StreamName=stream_name,\n+            ShardId=shard,\n+            **args))\n+        iterators.append(response.get('ShardIterator'))\n+    return iterators\n+\n+\n+def set_checkpoint(shard_consumer):\n+    checkpoint = shard_consumer.get_checkpoint()\n+    if checkpoint is not None:\n+        shard_consumer.checkpoint_table.update_item(\n+            sequence_number=checkpoint['SequenceNumber'],\n+            shard_id=shard_consumer.shard_id,\n+            subsequence_number=checkpoint.get('subSequenceNumber'),\n+            approximate_arrival_timestamp=checkpoint.get('ApproximateArrivalTimestamp'))\n+    threading.Timer(10, set_checkpoint, [shard_consumer]).start()\n+    # TODO an option to stop the threading with a call from shardconsumer\n+\n+\n+class ShardConsumer(object):\n+    \"\"\"Read and deaggregate records from a Kinesis stream\n+    \"\"\"\n+    def __init__(self, stream_name, shard_id, shard_iterator_type='TRIM_HORIZON', sequence_number=None, use_generator=True, **config):\n+        \"\"\" Provide a shard_iterator_type in ['AT_SEQUENCE_NUMBER','AFTER_SEQUENCE_NUMBER',\n+        'AT_TIMESTAMP', 'TRIM_HORIZON', 'LATEST']\n+        http://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html\n+        If you provide credentials/config do it as follows\n+        config ={ 'region_name':'region',\n+                  'aws_access_key_id': 'key',\n+                  'aws_secret_access_key': 'secret'}\n+        ShardConsumer(stream_name, shard_id, shard_iterator_type, **config)\n+        \"\"\"\n+        assert shard_iterator_type in ['AT_SEQUENCE_NUMBER', 'AFTER_SEQUENCE_NUMBER', 'TRIM_HORIZON']\n+\n+        if shard_iterator_type in ['AT_SEQUENCE_NUMBER', 'AFTER_SEQUENCE_NUMBER'] and (sequence_number is None):\n+            logger.error('With Shard iterators using sequence number,\\\n+                you must provide a sequence number string')\n+            raise Exception('No sequence_number string provided')\n+\n+        self.stream_name = stream_name\n+        self.kinesis_client = boto3.client('kinesis', **config)\n+        self.shard_id = shard_id\n+        self.use_generator = use_generator\n+        self.checkpoint = None\n+        self.digest_table = MD5DigestTable(table_name='{}-connector-digest'\n+                                                      .format(self.stream_name))\n+        self.checkpoint_table = CheckpointTable(table_name='{}-connector-checkpoint'\n+                                                           .format(self.stream_name),\n+                                                shards_ids=get_shards(self.kinesis_client,\n+                                                                      self.stream_name))\n+        # Initiate the iteration\n+        if shard_iterator_type in ['AT_SEQUENCE_NUMBER', 'AFTER_SEQUENCE_NUMBER']:\n+            self.shard_iterator = parse_response(self.kinesis_client.get_shard_iterator(\n+                StreamName=stream_name,\n+                ShardId=shard_id,\n+                ShardIteratorType=shard_iterator_type,\n+                StartingSequenceNumber=sequence_number))[\"ShardIterator\"]\n+        else:\n+            assert shard_iterator_type == 'TRIM_HORIZON'\n+            self.checkpoint = self.checkpoint_table.get_item(shard_id=self.shard_id)[0]\n+            if self.checkpoint['SequenceNumber'] == '0':\n+                self.shard_iterator = parse_response(self.kinesis_client.get_shard_iterator(\n+                    StreamName=stream_name,\n+                    ShardId=shard_id,\n+                    ShardIteratorType=shard_iterator_type))[\"ShardIterator\"]\n+            else:\n+                # we are conservative by starting AT checkpoint and not AFTER since we skip elements\n+                # already in digest table anyway\n+                self.shard_iterator = parse_response(self.kinesis_client.get_shard_iterator(\n+                    StreamName=stream_name,\n+                    ShardId=shard_id,\n+                    ShardIteratorType='AT_SEQUENCE_NUMBER',\n+                    StartingSequenceNumber=self.checkpoint['SequenceNumber']))[\"ShardIterator\"]\n+        set_checkpoint(self)\n+\n+    def _return_bulk_records(self, result):\n+        '''function to process Kinesis aggregated\n+        records in a bulk fashion (return a list).'''\n+        try:\n+            kinesis_records = self.deaggregate_records(result['Records'])\n+            # Deaggregate all records in one call\n+            return kinesis_records\n+        except Exception as e:\n+            raise e\n+        finally:\n+            # After returning the records\n+            self.checkpoint = kinesis_records[-1]\n+\n+    def _return_iter_records(self, result):\n+        '''function to process Kinesis aggregated\n+        records in a generator-based fashion (return a generator).'''\n+        raw_kinesis_records = result['Records']\n+        # Deaggregate all records using a generator function\n+        for record in self.iter_deaggregate_records(raw_kinesis_records):\n+            yield record\n+            self.checkpoint = record\n+\n+    def get_records(self, limit):\n+        '''function to process Kinesis aggregated\n+        records. Returns a generator if self.use_generator=True and a list otherwise '''\n+        try:\n+            result = parse_response(self.kinesis_client.get_records(\n+                ShardIterator=self.shard_iterator,\n+                Limit=limit))\n+            self.shard_iterator = result[\"NextShardIterator\"]\n+\n+        except ClientError as e:\n+            # botocore.errorfactory.ProvisionedThroughputExceededException raised when iterator timeout\n+            if self.checkpoint is None:\n+                # corner case of initializing with no checkpoint\n+                # followed with many empty iterations not setting it\n+                self.checkpoint = self.checkpoint_table.get_item(shard_id=self.shard_id)[0]\n+            if self.checkpoint['SequenceNumber'] == '0':\n+                self.shard_iterator = parse_response(self.kinesis_client.get_shard_iterator(\n+                    StreamName=self.stream_name,\n+                    ShardId=self.shard_id,\n+                    ShardIteratorType='TRIM_HORIZON'))[\"ShardIterator\"]\n+            else:\n+                self.shard_iterator = parse_response(self.kinesis_client.get_shard_iterator(\n+                    StreamName=self.stream_name,\n+                    ShardId=self.shard_id,\n+                    ShardIteratorType='AT_SEQUENCE_NUMBER',\n+                    StartingSequenceNumber=self.checkpoint['SequenceNumber']\n+                ))[\"ShardIterator\"]\n+            return self.get_records(limit=limit)","path":"artefact/connectors/kinesis/api/consumer.py","position":192,"original_position":192,"commit_id":"b0224e5abce81ed7d79dfe4e6ee17655e29b32ac","original_commit_id":"b0224e5abce81ed7d79dfe4e6ee17655e29b32ac","user":{"login":"lboudard","id":1303480,"avatar_url":"https://avatars1.githubusercontent.com/u/1303480?v=4","gravatar_id":"","url":"https://api.github.com/users/lboudard","html_url":"https://github.com/lboudard","followers_url":"https://api.github.com/users/lboudard/followers","following_url":"https://api.github.com/users/lboudard/following{/other_user}","gists_url":"https://api.github.com/users/lboudard/gists{/gist_id}","starred_url":"https://api.github.com/users/lboudard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lboudard/subscriptions","organizations_url":"https://api.github.com/users/lboudard/orgs","repos_url":"https://api.github.com/users/lboudard/repos","events_url":"https://api.github.com/users/lboudard/events{/privacy}","received_events_url":"https://api.github.com/users/lboudard/received_events","type":"User","site_admin":false},"body":"so there is possibly an infinite retry;).... also, seems that shard_iterator init is a bit duplicated and I wouldn't re-initialize it in all cases.","created_at":"2017-08-11T09:14:27Z","updated_at":"2017-08-11T09:21:38Z","html_url":"https://github.com/artefactory/artefact.connectors/pull/71#discussion_r132644634","pull_request_url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71","_links":{"self":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/comments/132644634"},"html":{"href":"https://github.com/artefactory/artefact.connectors/pull/71#discussion_r132644634"},"pull_request":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71"}}},"pull_request":{"url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71","id":128646496,"html_url":"https://github.com/artefactory/artefact.connectors/pull/71","diff_url":"https://github.com/artefactory/artefact.connectors/pull/71.diff","patch_url":"https://github.com/artefactory/artefact.connectors/pull/71.patch","issue_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues/71","number":71,"state":"open","locked":false,"title":"Kinesis","user":{"login":"lboudard","id":1303480,"avatar_url":"https://avatars1.githubusercontent.com/u/1303480?v=4","gravatar_id":"","url":"https://api.github.com/users/lboudard","html_url":"https://github.com/lboudard","followers_url":"https://api.github.com/users/lboudard/followers","following_url":"https://api.github.com/users/lboudard/following{/other_user}","gists_url":"https://api.github.com/users/lboudard/gists{/gist_id}","starred_url":"https://api.github.com/users/lboudard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lboudard/subscriptions","organizations_url":"https://api.github.com/users/lboudard/orgs","repos_url":"https://api.github.com/users/lboudard/repos","events_url":"https://api.github.com/users/lboudard/events{/privacy}","received_events_url":"https://api.github.com/users/lboudard/received_events","type":"User","site_admin":false},"body":"","created_at":"2017-07-03T14:57:25Z","updated_at":"2017-08-11T09:21:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fd55c68e323c59da91e6a4717c73a026586b686c","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71/commits","review_comments_url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71/comments","review_comment_url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/comments{/number}","comments_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues/71/comments","statuses_url":"https://api.github.com/repos/artefactory/artefact.connectors/statuses/b0224e5abce81ed7d79dfe4e6ee17655e29b32ac","head":{"label":"artefactory:kinesis","ref":"kinesis","sha":"b0224e5abce81ed7d79dfe4e6ee17655e29b32ac","user":{"login":"artefactory","id":16650088,"avatar_url":"https://avatars0.githubusercontent.com/u/16650088?v=4","gravatar_id":"","url":"https://api.github.com/users/artefactory","html_url":"https://github.com/artefactory","followers_url":"https://api.github.com/users/artefactory/followers","following_url":"https://api.github.com/users/artefactory/following{/other_user}","gists_url":"https://api.github.com/users/artefactory/gists{/gist_id}","starred_url":"https://api.github.com/users/artefactory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artefactory/subscriptions","organizations_url":"https://api.github.com/users/artefactory/orgs","repos_url":"https://api.github.com/users/artefactory/repos","events_url":"https://api.github.com/users/artefactory/events{/privacy}","received_events_url":"https://api.github.com/users/artefactory/received_events","type":"Organization","site_admin":false},"repo":{"id":48113228,"name":"artefact.connectors","full_name":"artefactory/artefact.connectors","owner":{"login":"artefactory","id":16650088,"avatar_url":"https://avatars0.githubusercontent.com/u/16650088?v=4","gravatar_id":"","url":"https://api.github.com/users/artefactory","html_url":"https://github.com/artefactory","followers_url":"https://api.github.com/users/artefactory/followers","following_url":"https://api.github.com/users/artefactory/following{/other_user}","gists_url":"https://api.github.com/users/artefactory/gists{/gist_id}","starred_url":"https://api.github.com/users/artefactory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artefactory/subscriptions","organizations_url":"https://api.github.com/users/artefactory/orgs","repos_url":"https://api.github.com/users/artefactory/repos","events_url":"https://api.github.com/users/artefactory/events{/privacy}","received_events_url":"https://api.github.com/users/artefactory/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/artefactory/artefact.connectors","description":null,"fork":false,"url":"https://api.github.com/repos/artefactory/artefact.connectors","forks_url":"https://api.github.com/repos/artefactory/artefact.connectors/forks","keys_url":"https://api.github.com/repos/artefactory/artefact.connectors/keys{/key_id}","collaborators_url":"https://api.github.com/repos/artefactory/artefact.connectors/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/artefactory/artefact.connectors/teams","hooks_url":"https://api.github.com/repos/artefactory/artefact.connectors/hooks","issue_events_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues/events{/number}","events_url":"https://api.github.com/repos/artefactory/artefact.connectors/events","assignees_url":"https://api.github.com/repos/artefactory/artefact.connectors/assignees{/user}","branches_url":"https://api.github.com/repos/artefactory/artefact.connectors/branches{/branch}","tags_url":"https://api.github.com/repos/artefactory/artefact.connectors/tags","blobs_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/refs{/sha}","trees_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/trees{/sha}","statuses_url":"https://api.github.com/repos/artefactory/artefact.connectors/statuses/{sha}","languages_url":"https://api.github.com/repos/artefactory/artefact.connectors/languages","stargazers_url":"https://api.github.com/repos/artefactory/artefact.connectors/stargazers","contributors_url":"https://api.github.com/repos/artefactory/artefact.connectors/contributors","subscribers_url":"https://api.github.com/repos/artefactory/artefact.connectors/subscribers","subscription_url":"https://api.github.com/repos/artefactory/artefact.connectors/subscription","commits_url":"https://api.github.com/repos/artefactory/artefact.connectors/commits{/sha}","git_commits_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/commits{/sha}","comments_url":"https://api.github.com/repos/artefactory/artefact.connectors/comments{/number}","issue_comment_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues/comments{/number}","contents_url":"https://api.github.com/repos/artefactory/artefact.connectors/contents/{+path}","compare_url":"https://api.github.com/repos/artefactory/artefact.connectors/compare/{base}...{head}","merges_url":"https://api.github.com/repos/artefactory/artefact.connectors/merges","archive_url":"https://api.github.com/repos/artefactory/artefact.connectors/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/artefactory/artefact.connectors/downloads","issues_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues{/number}","pulls_url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls{/number}","milestones_url":"https://api.github.com/repos/artefactory/artefact.connectors/milestones{/number}","notifications_url":"https://api.github.com/repos/artefactory/artefact.connectors/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/artefactory/artefact.connectors/labels{/name}","releases_url":"https://api.github.com/repos/artefactory/artefact.connectors/releases{/id}","deployments_url":"https://api.github.com/repos/artefactory/artefact.connectors/deployments","created_at":"2015-12-16T13:53:54Z","updated_at":"2016-04-01T15:54:36Z","pushed_at":"2017-08-10T11:39:35Z","git_url":"git://github.com/artefactory/artefact.connectors.git","ssh_url":"git@github.com:artefactory/artefact.connectors.git","clone_url":"https://github.com/artefactory/artefact.connectors.git","svn_url":"https://github.com/artefactory/artefact.connectors","homepage":null,"size":7211,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":4,"forks":0,"open_issues":4,"watchers":0,"default_branch":"develop"}},"base":{"label":"artefactory:develop","ref":"develop","sha":"8492d35f00ed73a4d8d3835ef289e16c29a49da2","user":{"login":"artefactory","id":16650088,"avatar_url":"https://avatars0.githubusercontent.com/u/16650088?v=4","gravatar_id":"","url":"https://api.github.com/users/artefactory","html_url":"https://github.com/artefactory","followers_url":"https://api.github.com/users/artefactory/followers","following_url":"https://api.github.com/users/artefactory/following{/other_user}","gists_url":"https://api.github.com/users/artefactory/gists{/gist_id}","starred_url":"https://api.github.com/users/artefactory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artefactory/subscriptions","organizations_url":"https://api.github.com/users/artefactory/orgs","repos_url":"https://api.github.com/users/artefactory/repos","events_url":"https://api.github.com/users/artefactory/events{/privacy}","received_events_url":"https://api.github.com/users/artefactory/received_events","type":"Organization","site_admin":false},"repo":{"id":48113228,"name":"artefact.connectors","full_name":"artefactory/artefact.connectors","owner":{"login":"artefactory","id":16650088,"avatar_url":"https://avatars0.githubusercontent.com/u/16650088?v=4","gravatar_id":"","url":"https://api.github.com/users/artefactory","html_url":"https://github.com/artefactory","followers_url":"https://api.github.com/users/artefactory/followers","following_url":"https://api.github.com/users/artefactory/following{/other_user}","gists_url":"https://api.github.com/users/artefactory/gists{/gist_id}","starred_url":"https://api.github.com/users/artefactory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artefactory/subscriptions","organizations_url":"https://api.github.com/users/artefactory/orgs","repos_url":"https://api.github.com/users/artefactory/repos","events_url":"https://api.github.com/users/artefactory/events{/privacy}","received_events_url":"https://api.github.com/users/artefactory/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/artefactory/artefact.connectors","description":null,"fork":false,"url":"https://api.github.com/repos/artefactory/artefact.connectors","forks_url":"https://api.github.com/repos/artefactory/artefact.connectors/forks","keys_url":"https://api.github.com/repos/artefactory/artefact.connectors/keys{/key_id}","collaborators_url":"https://api.github.com/repos/artefactory/artefact.connectors/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/artefactory/artefact.connectors/teams","hooks_url":"https://api.github.com/repos/artefactory/artefact.connectors/hooks","issue_events_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues/events{/number}","events_url":"https://api.github.com/repos/artefactory/artefact.connectors/events","assignees_url":"https://api.github.com/repos/artefactory/artefact.connectors/assignees{/user}","branches_url":"https://api.github.com/repos/artefactory/artefact.connectors/branches{/branch}","tags_url":"https://api.github.com/repos/artefactory/artefact.connectors/tags","blobs_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/refs{/sha}","trees_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/trees{/sha}","statuses_url":"https://api.github.com/repos/artefactory/artefact.connectors/statuses/{sha}","languages_url":"https://api.github.com/repos/artefactory/artefact.connectors/languages","stargazers_url":"https://api.github.com/repos/artefactory/artefact.connectors/stargazers","contributors_url":"https://api.github.com/repos/artefactory/artefact.connectors/contributors","subscribers_url":"https://api.github.com/repos/artefactory/artefact.connectors/subscribers","subscription_url":"https://api.github.com/repos/artefactory/artefact.connectors/subscription","commits_url":"https://api.github.com/repos/artefactory/artefact.connectors/commits{/sha}","git_commits_url":"https://api.github.com/repos/artefactory/artefact.connectors/git/commits{/sha}","comments_url":"https://api.github.com/repos/artefactory/artefact.connectors/comments{/number}","issue_comment_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues/comments{/number}","contents_url":"https://api.github.com/repos/artefactory/artefact.connectors/contents/{+path}","compare_url":"https://api.github.com/repos/artefactory/artefact.connectors/compare/{base}...{head}","merges_url":"https://api.github.com/repos/artefactory/artefact.connectors/merges","archive_url":"https://api.github.com/repos/artefactory/artefact.connectors/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/artefactory/artefact.connectors/downloads","issues_url":"https://api.github.com/repos/artefactory/artefact.connectors/issues{/number}","pulls_url":"https://api.github.com/repos/artefactory/artefact.connectors/pulls{/number}","milestones_url":"https://api.github.com/repos/artefactory/artefact.connectors/milestones{/number}","notifications_url":"https://api.github.com/repos/artefactory/artefact.connectors/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/artefactory/artefact.connectors/labels{/name}","releases_url":"https://api.github.com/repos/artefactory/artefact.connectors/releases{/id}","deployments_url":"https://api.github.com/repos/artefactory/artefact.connectors/deployments","created_at":"2015-12-16T13:53:54Z","updated_at":"2016-04-01T15:54:36Z","pushed_at":"2017-08-10T11:39:35Z","git_url":"git://github.com/artefactory/artefact.connectors.git","ssh_url":"git@github.com:artefactory/artefact.connectors.git","clone_url":"https://github.com/artefactory/artefact.connectors.git","svn_url":"https://github.com/artefactory/artefact.connectors","homepage":null,"size":7211,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":4,"forks":0,"open_issues":4,"watchers":0,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71"},"html":{"href":"https://github.com/artefactory/artefact.connectors/pull/71"},"issue":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/issues/71"},"comments":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/issues/71/comments"},"review_comments":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71/comments"},"review_comment":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/pulls/71/commits"},"statuses":{"href":"https://api.github.com/repos/artefactory/artefact.connectors/statuses/b0224e5abce81ed7d79dfe4e6ee17655e29b32ac"}}}}
{"actor":{"display_login":"lboudard"}}