mirror of
https://github.com/status-im/sourcecred.git
synced 2025-02-27 19:50:28 +00:00
Backend: implement PluginLoaders.createPluginGraphs (#1618)
Similar to CachedProject, we're using an opaque PluginGraphs return type. Because only PluginLoaders can add the semantic of this being all plugin graphs, and to use this semantic in future functions.
This commit is contained in:
parent
4c53558c65
commit
ffd6c38e4c
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import {TaskReporter} from "../util/taskReporter";
|
import {TaskReporter} from "../util/taskReporter";
|
||||||
import {type Project} from "../core/project";
|
import {type Project} from "../core/project";
|
||||||
|
import {type WeightedGraph as WeightedGraphT} from "../core/weightedGraph";
|
||||||
import {type PluginDeclaration} from "../analysis/pluginDeclaration";
|
import {type PluginDeclaration} from "../analysis/pluginDeclaration";
|
||||||
import {type CacheProvider} from "./cache";
|
import {type CacheProvider} from "./cache";
|
||||||
import {type GithubToken} from "../plugins/github/token";
|
import {type GithubToken} from "../plugins/github/token";
|
||||||
@ -31,12 +32,24 @@ opaque type CachedProject = {|
|
|||||||
+project: Project,
|
+project: Project,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents all disjoint WeightedGraphs for a CachedProject.
|
||||||
|
*/
|
||||||
|
opaque type PluginGraphs = {|
|
||||||
|
+graphs: $ReadOnlyArray<WeightedGraphT>,
|
||||||
|
+cachedProject: CachedProject,
|
||||||
|
|};
|
||||||
|
|
||||||
type MirrorEnv = {
|
type MirrorEnv = {
|
||||||
+githubToken: ?GithubToken,
|
+githubToken: ?GithubToken,
|
||||||
+reporter: TaskReporter,
|
+reporter: TaskReporter,
|
||||||
+cache: CacheProvider,
|
+cache: CacheProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type GraphEnv = {
|
||||||
|
+githubToken: ?GithubToken,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all relevant PluginDeclarations for a given Project.
|
* Gets all relevant PluginDeclarations for a given Project.
|
||||||
*/
|
*/
|
||||||
@ -82,3 +95,31 @@ export async function updateMirror(
|
|||||||
await Promise.all(tasks);
|
await Promise.all(tasks);
|
||||||
return {project, cache};
|
return {project, cache};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates PluginGraphs containing all plugins requested by the Project.
|
||||||
|
*/
|
||||||
|
export async function createPluginGraphs(
|
||||||
|
{github, discourse}: PluginLoaders,
|
||||||
|
{githubToken}: GraphEnv,
|
||||||
|
{cache, project}: CachedProject
|
||||||
|
): Promise<PluginGraphs> {
|
||||||
|
const tasks: Promise<WeightedGraphT>[] = [];
|
||||||
|
if (project.discourseServer) {
|
||||||
|
tasks.push(discourse.createGraph(project.discourseServer, cache));
|
||||||
|
}
|
||||||
|
if (project.repoIds.length) {
|
||||||
|
if (!githubToken) {
|
||||||
|
throw new Error("Tried to load GitHub, but no GitHub token set");
|
||||||
|
}
|
||||||
|
tasks.push(github.createGraph(project.repoIds, githubToken, cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's important to use Promise.all so that we can load the plugins in
|
||||||
|
// parallel -- since loading is often IO-bound, this can be a big performance
|
||||||
|
// improvement.
|
||||||
|
return {
|
||||||
|
graphs: await Promise.all(tasks),
|
||||||
|
cachedProject: {cache, project},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,11 +1,28 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import * as WeightedGraph from "../core/weightedGraph";
|
||||||
|
import {node as graphNode} from "../core/graphTestUtil";
|
||||||
import {createProject} from "../core/project";
|
import {createProject} from "../core/project";
|
||||||
import {TestTaskReporter} from "../util/taskReporter";
|
import {TestTaskReporter} from "../util/taskReporter";
|
||||||
import {validateToken} from "../plugins/github/token";
|
import {validateToken} from "../plugins/github/token";
|
||||||
import {makeRepoId} from "../plugins/github/repoId";
|
import {makeRepoId} from "../plugins/github/repoId";
|
||||||
import * as PluginLoaders from "./pluginLoaders";
|
import * as PluginLoaders from "./pluginLoaders";
|
||||||
|
|
||||||
|
const githubSentinel = graphNode("github-sentinel");
|
||||||
|
const discourseSentinel = graphNode("discourse-sentinel");
|
||||||
|
|
||||||
|
const mockGithubGraph = () => {
|
||||||
|
const wg = WeightedGraph.empty();
|
||||||
|
wg.graph.addNode(githubSentinel);
|
||||||
|
return wg;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockDiscourseGraph = () => {
|
||||||
|
const wg = WeightedGraph.empty();
|
||||||
|
wg.graph.addNode(discourseSentinel);
|
||||||
|
return wg;
|
||||||
|
};
|
||||||
|
|
||||||
const mockCacheProvider = () => ({
|
const mockCacheProvider = () => ({
|
||||||
database: jest.fn(),
|
database: jest.fn(),
|
||||||
});
|
});
|
||||||
@ -18,10 +35,12 @@ const mockPluginLoaders = () => ({
|
|||||||
github: {
|
github: {
|
||||||
declaration: jest.fn().mockReturnValue(fakeGithubDec),
|
declaration: jest.fn().mockReturnValue(fakeGithubDec),
|
||||||
updateMirror: jest.fn(),
|
updateMirror: jest.fn(),
|
||||||
|
createGraph: jest.fn().mockResolvedValue(mockGithubGraph()),
|
||||||
},
|
},
|
||||||
discourse: {
|
discourse: {
|
||||||
declaration: jest.fn().mockReturnValue(fakeDiscourseDec),
|
declaration: jest.fn().mockReturnValue(fakeDiscourseDec),
|
||||||
updateMirror: jest.fn(),
|
updateMirror: jest.fn(),
|
||||||
|
createGraph: jest.fn().mockResolvedValue(mockDiscourseGraph()),
|
||||||
},
|
},
|
||||||
identity: {
|
identity: {
|
||||||
declaration: jest.fn().mockReturnValue(fakeIdentityDec),
|
declaration: jest.fn().mockReturnValue(fakeIdentityDec),
|
||||||
@ -161,4 +180,93 @@ describe("src/backend/pluginLoaders", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("createPluginGraphs", () => {
|
||||||
|
it("should create discourse graph", async () => {
|
||||||
|
// Given
|
||||||
|
const loaders = mockPluginLoaders();
|
||||||
|
const cache = mockCacheProvider();
|
||||||
|
const githubToken = null;
|
||||||
|
const project = createProject({
|
||||||
|
id: "has-discourse",
|
||||||
|
discourseServer: {serverUrl: "http://foo.bar"},
|
||||||
|
});
|
||||||
|
const cachedProject = ({project, cache}: any);
|
||||||
|
|
||||||
|
// When
|
||||||
|
const pluginGraphs = await PluginLoaders.createPluginGraphs(
|
||||||
|
loaders,
|
||||||
|
{githubToken},
|
||||||
|
cachedProject
|
||||||
|
);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
const {discourse} = loaders;
|
||||||
|
expect(pluginGraphs).toEqual({
|
||||||
|
graphs: [mockDiscourseGraph()],
|
||||||
|
cachedProject,
|
||||||
|
});
|
||||||
|
expect(discourse.createGraph).toBeCalledTimes(1);
|
||||||
|
expect(discourse.createGraph).toBeCalledWith(
|
||||||
|
project.discourseServer,
|
||||||
|
cache
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fail when missing GithubToken", async () => {
|
||||||
|
// Given
|
||||||
|
const loaders = mockPluginLoaders();
|
||||||
|
const cache = mockCacheProvider();
|
||||||
|
const githubToken = null;
|
||||||
|
const project = createProject({
|
||||||
|
id: "has-github",
|
||||||
|
repoIds: [exampleRepoId],
|
||||||
|
});
|
||||||
|
const cachedProject = ({project, cache}: any);
|
||||||
|
|
||||||
|
// When
|
||||||
|
const p = PluginLoaders.createPluginGraphs(
|
||||||
|
loaders,
|
||||||
|
{githubToken},
|
||||||
|
cachedProject
|
||||||
|
);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
await expect(p).rejects.toThrow(
|
||||||
|
"Tried to load GitHub, but no GitHub token set"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create github graph", async () => {
|
||||||
|
// Given
|
||||||
|
const loaders = mockPluginLoaders();
|
||||||
|
const cache = mockCacheProvider();
|
||||||
|
const githubToken = exampleGithubToken;
|
||||||
|
const project = createProject({
|
||||||
|
id: "has-github",
|
||||||
|
repoIds: [exampleRepoId],
|
||||||
|
});
|
||||||
|
const cachedProject = ({project, cache}: any);
|
||||||
|
|
||||||
|
// When
|
||||||
|
const pluginGraphs = await PluginLoaders.createPluginGraphs(
|
||||||
|
loaders,
|
||||||
|
{githubToken},
|
||||||
|
cachedProject
|
||||||
|
);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
const {github} = loaders;
|
||||||
|
expect(pluginGraphs).toEqual({
|
||||||
|
graphs: [mockGithubGraph()],
|
||||||
|
cachedProject,
|
||||||
|
});
|
||||||
|
expect(github.createGraph).toBeCalledTimes(1);
|
||||||
|
expect(github.createGraph).toBeCalledWith(
|
||||||
|
project.repoIds,
|
||||||
|
githubToken,
|
||||||
|
cache
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
import base64url from "base64url";
|
import base64url from "base64url";
|
||||||
import {TaskReporter} from "../../util/taskReporter";
|
import {TaskReporter} from "../../util/taskReporter";
|
||||||
import {type CacheProvider} from "../../backend/cache";
|
import {type CacheProvider} from "../../backend/cache";
|
||||||
|
import {type WeightedGraph} from "../../core/weightedGraph";
|
||||||
import {type PluginDeclaration} from "../../analysis/pluginDeclaration";
|
import {type PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||||
import {type MirrorOptions, Mirror} from "./mirror";
|
import {type MirrorOptions, Mirror} from "./mirror";
|
||||||
import {SqliteMirrorRepository} from "./mirrorRepository";
|
import {SqliteMirrorRepository} from "./mirrorRepository";
|
||||||
|
import {weightsForDeclaration} from "../../analysis/pluginDeclaration";
|
||||||
|
import {createGraph as _createGraph} from "./createGraph";
|
||||||
import {declaration} from "./declaration";
|
import {declaration} from "./declaration";
|
||||||
import {Fetcher} from "./fetch";
|
import {Fetcher} from "./fetch";
|
||||||
|
|
||||||
@ -21,11 +24,16 @@ export interface Loader {
|
|||||||
cache: CacheProvider,
|
cache: CacheProvider,
|
||||||
reporter: TaskReporter
|
reporter: TaskReporter
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
createGraph(
|
||||||
|
server: DiscourseServer,
|
||||||
|
cache: CacheProvider
|
||||||
|
): Promise<WeightedGraph>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
declaration: () => declaration,
|
declaration: () => declaration,
|
||||||
updateMirror,
|
updateMirror,
|
||||||
|
createGraph,
|
||||||
}: Loader);
|
}: Loader);
|
||||||
|
|
||||||
export async function updateMirror(
|
export async function updateMirror(
|
||||||
@ -40,6 +48,16 @@ export async function updateMirror(
|
|||||||
await mirror.update(reporter);
|
await mirror.update(reporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createGraph(
|
||||||
|
{serverUrl}: DiscourseServer,
|
||||||
|
cache: CacheProvider
|
||||||
|
): Promise<WeightedGraph> {
|
||||||
|
const repo = await repository(cache, serverUrl);
|
||||||
|
const graph = _createGraph(serverUrl, repo);
|
||||||
|
const weights = weightsForDeclaration(declaration);
|
||||||
|
return {graph, weights};
|
||||||
|
}
|
||||||
|
|
||||||
async function repository(
|
async function repository(
|
||||||
cache: CacheProvider,
|
cache: CacheProvider,
|
||||||
serverUrl: string
|
serverUrl: string
|
||||||
|
@ -2,11 +2,19 @@
|
|||||||
|
|
||||||
import {TaskReporter} from "../../util/taskReporter";
|
import {TaskReporter} from "../../util/taskReporter";
|
||||||
import {type CacheProvider} from "../../backend/cache";
|
import {type CacheProvider} from "../../backend/cache";
|
||||||
|
import {type WeightedGraph} from "../../core/weightedGraph";
|
||||||
import {type PluginDeclaration} from "../../analysis/pluginDeclaration";
|
import {type PluginDeclaration} from "../../analysis/pluginDeclaration";
|
||||||
import {type GithubToken} from "./token";
|
import {type GithubToken} from "./token";
|
||||||
|
import {Graph} from "../../core/graph";
|
||||||
import {declaration} from "./declaration";
|
import {declaration} from "./declaration";
|
||||||
import {type RepoId, repoIdToString} from "./repoId";
|
import {type RepoId, repoIdToString} from "./repoId";
|
||||||
import {default as fetchGithubRepo} from "./fetchGithubRepo";
|
import {createGraph as _createGraph} from "./createGraph";
|
||||||
|
import {RelationalView} from "./relationalView";
|
||||||
|
import {weightsForDeclaration} from "../../analysis/pluginDeclaration";
|
||||||
|
import {
|
||||||
|
default as fetchGithubRepo,
|
||||||
|
fetchGithubRepoFromCache,
|
||||||
|
} from "./fetchGithubRepo";
|
||||||
|
|
||||||
export interface Loader {
|
export interface Loader {
|
||||||
declaration(): PluginDeclaration;
|
declaration(): PluginDeclaration;
|
||||||
@ -16,11 +24,17 @@ export interface Loader {
|
|||||||
cache: CacheProvider,
|
cache: CacheProvider,
|
||||||
reporter: TaskReporter
|
reporter: TaskReporter
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
createGraph(
|
||||||
|
repoIds: $ReadOnlyArray<RepoId>,
|
||||||
|
token: GithubToken,
|
||||||
|
cache: CacheProvider
|
||||||
|
): Promise<WeightedGraph>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
declaration: () => declaration,
|
declaration: () => declaration,
|
||||||
updateMirror,
|
updateMirror,
|
||||||
|
createGraph,
|
||||||
}: Loader);
|
}: Loader);
|
||||||
|
|
||||||
export async function updateMirror(
|
export async function updateMirror(
|
||||||
@ -39,3 +53,23 @@ export async function updateMirror(
|
|||||||
reporter.finish(taskId);
|
reporter.finish(taskId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createGraph(
|
||||||
|
repoIds: $ReadOnlyArray<RepoId>,
|
||||||
|
token: GithubToken,
|
||||||
|
cache: CacheProvider
|
||||||
|
): Promise<WeightedGraph> {
|
||||||
|
const repositories = [];
|
||||||
|
for (const repoId of repoIds) {
|
||||||
|
repositories.push(await fetchGithubRepoFromCache(repoId, {token, cache}));
|
||||||
|
}
|
||||||
|
const graph = Graph.merge(
|
||||||
|
repositories.map((r) => {
|
||||||
|
const rv = new RelationalView();
|
||||||
|
rv.addRepository(r);
|
||||||
|
return _createGraph(rv);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const weights = weightsForDeclaration(declaration);
|
||||||
|
return {graph, weights};
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user