{"action":"created","comment":{"url":"https://api.github.com/repos/release-engineering/assayist/pulls/comments/226247010","pull_request_review_id":166019507,"id":226247010,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNjI0NzAxMA==","diff_hunk":"@@ -44,3 +46,114 @@ def get_container_content_sources(build_id):\n         'internal_urls': internal_urls,\n         'upstream_urls': upstream_urls\n     }\n+\n+\n+def get_current_and_previous_versions(name, type_, version):\n+    \"\"\"\n+    Find the current and previous source locations.\n+\n+    :param str name: the canonical name of the component\n+    :param str type_: the canonical type of the component\n+    :param str version: the canonical version of the source location\n+    :return: a dictionary of all the previous source locations and the current source location\n+    :rtype: dict\n+    \"\"\"\n+    # TODO: Consider alternative names as well\n+    query = \"\"\"\n+        MATCH (:Component {{canonical_name: '{name}', canonical_type: '{type}'}})\n+            <-[:SOURCE_FOR]-(:SourceLocation {{canonical_version: '{version}'}})\n+            -[:SUPERSEDES*0..]->(sl:SourceLocation)\n+        RETURN sl\n+    \"\"\".format(name=name, type=type_, version=version)\n+    results, _ = neomodel.db.cypher_query(query)\n+    rv = []\n+    for result in results:\n+        rv.append(dict(result[0]))\n+    return rv\n+\n+\n+def get_container_built_with_sources(source_locations):\n+    \"\"\"\n+    Match container builds that used the input source locations to build the content in the image.\n+\n+    This means any container that:\n+    * embeds artifacts that were built with artifacts built from the input and related source\n+      locations\n+    * was built with a container that embeds artifacts that were built with the input and related\n+      source locations\n+\n+    :param list source_locations: a list of source location dictionaries to match against\n+    :return: a list of affected container build Koji IDs\n+    :rtype: list\n+    \"\"\"\n+    if not source_locations or not isinstance(source_locations, collections.Iterable):\n+        raise InvalidInput('The input must be a list of source locations')\n+\n+    # Get all the input source locations, then find the upstream or downstream source locations.\n+    # With that result, find all the source locations that embed the resulting source locations.\n+    # Then return the Neo4j IDs of the union of all the source locations in the query.\n+    query = \"\"\"\n+    // First get all the input source locations\n+    MATCH (input_sl:SourceLocation) WHERE input_sl.url IN [{0}]\n+    // Then find all the source locations that are upstream or downstream of the input source\n+    // locations recursively. The resulting `input_and_upstream_sl` variable has all the input\n+    // source locations and all the upstream or downstream source locations of the input source\n+    // locations.\n+    MATCH (input_sl)-[:UPSTREAM*0..]-(input_and_upstream_sl:SourceLocation)\n+    // Then find all the source locations that embed the source locations in\n+    // `input_and_upstream_sl` recursively. The resulting `input_upstream_and_embedded_sl`\n+    // variable will have the contents of the `input_and_upstream_sl` variable previously and\n+    // all the source locations that eventually embed those source locations.\n+    MATCH (input_and_upstream_sl)<-[:EMBEDS*0..]-(input_upstream_and_embedded_sl:SourceLocation)\n+    RETURN ID(input_upstream_and_embedded_sl)\n+    \"\"\".format(', '.join(repr(sl['url']) for sl in source_locations if 'url' in sl))\n+    results, _ = neomodel.db.cypher_query(query)\n+    # This should only be true if none of the input source locations are in the DB\n+    if not results:\n+        return []\n+    all_sl_ids = set([r[0] for r in results])\n+\n+    # Find all the artifacts that were built from the source locations, and those that embed them.\n+    # Then return the Neo4j IDs of the resulting artifacts.\n+    query = \"\"\"\n+    // First get all the input source locations\n+    MATCH (sl) WHERE ID(sl) IN [{0}]\n+    // Find all the artifacts that were built from the source locations, and all the artifacts that\n+    // embed those artifacts\n+    MATCH (sl)<-[:BUILT_FROM]-(:Build)-[:PRODUCED]->(:Artifact)<-[:EMBEDS*0..]-(artifact:Artifact)\n+    RETURN ID(artifact)\n+    \"\"\".format(', '.join(str(sl_id) for sl_id in all_sl_ids))\n+    results, _ = neomodel.db.cypher_query(query)\n+    affected_artifact_ids = set([r[0] for r in results])\n+\n+    # Find all the builds of container artifacts that were built from any of the containers in","path":"assayist/client/query.py","position":97,"original_position":97,"commit_id":"025242c3723b59270151273c5e87ebcfa2f069db","original_commit_id":"025242c3723b59270151273c5e87ebcfa2f069db","user":{"login":"twaugh","id":6985468,"node_id":"MDQ6VXNlcjY5ODU0Njg=","avatar_url":"https://avatars1.githubusercontent.com/u/6985468?v=4","gravatar_id":"","url":"https://api.github.com/users/twaugh","html_url":"https://github.com/twaugh","followers_url":"https://api.github.com/users/twaugh/followers","following_url":"https://api.github.com/users/twaugh/following{/other_user}","gists_url":"https://api.github.com/users/twaugh/gists{/gist_id}","starred_url":"https://api.github.com/users/twaugh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/twaugh/subscriptions","organizations_url":"https://api.github.com/users/twaugh/orgs","repos_url":"https://api.github.com/users/twaugh/repos","events_url":"https://api.github.com/users/twaugh/events{/privacy}","received_events_url":"https://api.github.com/users/twaugh/received_events","type":"User","site_admin":false},"body":"Should this read \"that were built with\" for clarity?","created_at":"2018-10-18T10:10:05Z","updated_at":"2018-10-18T10:10:05Z","html_url":"https://github.com/release-engineering/assayist/pull/17#discussion_r226247010","pull_request_url":"https://api.github.com/repos/release-engineering/assayist/pulls/17","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/release-engineering/assayist/pulls/comments/226247010"},"html":{"href":"https://github.com/release-engineering/assayist/pull/17#discussion_r226247010"},"pull_request":{"href":"https://api.github.com/repos/release-engineering/assayist/pulls/17"}}},"pull_request":{"url":"https://api.github.com/repos/release-engineering/assayist/pulls/17","id":221459081,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIxNDU5MDgx","html_url":"https://github.com/release-engineering/assayist/pull/17","diff_url":"https://github.com/release-engineering/assayist/pull/17.diff","patch_url":"https://github.com/release-engineering/assayist/pull/17.patch","issue_url":"https://api.github.com/repos/release-engineering/assayist/issues/17","number":17,"state":"open","locked":false,"title":"Add APIs to find container builds affected by buildroots containing a specific component","user":{"login":"mprahl","id":11711106,"node_id":"MDQ6VXNlcjExNzExMTA2","avatar_url":"https://avatars3.githubusercontent.com/u/11711106?v=4","gravatar_id":"","url":"https://api.github.com/users/mprahl","html_url":"https://github.com/mprahl","followers_url":"https://api.github.com/users/mprahl/followers","following_url":"https://api.github.com/users/mprahl/following{/other_user}","gists_url":"https://api.github.com/users/mprahl/gists{/gist_id}","starred_url":"https://api.github.com/users/mprahl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mprahl/subscriptions","organizations_url":"https://api.github.com/users/mprahl/orgs","repos_url":"https://api.github.com/users/mprahl/repos","events_url":"https://api.github.com/users/mprahl/events{/privacy}","received_events_url":"https://api.github.com/users/mprahl/received_events","type":"User","site_admin":false},"body":"This finds any container build that:\r\n* embeds artifacts that were built with artifacts built from the input and related source locations\r\n* was built with a container that embeds artifacts that were built with the input and related source locations","created_at":"2018-10-09T14:21:24Z","updated_at":"2018-10-18T10:10:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2a50b8240654443849a283eabc027e3ed314e9c6","assignee":null,"assignees":[],"requested_reviewers":[{"login":"jdcasey","id":65614,"node_id":"MDQ6VXNlcjY1NjE0","avatar_url":"https://avatars3.githubusercontent.com/u/65614?v=4","gravatar_id":"","url":"https://api.github.com/users/jdcasey","html_url":"https://github.com/jdcasey","followers_url":"https://api.github.com/users/jdcasey/followers","following_url":"https://api.github.com/users/jdcasey/following{/other_user}","gists_url":"https://api.github.com/users/jdcasey/gists{/gist_id}","starred_url":"https://api.github.com/users/jdcasey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jdcasey/subscriptions","organizations_url":"https://api.github.com/users/jdcasey/orgs","repos_url":"https://api.github.com/users/jdcasey/repos","events_url":"https://api.github.com/users/jdcasey/events{/privacy}","received_events_url":"https://api.github.com/users/jdcasey/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/release-engineering/assayist/pulls/17/commits","review_comments_url":"https://api.github.com/repos/release-engineering/assayist/pulls/17/comments","review_comment_url":"https://api.github.com/repos/release-engineering/assayist/pulls/comments{/number}","comments_url":"https://api.github.com/repos/release-engineering/assayist/issues/17/comments","statuses_url":"https://api.github.com/repos/release-engineering/assayist/statuses/025242c3723b59270151273c5e87ebcfa2f069db","head":{"label":"release-engineering:container-vulnerable-buildroot-api","ref":"container-vulnerable-buildroot-api","sha":"025242c3723b59270151273c5e87ebcfa2f069db","user":{"login":"release-engineering","id":9591189,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk1OTExODk=","avatar_url":"https://avatars3.githubusercontent.com/u/9591189?v=4","gravatar_id":"","url":"https://api.github.com/users/release-engineering","html_url":"https://github.com/release-engineering","followers_url":"https://api.github.com/users/release-engineering/followers","following_url":"https://api.github.com/users/release-engineering/following{/other_user}","gists_url":"https://api.github.com/users/release-engineering/gists{/gist_id}","starred_url":"https://api.github.com/users/release-engineering/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-engineering/subscriptions","organizations_url":"https://api.github.com/users/release-engineering/orgs","repos_url":"https://api.github.com/users/release-engineering/repos","events_url":"https://api.github.com/users/release-engineering/events{/privacy}","received_events_url":"https://api.github.com/users/release-engineering/received_events","type":"Organization","site_admin":false},"repo":{"id":145765558,"node_id":"MDEwOlJlcG9zaXRvcnkxNDU3NjU1NTg=","name":"assayist","full_name":"release-engineering/assayist","private":false,"owner":{"login":"release-engineering","id":9591189,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk1OTExODk=","avatar_url":"https://avatars3.githubusercontent.com/u/9591189?v=4","gravatar_id":"","url":"https://api.github.com/users/release-engineering","html_url":"https://github.com/release-engineering","followers_url":"https://api.github.com/users/release-engineering/followers","following_url":"https://api.github.com/users/release-engineering/following{/other_user}","gists_url":"https://api.github.com/users/release-engineering/gists{/gist_id}","starred_url":"https://api.github.com/users/release-engineering/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-engineering/subscriptions","organizations_url":"https://api.github.com/users/release-engineering/orgs","repos_url":"https://api.github.com/users/release-engineering/repos","events_url":"https://api.github.com/users/release-engineering/events{/privacy}","received_events_url":"https://api.github.com/users/release-engineering/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/release-engineering/assayist","description":"Application to determining composition of build outputs and containers in the product pipeline","fork":false,"url":"https://api.github.com/repos/release-engineering/assayist","forks_url":"https://api.github.com/repos/release-engineering/assayist/forks","keys_url":"https://api.github.com/repos/release-engineering/assayist/keys{/key_id}","collaborators_url":"https://api.github.com/repos/release-engineering/assayist/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/release-engineering/assayist/teams","hooks_url":"https://api.github.com/repos/release-engineering/assayist/hooks","issue_events_url":"https://api.github.com/repos/release-engineering/assayist/issues/events{/number}","events_url":"https://api.github.com/repos/release-engineering/assayist/events","assignees_url":"https://api.github.com/repos/release-engineering/assayist/assignees{/user}","branches_url":"https://api.github.com/repos/release-engineering/assayist/branches{/branch}","tags_url":"https://api.github.com/repos/release-engineering/assayist/tags","blobs_url":"https://api.github.com/repos/release-engineering/assayist/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/release-engineering/assayist/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/release-engineering/assayist/git/refs{/sha}","trees_url":"https://api.github.com/repos/release-engineering/assayist/git/trees{/sha}","statuses_url":"https://api.github.com/repos/release-engineering/assayist/statuses/{sha}","languages_url":"https://api.github.com/repos/release-engineering/assayist/languages","stargazers_url":"https://api.github.com/repos/release-engineering/assayist/stargazers","contributors_url":"https://api.github.com/repos/release-engineering/assayist/contributors","subscribers_url":"https://api.github.com/repos/release-engineering/assayist/subscribers","subscription_url":"https://api.github.com/repos/release-engineering/assayist/subscription","commits_url":"https://api.github.com/repos/release-engineering/assayist/commits{/sha}","git_commits_url":"https://api.github.com/repos/release-engineering/assayist/git/commits{/sha}","comments_url":"https://api.github.com/repos/release-engineering/assayist/comments{/number}","issue_comment_url":"https://api.github.com/repos/release-engineering/assayist/issues/comments{/number}","contents_url":"https://api.github.com/repos/release-engineering/assayist/contents/{+path}","compare_url":"https://api.github.com/repos/release-engineering/assayist/compare/{base}...{head}","merges_url":"https://api.github.com/repos/release-engineering/assayist/merges","archive_url":"https://api.github.com/repos/release-engineering/assayist/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/release-engineering/assayist/downloads","issues_url":"https://api.github.com/repos/release-engineering/assayist/issues{/number}","pulls_url":"https://api.github.com/repos/release-engineering/assayist/pulls{/number}","milestones_url":"https://api.github.com/repos/release-engineering/assayist/milestones{/number}","notifications_url":"https://api.github.com/repos/release-engineering/assayist/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/release-engineering/assayist/labels{/name}","releases_url":"https://api.github.com/repos/release-engineering/assayist/releases{/id}","deployments_url":"https://api.github.com/repos/release-engineering/assayist/deployments","created_at":"2018-08-22T21:37:18Z","updated_at":"2018-10-15T08:23:26Z","pushed_at":"2018-10-17T09:04:48Z","git_url":"git://github.com/release-engineering/assayist.git","ssh_url":"git@github.com:release-engineering/assayist.git","clone_url":"https://github.com/release-engineering/assayist.git","svn_url":"https://github.com/release-engineering/assayist","homepage":null,"size":120,"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":1,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":1,"open_issues":3,"watchers":0,"default_branch":"master"}},"base":{"label":"release-engineering:master","ref":"master","sha":"d88c981fc8a6dffcffb773c74703c84feb34b3e0","user":{"login":"release-engineering","id":9591189,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk1OTExODk=","avatar_url":"https://avatars3.githubusercontent.com/u/9591189?v=4","gravatar_id":"","url":"https://api.github.com/users/release-engineering","html_url":"https://github.com/release-engineering","followers_url":"https://api.github.com/users/release-engineering/followers","following_url":"https://api.github.com/users/release-engineering/following{/other_user}","gists_url":"https://api.github.com/users/release-engineering/gists{/gist_id}","starred_url":"https://api.github.com/users/release-engineering/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-engineering/subscriptions","organizations_url":"https://api.github.com/users/release-engineering/orgs","repos_url":"https://api.github.com/users/release-engineering/repos","events_url":"https://api.github.com/users/release-engineering/events{/privacy}","received_events_url":"https://api.github.com/users/release-engineering/received_events","type":"Organization","site_admin":false},"repo":{"id":145765558,"node_id":"MDEwOlJlcG9zaXRvcnkxNDU3NjU1NTg=","name":"assayist","full_name":"release-engineering/assayist","private":false,"owner":{"login":"release-engineering","id":9591189,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk1OTExODk=","avatar_url":"https://avatars3.githubusercontent.com/u/9591189?v=4","gravatar_id":"","url":"https://api.github.com/users/release-engineering","html_url":"https://github.com/release-engineering","followers_url":"https://api.github.com/users/release-engineering/followers","following_url":"https://api.github.com/users/release-engineering/following{/other_user}","gists_url":"https://api.github.com/users/release-engineering/gists{/gist_id}","starred_url":"https://api.github.com/users/release-engineering/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/release-engineering/subscriptions","organizations_url":"https://api.github.com/users/release-engineering/orgs","repos_url":"https://api.github.com/users/release-engineering/repos","events_url":"https://api.github.com/users/release-engineering/events{/privacy}","received_events_url":"https://api.github.com/users/release-engineering/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/release-engineering/assayist","description":"Application to determining composition of build outputs and containers in the product pipeline","fork":false,"url":"https://api.github.com/repos/release-engineering/assayist","forks_url":"https://api.github.com/repos/release-engineering/assayist/forks","keys_url":"https://api.github.com/repos/release-engineering/assayist/keys{/key_id}","collaborators_url":"https://api.github.com/repos/release-engineering/assayist/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/release-engineering/assayist/teams","hooks_url":"https://api.github.com/repos/release-engineering/assayist/hooks","issue_events_url":"https://api.github.com/repos/release-engineering/assayist/issues/events{/number}","events_url":"https://api.github.com/repos/release-engineering/assayist/events","assignees_url":"https://api.github.com/repos/release-engineering/assayist/assignees{/user}","branches_url":"https://api.github.com/repos/release-engineering/assayist/branches{/branch}","tags_url":"https://api.github.com/repos/release-engineering/assayist/tags","blobs_url":"https://api.github.com/repos/release-engineering/assayist/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/release-engineering/assayist/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/release-engineering/assayist/git/refs{/sha}","trees_url":"https://api.github.com/repos/release-engineering/assayist/git/trees{/sha}","statuses_url":"https://api.github.com/repos/release-engineering/assayist/statuses/{sha}","languages_url":"https://api.github.com/repos/release-engineering/assayist/languages","stargazers_url":"https://api.github.com/repos/release-engineering/assayist/stargazers","contributors_url":"https://api.github.com/repos/release-engineering/assayist/contributors","subscribers_url":"https://api.github.com/repos/release-engineering/assayist/subscribers","subscription_url":"https://api.github.com/repos/release-engineering/assayist/subscription","commits_url":"https://api.github.com/repos/release-engineering/assayist/commits{/sha}","git_commits_url":"https://api.github.com/repos/release-engineering/assayist/git/commits{/sha}","comments_url":"https://api.github.com/repos/release-engineering/assayist/comments{/number}","issue_comment_url":"https://api.github.com/repos/release-engineering/assayist/issues/comments{/number}","contents_url":"https://api.github.com/repos/release-engineering/assayist/contents/{+path}","compare_url":"https://api.github.com/repos/release-engineering/assayist/compare/{base}...{head}","merges_url":"https://api.github.com/repos/release-engineering/assayist/merges","archive_url":"https://api.github.com/repos/release-engineering/assayist/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/release-engineering/assayist/downloads","issues_url":"https://api.github.com/repos/release-engineering/assayist/issues{/number}","pulls_url":"https://api.github.com/repos/release-engineering/assayist/pulls{/number}","milestones_url":"https://api.github.com/repos/release-engineering/assayist/milestones{/number}","notifications_url":"https://api.github.com/repos/release-engineering/assayist/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/release-engineering/assayist/labels{/name}","releases_url":"https://api.github.com/repos/release-engineering/assayist/releases{/id}","deployments_url":"https://api.github.com/repos/release-engineering/assayist/deployments","created_at":"2018-08-22T21:37:18Z","updated_at":"2018-10-15T08:23:26Z","pushed_at":"2018-10-17T09:04:48Z","git_url":"git://github.com/release-engineering/assayist.git","ssh_url":"git@github.com:release-engineering/assayist.git","clone_url":"https://github.com/release-engineering/assayist.git","svn_url":"https://github.com/release-engineering/assayist","homepage":null,"size":120,"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":1,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":1,"open_issues":3,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/release-engineering/assayist/pulls/17"},"html":{"href":"https://github.com/release-engineering/assayist/pull/17"},"issue":{"href":"https://api.github.com/repos/release-engineering/assayist/issues/17"},"comments":{"href":"https://api.github.com/repos/release-engineering/assayist/issues/17/comments"},"review_comments":{"href":"https://api.github.com/repos/release-engineering/assayist/pulls/17/comments"},"review_comment":{"href":"https://api.github.com/repos/release-engineering/assayist/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/release-engineering/assayist/pulls/17/commits"},"statuses":{"href":"https://api.github.com/repos/release-engineering/assayist/statuses/025242c3723b59270151273c5e87ebcfa2f069db"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"twaugh"}}