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.
This commit is contained in:
Dandelion Mané 2018-09-12 19:06:06 -07:00 committed by GitHub
parent 7dc9449fe7
commit 3e06c054db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 4 deletions

View File

@ -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 [

View File

@ -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),

View File

@ -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)}`);
}

View File

@ -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");
});
});
});
});

View File

@ -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<string, N.StructuredAddress> = new Map();
const refToAddress: Map<string, N.ReferentAddress> = new Map();
for (const e: ReferentEntity of this.referentEntities()) {
const a = e.address();
refToAddress.set(e.url(), a);