Implement bare-bones sc2 merge and score (#1815)
This adds the missing `merge` and `score` commands to the sc2 CLI. `merge` currently just merges the plugin graphs, and doesn't yet support identity resolution or weight overrides. `score` computes the new data output format (cf #1773) and writes it to disk. It doesn't yet support using custom parameters. Test plan: Follow the test plans for the previous commits, then run `sc2 merge`. It will create a combined graph at `output/graph.json`, which will contain data for both Discourse and GitHub. Then run `sc2 score` and the `output/cred.json` file will contain scores for the combined graph.
This commit is contained in:
parent
c2510d0c1d
commit
40426f353c
|
@ -0,0 +1,53 @@
|
|||
// @flow
|
||||
|
||||
import fs from "fs-extra";
|
||||
import stringify from "json-stable-stringify";
|
||||
import {join as pathJoin} from "path";
|
||||
|
||||
import {LoggingTaskReporter} from "../util/taskReporter";
|
||||
import type {Command} from "./command";
|
||||
import {makePluginDir, loadInstanceConfig} from "./common";
|
||||
import {
|
||||
toJSON as weightedGraphToJSON,
|
||||
fromJSON as weightedGraphFromJSON,
|
||||
type WeightedGraph,
|
||||
merge,
|
||||
} from "../core/weightedGraph";
|
||||
|
||||
function die(std, message) {
|
||||
std.err("fatal: " + message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const mergeCommand: Command = async (args, std) => {
|
||||
if (args.length !== 0) {
|
||||
return die(std, "usage: sourcecred merge");
|
||||
}
|
||||
const taskReporter = new LoggingTaskReporter();
|
||||
taskReporter.start("merge");
|
||||
const baseDir = process.cwd();
|
||||
const config = await loadInstanceConfig(baseDir);
|
||||
const graphOutputPrefix = ["output", "graphs"];
|
||||
|
||||
async function loadGraph(pluginName): Promise<WeightedGraph> {
|
||||
const outputDir = makePluginDir(baseDir, graphOutputPrefix, pluginName);
|
||||
const outputPath = pathJoin(outputDir, "graph.json");
|
||||
const graphJSON = JSON.parse(await fs.readFile(outputPath));
|
||||
return weightedGraphFromJSON(graphJSON);
|
||||
}
|
||||
|
||||
const pluginNames = Array.from(config.bundledPlugins.keys());
|
||||
const graphs = await Promise.all(pluginNames.map(loadGraph));
|
||||
|
||||
// TODO: Support identity merging.
|
||||
// TODO: Support weight overrides.
|
||||
const combinedGraph = merge(graphs);
|
||||
|
||||
const outputPath = pathJoin(baseDir, "output", "graph.json");
|
||||
const serializedGraph = stringify(weightedGraphToJSON(combinedGraph));
|
||||
await fs.writeFile(outputPath, serializedGraph);
|
||||
taskReporter.finish("merge");
|
||||
return 0;
|
||||
};
|
||||
|
||||
export default mergeCommand;
|
|
@ -0,0 +1,56 @@
|
|||
// @flow
|
||||
|
||||
import fs from "fs-extra";
|
||||
import stringify from "json-stable-stringify";
|
||||
import {join as pathJoin} from "path";
|
||||
|
||||
import type {Command} from "./command";
|
||||
import {loadInstanceConfig} from "./common";
|
||||
import {fromJSON as weightedGraphFromJSON} from "../core/weightedGraph";
|
||||
import {defaultParams} from "../analysis/timeline/params";
|
||||
import {TimelineCred} from "../analysis/timeline/timelineCred";
|
||||
import {LoggingTaskReporter} from "../util/taskReporter";
|
||||
import {
|
||||
fromTimelineCredAndPlugins,
|
||||
COMPAT_INFO as OUTPUT_COMPAT_INFO,
|
||||
} from "../analysis/output";
|
||||
import {toCompat} from "../util/compat";
|
||||
|
||||
function die(std, message) {
|
||||
std.err("fatal: " + message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const scoreCommand: Command = async (args, std) => {
|
||||
if (args.length !== 0) {
|
||||
return die(std, "usage: sourcecred score");
|
||||
}
|
||||
const taskReporter = new LoggingTaskReporter();
|
||||
taskReporter.start("score");
|
||||
const baseDir = process.cwd();
|
||||
const config = await loadInstanceConfig(baseDir);
|
||||
|
||||
const graphFilePath = pathJoin(baseDir, "output", "graph.json");
|
||||
const graphJSON = JSON.parse(await fs.readFile(graphFilePath));
|
||||
const graph = weightedGraphFromJSON(graphJSON);
|
||||
|
||||
const plugins = Array.from(config.bundledPlugins.values());
|
||||
const declarations = plugins.map((x) => x.declaration());
|
||||
|
||||
// TODO: Support loading params from config.
|
||||
const params = defaultParams();
|
||||
|
||||
const tc = await TimelineCred.compute({
|
||||
weightedGraph: graph,
|
||||
params,
|
||||
plugins: declarations,
|
||||
});
|
||||
const output = fromTimelineCredAndPlugins(tc, declarations);
|
||||
const outputJSON = stringify(toCompat(OUTPUT_COMPAT_INFO, output));
|
||||
const outputPath = pathJoin(baseDir, "output", "cred.json");
|
||||
await fs.writeFile(outputPath, outputJSON);
|
||||
taskReporter.finish("score");
|
||||
return 0;
|
||||
};
|
||||
|
||||
export default scoreCommand;
|
|
@ -4,6 +4,8 @@ import type {Command} from "./command";
|
|||
|
||||
import load from "./load";
|
||||
import graph from "./graph";
|
||||
import merge from "./merge";
|
||||
import score from "./score";
|
||||
|
||||
const sourcecred: Command = async (args, std) => {
|
||||
if (args.length === 0) {
|
||||
|
@ -15,6 +17,10 @@ const sourcecred: Command = async (args, std) => {
|
|||
return load(args.slice(1), std);
|
||||
case "graph":
|
||||
return graph(args.slice(1), std);
|
||||
case "merge":
|
||||
return merge(args.slice(1), std);
|
||||
case "score":
|
||||
return score(args.slice(1), std);
|
||||
default:
|
||||
std.err("fatal: unknown command: " + JSON.stringify(args[0]));
|
||||
return 1;
|
||||
|
|
Loading…
Reference in New Issue