From 62d3c180ee9b1ebed8bf95bbf51dbbdf1a29816b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Mon, 17 Sep 2018 13:44:11 -0700 Subject: [PATCH] Add GitHub reactions to the graph (#846) * Define Reaction edges This adds support to `github/edges` for creating edges representing GitHub reactions. These edges are not actually added to the graph. Test plan: Unit tests * Add GitHub reactions to the graph This commit adds functional support for reactions in SourceCred. Only thumbs-up, heart, and hooray reactions are supported for now, as they are all unambiguously positive; adding support for negative reactions like thumbs-down will require some more thought. The reactions are added to the graph, and new edge types have been added to the UI. Test plan: The `graphView` class has been updated to do invariant checking for the reaction edges, including that the unsupported reaction types like "THUMBS_DOWN" aren't added to the graph. I've tested this feature by downloading data for a large repository (ipfs/go-ipfs). The reaction edges appear and transfer cred reasonably. The edge types are displayed in the weight config appropriately. Builds on #839, #840, and #845. --- CHANGELOG.md | 1 + .../__snapshots__/createGraph.test.js.snap | 236 ++++++++++++++++++ src/plugins/github/createGraph.js | 17 ++ src/plugins/github/graphView.js | 31 +++ src/plugins/github/graphView.test.js | 8 + src/plugins/github/pluginAdapter.js | 24 ++ 6 files changed, 317 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b32e614..b452086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [Unreleased] +- Add GitHub reactions to the graph (#846) - Detect references to commits (#833) - Detect references in commit messages (#829) - Add commit authorship to the graph (#826) diff --git a/src/plugins/github/__snapshots__/createGraph.test.js.snap b/src/plugins/github/__snapshots__/createGraph.test.js.snap index bdbae46..e28c584 100644 --- a/src/plugins/github/__snapshots__/createGraph.test.js.snap +++ b/src/plugins/github/__snapshots__/createGraph.test.js.snap @@ -1541,6 +1541,242 @@ Array [ "dstIndex": 2, "srcIndex": 36, }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "HEART", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "1", + ], + "dstIndex": 25, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "HEART", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "13", + ], + "dstIndex": 29, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "HEART", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "PULL", + "sourcecred", + "example-github", + "9", + ], + "dstIndex": 37, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "HEART", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "8", + "sourcecred", + "github", + "COMMENT", + "PULL", + "sourcecred", + "example-github", + "5", + "396430464", + ], + "dstIndex": 23, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "HOORAY", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "13", + ], + "dstIndex": 29, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "HOORAY", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "8", + "sourcecred", + "github", + "COMMENT", + "ISSUE", + "sourcecred", + "example-github", + "11", + "420813206", + ], + "dstIndex": 8, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "THUMBS_UP", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "12", + ], + "dstIndex": 28, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "THUMBS_UP", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "ISSUE", + "sourcecred", + "example-github", + "13", + ], + "dstIndex": 29, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "THUMBS_UP", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "6", + "sourcecred", + "github", + "PULL", + "sourcecred", + "example-github", + "9", + ], + "dstIndex": 37, + "srcIndex": 42, + }, + Object { + "address": Array [ + "sourcecred", + "github", + "REACTS", + "THUMBS_UP", + "5", + "sourcecred", + "github", + "USERLIKE", + "USER", + "decentralion", + "8", + "sourcecred", + "github", + "COMMENT", + "ISSUE", + "sourcecred", + "example-github", + "11", + "420813206", + ], + "dstIndex": 8, + "srcIndex": 42, + }, Object { "address": Array [ "sourcecred", diff --git a/src/plugins/github/createGraph.js b/src/plugins/github/createGraph.js index d6f68cc..2f3cc9a 100644 --- a/src/plugins/github/createGraph.js +++ b/src/plugins/github/createGraph.js @@ -6,6 +6,8 @@ import * as N from "./nodes"; import * as R from "./relationalView"; import {createEdge} from "./edges"; import {findMentionsAuthorReferences} from "./heuristics/mentionsAuthorReference"; +// TODO(@decentralion): Opportunity to reduce bundle size +import {Reactions} from "./graphql"; export function createGraph(view: R.RelationalView): Graph { const creator = new GraphCreator(); @@ -49,6 +51,21 @@ class GraphCreator { } } + for (const reactable of view.reactableEntities()) { + for (const {content, user} of reactable.reactions()) { + // We only support unambiguously positive reactions for now + if ( + content === Reactions.THUMBS_UP || + content === Reactions.HEART || + content === Reactions.HOORAY + ) { + this.graph.addEdge( + createEdge.reacts(content, user, reactable.address()) + ); + } + } + } + for (const mentionsAuthorReference of findMentionsAuthorReferences(view)) { this.graph.addEdge(createEdge.mentionsAuthor(mentionsAuthorReference)); } diff --git a/src/plugins/github/graphView.js b/src/plugins/github/graphView.js index 11a7cd0..d547115 100644 --- a/src/plugins/github/graphView.js +++ b/src/plugins/github/graphView.js @@ -7,6 +7,8 @@ import * as GN from "./nodes"; import * as GE from "./edges"; import * as GitNode from "../git/nodes"; +// TODO(@decentralion): Opportunity to reduce bundle size +import {Reactions} from "./graphql"; import { Graph, @@ -245,6 +247,14 @@ export class GraphView { srcAccessor: (x) => GN.toRaw((x: any).reference.src), dstAccessor: (x) => GN.toRaw((x: any).reference.dst), }, + [GE.REACTS_TYPE]: { + homs: homProduct( + [GN.Prefix.userlike], + [GN.Prefix.issue, GN.Prefix.pull, GN.Prefix.comment] + ), + srcAccessor: (x) => GN.toRaw((x: any).user), + dstAccessor: (x) => GN.toRaw((x: any).reactable), + }, }; for (const edge of this._graph.edges({ @@ -299,5 +309,26 @@ export class GraphView { ); } } + + for (const reactionEdge of this._graph.edges({ + addressPrefix: GE.Prefix.reacts, + srcPrefix: NodeAddress.empty, + dstPrefix: NodeAddress.empty, + })) { + const address: GE.RawAddress = (reactionEdge.address: any); + const reactsAddress: GE.ReactsAddress = (GE.fromRaw(address): any); + const {reactionType} = reactsAddress; + if ( + reactionType !== Reactions.THUMBS_UP && + reactionType !== Reactions.HEART && + reactionType !== Reactions.HOORAY + ) { + throw new Error( + `Invariant: Edge ${stringify( + reactsAddress + )} has unspported reactionType` + ); + } + } } } diff --git a/src/plugins/github/graphView.test.js b/src/plugins/github/graphView.test.js index dde8f88..b625a7d 100644 --- a/src/plugins/github/graphView.test.js +++ b/src/plugins/github/graphView.test.js @@ -339,6 +339,14 @@ describe("plugins/github/graphView", () => { expect(() => new GraphView(g)).toThrow("Invariant: Expected src"); }); }); + describe("reactions edges", () => { + it("must have a supported type", () => { + const unsupported = ["THUMBS_DOWN", "LAUGH", "CONFUSED"]; + for (const u of unsupported) { + failsForEdge(GE.createEdge.reacts(u, userlike, issue)); + } + }); + }); }); it("are properly re-entrant", () => { diff --git a/src/plugins/github/pluginAdapter.js b/src/plugins/github/pluginAdapter.js index 26f07df..dc3f093 100644 --- a/src/plugins/github/pluginAdapter.js +++ b/src/plugins/github/pluginAdapter.js @@ -108,6 +108,30 @@ export class StaticPluginAdapter implements IStaticPluginAdapter { defaultBackwardWeight: 1 / 32, prefix: E.Prefix.mentionsAuthor, }, + { + forwardName: "reacted ❤️ to", + backwardName: "got ❤️ from", + defaultForwardWeight: 2, + // TODO(#811): Probably change this to 0 + defaultBackwardWeight: 1 / 32, + prefix: E.Prefix.reactsHeart, + }, + { + forwardName: "reacted 👍 to", + backwardName: "got 👍 from", + defaultForwardWeight: 1, + // TODO(#811): Probably change this to 0 + defaultBackwardWeight: 1 / 32, + prefix: E.Prefix.reactsThumbsUp, + }, + { + forwardName: "reacted 🎉 to", + backwardName: "got 🎉 from", + defaultForwardWeight: 4, + // TODO(#811): Probably change this to 0 + defaultBackwardWeight: 1 / 32, + prefix: E.Prefix.reactsHooray, + }, ]; } async load(assets: Assets, repo: Repo): Promise {