mirror of
https://github.com/status-im/sourcecred.git
synced 2025-02-27 19:50:28 +00:00
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.
This commit is contained in:
parent
488c98c3e1
commit
62d3c180ee
@ -1,6 +1,7 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
- Add GitHub reactions to the graph (#846)
|
||||||
- Detect references to commits (#833)
|
- Detect references to commits (#833)
|
||||||
- Detect references in commit messages (#829)
|
- Detect references in commit messages (#829)
|
||||||
- Add commit authorship to the graph (#826)
|
- Add commit authorship to the graph (#826)
|
||||||
|
@ -1541,6 +1541,242 @@ Array [
|
|||||||
"dstIndex": 2,
|
"dstIndex": 2,
|
||||||
"srcIndex": 36,
|
"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 {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
"sourcecred",
|
"sourcecred",
|
||||||
|
@ -6,6 +6,8 @@ import * as N from "./nodes";
|
|||||||
import * as R from "./relationalView";
|
import * as R from "./relationalView";
|
||||||
import {createEdge} from "./edges";
|
import {createEdge} from "./edges";
|
||||||
import {findMentionsAuthorReferences} from "./heuristics/mentionsAuthorReference";
|
import {findMentionsAuthorReferences} from "./heuristics/mentionsAuthorReference";
|
||||||
|
// TODO(@decentralion): Opportunity to reduce bundle size
|
||||||
|
import {Reactions} from "./graphql";
|
||||||
|
|
||||||
export function createGraph(view: R.RelationalView): Graph {
|
export function createGraph(view: R.RelationalView): Graph {
|
||||||
const creator = new GraphCreator();
|
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)) {
|
for (const mentionsAuthorReference of findMentionsAuthorReferences(view)) {
|
||||||
this.graph.addEdge(createEdge.mentionsAuthor(mentionsAuthorReference));
|
this.graph.addEdge(createEdge.mentionsAuthor(mentionsAuthorReference));
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import * as GN from "./nodes";
|
|||||||
import * as GE from "./edges";
|
import * as GE from "./edges";
|
||||||
|
|
||||||
import * as GitNode from "../git/nodes";
|
import * as GitNode from "../git/nodes";
|
||||||
|
// TODO(@decentralion): Opportunity to reduce bundle size
|
||||||
|
import {Reactions} from "./graphql";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Graph,
|
Graph,
|
||||||
@ -245,6 +247,14 @@ export class GraphView {
|
|||||||
srcAccessor: (x) => GN.toRaw((x: any).reference.src),
|
srcAccessor: (x) => GN.toRaw((x: any).reference.src),
|
||||||
dstAccessor: (x) => GN.toRaw((x: any).reference.dst),
|
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({
|
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`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,6 +339,14 @@ describe("plugins/github/graphView", () => {
|
|||||||
expect(() => new GraphView(g)).toThrow("Invariant: Expected src");
|
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", () => {
|
it("are properly re-entrant", () => {
|
||||||
|
@ -108,6 +108,30 @@ export class StaticPluginAdapter implements IStaticPluginAdapter {
|
|||||||
defaultBackwardWeight: 1 / 32,
|
defaultBackwardWeight: 1 / 32,
|
||||||
prefix: E.Prefix.mentionsAuthor,
|
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<IDynamicPluginAdapater> {
|
async load(assets: Assets, repo: Repo): Promise<IDynamicPluginAdapater> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user