diff --git a/src/plugins/github/__snapshots__/createGraph.test.js.snap b/src/plugins/github/__snapshots__/createGraph.test.js.snap index 2812955..ee336aa 100644 --- a/src/plugins/github/__snapshots__/createGraph.test.js.snap +++ b/src/plugins/github/__snapshots__/createGraph.test.js.snap @@ -974,6 +974,31 @@ Array [ "dstIndex": 28, "srcIndex": 16, }, + Object { + "address": Array [ + "sourcecred", + "github", + "MENTIONS_AUTHOR", + "4", + "PULL", + "sourcecred", + "example-github", + "5", + "6", + "COMMENT", + "PULL", + "sourcecred", + "example-github", + "5", + "396430464", + "3", + "USERLIKE", + "USER", + "wchargin", + ], + "dstIndex": 15, + "srcIndex": 25, + }, Object { "address": Array [ "sourcecred", diff --git a/src/plugins/github/__snapshots__/edges.test.js.snap b/src/plugins/github/__snapshots__/edges.test.js.snap index f50e89f..41b7424 100644 --- a/src/plugins/github/__snapshots__/edges.test.js.snap +++ b/src/plugins/github/__snapshots__/edges.test.js.snap @@ -72,6 +72,46 @@ Object { } `; +exports[`plugins/github/edges createEdge works for "mentionsAuthor" 1`] = ` +Object { + "addressParts": Array [ + "sourcecred", + "github", + "MENTIONS_AUTHOR", + "4", + "ISSUE", + "sourcecred", + "example-github", + "2", + "4", + "ISSUE", + "sourcecred", + "example-github", + "2", + "3", + "USERLIKE", + "USER", + "decentralion", + ], + "dstParts": Array [ + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "2", + ], + "srcParts": Array [ + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "2", + ], +} +`; + exports[`plugins/github/edges createEdge works for "mergedAs" 1`] = ` Object { "addressParts": Array [ diff --git a/src/plugins/github/createGraph.js b/src/plugins/github/createGraph.js index 3d2b74b..0d8412b 100644 --- a/src/plugins/github/createGraph.js +++ b/src/plugins/github/createGraph.js @@ -5,6 +5,7 @@ import * as GitNode from "../git/nodes"; import * as N from "./nodes"; import * as R from "./relationalView"; import {createEdge} from "./edges"; +import {findMentionsAuthorReferences} from "./heuristics/mentionsAuthorReference"; export function createGraph(view: R.RelationalView): Graph { const creator = new GraphCreator(); @@ -47,6 +48,10 @@ class GraphCreator { ); } } + + for (const mentionsAuthorReference of findMentionsAuthorReferences(view)) { + this.graph.addEdge(createEdge.mentionsAuthor(mentionsAuthorReference)); + } } addNode(addr: N.StructuredAddress) { diff --git a/src/plugins/github/edges.js b/src/plugins/github/edges.js index 770f930..f303606 100644 --- a/src/plugins/github/edges.js +++ b/src/plugins/github/edges.js @@ -8,6 +8,7 @@ import { } from "../../core/graph"; import * as GithubNode from "./nodes"; import * as GitNode from "../git/nodes"; +import type {MentionsAuthorReference} from "./heuristics/mentionsAuthorReference"; export opaque type RawAddress: EdgeAddressT = EdgeAddressT; @@ -15,6 +16,7 @@ export const AUTHORS_TYPE = "AUTHORS"; export const MERGED_AS_TYPE = "MERGED_AS"; export const HAS_PARENT_TYPE = "HAS_PARENT"; export const REFERENCES_TYPE = "REFERENCES"; +export const MENTIONS_AUTHOR_TYPE = "MENTIONS_AUTHOR"; const GITHUB_PREFIX = EdgeAddress.fromParts(["sourcecred", "github"]); function githubEdgeAddress(...parts: string[]): RawAddress { @@ -27,6 +29,7 @@ export const _Prefix = Object.freeze({ mergedAs: githubEdgeAddress(MERGED_AS_TYPE), references: githubEdgeAddress(REFERENCES_TYPE), hasParent: githubEdgeAddress(HAS_PARENT_TYPE), + mentionsAuthor: githubEdgeAddress(MENTIONS_AUTHOR_TYPE), }); export type AuthorsAddress = {| @@ -47,12 +50,17 @@ export type ReferencesAddress = {| +referrer: GithubNode.TextContentAddress, +referent: GithubNode.ReferentAddress, |}; +export type MentionsAuthorAddress = {| + +type: typeof MENTIONS_AUTHOR_TYPE, + +reference: MentionsAuthorReference, +|}; export type StructuredAddress = | AuthorsAddress | MergedAsAddress | HasParentAddress - | ReferencesAddress; + | ReferencesAddress + | MentionsAuthorAddress; export const createEdge = Object.freeze({ authors: ( @@ -87,6 +95,11 @@ export const createEdge = Object.freeze({ src: GithubNode.toRaw(referrer), dst: GithubNode.toRaw(referent), }), + mentionsAuthor: (reference: MentionsAuthorReference): Edge => ({ + address: toRaw({type: MENTIONS_AUTHOR_TYPE, reference}), + src: GithubNode.toRaw(reference.src), + dst: GithubNode.toRaw(reference.dst), + }), }); const NODE_PREFIX_LENGTH = NodeAddress.toParts(GithubNode._githubAddress()) @@ -185,6 +198,24 @@ export function fromRaw(x: RawAddress): StructuredAddress { ): any); return ({type: REFERENCES_TYPE, referrer, referent}: ReferencesAddress); } + case MENTIONS_AUTHOR_TYPE: { + const parts = multiLengthDecode(rest, fail); + if (parts.length !== 3) { + throw fail(); + } + const [srcParts, dstParts, whoParts] = parts; + const src: GithubNode.TextContentAddress = (GithubNode.fromRaw( + GithubNode._githubAddress(...srcParts) + ): any); + const dst: GithubNode.TextContentAddress = (GithubNode.fromRaw( + GithubNode._githubAddress(...dstParts) + ): any); + const who: GithubNode.UserlikeAddress = (GithubNode.fromRaw( + GithubNode._githubAddress(...whoParts) + ): any); + const reference = {src, dst, who}; + return {type: MENTIONS_AUTHOR_TYPE, reference}; + } default: throw fail(); } @@ -214,6 +245,13 @@ export function toRaw(x: StructuredAddress): RawAddress { ...lengthEncode(GithubNode.toRaw(x.referrer)), ...lengthEncode(GithubNode.toRaw(x.referent)) ); + case MENTIONS_AUTHOR_TYPE: + return EdgeAddress.append( + _Prefix.mentionsAuthor, + ...lengthEncode(GithubNode.toRaw(x.reference.src)), + ...lengthEncode(GithubNode.toRaw(x.reference.dst)), + ...lengthEncode(GithubNode.toRaw(x.reference.who)) + ); default: throw new Error((x.type: empty)); } diff --git a/src/plugins/github/edges.test.js b/src/plugins/github/edges.test.js index 9b8cb96..855ea3a 100644 --- a/src/plugins/github/edges.test.js +++ b/src/plugins/github/edges.test.js @@ -57,6 +57,12 @@ describe("plugins/github/edges", () => { createEdge.hasParent(nodeExamples.reviewComment(), nodeExamples.review()), references: () => createEdge.references(nodeExamples.issue(), nodeExamples.pull()), + mentionsAuthor: () => + createEdge.mentionsAuthor({ + src: nodeExamples.issue(), + dst: nodeExamples.issue(), + who: nodeExamples.user(), + }), }; describe("createEdge", () => { diff --git a/src/plugins/github/graphView.js b/src/plugins/github/graphView.js index 2ed6e5e..b00ad8b 100644 --- a/src/plugins/github/graphView.js +++ b/src/plugins/github/graphView.js @@ -233,6 +233,14 @@ export class GraphView { srcAccessor: (x) => GN.toRaw((x: any).author), dstAccessor: (x) => GN.toRaw((x: any).content), }, + [GE.MENTIONS_AUTHOR_TYPE]: { + homs: homProduct( + [GN._Prefix.issue, GN._Prefix.pull, GN._Prefix.comment], + [GN._Prefix.issue, GN._Prefix.pull, GN._Prefix.comment] + ), + srcAccessor: (x) => GN.toRaw((x: any).reference.src), + dstAccessor: (x) => GN.toRaw((x: any).reference.dst), + }, }; for (const edge of this._graph.edges({ diff --git a/src/plugins/github/pluginAdapter.js b/src/plugins/github/pluginAdapter.js index 3ba1476..6896e70 100644 --- a/src/plugins/github/pluginAdapter.js +++ b/src/plugins/github/pluginAdapter.js @@ -100,6 +100,14 @@ export class StaticPluginAdapter implements IStaticPluginAdapter { defaultBackwardWeight: 1 / 16, prefix: E._Prefix.references, }, + { + forwardName: "mentions author of", + backwardName: "has author mentioned by", + defaultForwardWeight: 1, + // TODO(#811): Probably change this to 0 + defaultBackwardWeight: 1 / 32, + prefix: E._Prefix.mentionsAuthor, + }, ]; } async load(assets: Assets, repo: Repo): Promise {