Refactor GH parser to expose a functional api (#145)
Our GitHub parser is implemented via a `GithubParser` class which builds the GitHub graph. This is a convenient implementation, but an awkward API. This commit refactors the module so that it exposes a clean `parse` function, which ingests the GitHub JSON data and returns as completed graph. Test plan: The unit tests have been re-written to use the new public API. All the snapshots are unchanged, and flow passes. Additionally, I ran `yarn start` and verified that the GithubGraphFetcher for the Artifact plugin is still working.
This commit is contained in:
parent
5e4b7b1fcc
commit
18ce9982d2
|
@ -9,7 +9,7 @@ import type {
|
||||||
NodePayload as GithubNodePayload,
|
NodePayload as GithubNodePayload,
|
||||||
EdgePayload as GithubEdgePayload,
|
EdgePayload as GithubEdgePayload,
|
||||||
} from "../../github/types";
|
} from "../../github/types";
|
||||||
import {GithubParser} from "../../github/parser";
|
import {parse} from "../../github/parser";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
|
@ -32,9 +32,7 @@ export class GithubGraphFetcher extends React.Component<Props> {
|
||||||
const {repoOwner, repoName, githubApiToken} = this.props.settings;
|
const {repoOwner, repoName, githubApiToken} = this.props.settings;
|
||||||
fetchGithubRepo(repoOwner, repoName, githubApiToken)
|
fetchGithubRepo(repoOwner, repoName, githubApiToken)
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
const parser = new GithubParser(`${repoOwner}/${repoName}`);
|
return Promise.resolve(parse(`${repoOwner}/${repoName}`, json));
|
||||||
parser.addData(json);
|
|
||||||
return Promise.resolve(parser.graph);
|
|
||||||
})
|
})
|
||||||
.then((graph) => {
|
.then((graph) => {
|
||||||
this.props.onCreateGraph(graph);
|
this.props.onCreateGraph(graph);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {shallow} from "enzyme";
|
||||||
import enzymeToJSON from "enzyme-to-json";
|
import enzymeToJSON from "enzyme-to-json";
|
||||||
import stringify from "json-stable-stringify";
|
import stringify from "json-stable-stringify";
|
||||||
|
|
||||||
import {GithubParser} from "../../../github/parser";
|
import {parse} from "../../../github/parser";
|
||||||
import exampleRepoData from "../../../github/demoData/example-repo.json";
|
import exampleRepoData from "../../../github/demoData/example-repo.json";
|
||||||
import adapter from "./githubPluginAdapter";
|
import adapter from "./githubPluginAdapter";
|
||||||
|
|
||||||
|
@ -13,9 +13,7 @@ require("../testUtil").configureEnzyme();
|
||||||
|
|
||||||
describe("githubPluginAdapter", () => {
|
describe("githubPluginAdapter", () => {
|
||||||
it("operates on the example repo", () => {
|
it("operates on the example repo", () => {
|
||||||
const parser = new GithubParser("sourcecred/example-repo");
|
const graph = parse("sourcecred/example-repo", exampleRepoData);
|
||||||
parser.addData(exampleRepoData);
|
|
||||||
const graph = parser.graph;
|
|
||||||
|
|
||||||
const result = graph
|
const result = graph
|
||||||
.getNodes()
|
.getNodes()
|
||||||
|
|
|
@ -30,7 +30,16 @@ import {PLUGIN_NAME} from "./pluginName";
|
||||||
import {Graph, edgeID} from "../../core/graph";
|
import {Graph, edgeID} from "../../core/graph";
|
||||||
const stringify = require("json-stable-stringify");
|
const stringify = require("json-stable-stringify");
|
||||||
|
|
||||||
export class GithubParser {
|
export function parse(
|
||||||
|
repositoryName: string,
|
||||||
|
repositoryJSON: RepositoryJSON
|
||||||
|
): Graph<NodePayload, EdgePayload> {
|
||||||
|
const parser = new GithubParser(repositoryName);
|
||||||
|
parser.addData(repositoryJSON);
|
||||||
|
return parser.graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GithubParser {
|
||||||
repositoryName: string;
|
repositoryName: string;
|
||||||
graph: Graph<NodePayload, EdgePayload>;
|
graph: Graph<NodePayload, EdgePayload>;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import {AUTHORS_EDGE_TYPE, CONTAINS_EDGE_TYPE} from "./types";
|
import {AUTHORS_EDGE_TYPE, CONTAINS_EDGE_TYPE} from "./types";
|
||||||
|
import type {NodePayload, EdgePayload} from "./types";
|
||||||
import {GithubParser} from "./parser";
|
import {parse} from "./parser";
|
||||||
|
import type {RepositoryJSON, PullRequestJSON, IssueJSON} from "./graphql";
|
||||||
|
import {Graph} from "../../core/graph";
|
||||||
import exampleRepoData from "./demoData/example-repo.json";
|
import exampleRepoData from "./demoData/example-repo.json";
|
||||||
|
|
||||||
describe("GithubParser", () => {
|
describe("GithubParser", () => {
|
||||||
describe("whole repo parsing", () => {
|
describe("whole repo parsing", () => {
|
||||||
const parser = new GithubParser("sourcecred/example-repo");
|
const graph = parse("sourcecred/example-repo", exampleRepoData);
|
||||||
parser.addData(exampleRepoData);
|
|
||||||
const graph = parser.graph;
|
|
||||||
|
|
||||||
it("parses the entire example-repo as expected", () => {
|
it("parses the entire example-repo as expected", () => {
|
||||||
expect(graph).toMatchSnapshot();
|
expect(graph).toMatchSnapshot();
|
||||||
|
@ -66,38 +66,70 @@ describe("GithubParser", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getIssue(n: number): IssueJSON {
|
||||||
|
const issues = exampleRepoData.repository.issues.nodes;
|
||||||
|
const selected = issues.filter((x) => x.number === n);
|
||||||
|
if (selected.length !== 1) {
|
||||||
|
throw new Error(`Failure finding issue #${n}`);
|
||||||
|
}
|
||||||
|
return selected[0];
|
||||||
|
}
|
||||||
|
function getPR(n: number): PullRequestJSON {
|
||||||
|
const pulls = exampleRepoData.repository.pullRequests.nodes;
|
||||||
|
const selected = pulls.filter((x) => x.number === n);
|
||||||
|
if (selected.length !== 1) {
|
||||||
|
throw new Error(`Failure finding PR #${n}`);
|
||||||
|
}
|
||||||
|
return selected[0];
|
||||||
|
}
|
||||||
|
type ExampleInput = {
|
||||||
|
issues?: number[],
|
||||||
|
prs?: number[],
|
||||||
|
};
|
||||||
|
function parseExample({
|
||||||
|
issues: issueNums = [],
|
||||||
|
prs: prNums = [],
|
||||||
|
}: ExampleInput): Graph<NodePayload, EdgePayload> {
|
||||||
|
const issues = issueNums.map(getIssue);
|
||||||
|
const pullRequests = prNums.map(getPR);
|
||||||
|
const exampleData: RepositoryJSON = {
|
||||||
|
repository: {
|
||||||
|
id: exampleRepoData.repository.id,
|
||||||
|
issues: {
|
||||||
|
nodes: issues,
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
endCursor: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pullRequests: {
|
||||||
|
nodes: pullRequests,
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
endCursor: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return parse("sourcecred/example-repo", exampleData);
|
||||||
|
}
|
||||||
|
|
||||||
describe("issue parsing", () => {
|
describe("issue parsing", () => {
|
||||||
it("parses a simple issue (https://github.com/sourcecred/example-repo/issues/1)", () => {
|
it("parses a simple issue (https://github.com/sourcecred/example-repo/issues/1)", () => {
|
||||||
const issue1 = exampleRepoData.repository.issues.nodes[0];
|
expect(parseExample({issues: [1]})).toMatchSnapshot();
|
||||||
expect(issue1.number).toBe(1);
|
|
||||||
const parser = new GithubParser("sourcecred/example-repo");
|
|
||||||
parser.addIssue(issue1);
|
|
||||||
expect(parser.graph).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("parses an issue with comments (https://github.com/sourcecred/example-repo/issues/6)", () => {
|
it("parses an issue with comments (https://github.com/sourcecred/example-repo/issues/6)", () => {
|
||||||
const issue6 = exampleRepoData.repository.issues.nodes[3];
|
expect(parseExample({issues: [6]})).toMatchSnapshot();
|
||||||
expect(issue6.number).toBe(6);
|
|
||||||
const parser = new GithubParser("sourcecred/example-repo");
|
|
||||||
parser.addIssue(issue6);
|
|
||||||
expect(parser.graph).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("pull request parsing", () => {
|
describe("pull request parsing", () => {
|
||||||
it("parses a simple pull request (https://github.com/sourcecred/example-repo/pull/3)", () => {
|
it("parses a simple pull request (https://github.com/sourcecred/example-repo/pull/3)", () => {
|
||||||
const pr3 = exampleRepoData.repository.pullRequests.nodes[0];
|
expect(parseExample({prs: [3]})).toMatchSnapshot();
|
||||||
expect(pr3.number).toBe(3);
|
|
||||||
const parser = new GithubParser("sourcecred/example-repo");
|
|
||||||
parser.addPullRequest(pr3);
|
|
||||||
expect(parser.graph).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
it("parses a pr with review comments (https://github.com/sourcecred/example-repo/pull/3)", () => {
|
it("parses a pr with review comments (https://github.com/sourcecred/example-repo/pull/3)", () => {
|
||||||
const pr5 = exampleRepoData.repository.pullRequests.nodes[1];
|
expect(parseExample({prs: [5]})).toMatchSnapshot();
|
||||||
expect(pr5.number).toBe(5);
|
|
||||||
const parser = new GithubParser("sourcecred/example-repo");
|
|
||||||
parser.addPullRequest(pr5);
|
|
||||||
expect(parser.graph).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue