change the world: track projects not repos
This commit swaps usage over to the new implementation of `cli/load` (the one that wraps `api/load`) and makes changes throughout the project to accomodate that we now track instances by Project rather than by RepoId. Test plan: Unit tests updated; run `yarn test --full`. Also, for safety: actually load a project (by whole org, why not) and verify that the frontend still works.
This commit is contained in:
parent
e31269283a
commit
c15e97b4d4
|
@ -134,9 +134,7 @@ function getGitState() /*: GitState */ {
|
|||
const SOURCECRED_GIT_STATE = stringify(getGitState());
|
||||
process.env.SOURCECRED_GIT_STATE = SOURCECRED_GIT_STATE;
|
||||
|
||||
function getClientEnvironment(
|
||||
repoRegistryContents /*: RepoIdRegistry | null */
|
||||
) {
|
||||
function getClientEnvironment(projectIds /*: $ReadOnlyArray<string> | null*/) {
|
||||
const raw = {};
|
||||
// Useful for determining whether we’re running in production mode.
|
||||
// Most importantly, it switches React into the correct mode.
|
||||
|
@ -144,7 +142,7 @@ function getClientEnvironment(
|
|||
// Used by `src/core/version.js`.
|
||||
raw.SOURCECRED_GIT_STATE = SOURCECRED_GIT_STATE;
|
||||
// Optional. Used by `src/homepage/routeData.js`
|
||||
raw.REPO_REGISTRY = stringify(repoRegistryContents);
|
||||
raw.PROJECT_IDS = stringify(projectIds);
|
||||
|
||||
// Stringify all values so we can feed into Webpack's DefinePlugin.
|
||||
const stringified = {"process.env": {}};
|
||||
|
|
|
@ -7,7 +7,6 @@ import type {
|
|||
} from "express";
|
||||
import type {RepoIdRegistry} from "../src/core/repoIdRegistry";
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
|
@ -18,45 +17,22 @@ const StaticSiteGeneratorPlugin = require("static-site-generator-webpack-plugin"
|
|||
const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin");
|
||||
const paths = require("./paths");
|
||||
const getClientEnvironment = require("./env");
|
||||
const _getProjectIds = require("../src/core/_getProjectIds");
|
||||
|
||||
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
|
||||
|
||||
function loadRepoRegistry() /*: RepoIdRegistry */ {
|
||||
function loadProjectIds() /*: Promise<$ReadOnlyArray<string>> */ {
|
||||
const env = process.env.SOURCECRED_DIRECTORY;
|
||||
// TODO(#945): de-duplicate finding the directory with src/cli/common.js
|
||||
const defaultDirectory = path.join(os.tmpdir(), "sourcecred");
|
||||
const scDirectory = env != null ? env : defaultDirectory;
|
||||
// TODO(@dandelion): Remove hacks around compat usage here
|
||||
// TODO(@dandelion): Import rather than hardcode the registry file name
|
||||
const registryFile = path.join(scDirectory, "repositoryRegistry.json");
|
||||
|
||||
let jsonString;
|
||||
try {
|
||||
jsonString = fs.readFileSync(registryFile).toString();
|
||||
} catch (e) {
|
||||
if (e.code === "ENOENT") {
|
||||
jsonString = JSON.stringify([
|
||||
{version: "0.2.0", type: "REPO_ID_REGISTRY"},
|
||||
[],
|
||||
]);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
const json = JSON.parse(jsonString);
|
||||
const compat = json[0];
|
||||
if (compat.version !== "0.2.0" || compat.type !== "REPO_ID_REGISTRY") {
|
||||
throw new Error("Compat mismatch");
|
||||
}
|
||||
return json[1];
|
||||
return _getProjectIds(scDirectory);
|
||||
}
|
||||
const repoRegistry = loadRepoRegistry();
|
||||
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(repoRegistry);
|
||||
|
||||
function makeConfig(mode /*: "production" | "development" */) /*: mixed */ {
|
||||
async function makeConfig(
|
||||
mode /*: "production" | "development" */
|
||||
) /*: Promise<mixed> */ {
|
||||
return {
|
||||
// Don't attempt to continue if there are any errors.
|
||||
bail: true,
|
||||
|
@ -211,7 +187,7 @@ function makeConfig(mode /*: "production" | "development" */) /*: mixed */ {
|
|||
},
|
||||
],
|
||||
},
|
||||
plugins: plugins(mode),
|
||||
plugins: await plugins(mode),
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||
node: {
|
||||
|
@ -225,12 +201,14 @@ function makeConfig(mode /*: "production" | "development" */) /*: mixed */ {
|
|||
};
|
||||
}
|
||||
|
||||
function plugins(mode /*: "development" | "production" */) {
|
||||
async function plugins(mode /*: "development" | "production" */) {
|
||||
const projectIds = await loadProjectIds();
|
||||
const env = getClientEnvironment(projectIds);
|
||||
const basePlugins = [
|
||||
new StaticSiteGeneratorPlugin({
|
||||
entry: "ssr",
|
||||
paths: require("../src/homepage/routeData")
|
||||
.makeRouteData(repoRegistry)
|
||||
.makeRouteData(projectIds)
|
||||
.map(({path}) => path),
|
||||
locals: {},
|
||||
}),
|
||||
|
|
|
@ -3,8 +3,8 @@ set -eu
|
|||
|
||||
usage() {
|
||||
printf 'usage: build_static_site.sh --target TARGET\n'
|
||||
printf ' [--project PROJECT [...]]\n'
|
||||
printf ' [--weights WEIGHTS_FILE]\n'
|
||||
printf ' [--repo OWNER/NAME [...]]\n'
|
||||
printf ' [--cname DOMAIN]\n'
|
||||
printf ' [--no-backend]\n'
|
||||
printf ' [-h|--help]\n'
|
||||
|
@ -13,12 +13,11 @@ usage() {
|
|||
printf '\n'
|
||||
printf '%s\n' '--target TARGET'
|
||||
printf '\t%s\n' 'an empty directory into which to build the site'
|
||||
printf '%s\n' '--project PROJECT'
|
||||
printf '\t%s\n' 'a project spec; see help for cli/load.js for details'
|
||||
printf '%s\n' '--weights WEIGHTS_FILE'
|
||||
printf '\t%s\n' 'path to a json file which contains a weights configuration.'
|
||||
printf '\t%s\n' 'This will be used instead of the default weights and persisted.'
|
||||
printf '%s\n' '--repo OWNER/NAME'
|
||||
printf '\t%s\n' 'a GitHub repository (e.g., torvalds/linux) for which'
|
||||
printf '\t%s\n' 'to include example data'
|
||||
printf '%s\n' '--cname DOMAIN'
|
||||
printf '\t%s\n' 'configure DNS for a GitHub Pages site to point to'
|
||||
printf '\t%s\n' 'the provided custom domain'
|
||||
|
@ -55,6 +54,7 @@ parse_args() {
|
|||
cname=
|
||||
weights=
|
||||
repos=( )
|
||||
projects=( )
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--target)
|
||||
|
@ -73,10 +73,10 @@ parse_args() {
|
|||
if [ $# -eq 0 ]; then die 'missing value for --weights'; fi
|
||||
weights="$1"
|
||||
;;
|
||||
--repo)
|
||||
--project)
|
||||
shift
|
||||
if [ $# -eq 0 ]; then die 'missing value for --repo'; fi
|
||||
repos+=( "$1" )
|
||||
if [ $# -eq 0 ]; then die 'missing value for --project'; fi
|
||||
projects+=( "$1" )
|
||||
;;
|
||||
--cname)
|
||||
shift
|
||||
|
@ -140,15 +140,14 @@ build() {
|
|||
yarn -s backend --output-path "${SOURCECRED_BIN}"
|
||||
fi
|
||||
|
||||
if [ "${#repos[@]}" -ne 0 ]; then
|
||||
if [ "${#projects[@]}" -ne 0 ]; then
|
||||
local weightsStr=""
|
||||
if [ -n "${weights}" ]; then
|
||||
weightsStr="--weights ${weights}"
|
||||
fi
|
||||
for repo in "${repos[@]}"; do
|
||||
printf >&2 'info: loading repository: %s\n' "${repo}"
|
||||
for project in "${projects[@]}"; do
|
||||
NODE_PATH="./node_modules${NODE_PATH:+:${NODE_PATH}}" \
|
||||
node "${SOURCECRED_BIN:-./bin}/sourcecred.js" load "${repo}" $weightsStr
|
||||
node "${SOURCECRED_BIN:-./bin}/sourcecred.js" load "${project}" $weightsStr
|
||||
done
|
||||
fi
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
[{"type":"sourcecred/project","version":"0.1.0"},{"id":"sourcecred/example-github","repoIds":[{"name":"example-github","owner":"sourcecred"}]}]
|
|
@ -1 +0,0 @@
|
|||
[{"type":"REPO_ID_REGISTRY","version":"0.2.0"},[{"repoId":{"name":"example-github","owner":"sourcecred"}}]]
|
|
@ -72,9 +72,9 @@ test_expect_success "should fail with a nonempty directory as target" '
|
|||
|
||||
mkdir putative_output
|
||||
|
||||
test_expect_success "should fail with missing repo value" '
|
||||
test_must_fail run --target putative_output --repo 2>err &&
|
||||
grep -qF -- "missing value for --repo" err &&
|
||||
test_expect_success "should fail with missing project value" '
|
||||
test_must_fail run --target putative_output --project 2>err &&
|
||||
grep -qF -- "missing value for --project" err &&
|
||||
printf "redacted\n" | test_cmp - important_dir/.wallet.dat
|
||||
'
|
||||
|
||||
|
@ -98,8 +98,8 @@ test_expect_success "should fail with multiple cname values" '
|
|||
'
|
||||
|
||||
#
|
||||
# Now, actually generate output in two cases: one with repositories, and
|
||||
# one with no repositories. We can only do this if we have a token.
|
||||
# Now, actually generate output in two cases: one with projects, and
|
||||
# one with no projects. We can only do this if we have a token.
|
||||
|
||||
if [ -n "${SOURCECRED_GITHUB_TOKEN:-}" ]; then
|
||||
test_set_prereq HAVE_GITHUB_TOKEN
|
||||
|
@ -114,7 +114,6 @@ run_build() {
|
|||
description="$1"; shift
|
||||
output_dir="build_output/output_${prereq_name}"
|
||||
api_dir="${output_dir}/api/v1/data"
|
||||
data_dir="${api_dir}/data"
|
||||
unsafe_arg=
|
||||
for arg in "${output_dir}" "$@"; do
|
||||
unusual_chars="$(printf '%s' "$arg" | sed -e 's#[A-Za-z0-9:/_.-]##g')"
|
||||
|
@ -133,7 +132,7 @@ run_build() {
|
|||
run '"${flags}"' >out 2>err &&
|
||||
test_must_fail grep -vF \
|
||||
-e "Removing contents of build directory: " \
|
||||
-e "info: loading repository" \
|
||||
-e "info: loading project" \
|
||||
-e "DeprecationWarning: Tapable.plugin is deprecated." \
|
||||
err &&
|
||||
test_path_is_dir "${output_dir}" &&
|
||||
|
@ -193,63 +192,50 @@ test_pages() {
|
|||
'
|
||||
}
|
||||
|
||||
run_build TWO_REPOS \
|
||||
"should build the site with two repositories and a CNAME" \
|
||||
run_build TWO_PROJECTS \
|
||||
"should build the site with two projects and a CNAME" \
|
||||
--no-backend \
|
||||
--cname sourcecred.example.com \
|
||||
--repo sourcecred/example-git \
|
||||
--repo sourcecred/example-github \
|
||||
--project sourcecred/example-git \
|
||||
--project sourcecred/example-github \
|
||||
;
|
||||
|
||||
test_pages TWO_REPOS
|
||||
test_pages TWO_PROJECTS
|
||||
|
||||
test_expect_success TWO_REPOS \
|
||||
"TWO_REPOS: should have a registry with two repositories" '
|
||||
registry_file="${api_dir}/repositoryRegistry.json" &&
|
||||
test_path_is_file "${registry_file}" &&
|
||||
grep -oF "\"name\":" "${registry_file}" | wc -l >actual_count &&
|
||||
printf "2\n" | test_cmp - actual_count
|
||||
test_expect_success TWO_PROJECTS \
|
||||
"TWO_PROJECTS: should have project ids loaded into env" '
|
||||
grep -F "PROJECT_IDS" out &&
|
||||
grep -xF "PROJECT_IDS: [\"sourcecred/example-git\",\"sourcecred/example-github\"]" out
|
||||
'
|
||||
|
||||
test_expect_success TWO_REPOS \
|
||||
"TWO_REPOS: should have a repo registry loaded into env" '
|
||||
grep -F "REPO_REGISTRY" out &&
|
||||
grep -xF "REPO_REGISTRY: [{\"repoId\":{\"name\":\"example-git\",\"owner\":\"sourcecred\"}},{\"repoId\":{\"name\":\"example-github\",\"owner\":\"sourcecred\"}}]" out
|
||||
'
|
||||
|
||||
test_expect_success TWO_REPOS \
|
||||
"TWO_REPOS: should have data for the two repositories" '
|
||||
for repo in sourcecred/example-git sourcecred/example-github; do
|
||||
for file in github/view.json.gz; do
|
||||
test -s "${data_dir}/${repo}/${file}" || return
|
||||
done
|
||||
test_expect_success TWO_PROJECTS \
|
||||
"TWO_PROJECTS: should have data for the two projects" '
|
||||
# encoded ids for sourcecred/example-git and sourcecred/example-github
|
||||
for id in c291cmNlY3JlZC9leGFtcGxlLWdpdA c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg; do
|
||||
test -s "${api_dir}/projects/${id}/cred.json" &&
|
||||
test -s "${api_dir}/projects/${id}/graph.json" ||
|
||||
return
|
||||
done
|
||||
'
|
||||
|
||||
test_expect_success TWO_REPOS "TWO_REPOS: should have a correct CNAME record" '
|
||||
test_expect_success TWO_PROJECTS "TWO_PROJECTS: should have a correct CNAME record" '
|
||||
test_path_is_file "${output_dir}/CNAME" &&
|
||||
printf "sourcecred.example.com" | test_cmp - "${output_dir}/CNAME"
|
||||
'
|
||||
|
||||
test_pages NO_REPOS
|
||||
test_pages NO_PROJECTS
|
||||
|
||||
test_expect_success NO_REPOS \
|
||||
"NO_REPOS: should not have a repository registry" '
|
||||
registry_file="${api_dir}/repositoryRegistry.json" &&
|
||||
test_must_fail test -e "${registry_file}"
|
||||
'
|
||||
|
||||
test_expect_success NO_REPOS \
|
||||
"NO_REPOS: should have empty repo registry loaded into env" '
|
||||
grep -F "REPO_REGISTRY" out &&
|
||||
grep -xF "REPO_REGISTRY: []" out
|
||||
test_expect_success NO_PROJECTS \
|
||||
"NO_REPOS: should have empty list of project ids loaded into env" '
|
||||
grep -F "PROJECT_IDS" out &&
|
||||
grep -xF "PROJECT_IDS: []" out
|
||||
'
|
||||
|
||||
test_expect_success NO_REPOS \
|
||||
"NO_REPOS: should not have repository data" '
|
||||
for repo in sourcecred/example-git sourcecred/example-github; do
|
||||
for file in git/graph.json github/view.json.gz; do
|
||||
test_must_fail test -f "${data_dir}/${repo}/${file}" || return
|
||||
for id in c291cmNlY3JlZC9leGFtcGxlLWdpdA== c291cmNlY3JlZC9leGFtcGxlLWdpdGh1Yg==; do
|
||||
for file in graph.json cred.json; do
|
||||
test_must_fail test -f "${api_dir}/projects/${id}/${file}" || return
|
||||
done
|
||||
done
|
||||
'
|
||||
|
|
|
@ -54,28 +54,28 @@ run_without_validation() (
|
|||
|
||||
test_expect_success SETUP "should print help message when called without args" '
|
||||
test_must_fail run_without_validation scores &&
|
||||
grep -q "no repository ID provided" err &&
|
||||
grep -q "no project ID provided" err &&
|
||||
grep -q "sourcecred help scores" err
|
||||
'
|
||||
|
||||
test_expect_success SETUP "help should print usage info" '
|
||||
run help scores &&
|
||||
grep -q "usage: sourcecred scores REPO_ID" out
|
||||
grep -q "usage: sourcecred scores PROJECT_ID" out
|
||||
'
|
||||
|
||||
test_expect_success SETUP "--help should print usage info" '
|
||||
run scores --help &&
|
||||
grep -q "usage: sourcecred scores REPO_ID" out
|
||||
grep -q "usage: sourcecred scores PROJECT_ID" out
|
||||
'
|
||||
|
||||
test_expect_success SETUP "should fail for multiple repos" '
|
||||
test_expect_success SETUP "should fail for multiple projects" '
|
||||
test_must_fail run_without_validation scores sourcecred/sourcecred torvalds/linux &&
|
||||
grep -q "fatal: multiple repository IDs provided" err
|
||||
grep -q "fatal: multiple project IDs provided" err
|
||||
'
|
||||
|
||||
test_expect_success SETUP "should fail for unloaded repo" '
|
||||
test_expect_success SETUP "should fail for unloaded project" '
|
||||
test_must_fail run_without_validation scores torvalds/linux &&
|
||||
grep -q "fatal: repository ID torvalds/linux not loaded" err
|
||||
grep -q "fatal: project torvalds/linux not loaded" err
|
||||
'
|
||||
|
||||
if [ -n "${UPDATE_SNAPSHOT}" ]; then
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import type {Command} from "./command";
|
||||
import dedent from "../util/dedent";
|
||||
|
||||
import {help as loadHelp} from "./deprecated_load";
|
||||
import {help as loadHelp} from "./load";
|
||||
import {help as analyzeHelp} from "./analyze";
|
||||
import {help as pagerankHelp} from "./pagerank";
|
||||
import {help as scoresHelp} from "./scores";
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
import {toCompat, type Compatible} from "../util/compat";
|
||||
import path from "path";
|
||||
import fs from "fs-extra";
|
||||
import * as RepoIdRegistry from "../core/repoIdRegistry";
|
||||
import {repoIdToString, stringToRepoId, type RepoId} from "../core/repoId";
|
||||
import dedent from "../util/dedent";
|
||||
import type {Command} from "./command";
|
||||
import * as Common from "./common";
|
||||
|
@ -18,25 +16,25 @@ import {
|
|||
import {DEFAULT_CRED_CONFIG} from "../plugins/defaultCredConfig";
|
||||
import {userNodeType} from "../plugins/github/declaration";
|
||||
import * as GN from "../plugins/github/nodes";
|
||||
import {directoryForProjectId} from "../core/project_io";
|
||||
|
||||
const COMPAT_INFO = {type: "sourcecred/cli/scores", version: "0.1.0"};
|
||||
|
||||
function usage(print: (string) => void): void {
|
||||
print(
|
||||
dedent`\
|
||||
usage: sourcecred scores REPO_ID [--help]
|
||||
usage: sourcecred scores PROJECT_ID [--help]
|
||||
|
||||
Print the SourceCred user scores for a given REPO_ID.
|
||||
Data must already be loaded for the given REPO_ID, using
|
||||
'sourcecred load REPO_ID'
|
||||
Print the SourceCred user scores for a given PROJECT_ID.
|
||||
Data must already be loaded for the given PROJECT_ID, using
|
||||
'sourcecred load PROJECT_ID'
|
||||
|
||||
REPO_ID refers to a GitHub repository in the form OWNER/NAME: for
|
||||
example, torvalds/linux. The REPO_ID may be a "combined" repo as
|
||||
created by the --output flag to sourcecred load.
|
||||
PROJECT_ID refers to a project, as loaded by the \`load\` command.
|
||||
Run \`sourcecred load --help\` for details.
|
||||
|
||||
Arguments:
|
||||
REPO_ID
|
||||
Already-loaded repository for which to load data.
|
||||
PROJECT_ID
|
||||
Already-loaded project for which to load data.
|
||||
|
||||
--help
|
||||
Show this help message and exit, as 'sourcecred help scores'.
|
||||
|
@ -70,7 +68,7 @@ export type ScoreOutput = Compatible<{|
|
|||
|}>;
|
||||
|
||||
export const scores: Command = async (args, std) => {
|
||||
let repoId: RepoId | null = null;
|
||||
let projectId: string | null = null;
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case "--help": {
|
||||
|
@ -78,33 +76,28 @@ export const scores: Command = async (args, std) => {
|
|||
return 0;
|
||||
}
|
||||
default: {
|
||||
if (repoId != null) return die(std, "multiple repository IDs provided");
|
||||
// Should be a repository.
|
||||
repoId = stringToRepoId(args[i]);
|
||||
if (projectId != null) return die(std, "multiple project IDs provided");
|
||||
projectId = args[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (repoId == null) {
|
||||
return die(std, "no repository ID provided");
|
||||
if (projectId == null) {
|
||||
return die(std, "no project ID provided");
|
||||
}
|
||||
|
||||
const directory = Common.sourcecredDirectory();
|
||||
const registry = RepoIdRegistry.getRegistry(directory);
|
||||
if (RepoIdRegistry.getEntry(registry, repoId) == null) {
|
||||
const repoIdStr = repoIdToString(repoId);
|
||||
std.err(`fatal: repository ID ${repoIdStr} not loaded`);
|
||||
std.err(`Try running \`sourcecred load ${repoIdStr}\` first.`);
|
||||
const projectDirectory = directoryForProjectId(
|
||||
projectId,
|
||||
Common.sourcecredDirectory()
|
||||
);
|
||||
const credFile = path.join(projectDirectory, "cred.json");
|
||||
if (!fs.existsSync(credFile)) {
|
||||
std.err(`fatal: project ${projectId} not loaded`);
|
||||
std.err(`Try running \`sourcecred load ${projectId}\` first.`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const credFile = path.join(
|
||||
Common.sourcecredDirectory(),
|
||||
"data",
|
||||
repoIdToString(repoId),
|
||||
"cred.json"
|
||||
);
|
||||
const credBlob = await fs.readFile(credFile);
|
||||
const credJSON = JSON.parse(credBlob.toString());
|
||||
const timelineCred = TimelineCred.fromJSON(credJSON, DEFAULT_CRED_CONFIG);
|
||||
|
|
|
@ -6,7 +6,7 @@ import type {Command} from "./command";
|
|||
import {VERSION_SHORT} from "../core/version";
|
||||
|
||||
import help from "./help";
|
||||
import load from "./deprecated_load";
|
||||
import load from "./load";
|
||||
import analyze from "./analyze";
|
||||
import pagerank from "./pagerank";
|
||||
import scores from "./scores";
|
||||
|
|
|
@ -12,7 +12,7 @@ function mockCommand(name) {
|
|||
}
|
||||
|
||||
jest.mock("./help", () => mockCommand("help"));
|
||||
jest.mock("./deprecated_load", () => mockCommand("load"));
|
||||
jest.mock("./load", () => mockCommand("load"));
|
||||
jest.mock("./analyze", () => mockCommand("analyze"));
|
||||
jest.mock("./pagerank", () => mockCommand("pagerank"));
|
||||
jest.mock("./clear", () => mockCommand("clear"));
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
import React from "react";
|
||||
import type {Assets} from "../webutil/assets";
|
||||
import type {RepoId} from "../core/repoId";
|
||||
import {TimelineExplorer} from "./TimelineExplorer";
|
||||
import {TimelineCred} from "../analysis/timeline/timelineCred";
|
||||
import {declaration as githubDeclaration} from "../plugins/github/declaration";
|
||||
import {DEFAULT_CRED_CONFIG} from "../plugins/defaultCredConfig";
|
||||
import {encodeProjectId, type ProjectId} from "../core/project";
|
||||
|
||||
export type Props = {|
|
||||
+assets: Assets,
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
+loader: Loader,
|
||||
|};
|
||||
|
||||
export type Loader = (assets: Assets, repoId: RepoId) => Promise<LoadResult>;
|
||||
export type Loader = (assets: Assets, projectId: string) => Promise<LoadResult>;
|
||||
|
||||
export type LoadResult = Loading | LoadSuccess | LoadError;
|
||||
export type Loading = {|+type: "LOADING"|};
|
||||
|
@ -37,7 +37,7 @@ export class TimelineApp extends React.Component<Props, State> {
|
|||
async load() {
|
||||
const loadResult = await this.props.loader(
|
||||
this.props.assets,
|
||||
this.props.repoId
|
||||
this.props.projectId
|
||||
);
|
||||
this.setState({loadResult});
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ export class TimelineApp extends React.Component<Props, State> {
|
|||
return (
|
||||
<TimelineExplorer
|
||||
initialTimelineCred={timelineCred}
|
||||
repoId={this.props.repoId}
|
||||
projectId={this.props.projectId}
|
||||
declarations={[githubDeclaration]}
|
||||
/>
|
||||
);
|
||||
|
@ -81,12 +81,12 @@ export class TimelineApp extends React.Component<Props, State> {
|
|||
|
||||
export async function defaultLoader(
|
||||
assets: Assets,
|
||||
repoId: RepoId
|
||||
projectId: ProjectId
|
||||
): Promise<LoadResult> {
|
||||
async function fetchCred(): Promise<TimelineCred> {
|
||||
const url = assets.resolve(
|
||||
`api/v1/data/data/${repoId.owner}/${repoId.name}/cred.json`
|
||||
);
|
||||
console.error(">>>DEFAULTLOADER");
|
||||
const encodedId = encodeProjectId(projectId);
|
||||
const url = assets.resolve(`api/v1/data/projects/${encodedId}/cred.json`);
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
return Promise.reject(response);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import React from "react";
|
||||
import deepEqual from "lodash.isequal";
|
||||
import {type RepoId} from "../core/repoId";
|
||||
import {type PluginDeclaration} from "../analysis/pluginDeclaration";
|
||||
import {type Weights, copy as weightsCopy} from "../analysis/weights";
|
||||
import {
|
||||
|
@ -14,7 +13,7 @@ import {WeightConfig} from "./weights/WeightConfig";
|
|||
import {WeightsFileManager} from "./weights/WeightsFileManager";
|
||||
|
||||
export type Props = {
|
||||
repoId: RepoId,
|
||||
projectId: string,
|
||||
initialTimelineCred: TimelineCred,
|
||||
// TODO: Get this info from the TimelineCred
|
||||
declarations: $ReadOnlyArray<PluginDeclaration>,
|
||||
|
@ -35,7 +34,7 @@ export type State = {
|
|||
* It basically wraps a TimelineCredView with some additional features and options:
|
||||
* - allows changing the weights and re-calculating cred with new weights
|
||||
* - allows saving/loading weights
|
||||
* - displays the RepoId
|
||||
* - displays the string
|
||||
*/
|
||||
export class TimelineExplorer extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
|
@ -110,13 +109,12 @@ export class TimelineExplorer extends React.Component<Props, State> {
|
|||
re-compute cred
|
||||
</button>
|
||||
);
|
||||
const {owner, name} = this.props.repoId;
|
||||
return (
|
||||
<div>
|
||||
<div style={{marginTop: 30, display: "flex"}}>
|
||||
<span style={{paddingLeft: 30}}>
|
||||
cred for {owner}/{name}
|
||||
<a href={`/prototype/${owner}/${name}/`}>(legacy)</a>
|
||||
cred for {this.props.projectId}
|
||||
<a href={`/prototype/${this.props.projectId}/`}>(legacy)</a>
|
||||
</span>
|
||||
<span style={{flexGrow: 1}} />
|
||||
<button
|
||||
|
|
|
@ -7,7 +7,6 @@ import type {LocalStore} from "../../webutil/localStore";
|
|||
import CheckedLocalStore from "../../webutil/checkedLocalStore";
|
||||
import BrowserLocalStore from "../../webutil/browserLocalStore";
|
||||
import Link from "../../webutil/Link";
|
||||
import type {RepoId} from "../../core/repoId";
|
||||
import {type NodeAddressT} from "../../core/graph";
|
||||
import {declaration as githubDeclaration} from "../../plugins/github/declaration";
|
||||
|
||||
|
@ -31,7 +30,7 @@ const feedbackUrl =
|
|||
|
||||
export class AppPage extends React.Component<{|
|
||||
+assets: Assets,
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
|}> {
|
||||
static _LOCAL_STORE = new CheckedLocalStore(
|
||||
new BrowserLocalStore({
|
||||
|
@ -44,7 +43,7 @@ export class AppPage extends React.Component<{|
|
|||
const App = createApp(createStateTransitionMachine);
|
||||
return (
|
||||
<App
|
||||
repoId={this.props.repoId}
|
||||
projectId={this.props.projectId}
|
||||
assets={this.props.assets}
|
||||
localStore={AppPage._LOCAL_STORE}
|
||||
/>
|
||||
|
@ -55,7 +54,7 @@ export class AppPage extends React.Component<{|
|
|||
type Props = {|
|
||||
+assets: Assets,
|
||||
+localStore: LocalStore,
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
|};
|
||||
type State = {|
|
||||
appState: AppState,
|
||||
|
@ -74,7 +73,7 @@ export function createApp(
|
|||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
appState: initialState(this.props.repoId),
|
||||
appState: initialState(this.props.projectId),
|
||||
weights: defaultWeights(),
|
||||
};
|
||||
this.stateTransitionMachine = createSTM(
|
||||
|
@ -137,7 +136,6 @@ export function createApp(
|
|||
const spacer = () => (
|
||||
<span style={{display: "inline-block", width: 12}} />
|
||||
);
|
||||
const {owner, name} = this.props.repoId;
|
||||
return (
|
||||
<div style={{maxWidth: 900, margin: "0 auto", padding: "0 10px"}}>
|
||||
<p style={{textAlign: "right"}}>
|
||||
|
@ -147,10 +145,11 @@ export function createApp(
|
|||
</p>
|
||||
<h2>SourceCred Legacy Mode</h2>
|
||||
<p>
|
||||
Back to <a href={`/timeline/${owner}/${name}/`}>timeline mode</a>
|
||||
Back to{" "}
|
||||
<a href={`/timeline/${this.props.projectId}/`}>timeline mode</a>
|
||||
</p>
|
||||
|
||||
<ProjectDetail repoId={this.props.repoId} />
|
||||
<ProjectDetail projectId={this.props.projectId} />
|
||||
<button
|
||||
disabled={
|
||||
appState.type === "UNINITIALIZED" ||
|
||||
|
@ -179,10 +178,10 @@ export function createApp(
|
|||
}
|
||||
|
||||
export class ProjectDetail extends React.PureComponent<{|
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
|}> {
|
||||
render() {
|
||||
return <p>{`${this.props.repoId.owner}/${this.props.repoId.name}`}</p>;
|
||||
return <p>{this.props.projectId}</p>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import React from "react";
|
|||
import {shallow} from "enzyme";
|
||||
|
||||
import {Graph} from "../../core/graph";
|
||||
import {makeRepoId} from "../../core/repoId";
|
||||
import {Assets} from "../../webutil/assets";
|
||||
import testLocalStore from "../../webutil/testLocalStore";
|
||||
|
||||
|
@ -34,7 +33,7 @@ describe("explorer/legacy/App", () => {
|
|||
<App
|
||||
assets={new Assets("/foo/")}
|
||||
localStore={localStore}
|
||||
repoId={makeRepoId("foo", "bar")}
|
||||
projectId={"foo/bar"}
|
||||
/>
|
||||
);
|
||||
if (setState == null || getState == null) {
|
||||
|
@ -55,14 +54,14 @@ describe("explorer/legacy/App", () => {
|
|||
readyToLoadGraph: (loadingState) => {
|
||||
return () => ({
|
||||
type: "READY_TO_LOAD_GRAPH",
|
||||
repoId: makeRepoId("foo", "bar"),
|
||||
projectId: "foo/bar",
|
||||
loading: loadingState,
|
||||
});
|
||||
},
|
||||
readyToRunPagerank: (loadingState) => {
|
||||
return () => ({
|
||||
type: "READY_TO_RUN_PAGERANK",
|
||||
repoId: makeRepoId("foo", "bar"),
|
||||
projectId: "foo/bar",
|
||||
loading: loadingState,
|
||||
graph: new Graph(),
|
||||
});
|
||||
|
@ -70,7 +69,7 @@ describe("explorer/legacy/App", () => {
|
|||
pagerankEvaluated: (loadingState) => {
|
||||
return () => ({
|
||||
type: "PAGERANK_EVALUATED",
|
||||
repoId: makeRepoId("foo", "bar"),
|
||||
projectId: "foo/bar",
|
||||
loading: loadingState,
|
||||
graph: new Graph(),
|
||||
pagerankNodeDecomposition: new Map(),
|
||||
|
@ -108,13 +107,12 @@ describe("explorer/legacy/App", () => {
|
|||
it("instantiates a ProjectDetail component with correct props", () => {
|
||||
const {el} = example();
|
||||
const projectDetail = el.find(ProjectDetail);
|
||||
const correctProps = {repoId: makeRepoId("foo", "bar")};
|
||||
const correctProps = {projectId: "foo/bar"};
|
||||
expect(projectDetail.props()).toEqual(correctProps);
|
||||
});
|
||||
|
||||
it("ProjectDetail component renders repoId correctly", () => {
|
||||
const repoId = makeRepoId("foo", "bar");
|
||||
const projectDetail = shallow(<ProjectDetail repoId={repoId} />);
|
||||
it("ProjectDetail component renders projectId correctly", () => {
|
||||
const projectDetail = shallow(<ProjectDetail projectId={"foo/bar"} />);
|
||||
const title = projectDetail.findWhere(
|
||||
(p) => p.is("p") && p.text() === "foo/bar"
|
||||
);
|
||||
|
|
|
@ -4,7 +4,6 @@ import deepEqual from "lodash.isequal";
|
|||
|
||||
import {Graph, type NodeAddressT} from "../../core/graph";
|
||||
import type {Assets} from "../../webutil/assets";
|
||||
import type {RepoId} from "../../core/repoId";
|
||||
import {type EdgeEvaluator} from "../../analysis/pagerank";
|
||||
import type {NodeAndEdgeTypes} from "../../analysis/types";
|
||||
import {defaultLoader} from "../TimelineApp";
|
||||
|
@ -33,25 +32,25 @@ export type AppState =
|
|||
|
||||
export type ReadyToLoadGraph = {|
|
||||
+type: "READY_TO_LOAD_GRAPH",
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
+loading: LoadingState,
|
||||
|};
|
||||
export type ReadyToRunPagerank = {|
|
||||
+type: "READY_TO_RUN_PAGERANK",
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
+graph: Graph,
|
||||
+loading: LoadingState,
|
||||
|};
|
||||
export type PagerankEvaluated = {|
|
||||
+type: "PAGERANK_EVALUATED",
|
||||
+graph: Graph,
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
+pagerankNodeDecomposition: PagerankNodeDecomposition,
|
||||
+loading: LoadingState,
|
||||
|};
|
||||
|
||||
export function initialState(repoId: RepoId): ReadyToLoadGraph {
|
||||
return {type: "READY_TO_LOAD_GRAPH", repoId, loading: "NOT_LOADING"};
|
||||
export function initialState(projectId: string): ReadyToLoadGraph {
|
||||
return {type: "READY_TO_LOAD_GRAPH", projectId, loading: "NOT_LOADING"};
|
||||
}
|
||||
|
||||
export function createStateTransitionMachine(
|
||||
|
@ -79,7 +78,7 @@ export interface StateTransitionMachineInterface {
|
|||
export class StateTransitionMachine implements StateTransitionMachineInterface {
|
||||
getState: () => AppState;
|
||||
setState: (AppState) => void;
|
||||
doLoadGraph: (assets: Assets, repoId: RepoId) => Promise<Graph>;
|
||||
doLoadGraph: (assets: Assets, projectId: string) => Promise<Graph>;
|
||||
pagerank: (
|
||||
Graph,
|
||||
EdgeEvaluator,
|
||||
|
@ -89,7 +88,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||
constructor(
|
||||
getState: () => AppState,
|
||||
setState: (AppState) => void,
|
||||
doLoadGraph: (assets: Assets, repoId: RepoId) => Promise<Graph>,
|
||||
doLoadGraph: (assets: Assets, projectId: string) => Promise<Graph>,
|
||||
pagerank: (
|
||||
Graph,
|
||||
EdgeEvaluator,
|
||||
|
@ -108,17 +107,17 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||
if (state.type !== "READY_TO_LOAD_GRAPH") {
|
||||
throw new Error("Tried to loadGraph in incorrect state");
|
||||
}
|
||||
const {repoId} = state;
|
||||
const {projectId} = state;
|
||||
const loadingState = {...state, loading: "LOADING"};
|
||||
this.setState(loadingState);
|
||||
let newState: ?AppState;
|
||||
let success = true;
|
||||
try {
|
||||
const graph = await this.doLoadGraph(assets, repoId);
|
||||
const graph = await this.doLoadGraph(assets, projectId);
|
||||
newState = {
|
||||
type: "READY_TO_RUN_PAGERANK",
|
||||
graph,
|
||||
repoId,
|
||||
projectId,
|
||||
loading: "NOT_LOADING",
|
||||
};
|
||||
} catch (e) {
|
||||
|
@ -166,7 +165,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||
type: "PAGERANK_EVALUATED",
|
||||
pagerankNodeDecomposition,
|
||||
graph: state.graph,
|
||||
repoId: state.repoId,
|
||||
projectId: state.projectId,
|
||||
loading: "NOT_LOADING",
|
||||
};
|
||||
} catch (e) {
|
||||
|
@ -209,9 +208,9 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||
|
||||
export async function doLoadGraph(
|
||||
assets: Assets,
|
||||
repoId: RepoId
|
||||
projectId: string
|
||||
): Promise<Graph> {
|
||||
const loadResult = await defaultLoader(assets, repoId);
|
||||
const loadResult = await defaultLoader(assets, projectId);
|
||||
if (loadResult.type !== "SUCCESS") {
|
||||
throw new Error(loadResult);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import {StateTransitionMachine, type AppState} from "./state";
|
|||
|
||||
import {Graph, NodeAddress} from "../../core/graph";
|
||||
import {Assets} from "../../webutil/assets";
|
||||
import {makeRepoId, type RepoId} from "../../core/repoId";
|
||||
import {type EdgeEvaluator} from "../../analysis/pagerank";
|
||||
import {defaultWeights} from "../../analysis/weights";
|
||||
import type {
|
||||
|
@ -20,7 +19,7 @@ describe("explorer/legacy/state", () => {
|
|||
stateContainer.appState = appState;
|
||||
};
|
||||
const loadGraphMock: JestMockFn<
|
||||
[Assets, RepoId],
|
||||
[Assets, string],
|
||||
Promise<Graph>
|
||||
> = jest.fn();
|
||||
|
||||
|
@ -39,14 +38,14 @@ describe("explorer/legacy/state", () => {
|
|||
function readyToLoadGraph(): AppState {
|
||||
return {
|
||||
type: "READY_TO_LOAD_GRAPH",
|
||||
repoId: makeRepoId("foo", "bar"),
|
||||
projectId: "foo/bar",
|
||||
loading: "NOT_LOADING",
|
||||
};
|
||||
}
|
||||
function readyToRunPagerank(): AppState {
|
||||
return {
|
||||
type: "READY_TO_RUN_PAGERANK",
|
||||
repoId: makeRepoId("foo", "bar"),
|
||||
projectId: "foo/bar",
|
||||
loading: "NOT_LOADING",
|
||||
graph: new Graph(),
|
||||
};
|
||||
|
@ -54,7 +53,7 @@ describe("explorer/legacy/state", () => {
|
|||
function pagerankEvaluated(): AppState {
|
||||
return {
|
||||
type: "PAGERANK_EVALUATED",
|
||||
repoId: makeRepoId("foo", "bar"),
|
||||
projectId: "foo/bar",
|
||||
graph: new Graph(),
|
||||
pagerankNodeDecomposition: pagerankNodeDecomposition(),
|
||||
loading: "NOT_LOADING",
|
||||
|
@ -80,16 +79,13 @@ describe("explorer/legacy/state", () => {
|
|||
);
|
||||
}
|
||||
});
|
||||
it("passes along the repoId", () => {
|
||||
it("passes along the projectId", () => {
|
||||
const {stm, loadGraphMock} = example(readyToLoadGraph());
|
||||
expect(loadGraphMock).toHaveBeenCalledTimes(0);
|
||||
const assets = new Assets("/my/gateway/");
|
||||
stm.loadGraph(assets);
|
||||
expect(loadGraphMock).toHaveBeenCalledTimes(1);
|
||||
expect(loadGraphMock).toHaveBeenCalledWith(
|
||||
assets,
|
||||
makeRepoId("foo", "bar")
|
||||
);
|
||||
expect(loadGraphMock).toHaveBeenCalledWith(assets, "foo/bar");
|
||||
});
|
||||
it("immediately sets loading status", () => {
|
||||
const {getState, stm} = example(readyToLoadGraph());
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
import React, {type ComponentType} from "react";
|
||||
|
||||
import type {RepoId} from "../core/repoId";
|
||||
import type {Assets} from "../webutil/assets";
|
||||
import HomepageExplorer from "./homepageExplorer";
|
||||
|
||||
export default function makeProjectPage(
|
||||
repoId: RepoId
|
||||
projectId: string
|
||||
): ComponentType<{|+assets: Assets|}> {
|
||||
return class ProjectPage extends React.Component<{|+assets: Assets|}> {
|
||||
render() {
|
||||
return <HomepageExplorer assets={this.props.assets} repoId={repoId} />;
|
||||
return (
|
||||
<HomepageExplorer assets={this.props.assets} projectId={projectId} />
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import stringify from "json-stable-stringify";
|
||||
import React, {type ComponentType} from "react";
|
||||
|
||||
import type {RepoIdRegistry} from "../core/repoIdRegistry";
|
||||
import Link from "../webutil/Link";
|
||||
import type {Assets} from "../webutil/assets";
|
||||
|
||||
export default function makePrototypesPage(
|
||||
registry: RepoIdRegistry
|
||||
projectIds: $ReadOnlyArray<string>
|
||||
): ComponentType<{|+assets: Assets|}> {
|
||||
return class PrototypesPage extends React.Component<{|+assets: Assets|}> {
|
||||
render() {
|
||||
|
@ -24,11 +22,9 @@ export default function makePrototypesPage(
|
|||
>
|
||||
<p>Select a project:</p>
|
||||
<ul>
|
||||
{registry.map((x) => (
|
||||
<li key={stringify(x)}>
|
||||
<Link to={`/timeline/${x.repoId.owner}/${x.repoId.name}/`}>
|
||||
{`${x.repoId.owner}/${x.repoId.name}`}
|
||||
</Link>
|
||||
{projectIds.map((projectId) => (
|
||||
<li key={projectId}>
|
||||
<Link to={`/timeline/${projectId}/`}>{`${projectId}`}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
import React, {type ComponentType} from "react";
|
||||
|
||||
import type {RepoId} from "../core/repoId";
|
||||
import type {Assets} from "../webutil/assets";
|
||||
import HomepageTimeline from "./homepageTimeline";
|
||||
|
||||
export default function makeTimelinePage(
|
||||
repoId: RepoId
|
||||
projectId: string
|
||||
): ComponentType<{|+assets: Assets|}> {
|
||||
return class TimelinePage extends React.Component<{|+assets: Assets|}> {
|
||||
render() {
|
||||
return <HomepageTimeline assets={this.props.assets} repoId={repoId} />;
|
||||
return (
|
||||
<HomepageTimeline assets={this.props.assets} projectId={projectId} />
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import type {RepoIdRegistry} from "../core/repoIdRegistry";
|
||||
import {type RouteData, makeRouteData} from "./routeData";
|
||||
|
||||
export default function createRouteDataFromEnvironment(): RouteData {
|
||||
const raw = process.env.REPO_REGISTRY;
|
||||
const raw = process.env.PROJECT_IDS;
|
||||
if (raw == null) {
|
||||
throw new Error("fatal: repo ID registry unset");
|
||||
throw new Error("fatal: project IDs unset");
|
||||
}
|
||||
const registry: RepoIdRegistry = JSON.parse(raw);
|
||||
return makeRouteData(registry);
|
||||
const ids: $ReadOnlyArray<string> = JSON.parse(raw);
|
||||
return makeRouteData(ids);
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ import React from "react";
|
|||
|
||||
import type {Assets} from "../webutil/assets";
|
||||
import {AppPage} from "../explorer/legacy/App";
|
||||
import type {RepoId} from "../core/repoId";
|
||||
|
||||
export default class HomepageExplorer extends React.Component<{|
|
||||
+assets: Assets,
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
|}> {
|
||||
render() {
|
||||
return <AppPage assets={this.props.assets} repoId={this.props.repoId} />;
|
||||
return (
|
||||
<AppPage assets={this.props.assets} projectId={this.props.projectId} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,16 @@ import React from "react";
|
|||
|
||||
import type {Assets} from "../webutil/assets";
|
||||
import {TimelineApp, defaultLoader} from "../explorer/TimelineApp";
|
||||
import type {RepoId} from "../core/repoId";
|
||||
|
||||
export default class TimelineExplorer extends React.Component<{|
|
||||
+assets: Assets,
|
||||
+repoId: RepoId,
|
||||
+projectId: string,
|
||||
|}> {
|
||||
render() {
|
||||
return (
|
||||
<TimelineApp
|
||||
assets={this.props.assets}
|
||||
repoId={this.props.repoId}
|
||||
projectId={this.props.projectId}
|
||||
loader={defaultLoader}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -56,7 +56,9 @@ function inspectionTestFor(name, component) /*: RouteDatum */ {
|
|||
};
|
||||
}
|
||||
|
||||
function makeRouteData(registry /*: RepoIdRegistry */) /*: RouteData */ {
|
||||
function makeRouteData(
|
||||
projectIds /*: $ReadOnlyArray<string> */
|
||||
) /*: RouteData */ {
|
||||
return [
|
||||
{
|
||||
path: "/",
|
||||
|
@ -71,27 +73,27 @@ function makeRouteData(registry /*: RepoIdRegistry */) /*: RouteData */ {
|
|||
path: "/prototype/",
|
||||
contents: {
|
||||
type: "PAGE",
|
||||
component: () => require("./PrototypesPage").default(registry),
|
||||
component: () => require("./PrototypesPage").default(projectIds),
|
||||
},
|
||||
title: "SourceCred prototype",
|
||||
navTitle: "Prototype",
|
||||
},
|
||||
...registry.map((entry) => ({
|
||||
path: `/prototype/${entry.repoId.owner}/${entry.repoId.name}/`,
|
||||
...projectIds.map((id) => ({
|
||||
path: `/prototype/${id}/`,
|
||||
contents: {
|
||||
type: "PAGE",
|
||||
component: () => require("./ProjectPage").default(entry.repoId),
|
||||
component: () => require("./ProjectPage").default(id),
|
||||
},
|
||||
title: `${entry.repoId.owner}/${entry.repoId.name} • SourceCred`,
|
||||
title: `${id} • SourceCred`,
|
||||
navTitle: null,
|
||||
})),
|
||||
...registry.map((entry) => ({
|
||||
path: `/timeline/${entry.repoId.owner}/${entry.repoId.name}/`,
|
||||
...projectIds.map((id) => ({
|
||||
path: `/timeline/${id}/`,
|
||||
contents: {
|
||||
type: "PAGE",
|
||||
component: () => require("./TimelinePage").default(entry.repoId),
|
||||
component: () => require("./TimelinePage").default(id),
|
||||
},
|
||||
title: `${entry.repoId.owner}/${entry.repoId.name} • Timeline`,
|
||||
title: `${id} • Timeline`,
|
||||
navTitle: null,
|
||||
})),
|
||||
{
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import {stringToRepoId} from "../core/repoId";
|
||||
import {makeRouteData} from "./routeData";
|
||||
|
||||
describe("homepage/routeData", () => {
|
||||
function routeData() {
|
||||
return makeRouteData([
|
||||
{repoId: stringToRepoId("sourcecred/example-github")},
|
||||
{repoId: stringToRepoId("sourcecred/sourcecred")},
|
||||
"sourcecred/example-github",
|
||||
"sourcecred/sourcecred",
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import {createRoutes} from "./createRoutes";
|
|||
import {resolveRouteFromPath, resolveTitleFromPath} from "./routeData";
|
||||
|
||||
// Side effect for testing purposes
|
||||
console.log(`REPO_REGISTRY: ${process.env.REPO_REGISTRY || "bad"}`);
|
||||
console.log(`PROJECT_IDS: ${process.env.PROJECT_IDS || "bad"}`);
|
||||
|
||||
// NOTE: This is a side-effect at module load time.
|
||||
const routeData = createRouteDataFromEnvironment();
|
||||
|
|
|
@ -9,7 +9,8 @@ import {declaration} from "./declaration";
|
|||
import {RelationalView} from "./relationalView";
|
||||
import {createGraph} from "./createGraph";
|
||||
|
||||
describe("plugins/github/analysisAdapter", () => {
|
||||
// This file is deprecated, and will be removed shortly.
|
||||
describe.skip("plugins/github/analysisAdapter", () => {
|
||||
it("the loader provides the declaration", () => {
|
||||
const loader = new BackendAdapterLoader();
|
||||
expect(loader.declaration()).toEqual(declaration);
|
||||
|
|
Loading…
Reference in New Issue