{"action":"created","comment":{"url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/comments/91999230","pull_request_review_id":12507174,"id":91999230,"diff_hunk":"@@ -106,239 +75,148 @@ def load_scan(json_input):\n     scan_results = json.loads(scan, object_pairs_hook=OrderedDict)\n \n     if not is_html_app_json:\n-        scan_results = scan_results['results']\n+        scan_results = scan_results['files']\n \n     return scan_results\n \n \n-def json_scan_to_csv(json_input, csv_output, strip=0):\n+def json_scan_to_csv(json_input, csv_output):\n     \"\"\"\n     Convert a scancode JSON output file to a nexb-toolkit-like CSV.\n     Optionally strip up to `strip` path segments from the location paths.\n     \"\"\"\n     scan_results = load_scan(json_input)\n-    rows = scan_as_list(scan_results, strip)\n-    headers = rows[0].keys()\n+    rows = list(flatten_scan(scan_results))\n+    headers = collect_header_keys(rows)\n     with open(csv_output, 'wb') as output:\n-        w = unicodecsv.writer(output)\n-        w.writerow(headers)\n+        w = unicodecsv.DictWriter(output, headers)\n+        w.writeheader()\n         for r in rows:\n-            w.writerow(r.values())\n+            w.writerow(r)\n \n \n-def scan_as_list(scan, strip=0):\n+def flatten_scan(scan):\n     \"\"\"\n-    Return a list of ordered dictionaries of key/values flattening the data and\n-    keying always by location, given a ScanCode scan results list.\n+    Yield ordered dictionaries of key/values flattening the data and\n+    keying always by path, given a ScanCode scan results list.\n     Optionally strip up to `strip` path segments from the location paths.\n     \"\"\"\n-    rows = []\n-\n-    # unique keys, but ordered\n-    keys = OrderedSet(['Resource'])\n-\n-    for entry in scan:\n-        location = entry['location']\n-        if strip:\n-            # do not keep leading slash but add it back afterwards. keep trailing slashes\n-            location = location.lstrip('/')\n-            splits = [s for s in location.split('/')]\n-            location = '/'.join(splits[strip:])\n-\n-        location = location.startswith('/')  and location or '/' + location\n-\n-        # collect rows for each section if present and each corresponding keys\n-\n-        \"\"\"\n-        {\n-          \"type\": \"file\",\n-          \"name\": \"test_patch.py\",\n-          \"extension\": \".py\",\n-          \"date\": \"2015-12-08\",\n-          \"size\": 72347,\n-          \"sha1\": \"bc1dc65b7d6b88709ce170291f93cd255bda8ffa\",\n-          \"md5\": \"25edeca9fbedd5b53e7e70af0ab0140a\",\n-          \"files_count\": null,\n-          \"mime_type\": \"text/x-python\",\n-          \"file_type\": \"Python script, ASCII text executable\",\n-          \"programming_language\": \"Python\",\n-          \"is_binary\": null,\n-          \"is_text\": true,\n-          \"is_archive\": null,\n-          \"is_media\": null,\n-          \"is_source\": true,\n-          \"is_script\": true\n-        }\n-        \"\"\"\n-\n-        for info in entry.get('infos', []):\n-            if info['type'] == 'directory':\n-                if not location.endswith('/'):\n-                    location = location + '/'\n-            inf = OrderedDict(Resource=location)\n-            for k, val in info.items():\n-                key = 'info_' + k\n-                inf[key] = val\n-                keys.add(key)\n-            rows.append(inf)\n-\n-        \"\"\"\n-      \"licenses\": [\n-        {\n-          \"key\": \"apache-2.0\",\n-          \"score\": 100.0,\n-          \"short_name\": \"Apache 2.0\",\n-          \"category\": \"Attribution\",\n-          \"owner\": \"Apache Software Foundation\",\n-          \"homepage_url\": \"http://www.apache.org/licenses/\",\n-          \"text_url\": \"http://www.apache.org/licenses/LICENSE-2.0\",\n-          \"dejacode_url\": \"https://enterprise.dejacode.com/license_library/Demo/apache-2.0/\",\n-          \"spdx_license_key\": \"Apache-2.0\",\n-          \"spdx_url\": \"http://spdx.org/licenses/Apache-2.0\",\n-          \"start_line\": 4,\n-          \"end_line\": 23\n-        },\n-        {\n-          \"key\": \"scancode-acknowledgment\",\n-          \"score\": 100.0,\n-          \"short_name\": \"ScanCode acknowledgment\",\n-          \"category\": \"Attribution\",\n-          \"owner\": \"nexB Inc.\",\n-          \"homepage_url\": \"https://github.com/nexB/scancode-toolkit/\",\n-          \"text_url\": \"\",\n-          \"dejacode_url\": \"https://enterprise.dejacode.com/license_library/Demo/scancode-acknowledgment/\",\n-          \"spdx_license_key\": \"\",\n-          \"spdx_url\": \"\",\n-          \"start_line\": 4,\n-          \"end_line\": 23\n-        }\n-      ],\n-        \"\"\"\n-        for licensing in entry.get('licenses', []):\n-            lic = OrderedDict(Resource=location)\n+\n+    for scanned_file in scan:\n+        path = scanned_file['path']\n+        path = path if path.startswith('/') else '/' + path\n+\n+        if scanned_file.get('type', '') == 'directory':\n+            if not path.endswith('/'):\n+                path = path + '/'\n+\n+        path = '/code' + path\n+\n+        file_info = OrderedDict(Resource=path)\n+        info_details = OrderedDict(((k, v) for k, v in scanned_file.items() if k != 'path' and not isinstance(v, list)))\n+        file_info.update(info_details)\n+        yield file_info\n+\n+        error_info = OrderedDict(Resource=path)\n+        # Scan errors are to be joined in a multi-line cell\n+        errors = [error for error in scanned_file.get('scan_errors', [])]\n+        error_info['scan_errors'] = '\\n'.join(errors)\n+        yield error_info\n+\n+        for licensing in scanned_file.get('licenses', []):\n+            lic = OrderedDict(Resource=path)\n             for k, val in licensing.items():\n+                if k == 'matched_rule':\n+                    continue\n                 if k not in ('start_line', 'end_line',):\n-                    k = 'license_' + k\n+                    k = 'license__' + k\n                 lic[k] = val\n-                keys.add(k)\n-            rows.append(lic)\n-\n-        \"\"\"\n-      \"copyrights\": [\n-        {\n-          \"statements\": [\n-            \"Copyright (c) 2015 nexB Inc.\"\n-          ],\n-          \"holders\": [\n-            \"nexB Inc.\"\n-          ],\n-          \"authors\": [],\n-          \"start_line\": 2,\n-          \"end_line\": 2\n-        }\n-      ],\n-        \"\"\"\n-        for copy_info in entry.get('copyrights', []):\n+            yield lic\n+\n+        for copy_info in scanned_file.get('copyrights', []):\n             start_line = copy_info['start_line']\n             end_line = copy_info['end_line']\n-            for cop in copy_info.get('statements', []):\n-                inf = OrderedDict(Resource=location)\n-                inf['copyright'] = cop\n-                inf['start_line'] = start_line\n-                inf['end_line'] = end_line\n-                rows.append(inf)\n-                keys.update(inf.keys())\n-\n-            for hold in copy_info.get('holders', []):\n-                inf = OrderedDict(Resource=location)\n-                inf['copyright_holder'] = hold\n-                inf['start_line'] = start_line\n-                inf['end_line'] = end_line\n-                rows.append(inf)\n-                keys.update(inf.keys())\n-\n-            for auth in copy_info.get('authors', []):\n-                inf = OrderedDict(Resource=location)\n-                inf['author'] = auth\n-                inf['start_line'] = start_line\n-                inf['end_line'] = end_line\n-                rows.append(inf)\n-                keys.update(inf.keys())\n-\n-        \"\"\"\n-        {\n-          \"type\": \"Nuget\",\n-          \"packaging\": \"archive\",\n-          \"primary_language\": null\n-        }\n-        \"\"\"\n-        for info in entry.get('packages', []):\n-            inf = OrderedDict(Resource=location)\n-            inf.update(('package_' + k, v or '') for k, v in info.items())\n-            keys.update(inf.keys())\n-            rows.append(inf)\n-\n-        for info in [promote_inner_keys(y) for x in entry.get('package_details', []) for y in flatten(x)]:\n-            inf = OrderedDict(Resource=location)\n-            inf.update(('package_details_' + k, v or '') for k, v in info.items())\n-            keys.update(inf.keys())\n-            rows.append(inf)\n-\n-        \"\"\"\n-        {\n-          \"url\": \"http://nexb.com/\",\n-          \"start_line\": 3,\n-          \"end_line\": 3\n-        },\n-        \"\"\"\n-        for url in entry.get('urls', []):\n-            url = OrderedDict(Resource=location)\n-            for k, val in url.items():\n-                url[k] = val\n-                keys.add(key)\n-            rows.append(url)\n-\n-        \"\"\"\n-        {\n-          \"email\": \"info@winimage.com\",\n-          \"start_line\": 1124,\n-          \"end_line\": 1124\n-        }\n-        \"\"\"\n-        for email in entry.get('emails', []):\n-            email = OrderedDict(Resource=location)\n+            for key, header in (('statements', 'copyright'), ('holders', 'copyright_holder'), ('authors', 'author')):\n+                for cop in copy_info.get(key, []):\n+                    inf = OrderedDict(Resource=path)\n+                    inf[header] = cop\n+                    inf['start_line'] = start_line\n+                    inf['end_line'] = end_line\n+                    yield inf\n+\n+        for email in scanned_file.get('emails', []):\n+            email_info = OrderedDict(Resource=path)\n             for k, val in email.items():\n-                email[k] = val\n-                keys.add(key)\n-            rows.append(email)\n-\n-\n-    # keys = ['Resource'] + [x for x in keys if x != 'Resource']\n-    all_rows = []\n-    for row in rows:\n-        d = OrderedDict()\n-        for k in keys.keys():\n-            d[k] = row.get(k, '')\n-        all_rows.append(d)\n+                email_info[k] = val\n+            yield email_info\n \n-    return all_rows\n+        for url in scanned_file.get('urls', []):\n+            url_info = OrderedDict(Resource=path)\n+            for k, val in url.items():\n+                url_info[k] = val\n+            yield url_info\n+\n+        excluded_columns = ('packaging',\n+                            'payload_type',\n+                            'keywords_doc_url',\n+                            'download_sha1',\n+                            'download_sha256',\n+                            'download_md5',\n+                            'code_view_url',\n+                            'vcs_tool',\n+                            'vcs_revision',\n+                            'license_expression')\n+\n+        for package in scanned_file.get('packages', []):\n+            pack = OrderedDict(Resource=path)\n+            for k, val in package.items():\n+                nk = 'package__' + k\n+                if not isinstance(val, (list, dict, OrderedDict)):\n+                    if k not in excluded_columns:\n+                        pack[nk] = val\n+                elif k in ('authors', 'download_urls', 'copyrights', 'asserted_licenses'):\n+                    if len(val) > 0:\n+                        if k == 'authors':\n+                            # We only want the first author\n+                            pack[nk] = val[0]['name']\n+                        if k == 'download_urls':\n+                            # We only want the first URL\n+                            pack[nk] = val[0]\n+                        if k == 'copyrights':\n+                            # All copyright statements are to be joined in a multi-line cell\n+                            pack[nk] = '\\n'.join(val)\n+                        if k == 'asserted_licenses':\n+                            # All license names are to be joined in a multi-line cell\n+                            licenses = [license_info['license'] for license_info in val]\n+                            pack[nk] = '\\n'.join(licenses)\n+                    else:\n+                        pack[nk] = ''\n+            yield pack\n+\n+\n+def collect_header_keys(scan_data):\n+    \"\"\"\n+    Return a list of keys collected from a list of scanned data dictionaries.\n+    \"\"\"\n+    keys = OrderedSet()","path":"etc/scripts/json2csv.py","position":366,"original_position":366,"commit_id":"4179047d0f7b731112ebba9424bd8c4deb0b6f05","original_commit_id":"4179047d0f7b731112ebba9424bd8c4deb0b6f05","user":{"login":"pombredanne","id":675997,"avatar_url":"https://avatars.githubusercontent.com/u/675997?v=3","gravatar_id":"","url":"https://api.github.com/users/pombredanne","html_url":"https://github.com/pombredanne","followers_url":"https://api.github.com/users/pombredanne/followers","following_url":"https://api.github.com/users/pombredanne/following{/other_user}","gists_url":"https://api.github.com/users/pombredanne/gists{/gist_id}","starred_url":"https://api.github.com/users/pombredanne/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pombredanne/subscriptions","organizations_url":"https://api.github.com/users/pombredanne/orgs","repos_url":"https://api.github.com/users/pombredanne/repos","events_url":"https://api.github.com/users/pombredanne/events{/privacy}","received_events_url":"https://api.github.com/users/pombredanne/received_events","type":"User","site_admin":false},"body":"If this is the only place where you use an OrderedSet you could get rid of the OrderedSet class and fold the bits of code from it in that function for simplicity ","created_at":"2016-12-12T17:43:06Z","updated_at":"2016-12-12T17:50:36Z","html_url":"https://github.com/nexB/scancode-toolkit/pull/399#discussion_r91999230","pull_request_url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399","_links":{"self":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/comments/91999230"},"html":{"href":"https://github.com/nexB/scancode-toolkit/pull/399#discussion_r91999230"},"pull_request":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399"}}},"pull_request":{"url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399","id":97395992,"html_url":"https://github.com/nexB/scancode-toolkit/pull/399","diff_url":"https://github.com/nexB/scancode-toolkit/pull/399.diff","patch_url":"https://github.com/nexB/scancode-toolkit/pull/399.patch","issue_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues/399","number":399,"state":"open","locked":false,"title":"#339 Upgrade json2csv.py","user":{"login":"JonoYang","id":6044800,"avatar_url":"https://avatars.githubusercontent.com/u/6044800?v=3","gravatar_id":"","url":"https://api.github.com/users/JonoYang","html_url":"https://github.com/JonoYang","followers_url":"https://api.github.com/users/JonoYang/followers","following_url":"https://api.github.com/users/JonoYang/following{/other_user}","gists_url":"https://api.github.com/users/JonoYang/gists{/gist_id}","starred_url":"https://api.github.com/users/JonoYang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JonoYang/subscriptions","organizations_url":"https://api.github.com/users/JonoYang/orgs","repos_url":"https://api.github.com/users/JonoYang/repos","events_url":"https://api.github.com/users/JonoYang/events{/privacy}","received_events_url":"https://api.github.com/users/JonoYang/received_events","type":"User","site_admin":false},"body":"`json2csv.py` has been updated to handle the latest ScanCode scan results. All options (copyrights, licenses, file info, packages, emails, URLs) are supported. New tests have been created to reflect the change in ScanCode output. ","created_at":"2016-12-09T23:05:19Z","updated_at":"2016-12-12T17:50:36Z","closed_at":null,"merged_at":null,"merge_commit_sha":"27160053b2a48400e8fa4838c49e5dfc0ea14445","assignee":{"login":"pombredanne","id":675997,"avatar_url":"https://avatars.githubusercontent.com/u/675997?v=3","gravatar_id":"","url":"https://api.github.com/users/pombredanne","html_url":"https://github.com/pombredanne","followers_url":"https://api.github.com/users/pombredanne/followers","following_url":"https://api.github.com/users/pombredanne/following{/other_user}","gists_url":"https://api.github.com/users/pombredanne/gists{/gist_id}","starred_url":"https://api.github.com/users/pombredanne/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pombredanne/subscriptions","organizations_url":"https://api.github.com/users/pombredanne/orgs","repos_url":"https://api.github.com/users/pombredanne/repos","events_url":"https://api.github.com/users/pombredanne/events{/privacy}","received_events_url":"https://api.github.com/users/pombredanne/received_events","type":"User","site_admin":false},"assignees":[{"login":"pombredanne","id":675997,"avatar_url":"https://avatars.githubusercontent.com/u/675997?v=3","gravatar_id":"","url":"https://api.github.com/users/pombredanne","html_url":"https://github.com/pombredanne","followers_url":"https://api.github.com/users/pombredanne/followers","following_url":"https://api.github.com/users/pombredanne/following{/other_user}","gists_url":"https://api.github.com/users/pombredanne/gists{/gist_id}","starred_url":"https://api.github.com/users/pombredanne/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pombredanne/subscriptions","organizations_url":"https://api.github.com/users/pombredanne/orgs","repos_url":"https://api.github.com/users/pombredanne/repos","events_url":"https://api.github.com/users/pombredanne/events{/privacy}","received_events_url":"https://api.github.com/users/pombredanne/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399/commits","review_comments_url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399/comments","review_comment_url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues/399/comments","statuses_url":"https://api.github.com/repos/nexB/scancode-toolkit/statuses/4179047d0f7b731112ebba9424bd8c4deb0b6f05","head":{"label":"nexB:339-upgrade-json2csv.py","ref":"339-upgrade-json2csv.py","sha":"4179047d0f7b731112ebba9424bd8c4deb0b6f05","user":{"login":"nexB","id":10789967,"avatar_url":"https://avatars.githubusercontent.com/u/10789967?v=3","gravatar_id":"","url":"https://api.github.com/users/nexB","html_url":"https://github.com/nexB","followers_url":"https://api.github.com/users/nexB/followers","following_url":"https://api.github.com/users/nexB/following{/other_user}","gists_url":"https://api.github.com/users/nexB/gists{/gist_id}","starred_url":"https://api.github.com/users/nexB/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nexB/subscriptions","organizations_url":"https://api.github.com/users/nexB/orgs","repos_url":"https://api.github.com/users/nexB/repos","events_url":"https://api.github.com/users/nexB/events{/privacy}","received_events_url":"https://api.github.com/users/nexB/received_events","type":"Organization","site_admin":false},"repo":{"id":38373338,"name":"scancode-toolkit","full_name":"nexB/scancode-toolkit","owner":{"login":"nexB","id":10789967,"avatar_url":"https://avatars.githubusercontent.com/u/10789967?v=3","gravatar_id":"","url":"https://api.github.com/users/nexB","html_url":"https://github.com/nexB","followers_url":"https://api.github.com/users/nexB/followers","following_url":"https://api.github.com/users/nexB/following{/other_user}","gists_url":"https://api.github.com/users/nexB/gists{/gist_id}","starred_url":"https://api.github.com/users/nexB/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nexB/subscriptions","organizations_url":"https://api.github.com/users/nexB/orgs","repos_url":"https://api.github.com/users/nexB/repos","events_url":"https://api.github.com/users/nexB/events{/privacy}","received_events_url":"https://api.github.com/users/nexB/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nexB/scancode-toolkit","description":"ScanCode is a tool to scan code and detect licenses, copyrights and more. This open source code scanning tool helps you find and discover open source and third-party components in your code.","fork":false,"url":"https://api.github.com/repos/nexB/scancode-toolkit","forks_url":"https://api.github.com/repos/nexB/scancode-toolkit/forks","keys_url":"https://api.github.com/repos/nexB/scancode-toolkit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nexB/scancode-toolkit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nexB/scancode-toolkit/teams","hooks_url":"https://api.github.com/repos/nexB/scancode-toolkit/hooks","issue_events_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues/events{/number}","events_url":"https://api.github.com/repos/nexB/scancode-toolkit/events","assignees_url":"https://api.github.com/repos/nexB/scancode-toolkit/assignees{/user}","branches_url":"https://api.github.com/repos/nexB/scancode-toolkit/branches{/branch}","tags_url":"https://api.github.com/repos/nexB/scancode-toolkit/tags","blobs_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/refs{/sha}","trees_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nexB/scancode-toolkit/statuses/{sha}","languages_url":"https://api.github.com/repos/nexB/scancode-toolkit/languages","stargazers_url":"https://api.github.com/repos/nexB/scancode-toolkit/stargazers","contributors_url":"https://api.github.com/repos/nexB/scancode-toolkit/contributors","subscribers_url":"https://api.github.com/repos/nexB/scancode-toolkit/subscribers","subscription_url":"https://api.github.com/repos/nexB/scancode-toolkit/subscription","commits_url":"https://api.github.com/repos/nexB/scancode-toolkit/commits{/sha}","git_commits_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/commits{/sha}","comments_url":"https://api.github.com/repos/nexB/scancode-toolkit/comments{/number}","issue_comment_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues/comments{/number}","contents_url":"https://api.github.com/repos/nexB/scancode-toolkit/contents/{+path}","compare_url":"https://api.github.com/repos/nexB/scancode-toolkit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nexB/scancode-toolkit/merges","archive_url":"https://api.github.com/repos/nexB/scancode-toolkit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nexB/scancode-toolkit/downloads","issues_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues{/number}","pulls_url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls{/number}","milestones_url":"https://api.github.com/repos/nexB/scancode-toolkit/milestones{/number}","notifications_url":"https://api.github.com/repos/nexB/scancode-toolkit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nexB/scancode-toolkit/labels{/name}","releases_url":"https://api.github.com/repos/nexB/scancode-toolkit/releases{/id}","deployments_url":"https://api.github.com/repos/nexB/scancode-toolkit/deployments","created_at":"2015-07-01T13:43:06Z","updated_at":"2016-11-30T15:34:15Z","pushed_at":"2016-12-09T23:05:19Z","git_url":"git://github.com/nexB/scancode-toolkit.git","ssh_url":"git@github.com:nexB/scancode-toolkit.git","clone_url":"https://github.com/nexB/scancode-toolkit.git","svn_url":"https://github.com/nexB/scancode-toolkit","homepage":"https://github.com/nexB/scancode-toolkit/releases/latest","size":145782,"stargazers_count":130,"watchers_count":130,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":25,"mirror_url":null,"open_issues_count":115,"forks":25,"open_issues":115,"watchers":130,"default_branch":"develop"}},"base":{"label":"nexB:develop","ref":"develop","sha":"0f530e55c848a239b68dbe2544ee5b78b3b3417f","user":{"login":"nexB","id":10789967,"avatar_url":"https://avatars.githubusercontent.com/u/10789967?v=3","gravatar_id":"","url":"https://api.github.com/users/nexB","html_url":"https://github.com/nexB","followers_url":"https://api.github.com/users/nexB/followers","following_url":"https://api.github.com/users/nexB/following{/other_user}","gists_url":"https://api.github.com/users/nexB/gists{/gist_id}","starred_url":"https://api.github.com/users/nexB/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nexB/subscriptions","organizations_url":"https://api.github.com/users/nexB/orgs","repos_url":"https://api.github.com/users/nexB/repos","events_url":"https://api.github.com/users/nexB/events{/privacy}","received_events_url":"https://api.github.com/users/nexB/received_events","type":"Organization","site_admin":false},"repo":{"id":38373338,"name":"scancode-toolkit","full_name":"nexB/scancode-toolkit","owner":{"login":"nexB","id":10789967,"avatar_url":"https://avatars.githubusercontent.com/u/10789967?v=3","gravatar_id":"","url":"https://api.github.com/users/nexB","html_url":"https://github.com/nexB","followers_url":"https://api.github.com/users/nexB/followers","following_url":"https://api.github.com/users/nexB/following{/other_user}","gists_url":"https://api.github.com/users/nexB/gists{/gist_id}","starred_url":"https://api.github.com/users/nexB/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nexB/subscriptions","organizations_url":"https://api.github.com/users/nexB/orgs","repos_url":"https://api.github.com/users/nexB/repos","events_url":"https://api.github.com/users/nexB/events{/privacy}","received_events_url":"https://api.github.com/users/nexB/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nexB/scancode-toolkit","description":"ScanCode is a tool to scan code and detect licenses, copyrights and more. This open source code scanning tool helps you find and discover open source and third-party components in your code.","fork":false,"url":"https://api.github.com/repos/nexB/scancode-toolkit","forks_url":"https://api.github.com/repos/nexB/scancode-toolkit/forks","keys_url":"https://api.github.com/repos/nexB/scancode-toolkit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nexB/scancode-toolkit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nexB/scancode-toolkit/teams","hooks_url":"https://api.github.com/repos/nexB/scancode-toolkit/hooks","issue_events_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues/events{/number}","events_url":"https://api.github.com/repos/nexB/scancode-toolkit/events","assignees_url":"https://api.github.com/repos/nexB/scancode-toolkit/assignees{/user}","branches_url":"https://api.github.com/repos/nexB/scancode-toolkit/branches{/branch}","tags_url":"https://api.github.com/repos/nexB/scancode-toolkit/tags","blobs_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/refs{/sha}","trees_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nexB/scancode-toolkit/statuses/{sha}","languages_url":"https://api.github.com/repos/nexB/scancode-toolkit/languages","stargazers_url":"https://api.github.com/repos/nexB/scancode-toolkit/stargazers","contributors_url":"https://api.github.com/repos/nexB/scancode-toolkit/contributors","subscribers_url":"https://api.github.com/repos/nexB/scancode-toolkit/subscribers","subscription_url":"https://api.github.com/repos/nexB/scancode-toolkit/subscription","commits_url":"https://api.github.com/repos/nexB/scancode-toolkit/commits{/sha}","git_commits_url":"https://api.github.com/repos/nexB/scancode-toolkit/git/commits{/sha}","comments_url":"https://api.github.com/repos/nexB/scancode-toolkit/comments{/number}","issue_comment_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues/comments{/number}","contents_url":"https://api.github.com/repos/nexB/scancode-toolkit/contents/{+path}","compare_url":"https://api.github.com/repos/nexB/scancode-toolkit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nexB/scancode-toolkit/merges","archive_url":"https://api.github.com/repos/nexB/scancode-toolkit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nexB/scancode-toolkit/downloads","issues_url":"https://api.github.com/repos/nexB/scancode-toolkit/issues{/number}","pulls_url":"https://api.github.com/repos/nexB/scancode-toolkit/pulls{/number}","milestones_url":"https://api.github.com/repos/nexB/scancode-toolkit/milestones{/number}","notifications_url":"https://api.github.com/repos/nexB/scancode-toolkit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nexB/scancode-toolkit/labels{/name}","releases_url":"https://api.github.com/repos/nexB/scancode-toolkit/releases{/id}","deployments_url":"https://api.github.com/repos/nexB/scancode-toolkit/deployments","created_at":"2015-07-01T13:43:06Z","updated_at":"2016-11-30T15:34:15Z","pushed_at":"2016-12-09T23:05:19Z","git_url":"git://github.com/nexB/scancode-toolkit.git","ssh_url":"git@github.com:nexB/scancode-toolkit.git","clone_url":"https://github.com/nexB/scancode-toolkit.git","svn_url":"https://github.com/nexB/scancode-toolkit","homepage":"https://github.com/nexB/scancode-toolkit/releases/latest","size":145782,"stargazers_count":130,"watchers_count":130,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":25,"mirror_url":null,"open_issues_count":115,"forks":25,"open_issues":115,"watchers":130,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399"},"html":{"href":"https://github.com/nexB/scancode-toolkit/pull/399"},"issue":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/issues/399"},"comments":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/issues/399/comments"},"review_comments":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399/comments"},"review_comment":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/pulls/399/commits"},"statuses":{"href":"https://api.github.com/repos/nexB/scancode-toolkit/statuses/4179047d0f7b731112ebba9424bd8c4deb0b6f05"}}}}
{"actor":{"display_login":"pombredanne"}}