From 3e06c054db41b6b0c9300085c30e764fdfbee12c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Wed, 12 Sep 2018 19:06:06 -0700 Subject: [PATCH] Give GitHub plugin support for Commit addresses (#816) The Git plugin owns Commits, but the GitHub plugin also creates commits. This commit reifies that relationship by making a Git commit address a valid GitHub structured address. This is precursor work for #815, which will require adding a commit entity to the GitHub relational view. Also, this commit surfaces and fixes a minor type bug, wherein a map from strings to referent addresses was typed to hold any structured address, rather than just referent addresses. Test plan: The unit tests confirm that serializing/deserializing a Git commit address using the GitHub plugin's methods works as intended. Also, unit tests were added that verify that (de)serializing Git addresses for non-commit objects is still an error. --- .../github/__snapshots__/nodes.test.js.snap | 15 ++++++++++++++ src/plugins/github/graphView.js | 5 +++-- src/plugins/github/nodes.js | 14 ++++++++++++- src/plugins/github/nodes.test.js | 20 +++++++++++++++++++ src/plugins/github/relationalView.js | 4 +++- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/plugins/github/__snapshots__/nodes.test.js.snap b/src/plugins/github/__snapshots__/nodes.test.js.snap index ed31102..dfd93c6 100644 --- a/src/plugins/github/__snapshots__/nodes.test.js.snap +++ b/src/plugins/github/__snapshots__/nodes.test.js.snap @@ -1,5 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`plugins/github/nodes snapshots as expected: commit 1`] = ` +Object { + "address": Array [ + "sourcecred", + "git", + "COMMIT", + "0000000000000000000000000000000000000000", + ], + "structured": Object { + "hash": "0000000000000000000000000000000000000000", + "type": "COMMIT", + }, +} +`; + exports[`plugins/github/nodes snapshots as expected: issue 1`] = ` Object { "address": Array [ diff --git a/src/plugins/github/graphView.js b/src/plugins/github/graphView.js index 0df3f9b..3309440 100644 --- a/src/plugins/github/graphView.js +++ b/src/plugins/github/graphView.js @@ -6,7 +6,7 @@ import deepEqual from "lodash.isequal"; import * as GN from "./nodes"; import * as GE from "./edges"; -import {Prefix as _GitPrefix} from "../git/nodes"; +import * as GitNode from "../git/nodes"; import { Graph, @@ -143,6 +143,7 @@ export class GraphView { [GN.COMMENT_TYPE]: (x) => x.parent, [GN.REVIEW_TYPE]: (x) => x.pull, [GN.USERLIKE_TYPE]: null, + [GitNode.COMMIT_TYPE]: null, }; for (const node of this._graph.nodes({prefix: GN.Prefix.base})) { const structuredNode = GN.fromRaw((node: any)); @@ -195,7 +196,7 @@ export class GraphView { homs: [ { srcPrefix: GN.Prefix.pull, - dstPrefix: _GitPrefix.commit, + dstPrefix: GitNode.Prefix.commit, }, ], srcAccessor: (x) => GN.toRaw((x: any).pull), diff --git a/src/plugins/github/nodes.js b/src/plugins/github/nodes.js index 4c44753..cfe34e7 100644 --- a/src/plugins/github/nodes.js +++ b/src/plugins/github/nodes.js @@ -1,6 +1,7 @@ // @flow import {NodeAddress, type NodeAddressT} from "../../core/graph"; +import * as GitNode from "../git/nodes"; export opaque type RawAddress: NodeAddressT = NodeAddressT; @@ -70,7 +71,8 @@ export type StructuredAddress = | PullAddress | ReviewAddress | CommentAddress - | UserlikeAddress; + | UserlikeAddress + | GitNode.CommitAddress; // Each of these types has 0 or more "AUTHORS" edges, each of which // leads to a UserlikeAddress. Note: It is not true that every @@ -125,6 +127,14 @@ export function fromRaw(x: RawAddress): StructuredAddress { function fail() { return new Error(`Bad address: ${NodeAddress.toString(x)}`); } + if (NodeAddress.hasPrefix(x, GitNode.Prefix.base)) { + const structured: GitNode.StructuredAddress = GitNode.fromRaw((x: any)); + if (structured.type === GitNode.COMMIT_TYPE) { + return (structured: GitNode.CommitAddress); + } else { + throw fail(); + } + } if (!NodeAddress.hasPrefix(x, GITHUB_PREFIX)) { throw fail(); } @@ -280,6 +290,8 @@ export function toRaw(x: StructuredAddress): RawAddress { default: throw new Error((x.subtype: empty)); } + case GitNode.COMMIT_TYPE: + return GitNode.toRaw(x); default: throw new Error(`Unexpected type ${(x.type: empty)}`); } diff --git a/src/plugins/github/nodes.test.js b/src/plugins/github/nodes.test.js index f52c004..ae50512 100644 --- a/src/plugins/github/nodes.test.js +++ b/src/plugins/github/nodes.test.js @@ -3,6 +3,7 @@ import {NodeAddress} from "../../core/graph"; import * as GN from "./nodes"; import {fromRaw, toRaw} from "./nodes"; +import * as GitNode from "../git/nodes"; describe("plugins/github/nodes", () => { const repo = (): GN.RepoAddress => ({ @@ -45,6 +46,14 @@ describe("plugins/github/nodes", () => { subtype: "USER", login: "decentralion", }); + const commit = (): GitNode.CommitAddress => ({ + type: GitNode.COMMIT_TYPE, + hash: "0000000000000000000000000000000000000000", + }); + const tree = (): GitNode.TreeAddress => ({ + type: GitNode.TREE_TYPE, + hash: "0000000000000000000000000000000000000000", + }); const examples = { repo, @@ -55,6 +64,7 @@ describe("plugins/github/nodes", () => { pullComment, reviewComment, user, + commit, }; // Incorrect types should be caught statically, either due to being @@ -140,6 +150,10 @@ describe("plugins/github/nodes", () => { ); }); expectBadAddress("no kind", []); + expectBadAddress( + "Git node that isn't a commit", + NodeAddress.toParts(GitNode.toRaw(tree())) + ); describe("repository with", () => { checkBadCases([ {name: "no owner", parts: [GN.REPO_TYPE]}, @@ -236,6 +250,12 @@ describe("plugins/github/nodes", () => { toRaw({type: "COMMENT", parent: {type: "ICE_CREAM"}}); }).toThrow("Bad comment parent type"); }); + it("a git address that isn't a commit", () => { + expect(() => { + // $ExpectFlowError + toRaw(tree()); + }).toThrow("Unexpected type"); + }); }); }); }); diff --git a/src/plugins/github/relationalView.js b/src/plugins/github/relationalView.js index f23e78b..a4f5980 100644 --- a/src/plugins/github/relationalView.js +++ b/src/plugins/github/relationalView.js @@ -176,6 +176,8 @@ export class RelationalView { return this.comment(address); case "USERLIKE": return this.userlike(address); + case "COMMIT": + return null; default: throw new Error(`Unexpected address type: ${(address.type: empty)}`); } @@ -393,7 +395,7 @@ export class RelationalView { // https://github.com/sourcecred/sourcecred/pull/416 // - A # followed by a number, such as #416 // - An @ followed by a login name, such as @decentralion - const refToAddress: Map = new Map(); + const refToAddress: Map = new Map(); for (const e: ReferentEntity of this.referentEntities()) { const a = e.address(); refToAddress.set(e.url(), a);