Factor out `github.porcelain.asEntity` (#246)
@wchargin suggested that the entity-wrapping logic in porcelain reference handling should be factored out as its own method. This was a great suggestion; it will be very useful for plugin consumers, and it also results in better test coverage. Test plan: The new unit tests are nice. For your own safety, do not question or quibble with the magnificent foo plugin.
This commit is contained in:
parent
9ea1f981aa
commit
d9b4673dbd
|
@ -48,6 +48,8 @@ import {
|
||||||
REFERENCES_EDGE_TYPE,
|
REFERENCES_EDGE_TYPE,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
import {PLUGIN_NAME} from "./pluginName";
|
||||||
|
|
||||||
import {COMMIT_NODE_TYPE} from "../git/types";
|
import {COMMIT_NODE_TYPE} from "../git/types";
|
||||||
|
|
||||||
export type Entity =
|
export type Entity =
|
||||||
|
@ -67,6 +69,44 @@ function assertEntityType(e: Entity, t: NodeType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function asEntity(
|
||||||
|
g: Graph<NodePayload, EdgePayload>,
|
||||||
|
addr: Address
|
||||||
|
): Entity {
|
||||||
|
const type: NodeType = (addr.type: any);
|
||||||
|
if (addr.pluginName !== PLUGIN_NAME) {
|
||||||
|
throw new Error(
|
||||||
|
`Tried to make GitHub porcelain, but got the wrong plugin name: ${stringify(
|
||||||
|
addr
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case "ISSUE":
|
||||||
|
return new Issue(g, addr);
|
||||||
|
case "PULL_REQUEST":
|
||||||
|
return new PullRequest(g, addr);
|
||||||
|
case "COMMENT":
|
||||||
|
return new Comment(g, addr);
|
||||||
|
case "AUTHOR":
|
||||||
|
return new Author(g, addr);
|
||||||
|
case "PULL_REQUEST_REVIEW":
|
||||||
|
return new PullRequestReview(g, addr);
|
||||||
|
case "PULL_REQUEST_REVIEW_COMMENT":
|
||||||
|
return new PullRequestReviewComment(g, addr);
|
||||||
|
case "REPOSITORY":
|
||||||
|
return new Repository(g, addr);
|
||||||
|
default:
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
(type: empty);
|
||||||
|
throw new Error(
|
||||||
|
`Tried to make GitHub porcelain, but got invalid type: ${stringify(
|
||||||
|
addr
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Porcelain {
|
export class Porcelain {
|
||||||
graph: Graph<NodePayload, EdgePayload>;
|
graph: Graph<NodePayload, EdgePayload>;
|
||||||
|
|
||||||
|
@ -190,45 +230,12 @@ class Post<
|
||||||
}
|
}
|
||||||
|
|
||||||
references(): Entity[] {
|
references(): Entity[] {
|
||||||
const result: Entity[] = [];
|
return this.graph
|
||||||
this.graph
|
|
||||||
.neighborhood(this.nodeAddress, {
|
.neighborhood(this.nodeAddress, {
|
||||||
edgeType: REFERENCES_EDGE_TYPE,
|
edgeType: REFERENCES_EDGE_TYPE,
|
||||||
direction: "OUT",
|
direction: "OUT",
|
||||||
})
|
})
|
||||||
.forEach(({neighbor}) => {
|
.map(({neighbor}) => asEntity(this.graph, neighbor));
|
||||||
const type: NodeType = (neighbor.type: any);
|
|
||||||
switch (type) {
|
|
||||||
case "ISSUE":
|
|
||||||
result.push(new Issue(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
case "PULL_REQUEST":
|
|
||||||
result.push(new PullRequest(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
case "COMMENT":
|
|
||||||
result.push(new Comment(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
case "AUTHOR":
|
|
||||||
result.push(new Author(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
case "PULL_REQUEST_REVIEW":
|
|
||||||
result.push(new PullRequestReview(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
case "PULL_REQUEST_REVIEW_COMMENT":
|
|
||||||
result.push(new PullRequestReviewComment(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
case "REPOSITORY":
|
|
||||||
result.push(new Repository(this.graph, neighbor));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
|
||||||
(type: empty);
|
|
||||||
throw new Error(
|
|
||||||
`Attempted to parse reference to unknown entity type ${type}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import type {Address} from "../../core/address";
|
||||||
import {parse} from "./parser";
|
import {parse} from "./parser";
|
||||||
import exampleRepoData from "./demoData/example-github.json";
|
import exampleRepoData from "./demoData/example-github.json";
|
||||||
import {Porcelain, Issue, PullRequest, Comment, Author} from "./porcelain";
|
import {
|
||||||
|
asEntity,
|
||||||
|
Porcelain,
|
||||||
|
Issue,
|
||||||
|
PullRequest,
|
||||||
|
Comment,
|
||||||
|
Author,
|
||||||
|
} from "./porcelain";
|
||||||
import {
|
import {
|
||||||
AUTHOR_NODE_TYPE,
|
AUTHOR_NODE_TYPE,
|
||||||
COMMENT_NODE_TYPE,
|
COMMENT_NODE_TYPE,
|
||||||
|
@ -12,6 +20,8 @@ import {
|
||||||
PULL_REQUEST_REVIEW_COMMENT_NODE_TYPE,
|
PULL_REQUEST_REVIEW_COMMENT_NODE_TYPE,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
|
import {PLUGIN_NAME} from "./pluginName";
|
||||||
|
|
||||||
describe("GitHub porcelain", () => {
|
describe("GitHub porcelain", () => {
|
||||||
const graph = parse(exampleRepoData);
|
const graph = parse(exampleRepoData);
|
||||||
const porcelain = new Porcelain(graph);
|
const porcelain = new Porcelain(graph);
|
||||||
|
@ -23,6 +33,26 @@ describe("GitHub porcelain", () => {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
describe("asEntity", () => {
|
||||||
|
// Note: In the "wrappers" block, we test that the asEntity method works
|
||||||
|
// for each wrapper type. Here, we just test that it fails as expected.
|
||||||
|
it("errors when given an address with the wrong plugin name", () => {
|
||||||
|
const addr: Address = {
|
||||||
|
pluginName: "the magnificent foo plugin",
|
||||||
|
id: "who are you to ask an id of the magnificent foo plugin?",
|
||||||
|
type: "ISSUE",
|
||||||
|
};
|
||||||
|
expect(() => asEntity(graph, addr)).toThrow("wrong plugin name");
|
||||||
|
});
|
||||||
|
it("errors when given an address with a bad node type", () => {
|
||||||
|
const addr: Address = {
|
||||||
|
pluginName: PLUGIN_NAME,
|
||||||
|
id: "if you keep asking for my id you will make me angry",
|
||||||
|
type: "the foo plugin's magnificence extends to many plugins",
|
||||||
|
};
|
||||||
|
expect(() => asEntity(graph, addr)).toThrow("invalid type");
|
||||||
|
});
|
||||||
|
});
|
||||||
describe("has repository finding", () => {
|
describe("has repository finding", () => {
|
||||||
it("which works for an existing repository", () => {
|
it("which works for an existing repository", () => {
|
||||||
expect(porcelain.repository("sourcecred", "example-github")).toEqual(
|
expect(porcelain.repository("sourcecred", "example-github")).toEqual(
|
||||||
|
@ -40,6 +70,7 @@ describe("GitHub porcelain", () => {
|
||||||
expect(repo.url()).toBe("https://github.com/sourcecred/example-github");
|
expect(repo.url()).toBe("https://github.com/sourcecred/example-github");
|
||||||
expect(repo.owner()).toBe("sourcecred");
|
expect(repo.owner()).toBe("sourcecred");
|
||||||
expect(repo.name()).toBe("example-github");
|
expect(repo.name()).toBe("example-github");
|
||||||
|
expect(repo).toEqual(asEntity(graph, repo.address()));
|
||||||
});
|
});
|
||||||
it("Issues", () => {
|
it("Issues", () => {
|
||||||
const issue = issueOrPRByNumber(1);
|
const issue = issueOrPRByNumber(1);
|
||||||
|
@ -53,6 +84,7 @@ describe("GitHub porcelain", () => {
|
||||||
expect(issue.node()).toMatchSnapshot();
|
expect(issue.node()).toMatchSnapshot();
|
||||||
expect(issue.address()).toEqual(issue.node().address);
|
expect(issue.address()).toEqual(issue.node().address);
|
||||||
expect(issue.authors().map((x) => x.login())).toEqual(["decentralion"]);
|
expect(issue.authors().map((x) => x.login())).toEqual(["decentralion"]);
|
||||||
|
expect(issue).toEqual(asEntity(graph, issue.address()));
|
||||||
});
|
});
|
||||||
describe("PullRequests", () => {
|
describe("PullRequests", () => {
|
||||||
it("Merged", () => {
|
it("Merged", () => {
|
||||||
|
@ -69,6 +101,7 @@ describe("GitHub porcelain", () => {
|
||||||
expect(pullRequest.mergeCommitHash()).toEqual(
|
expect(pullRequest.mergeCommitHash()).toEqual(
|
||||||
"0a223346b4e6dec0127b1e6aa892c4ee0424b66a"
|
"0a223346b4e6dec0127b1e6aa892c4ee0424b66a"
|
||||||
);
|
);
|
||||||
|
expect(pullRequest).toEqual(asEntity(graph, pullRequest.address()));
|
||||||
});
|
});
|
||||||
it("Unmerged", () => {
|
it("Unmerged", () => {
|
||||||
const pullRequest = PullRequest.from(issueOrPRByNumber(9));
|
const pullRequest = PullRequest.from(issueOrPRByNumber(9));
|
||||||
|
@ -82,6 +115,7 @@ describe("GitHub porcelain", () => {
|
||||||
expect(reviews).toHaveLength(2);
|
expect(reviews).toHaveLength(2);
|
||||||
expect(reviews[0].state()).toBe("CHANGES_REQUESTED");
|
expect(reviews[0].state()).toBe("CHANGES_REQUESTED");
|
||||||
expect(reviews[1].state()).toBe("APPROVED");
|
expect(reviews[1].state()).toBe("APPROVED");
|
||||||
|
expect(reviews[0]).toEqual(asEntity(graph, reviews[0].address()));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Pull Request Review Comments", () => {
|
it("Pull Request Review Comments", () => {
|
||||||
|
@ -96,6 +130,7 @@ describe("GitHub porcelain", () => {
|
||||||
);
|
);
|
||||||
expect(comment.body()).toBe("seems a bit capricious");
|
expect(comment.body()).toBe("seems a bit capricious");
|
||||||
expect(comment.authors().map((a) => a.login())).toEqual(["wchargin"]);
|
expect(comment.authors().map((a) => a.login())).toEqual(["wchargin"]);
|
||||||
|
expect(comment).toEqual(asEntity(graph, comment.address()));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Comments", () => {
|
it("Comments", () => {
|
||||||
|
@ -111,6 +146,7 @@ describe("GitHub porcelain", () => {
|
||||||
expect(comment.node()).toMatchSnapshot();
|
expect(comment.node()).toMatchSnapshot();
|
||||||
expect(comment.address()).toEqual(comment.node().address);
|
expect(comment.address()).toEqual(comment.node().address);
|
||||||
expect(comment.authors().map((x) => x.login())).toEqual(["decentralion"]);
|
expect(comment.authors().map((x) => x.login())).toEqual(["decentralion"]);
|
||||||
|
expect(comment).toEqual(asEntity(graph, comment.address()));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Authors", () => {
|
it("Authors", () => {
|
||||||
|
@ -127,6 +163,7 @@ describe("GitHub porcelain", () => {
|
||||||
expect(decentralion.subtype()).toBe("USER");
|
expect(decentralion.subtype()).toBe("USER");
|
||||||
expect(decentralion.node()).toMatchSnapshot();
|
expect(decentralion.node()).toMatchSnapshot();
|
||||||
expect(decentralion.address()).toEqual(decentralion.node().address);
|
expect(decentralion.address()).toEqual(decentralion.node().address);
|
||||||
|
expect(decentralion).toEqual(asEntity(graph, decentralion.address()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue