Add GitPluginAdapter and Git render module (#462)
Test plan: Run the following commands: ``` node bin/sourcecredV3.js load-plugin-v3 sourcecred example-github --plugin=git node bin/sourcecredV3.js load-plugin-v3 sourcecred example-github --plugin=github yarn start ``` Then, navigate in-browser to the v3 cred explorer and load data for `sourcecred/example-github`. The following messages are printed to console: ``` GitHub: Loaded graph: 31 nodes, 73 edges. Git: Loaded graph: 15 nodes, 19 edges. Combined: Loaded graph: 44 nodes, 92 edges. ``` Paired with @wchargin
This commit is contained in:
parent
4767dce749
commit
dd063f5203
|
@ -5,6 +5,8 @@ import {StyleSheet, css} from "aphrodite/no-important";
|
||||||
|
|
||||||
import LocalStore from "./LocalStore";
|
import LocalStore from "./LocalStore";
|
||||||
import {createPluginAdapter as createGithubAdapter} from "../../plugins/github/pluginAdapter";
|
import {createPluginAdapter as createGithubAdapter} from "../../plugins/github/pluginAdapter";
|
||||||
|
import {createPluginAdapter as createGitAdapter} from "../../plugins/git/pluginAdapter";
|
||||||
|
import {Graph} from "../../core/graph";
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -82,11 +84,38 @@ export default class App extends React.Component<Props, State> {
|
||||||
console.error(`Invalid repository name: ${JSON.stringify(repoName)}`);
|
console.error(`Invalid repository name: ${JSON.stringify(repoName)}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
createGithubAdapter(repoOwner, repoName).then((githubAdapter) => {
|
|
||||||
const graph = githubAdapter.graph();
|
const githubGraphPromise = createGithubAdapter(repoOwner, repoName).then(
|
||||||
|
(githubAdapter) => {
|
||||||
|
const graph = githubAdapter.graph();
|
||||||
|
const nodeCount = Array.from(graph.nodes()).length;
|
||||||
|
const edgeCount = Array.from(graph.edges()).length;
|
||||||
|
console.log(
|
||||||
|
`GitHub: Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.`
|
||||||
|
);
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const gitGraphPromise = createGitAdapter(repoOwner, repoName).then(
|
||||||
|
(gitAdapter) => {
|
||||||
|
const graph = gitAdapter.graph();
|
||||||
|
const nodeCount = Array.from(graph.nodes()).length;
|
||||||
|
const edgeCount = Array.from(graph.edges()).length;
|
||||||
|
console.log(
|
||||||
|
`Git: Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.`
|
||||||
|
);
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Promise.all([gitGraphPromise, githubGraphPromise]).then((graphs) => {
|
||||||
|
const graph = Graph.merge(graphs);
|
||||||
const nodeCount = Array.from(graph.nodes()).length;
|
const nodeCount = Array.from(graph.nodes()).length;
|
||||||
const edgeCount = Array.from(graph.edges()).length;
|
const edgeCount = Array.from(graph.edges()).length;
|
||||||
console.log(`Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.`);
|
console.log(
|
||||||
|
`Combined: Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`plugins/git/render blob snapshots as expected 1`] = `"blob f1f2514ca6d7a6a1a0511957021b1995bf9ace1c"`;
|
||||||
|
|
||||||
|
exports[`plugins/git/render commit snapshots as expected 1`] = `"commit 3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f"`;
|
||||||
|
|
||||||
|
exports[`plugins/git/render tree snapshots as expected 1`] = `"tree 7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed"`;
|
||||||
|
|
||||||
|
exports[`plugins/git/render treeEntry snapshots as expected 1`] = `"entry \\"science.txt\\" in tree 7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed"`;
|
|
@ -0,0 +1,47 @@
|
||||||
|
// @flow
|
||||||
|
import type {
|
||||||
|
PluginAdapter as IPluginAdapter,
|
||||||
|
Renderer as IRenderer,
|
||||||
|
} from "../../app/pluginAdapter";
|
||||||
|
import {Graph} from "../../core/graph";
|
||||||
|
import * as N from "./nodes";
|
||||||
|
import {description} from "./render";
|
||||||
|
|
||||||
|
export async function createPluginAdapter(
|
||||||
|
repoOwner: string,
|
||||||
|
repoName: string
|
||||||
|
): Promise<IPluginAdapter> {
|
||||||
|
const url = `/api/v1/data/data/${repoOwner}/${repoName}/git/graph.json`;
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
return Promise.reject(response);
|
||||||
|
}
|
||||||
|
const json = await response.json();
|
||||||
|
const graph = Graph.fromJSON(json);
|
||||||
|
return new PluginAdapter(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PluginAdapter implements IPluginAdapter {
|
||||||
|
+_graph: Graph;
|
||||||
|
constructor(graph: Graph) {
|
||||||
|
this._graph = graph;
|
||||||
|
}
|
||||||
|
graph() {
|
||||||
|
return this._graph;
|
||||||
|
}
|
||||||
|
renderer() {
|
||||||
|
return new Renderer();
|
||||||
|
}
|
||||||
|
nodePrefix() {
|
||||||
|
return N._Prefix.base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Renderer implements IRenderer {
|
||||||
|
nodeDescription(node) {
|
||||||
|
// This cast is unsound, and might throw at runtime, but won't have
|
||||||
|
// silent failures or cause problems down the road.
|
||||||
|
const address = N.fromRaw((node: any));
|
||||||
|
return description(address);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as N from "./nodes";
|
||||||
|
|
||||||
|
export function description(address: N.StructuredAddress) {
|
||||||
|
switch (address.type) {
|
||||||
|
case "COMMIT":
|
||||||
|
return `commit ${address.hash}`;
|
||||||
|
case "TREE":
|
||||||
|
return `tree ${address.hash}`;
|
||||||
|
case "BLOB":
|
||||||
|
return `blob ${address.hash}`;
|
||||||
|
case "TREE_ENTRY":
|
||||||
|
return `entry ${JSON.stringify(address.name)} in tree ${
|
||||||
|
address.treeHash
|
||||||
|
}`;
|
||||||
|
default:
|
||||||
|
throw new Error(`unknown type: ${(address.type: empty)}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as GN from "./nodes";
|
||||||
|
import {description} from "./render";
|
||||||
|
|
||||||
|
describe("plugins/git/render", () => {
|
||||||
|
const examples = {
|
||||||
|
blob: (): GN.BlobAddress => ({
|
||||||
|
type: GN.BLOB_TYPE,
|
||||||
|
hash: "f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||||
|
}),
|
||||||
|
commit: (): GN.CommitAddress => ({
|
||||||
|
type: GN.COMMIT_TYPE,
|
||||||
|
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||||
|
}),
|
||||||
|
tree: (): GN.TreeAddress => ({
|
||||||
|
type: GN.TREE_TYPE,
|
||||||
|
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||||
|
}),
|
||||||
|
treeEntry: (): GN.TreeEntryAddress => ({
|
||||||
|
type: GN.TREE_ENTRY_TYPE,
|
||||||
|
treeHash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||||
|
name: "science.txt",
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
it("blob snapshots as expected", () => {
|
||||||
|
expect(description(examples.blob())).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
it("commit snapshots as expected", () => {
|
||||||
|
expect(description(examples.commit())).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
it("tree snapshots as expected", () => {
|
||||||
|
expect(description(examples.tree())).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
it("treeEntry snapshots as expected", () => {
|
||||||
|
expect(description(examples.treeEntry())).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue