Modify `sourcecred load` to save timeline cred

Test plan: Observe changes to the snapshot for example-github-load.
`yarn test --full` passes.
This commit is contained in:
Dandelion Mané 2019-07-10 01:06:26 +01:00
parent aa7158dd95
commit a46500d704
3 changed files with 63 additions and 7 deletions

File diff suppressed because one or more lines are too long

View File

@ -3,6 +3,7 @@
import mkdirp from "mkdirp";
import path from "path";
import chalk from "chalk";
import fs from "fs-extra";
import stringify from "json-stable-stringify";
@ -11,13 +12,17 @@ import {repoIdToString, stringToRepoId, type RepoId} from "../core/repoId";
import dedent from "../util/dedent";
import type {Command} from "./command";
import * as Common from "./common";
import {Graph} from "../core/graph";
import {loadGraph, type LoadGraphResult} from "../analysis/loadGraph";
import {type IBackendAdapterLoader} from "../analysis/analysisAdapter";
import {TimelineCred} from "../analysis/timeline/timelineCred";
import {defaultWeights} from "../analysis/weights";
import execDependencyGraph from "../tools/execDependencyGraph";
import {loadGithubData} from "../plugins/github/loadGithubData";
import {loadGitData} from "../plugins/git/loadGitData";
import {defaultAdapterLoaders} from "./pagerank";
import {DEFAULT_CRED_CONFIG} from "../plugins/defaultCredConfig";
function usage(print: (string) => void): void {
print(
@ -170,7 +175,9 @@ export function makeLoadCommand(
export type SaveGraph = (
$ReadOnlyArray<IBackendAdapterLoader>,
RepoId
) => Promise<void>;
) => Promise<Graph>;
export type SaveCred = (Graph, RepoId) => Promise<void>;
/**
* A wrapper around the default plugin loader.
@ -179,7 +186,10 @@ export type SaveGraph = (
* (saveGraph depends on the directory state that's generated by running
* load.)
*/
export const makeLoadDefaultPlugins = (saveGraph: SaveGraph) => {
export const makeLoadDefaultPlugins = (
saveGraph: SaveGraph,
saveCred: SaveCred
) => {
return async (options: LoadOptions) => {
const sourcecredCommand = (args) => [
process.execPath,
@ -209,11 +219,39 @@ export const makeLoadDefaultPlugins = (saveGraph: SaveGraph) => {
throw new Error("Load tasks failed.");
}
addToRepoIdRegistry(options.output);
await saveGraph(defaultAdapterLoaders(), options.output);
const graph = await saveGraph(defaultAdapterLoaders(), options.output);
await saveCred(graph, options.output);
return;
};
};
export const saveCred = async (graph: Graph, repoId: RepoId) => {
const id = "compute-cred";
console.time(id);
// Imitate the task labels from execDependencyGraph for visual consistency
console.log(chalk.bgBlue.bold.white(" GO ") + ` ${id}`);
const cred = await TimelineCred.compute(
graph,
{
alpha: 0.05,
intervalDecay: 0.5,
weights: defaultWeights(),
},
DEFAULT_CRED_CONFIG
);
const credFile = path.join(
Common.sourcecredDirectory(),
"data",
repoIdToString(repoId),
"cred.json"
);
const credJSON = cred.toJSON();
await fs.writeFile(credFile, JSON.stringify(credJSON));
const badge = chalk.bgGreen.bold.white(" DONE ");
console.log(`${badge} ${id}`);
console.timeEnd(id);
};
export const loadIndividualPlugin = async (
plugin: Common.PluginName,
options: LoadOptions
@ -266,7 +304,7 @@ function addToRepoIdRegistry(repoId) {
export async function saveGraph(
adapterLoaders: $ReadOnlyArray<IBackendAdapterLoader>,
repoId: RepoId
) {
): Promise<Graph> {
const loadGraphResult: LoadGraphResult = await loadGraph(
Common.sourcecredDirectory(),
adapterLoaders,
@ -284,6 +322,7 @@ export async function saveGraph(
);
const graphJSON = graph.toJSON();
await fs.writeFile(graphFile, stringify(graphJSON));
return graph;
}
export const help: Command = async (args, std) => {
@ -296,7 +335,7 @@ export const help: Command = async (args, std) => {
}
};
const loadDefaultPlugins = makeLoadDefaultPlugins(saveGraph);
const loadDefaultPlugins = makeLoadDefaultPlugins(saveGraph, saveCred);
const load = makeLoadCommand(loadIndividualPlugin, loadDefaultPlugins);
export default load;

View File

@ -3,6 +3,7 @@
import path from "path";
import tmp from "tmp";
import {Graph} from "../core/graph";
import {run} from "./testUtil";
import {defaultPlugins} from "./common";
import {
@ -467,7 +468,7 @@ describe("cli/load", () => {
const fooCombined = makeRepoId("foo", "combined");
const fooBar = makeRepoId("foo", "bar");
const fooBaz = makeRepoId("foo", "baz");
const loadDefaultPlugins = makeLoadDefaultPlugins(jest.fn());
const loadDefaultPlugins = makeLoadDefaultPlugins(jest.fn(), jest.fn());
it("creates a load sub-task per plugin", async () => {
execDependencyGraph.mockResolvedValue({success: true});
@ -518,7 +519,7 @@ describe("cli/load", () => {
it("calls saveGraph on success", async () => {
const saveGraph = jest.fn();
const loadDefaultPlugins = makeLoadDefaultPlugins(saveGraph);
const loadDefaultPlugins = makeLoadDefaultPlugins(saveGraph, jest.fn());
execDependencyGraph.mockResolvedValue({success: true});
await loadDefaultPlugins({
output: fooCombined,
@ -531,6 +532,21 @@ describe("cli/load", () => {
);
});
it("calls saveCred with the output of saveGraph", async () => {
// $ExpectFlowError
const graph: Graph = "pretend_graph";
const saveGraph = jest.fn().mockResolvedValue(graph);
const saveCred = jest.fn();
const loadDefaultPlugins = makeLoadDefaultPlugins(saveGraph, saveCred);
execDependencyGraph.mockResolvedValue({success: true});
await loadDefaultPlugins({
output: fooCombined,
repoIds: [fooBar, fooBaz],
});
expect(saveCred).toHaveBeenCalledTimes(1);
expect(saveCred).toHaveBeenCalledWith(graph, fooCombined);
});
it("throws an load error on first execDependencyGraph failure", async () => {
execDependencyGraph.mockResolvedValueOnce({success: false});
const result = loadDefaultPlugins({