{"action":"created","comment":{"url":"https://api.github.com/repos/release-depot/atkinson/pulls/comments/238450394","pull_request_review_id":180994148,"id":238450394,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzODQ1MDM5NA==","diff_hunk":"@@ -0,0 +1,308 @@\n+#! /usr/bin/env python\n+\"\"\" Interface with rpmreq to determine build dependencies \"\"\"\n+from __future__ import print_function\n+\n+import copy\n+import os\n+import stat\n+import logging\n+\n+from toolchest.rpm.utils import split_filename, componentize\n+\n+try:\n+    from rpmreq.actions import build_requires\n+    from rpmreq.query import Repo\n+except ImportError:\n+    def build_requires(filename, repos, **kwargs):  # NOQA\n+        # pylint: disable=unused-argument\n+        \"\"\"\n+        Stub build-requires\n+        rpmreq and, by extension, hawkey is required for deployment,\n+        but not for testing.\n+        Hawkey is part of libdnf, written in C, and not published\n+        to PyPI.\n+        \"\"\"\n+        if 'logger' in kwargs:\n+            kwargs['logger'].warn('build_requires: hawkey missing')\n+        return [], [], []\n+\n+    from collections import namedtuple\n+    Repo = namedtuple('Repo', ['id', 'url'])\n+\n+from atkinson.config.manager import ConfigManager\n+\n+\n+class DependencySet():\n+    \"\"\"\n+    Dependency Set generated from a source spec file and a given build tag.\n+    Includes: Met dependencies, dependencies with the wrong version,\n+              and missing dependencies.\n+\n+    Met dependencies:\n+        [ {'name', 'version', 'release', 'epoch', 'component'}, ... ]\n+                                                   ^ From source rpm name\n+        ('comparison' is included, too, but is always '==')\n+\n+    Unmet dependencies:\n+        [ {'name', 'version', 'release', 'epoch', 'comparison'}, ... ]\n+                                                   ^ >=, ==, >, if available\n+    Missing:\n+        [ {'name', 'version', 'release', 'epoch', 'comparison'}, ... ]\n+\n+    Config file format:\n+    ---\n+\n+    build_sources:\n+        build-version-1:\n+            - http://whatever-location-1/x86_64\n+            - http://whatever-location-2/x86_64\n+        build-version-2:\n+            - http://whatever-location-3/arch/\n+    \"\"\"\n+\n+    def __init__(self, **kwargs):\n+        if 'config' not in kwargs:\n+            # Don't need to keep this around\n+            args = {}\n+            if 'config_file' in kwargs:\n+                args['filenames'] = [kwargs['config_file']]\n+                del kwargs['config_file']\n+            else:\n+                args['filenames'] = ['build_sources.yml']\n+\n+            if 'config_path' in kwargs:\n+                args['paths'] = kwargs['config_path']\n+\n+            mgr = ConfigManager(**args)\n+            self.config = copy.copy(mgr.config)\n+        else:\n+            self.config = copy.copy(kwargs['config'])\n+            del kwargs['config']\n+\n+        self.met = []\n+        self.wrong_version = []\n+        self.unmet = []\n+\n+        # Allow caller to inject logging infrastructure, if desired.\n+        # Eventually, pass to rpmreq, although, we don't log anything\n+        # in this code directly.\n+        if 'logger' in kwargs:\n+            self.log = kwargs['logger']\n+            self.provided_log = True\n+        else:\n+            self.log = logging.getLogger(__name__)\n+            self.provided_log = False\n+\n+        if 'filename' in kwargs and 'version' in kwargs:\n+            filename = kwargs['filename']\n+            del kwargs['filename']\n+            version = kwargs['version']\n+            del kwargs['version']\n+            self.get_spec_build_deps(filename, version, **kwargs)\n+\n+    def get_spec_build_deps(self, filename, version, **kwargs):\n+        \"\"\"Call in to rpmreq and retrieve dependencies.\"\"\"\n+        st_info = os.stat(filename)\n+        if not stat.S_ISREG(st_info.st_mode):\n+            raise ValueError('{0} is not a regular file'.format(filename))\n+\n+        if not filename.endswith('.spec'):\n+            raise ValueError('{0} is not a spec file'.format(filename))\n+\n+        self.filename = filename\n+\n+        if not self.config or self.config == {} or \\\n+                'build_sources' not in self.config:\n+            return\n+\n+        srcs = self.config['build_sources']\n+        if version not in srcs:\n+            raise ValueError('Invalid version: {0}, expected one of {1}'.format(\n+                version,\n+                [ver for ver in srcs]))\n+\n+        repos = []\n+        for idx in range(len(srcs[version])):\n+            repos.append(Repo(str(idx), srcs[version][idx]))\n+\n+        # TODO: rpmreq supporting passdown of logger\n+        # e.g. if self.provided_log:\n+        #          (add logger=self.log to kwargs)\n+        met_deps, wrong_version, unmet_deps = \\\n+            build_requires(filename, repos)\n+\n+        self.met = transmogrify_met(met_deps)\n+        self.wrong_version = transmogrify_unmet(wrong_version)\n+        self.unmet = transmogrify_unmet(unmet_deps)\n+\n+        if 'logger' in kwargs:\n+            kwargs['logger'].info(str(self))\n+\n+    def __str__(self):\n+        \"\"\"Report useful information about ourself.\"\"\"\n+        fname = os.path.basename(self.filename)\n+        str_format = '{0}: {1} met, {2} incorrect, {3} missing'\n+        return str_format.format(fname, len(self.met), len(self.wrong_version), len(self.unmet))\n+\n+\n+def transmogrify_met(met_deps):\n+    \"\"\"\n+    Convert a Hawkey dependency into a simple dict\n+\n+    This is generally only used by DependencySet, but could be used\n+    elsewhere\n+    \"\"\"\n+    if not isinstance(met_deps, list):\n+        raise ValueError('met_deps is not a list')\n+    ret = []\n+    for dep in met_deps:\n+        info = {'component': componentize(dep.sourcerpm),\n+                'epoch': dep.epoch,\n+                'name': dep.name,\n+                'comparison': '==',   # This is the version provided\n+                'version': dep.version,\n+                'release': dep.release}\n+        ret.append(info)\n+    return ret\n+\n+\n+def transmogrify_unmet(unmet_deps):\n+    \"\"\"\n+    Convert list of string or repo.Depends to our simple dict format\n+\n+    This is generally only used by DependencySet, but could be used\n+    elsewhere\n+    \"\"\"\n+    if not isinstance(unmet_deps, list):\n+        raise ValueError('unmet_deps is not a list')\n+    ret = []\n+    for dep in unmet_deps:\n+        info = rpmdep_to_dep(str(dep))\n+        ret.append(info)\n+    return ret\n+\n+\n+def dep_to_tuple(dep):\n+    \"\"\"Convert one of our dependencies into an RPM-style tuple\"\"\"\n+    if not isinstance(dep, dict):\n+        raise ValueError('dep is not a dict')\n+    if 'version' not in dep:\n+        raise ValueError('Cannot convert {0}: version missing'.format(str(dep)))\n+    epoch = 0\n+    version = None\n+    release = None\n+    if 'epoch' in dep:\n+        epoch = int(dep['epoch'])\n+    version = dep['version']\n+    if 'release' in dep:\n+        release = dep['release']\n+    return (epoch, version, release)\n+\n+\n+def dep_to_nevr(dep):\n+    \"\"\"Convert one of our dependencies into an RPM NEVR string\"\"\"\n+    if not isinstance(dep, dict):\n+        raise ValueError('dep is not a dict')\n+    for field in ('name', 'version', 'release'):\n+        if field not in dep:\n+            raise ValueError('Cannot convert {0}: {1} missing'.format(str(dep), field))\n+    ret = dep['name']\n+    ret = ret + '-'\n+    if 'epoch' in dep and dep['epoch'] not in ('0', 0, ''):\n+        ret = ret + str(dep['epoch']) + ':'\n+    ret = ret + str(dep['version'])\n+    ret = ret + '-' + dep['release']\n+    return ret\n+\n+\n+def dep_to_rpmdep(dep):\n+    \"\"\"Convert a dependency into an RPM dependency string\"\"\"\n+    if 'comparison' not in dep:\n+        return dep['name']\n+    ret = '{0} {1} '.format(dep['name'], dep['comparison'])\n+    if 'epoch' in dep and dep['epoch'] not in ('', 0, '0'):\n+        ret = ret + '{0}:'.format(dep['epoch'])\n+    ret = ret + '{0}'.format(dep['version'])\n+    if 'release' in dep and dep['release'] != '':\n+        ret = ret + '-{0}'.format(dep['release'])\n+    return ret\n+\n+\n+def rpmdep_to_dep(dep):\n+    \"\"\"Convert a RPM style dependency into a simple dict\"\"\"\n+    vals = dep.split(' ')\n+    if len(vals) == 1:\n+        return {'name': vals[0]}\n+    if len(vals) != 3:\n+        raise ValueError('Could not parse: \\\"' + dep + '\\\"')\n+    ret = {'name': vals[0],\n+           'comparison': vals[1]}\n+    evr = vals[2].split('-')\n+    if len(evr) > 2:\n+        raise ValueError('Could not parse: \\\"' + dep + '\\\"')\n+\n+    if len(evr) == 2:\n+        ret['release'] = evr[1]\n+        if ret['release'] == 'None':\n+            del ret['release']\n+\n+    if ':' in evr[0]:\n+        e_v = evr[0].split(':')\n+        ret['epoch'] = int(e_v[0])\n+        if ret['epoch'] == '0':\n+            del ret['epoch']\n+        ret['version'] = e_v[1]\n+    else:\n+        ret['version'] = evr[0]\n+\n+    return ret\n+\n+\n+def nevr_to_dep(dep):\n+    \"\"\"Convert a RPM NEVR string to a simple dict\"\"\"\n+    (name, version, release, epoch, _) = split_filename(dep)\n+    ret = {}\n+\n+    if name == '':\n+        raise ValueError('Could not parse: \\\"' + dep + '\\\"')\n+\n+    ret['name'] = name\n+    ret['version'] = version\n+    ret['comparison'] = '=='\n+    if epoch not in ('', 0, '0'):\n+        ret['epoch'] = int(epoch)\n+    if release != 'None' and release is not None:\n+        ret['release'] = release\n+\n+    return ret\n+\n+\n+def _main(argv):","path":"atkinson/pungi/depends.py","position":280,"original_position":280,"commit_id":"6fb8fab9f274acbbfe4e760fe6b31725f8d325bb","original_commit_id":"6fb8fab9f274acbbfe4e760fe6b31725f8d325bb","user":{"login":"fuzzball81","id":1987931,"node_id":"MDQ6VXNlcjE5ODc5MzE=","avatar_url":"https://avatars1.githubusercontent.com/u/1987931?v=4","gravatar_id":"","url":"https://api.github.com/users/fuzzball81","html_url":"https://github.com/fuzzball81","followers_url":"https://api.github.com/users/fuzzball81/followers","following_url":"https://api.github.com/users/fuzzball81/following{/other_user}","gists_url":"https://api.github.com/users/fuzzball81/gists{/gist_id}","starred_url":"https://api.github.com/users/fuzzball81/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fuzzball81/subscriptions","organizations_url":"https://api.github.com/users/fuzzball81/orgs","repos_url":"https://api.github.com/users/fuzzball81/repos","events_url":"https://api.github.com/users/fuzzball81/events{/privacy}","received_events_url":"https://api.github.com/users/fuzzball81/received_events","type":"User","site_admin":false},"body":"At some point we should remove this. But that can be at a later time when we have more of the runner infrastructure setup. We could however pull this out to a contrib or manual test area that just calls this module.","created_at":"2018-12-03T21:48:30Z","updated_at":"2018-12-03T21:50:00Z","html_url":"https://github.com/release-depot/atkinson/pull/13#discussion_r238450394","pull_request_url":"https://api.github.com/repos/release-depot/atkinson/pulls/13","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/release-depot/atkinson/pulls/comments/238450394"},"html":{"href":"https://github.com/release-depot/atkinson/pull/13#discussion_r238450394"},"pull_request":{"href":"https://api.github.com/repos/release-depot/atkinson/pulls/13"}}},"pull_request":{"url":"https://api.github.com/repos/release-depot/atkinson/pulls/13","id":234742232,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM0NzQyMjMy","html_url":"https://github.com/release-depot/atkinson/pull/13","diff_url":"https://github.com/release-depot/atkinson/pull/13.diff","patch_url":"https://github.com/release-depot/atkinson/pull/13.patch","issue_url":"https://api.github.com/repos/release-depot/atkinson/issues/13","number":13,"state":"open","locked":false,"title":"Add initial dependency loader (Hawkey based)","user":{"login":"lhh","id":700214,"node_id":"MDQ6VXNlcjcwMDIxNA==","avatar_url":"https://avatars2.githubusercontent.com/u/700214?v=4","gravatar_id":"","url":"https://api.github.com/users/lhh","html_url":"https://github.com/lhh","followers_url":"https://api.github.com/users/lhh/followers","following_url":"https://api.github.com/users/lhh/following{/other_user}","gists_url":"https://api.github.com/users/lhh/gists{/gist_id}","starred_url":"https://api.github.com/users/lhh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lhh/subscriptions","organizations_url":"https://api.github.com/users/lhh/orgs","repos_url":"https://api.github.com/users/lhh/repos","events_url":"https://api.github.com/users/lhh/events{/privacy}","received_events_url":"https://api.github.com/users/lhh/received_events","type":"User","site_admin":false},"body":"I'm working on other bits as well for pungi integration, but, wanted to make sure I got the layouts right.\r\n\r\nThis uses Hawkey to interface with libdnf and pull/parse package and repository metadata:\r\n\r\nhttps://github.com/rpm-software-management/libdnf/tree/master/python/hawkey","created_at":"2018-11-29T18:33:45Z","updated_at":"2018-12-03T21:50:00Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2deb05253cf5d6563d45f4ec276ba4504af6651b","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/release-depot/atkinson/pulls/13/commits","review_comments_url":"https://api.github.com/repos/release-depot/atkinson/pulls/13/comments","review_comment_url":"https://api.github.com/repos/release-depot/atkinson/pulls/comments{/number}","comments_url":"https://api.github.com/repos/release-depot/atkinson/issues/13/comments","statuses_url":"https://api.github.com/repos/release-depot/atkinson/statuses/6fb8fab9f274acbbfe4e760fe6b31725f8d325bb","head":{"label":"lhh:master","ref":"master","sha":"6fb8fab9f274acbbfe4e760fe6b31725f8d325bb","user":{"login":"lhh","id":700214,"node_id":"MDQ6VXNlcjcwMDIxNA==","avatar_url":"https://avatars2.githubusercontent.com/u/700214?v=4","gravatar_id":"","url":"https://api.github.com/users/lhh","html_url":"https://github.com/lhh","followers_url":"https://api.github.com/users/lhh/followers","following_url":"https://api.github.com/users/lhh/following{/other_user}","gists_url":"https://api.github.com/users/lhh/gists{/gist_id}","starred_url":"https://api.github.com/users/lhh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lhh/subscriptions","organizations_url":"https://api.github.com/users/lhh/orgs","repos_url":"https://api.github.com/users/lhh/repos","events_url":"https://api.github.com/users/lhh/events{/privacy}","received_events_url":"https://api.github.com/users/lhh/received_events","type":"User","site_admin":false},"repo":{"id":140747013,"node_id":"MDEwOlJlcG9zaXRvcnkxNDA3NDcwMTM=","name":"atkinson","full_name":"lhh/atkinson","private":false,"owner":{"login":"lhh","id":700214,"node_id":"MDQ6VXNlcjcwMDIxNA==","avatar_url":"https://avatars2.githubusercontent.com/u/700214?v=4","gravatar_id":"","url":"https://api.github.com/users/lhh","html_url":"https://github.com/lhh","followers_url":"https://api.github.com/users/lhh/followers","following_url":"https://api.github.com/users/lhh/following{/other_user}","gists_url":"https://api.github.com/users/lhh/gists{/gist_id}","starred_url":"https://api.github.com/users/lhh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lhh/subscriptions","organizations_url":"https://api.github.com/users/lhh/orgs","repos_url":"https://api.github.com/users/lhh/repos","events_url":"https://api.github.com/users/lhh/events{/privacy}","received_events_url":"https://api.github.com/users/lhh/received_events","type":"User","site_admin":false},"html_url":"https://github.com/lhh/atkinson","description":null,"fork":true,"url":"https://api.github.com/repos/lhh/atkinson","forks_url":"https://api.github.com/repos/lhh/atkinson/forks","keys_url":"https://api.github.com/repos/lhh/atkinson/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lhh/atkinson/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lhh/atkinson/teams","hooks_url":"https://api.github.com/repos/lhh/atkinson/hooks","issue_events_url":"https://api.github.com/repos/lhh/atkinson/issues/events{/number}","events_url":"https://api.github.com/repos/lhh/atkinson/events","assignees_url":"https://api.github.com/repos/lhh/atkinson/assignees{/user}","branches_url":"https://api.github.com/repos/lhh/atkinson/branches{/branch}","tags_url":"https://api.github.com/repos/lhh/atkinson/tags","blobs_url":"https://api.github.com/repos/lhh/atkinson/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lhh/atkinson/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lhh/atkinson/git/refs{/sha}","trees_url":"https://api.github.com/repos/lhh/atkinson/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lhh/atkinson/statuses/{sha}","languages_url":"https://api.github.com/repos/lhh/atkinson/languages","stargazers_url":"https://api.github.com/repos/lhh/atkinson/stargazers","contributors_url":"https://api.github.com/repos/lhh/atkinson/contributors","subscribers_url":"https://api.github.com/repos/lhh/atkinson/subscribers","subscription_url":"https://api.github.com/repos/lhh/atkinson/subscription","commits_url":"https://api.github.com/repos/lhh/atkinson/commits{/sha}","git_commits_url":"https://api.github.com/repos/lhh/atkinson/git/commits{/sha}","comments_url":"https://api.github.com/repos/lhh/atkinson/comments{/number}","issue_comment_url":"https://api.github.com/repos/lhh/atkinson/issues/comments{/number}","contents_url":"https://api.github.com/repos/lhh/atkinson/contents/{+path}","compare_url":"https://api.github.com/repos/lhh/atkinson/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lhh/atkinson/merges","archive_url":"https://api.github.com/repos/lhh/atkinson/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lhh/atkinson/downloads","issues_url":"https://api.github.com/repos/lhh/atkinson/issues{/number}","pulls_url":"https://api.github.com/repos/lhh/atkinson/pulls{/number}","milestones_url":"https://api.github.com/repos/lhh/atkinson/milestones{/number}","notifications_url":"https://api.github.com/repos/lhh/atkinson/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lhh/atkinson/labels{/name}","releases_url":"https://api.github.com/repos/lhh/atkinson/releases{/id}","deployments_url":"https://api.github.com/repos/lhh/atkinson/deployments","created_at":"2018-07-12T17:51:57Z","updated_at":"2018-11-29T19:30:59Z","pushed_at":"2018-11-29T19:30:57Z","git_url":"git://github.com/lhh/atkinson.git","ssh_url":"git@github.com:lhh/atkinson.git","clone_url":"https://github.com/lhh/atkinson.git","svn_url":"https://github.com/lhh/atkinson","homepage":null,"size":61,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"release-depot:master","ref":"master","sha":"4861d80981b74b1f436ad47d3e0698447b5724b9","user":{"login":"release-depot","id":33037928,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzMDM3OTI4","avatar_url":"https://avatars0.githubusercontent.com/u/33037928?v=4","gravatar_id":"","url":"https://api.github.com/users/release-depot","html_url":"https://github.com/release-depot","followers_url":"https://api.github.com/users/release-depot/followers","following_url":"https://api.github.com/users/release-depot/following{/other_user}","gists_url":"https://api.github.com/users/release-depot/gists{/gist_id}","starred_url":"https://api.github.com/users/release-depot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-depot/subscriptions","organizations_url":"https://api.github.com/users/release-depot/orgs","repos_url":"https://api.github.com/users/release-depot/repos","events_url":"https://api.github.com/users/release-depot/events{/privacy}","received_events_url":"https://api.github.com/users/release-depot/received_events","type":"Organization","site_admin":false},"repo":{"id":140580131,"node_id":"MDEwOlJlcG9zaXRvcnkxNDA1ODAxMzE=","name":"atkinson","full_name":"release-depot/atkinson","private":false,"owner":{"login":"release-depot","id":33037928,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMzMDM3OTI4","avatar_url":"https://avatars0.githubusercontent.com/u/33037928?v=4","gravatar_id":"","url":"https://api.github.com/users/release-depot","html_url":"https://github.com/release-depot","followers_url":"https://api.github.com/users/release-depot/followers","following_url":"https://api.github.com/users/release-depot/following{/other_user}","gists_url":"https://api.github.com/users/release-depot/gists{/gist_id}","starred_url":"https://api.github.com/users/release-depot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-depot/subscriptions","organizations_url":"https://api.github.com/users/release-depot/orgs","repos_url":"https://api.github.com/users/release-depot/repos","events_url":"https://api.github.com/users/release-depot/events{/privacy}","received_events_url":"https://api.github.com/users/release-depot/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/release-depot/atkinson","description":null,"fork":false,"url":"https://api.github.com/repos/release-depot/atkinson","forks_url":"https://api.github.com/repos/release-depot/atkinson/forks","keys_url":"https://api.github.com/repos/release-depot/atkinson/keys{/key_id}","collaborators_url":"https://api.github.com/repos/release-depot/atkinson/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/release-depot/atkinson/teams","hooks_url":"https://api.github.com/repos/release-depot/atkinson/hooks","issue_events_url":"https://api.github.com/repos/release-depot/atkinson/issues/events{/number}","events_url":"https://api.github.com/repos/release-depot/atkinson/events","assignees_url":"https://api.github.com/repos/release-depot/atkinson/assignees{/user}","branches_url":"https://api.github.com/repos/release-depot/atkinson/branches{/branch}","tags_url":"https://api.github.com/repos/release-depot/atkinson/tags","blobs_url":"https://api.github.com/repos/release-depot/atkinson/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/release-depot/atkinson/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/release-depot/atkinson/git/refs{/sha}","trees_url":"https://api.github.com/repos/release-depot/atkinson/git/trees{/sha}","statuses_url":"https://api.github.com/repos/release-depot/atkinson/statuses/{sha}","languages_url":"https://api.github.com/repos/release-depot/atkinson/languages","stargazers_url":"https://api.github.com/repos/release-depot/atkinson/stargazers","contributors_url":"https://api.github.com/repos/release-depot/atkinson/contributors","subscribers_url":"https://api.github.com/repos/release-depot/atkinson/subscribers","subscription_url":"https://api.github.com/repos/release-depot/atkinson/subscription","commits_url":"https://api.github.com/repos/release-depot/atkinson/commits{/sha}","git_commits_url":"https://api.github.com/repos/release-depot/atkinson/git/commits{/sha}","comments_url":"https://api.github.com/repos/release-depot/atkinson/comments{/number}","issue_comment_url":"https://api.github.com/repos/release-depot/atkinson/issues/comments{/number}","contents_url":"https://api.github.com/repos/release-depot/atkinson/contents/{+path}","compare_url":"https://api.github.com/repos/release-depot/atkinson/compare/{base}...{head}","merges_url":"https://api.github.com/repos/release-depot/atkinson/merges","archive_url":"https://api.github.com/repos/release-depot/atkinson/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/release-depot/atkinson/downloads","issues_url":"https://api.github.com/repos/release-depot/atkinson/issues{/number}","pulls_url":"https://api.github.com/repos/release-depot/atkinson/pulls{/number}","milestones_url":"https://api.github.com/repos/release-depot/atkinson/milestones{/number}","notifications_url":"https://api.github.com/repos/release-depot/atkinson/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/release-depot/atkinson/labels{/name}","releases_url":"https://api.github.com/repos/release-depot/atkinson/releases{/id}","deployments_url":"https://api.github.com/repos/release-depot/atkinson/deployments","created_at":"2018-07-11T13:36:49Z","updated_at":"2018-11-20T21:13:37Z","pushed_at":"2018-11-29T19:30:59Z","git_url":"git://github.com/release-depot/atkinson.git","ssh_url":"git@github.com:release-depot/atkinson.git","clone_url":"https://github.com/release-depot/atkinson.git","svn_url":"https://github.com/release-depot/atkinson","homepage":null,"size":48,"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":3,"mirror_url":null,"archived":false,"open_issues_count":1,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":3,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/release-depot/atkinson/pulls/13"},"html":{"href":"https://github.com/release-depot/atkinson/pull/13"},"issue":{"href":"https://api.github.com/repos/release-depot/atkinson/issues/13"},"comments":{"href":"https://api.github.com/repos/release-depot/atkinson/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/release-depot/atkinson/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/release-depot/atkinson/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/release-depot/atkinson/pulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/release-depot/atkinson/statuses/6fb8fab9f274acbbfe4e760fe6b31725f8d325bb"}},"author_association":"NONE"}}
{"actor":{"display_login":"fuzzball81"}}