diff --git a/src/v3/app/credExplorer/App.js b/src/v3/app/credExplorer/App.js index 1c648e6..4a4c2c4 100644 --- a/src/v3/app/credExplorer/App.js +++ b/src/v3/app/credExplorer/App.js @@ -5,6 +5,8 @@ import {StyleSheet, css} from "aphrodite/no-important"; import LocalStore from "./LocalStore"; import {createPluginAdapter as createGithubAdapter} from "../../plugins/github/pluginAdapter"; +import {createPluginAdapter as createGitAdapter} from "../../plugins/git/pluginAdapter"; +import {Graph} from "../../core/graph"; type Props = {}; type State = { @@ -82,11 +84,38 @@ export default class App extends React.Component { console.error(`Invalid repository name: ${JSON.stringify(repoName)}`); 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 edgeCount = Array.from(graph.edges()).length; - console.log(`Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.`); + console.log( + `Combined: Loaded graph: ${nodeCount} nodes, ${edgeCount} edges.` + ); }); } } diff --git a/src/v3/plugins/git/__snapshots__/render.test.js.snap b/src/v3/plugins/git/__snapshots__/render.test.js.snap new file mode 100644 index 0000000..256dba7 --- /dev/null +++ b/src/v3/plugins/git/__snapshots__/render.test.js.snap @@ -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"`; diff --git a/src/v3/plugins/git/pluginAdapter.js b/src/v3/plugins/git/pluginAdapter.js new file mode 100644 index 0000000..6d4d252 --- /dev/null +++ b/src/v3/plugins/git/pluginAdapter.js @@ -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 { + 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); + } +} diff --git a/src/v3/plugins/git/render.js b/src/v3/plugins/git/render.js new file mode 100644 index 0000000..04f0bee --- /dev/null +++ b/src/v3/plugins/git/render.js @@ -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)}`); + } +} diff --git a/src/v3/plugins/git/render.test.js b/src/v3/plugins/git/render.test.js new file mode 100644 index 0000000..7b6885e --- /dev/null +++ b/src/v3/plugins/git/render.test.js @@ -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(); + }); +});