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 load from "./load";
|
||||||
import graph from "./graph";
|
import graph from "./graph";
|
||||||
|
import merge from "./merge";
|
||||||
|
import score from "./score";
|
||||||
|
|
||||||
const sourcecred: Command = async (args, std) => {
|
const sourcecred: Command = async (args, std) => {
|
||||||
if (args.length === 0) {
|
if (args.length === 0) {
|
||||||
|
@ -15,6 +17,10 @@ const sourcecred: Command = async (args, std) => {
|
||||||
return load(args.slice(1), std);
|
return load(args.slice(1), std);
|
||||||
case "graph":
|
case "graph":
|
||||||
return graph(args.slice(1), std);
|
return graph(args.slice(1), std);
|
||||||
|
case "merge":
|
||||||
|
return merge(args.slice(1), std);
|
||||||
|
case "score":
|
||||||
|
return score(args.slice(1), std);
|
||||||
default:
|
default:
|
||||||
std.err("fatal: unknown command: " + JSON.stringify(args[0]));
|
std.err("fatal: unknown command: " + JSON.stringify(args[0]));
|
||||||
return 1;
|
return 1;
|
||||||
|
|
Loading…
Reference in New Issue