core: allow repo ID registry to store metadata (#1003)
Summary: Our registry was defined to simply be a list of IDs. This is insufficiently flexible; we want to be able to annotate these IDs with, e.g., last-updated times (#989). This commit wraps the entries in a simple object, updating clients appropriately. Test Plan: - Run `node ./bin/sourcecred.js load sourcecred/example-github` with a repository registry in the old format, and note that it errors appropriately. - Run `yarn build` with a repository registry in the old format, and note that it errors (“Compat mismatch”). - Delete the old registry and re-run the `load` command. Note that it runs successfully and outputs a registry. Run `yarn build`; note that this works. - Load data for two repositories. Run `yarn start`. Note that the list of prototypes still works, and that you can navigate to and render attributions for individual project pages. - Verify that `yarn test --full` passes. wchargin-branch: repo-id-registry-metadata
This commit is contained in:
parent
332e776317
commit
80b458d719
|
@ -37,7 +37,7 @@ function loadRepoRegistry() /*: RepoIdRegistry */ {
|
|||
} catch (e) {
|
||||
if (e.code === "ENOENT") {
|
||||
jsonString = JSON.stringify([
|
||||
{version: "0.1.0", type: "REPO_ID_REGISTRY"},
|
||||
{version: "0.2.0", type: "REPO_ID_REGISTRY"},
|
||||
[],
|
||||
]);
|
||||
} else {
|
||||
|
@ -46,7 +46,7 @@ function loadRepoRegistry() /*: RepoIdRegistry */ {
|
|||
}
|
||||
const json = JSON.parse(jsonString);
|
||||
const compat = json[0];
|
||||
if (compat.version !== "0.1.0" || compat.type !== "REPO_ID_REGISTRY") {
|
||||
if (compat.version !== "0.2.0" || compat.type !== "REPO_ID_REGISTRY") {
|
||||
throw new Error("Compat mismatch");
|
||||
}
|
||||
return json[1];
|
||||
|
|
|
@ -1 +1 @@
|
|||
[{"type":"REPO_ID_REGISTRY","version":"0.1.0"},[{"name":"example-github","owner":"sourcecred"}]]
|
||||
[{"type":"REPO_ID_REGISTRY","version":"0.2.0"},[{"repoId":{"name":"example-github","owner":"sourcecred"}}]]
|
|
@ -213,7 +213,7 @@ test_expect_success TWO_REPOS \
|
|||
test_expect_success TWO_REPOS \
|
||||
"TWO_REPOS: should have a repo registry loaded into env" '
|
||||
grep -F "REPO_REGISTRY" out &&
|
||||
grep -xF "REPO_REGISTRY: [{\"name\":\"example-git\",\"owner\":\"sourcecred\"},{\"name\":\"example-github\",\"owner\":\"sourcecred\"}]" out
|
||||
grep -xF "REPO_REGISTRY: [{\"repoId\":{\"name\":\"example-git\",\"owner\":\"sourcecred\"}},{\"repoId\":{\"name\":\"example-github\",\"owner\":\"sourcecred\"}}]" out
|
||||
'
|
||||
|
||||
test_expect_success TWO_REPOS \
|
||||
|
|
|
@ -213,7 +213,7 @@ function addToRepoIdRegistry(repoId) {
|
|||
} else {
|
||||
registry = RepoIdRegistry.emptyRegistry();
|
||||
}
|
||||
registry = RepoIdRegistry.addRepoId(repoId, registry);
|
||||
registry = RepoIdRegistry.addRepoId(registry, {repoId});
|
||||
|
||||
fs.writeFileSync(outputFile, stringify(RepoIdRegistry.toJSON(registry)));
|
||||
}
|
||||
|
|
|
@ -429,7 +429,10 @@ describe("cli/load", () => {
|
|||
)
|
||||
.toString();
|
||||
const registry = RepoIdRegistry.fromJSON(JSON.parse(blob));
|
||||
expect(registry).toEqual([stringToRepoId("foo/combined")]);
|
||||
const expected: RepoIdRegistry.RepoIdRegistry = [
|
||||
{repoId: stringToRepoId("foo/combined")},
|
||||
];
|
||||
expect(registry).toEqual(expected);
|
||||
});
|
||||
|
||||
it("appends to an existing registry", async () => {
|
||||
|
@ -438,8 +441,8 @@ describe("cli/load", () => {
|
|||
path.join(sourcecredDirectory, RepoIdRegistry.REPO_ID_REGISTRY_FILE),
|
||||
JSON.stringify(
|
||||
RepoIdRegistry.toJSON([
|
||||
stringToRepoId("previous/one"),
|
||||
stringToRepoId("previous/two"),
|
||||
{repoId: stringToRepoId("previous/one")},
|
||||
{repoId: stringToRepoId("previous/two")},
|
||||
])
|
||||
)
|
||||
);
|
||||
|
@ -451,11 +454,12 @@ describe("cli/load", () => {
|
|||
)
|
||||
.toString();
|
||||
const registry = RepoIdRegistry.fromJSON(JSON.parse(blob));
|
||||
expect(registry).toEqual([
|
||||
stringToRepoId("previous/one"),
|
||||
stringToRepoId("previous/two"),
|
||||
stringToRepoId("foo/combined"),
|
||||
]);
|
||||
const expected: RepoIdRegistry.RepoIdRegistry = [
|
||||
{repoId: stringToRepoId("previous/one")},
|
||||
{repoId: stringToRepoId("previous/two")},
|
||||
{repoId: stringToRepoId("foo/combined")},
|
||||
];
|
||||
expect(registry).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,9 +10,12 @@ import type {RepoId} from "../core/repoId";
|
|||
export const REPO_ID_REGISTRY_FILE = "repositoryRegistry.json";
|
||||
export const REPO_ID_REGISTRY_API = "/api/v1/data/repositoryRegistry.json";
|
||||
|
||||
const REPO_ID_REGISTRY_COMPAT = {type: "REPO_ID_REGISTRY", version: "0.1.0"};
|
||||
const REPO_ID_REGISTRY_COMPAT = {type: "REPO_ID_REGISTRY", version: "0.2.0"};
|
||||
|
||||
export type RepoIdRegistry = $ReadOnlyArray<RepoId>;
|
||||
export type RegistryEntry = {|
|
||||
+repoId: RepoId,
|
||||
|};
|
||||
export type RepoIdRegistry = $ReadOnlyArray<RegistryEntry>;
|
||||
export type RepoIdRegistryJSON = Compatible<RepoIdRegistry>;
|
||||
|
||||
export function toJSON(r: RepoIdRegistry): RepoIdRegistryJSON {
|
||||
|
@ -23,8 +26,16 @@ export function fromJSON(j: RepoIdRegistryJSON): RepoIdRegistry {
|
|||
return fromCompat(REPO_ID_REGISTRY_COMPAT, j);
|
||||
}
|
||||
|
||||
export function addRepoId(r: RepoId, reg: RepoIdRegistry): RepoIdRegistry {
|
||||
return [...reg.filter((x) => !deepEqual(x, r)), r];
|
||||
export function addRepoId(
|
||||
registry: RepoIdRegistry,
|
||||
entry: RegistryEntry
|
||||
): RepoIdRegistry {
|
||||
return [
|
||||
...registry.filter(
|
||||
(x: RegistryEntry) => !deepEqual(x.repoId, entry.repoId)
|
||||
),
|
||||
entry,
|
||||
];
|
||||
}
|
||||
|
||||
export function emptyRegistry(): RepoIdRegistry {
|
||||
|
|
|
@ -20,31 +20,42 @@ describe("core/repoIdRegistry", () => {
|
|||
checkExample(emptyRegistry());
|
||||
});
|
||||
it("nonempty registry", () => {
|
||||
checkExample([makeRepoId("foo", "bar"), makeRepoId("zoo", "zod")]);
|
||||
checkExample([
|
||||
{repoId: makeRepoId("foo", "bar")},
|
||||
{repoId: makeRepoId("zoo", "zod")},
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe("addRepoId", () => {
|
||||
it("adds to empty registry", () => {
|
||||
expect(addRepoId(makeRepoId("foo", "bar"), emptyRegistry())).toEqual([
|
||||
makeRepoId("foo", "bar"),
|
||||
]);
|
||||
expect(
|
||||
addRepoId(emptyRegistry(), {repoId: makeRepoId("foo", "bar")})
|
||||
).toEqual([{repoId: makeRepoId("foo", "bar")}]);
|
||||
});
|
||||
it("adds to nonempty registry", () => {
|
||||
const registry = [makeRepoId("foo", "bar")];
|
||||
expect(addRepoId(makeRepoId("zoo", "zod"), registry)).toEqual([
|
||||
makeRepoId("foo", "bar"),
|
||||
makeRepoId("zoo", "zod"),
|
||||
const registry = [{repoId: makeRepoId("foo", "bar")}];
|
||||
expect(addRepoId(registry, {repoId: makeRepoId("zoo", "zod")})).toEqual([
|
||||
{repoId: makeRepoId("foo", "bar")},
|
||||
{repoId: makeRepoId("zoo", "zod")},
|
||||
]);
|
||||
});
|
||||
it("adding repoId that is already the last has no effect", () => {
|
||||
const registry = [makeRepoId("zoo", "zod"), makeRepoId("foo", "bar")];
|
||||
expect(addRepoId(makeRepoId("foo", "bar"), registry)).toEqual(registry);
|
||||
const registry = [
|
||||
{repoId: makeRepoId("zoo", "zod")},
|
||||
{repoId: makeRepoId("foo", "bar")},
|
||||
];
|
||||
expect(addRepoId(registry, {repoId: makeRepoId("foo", "bar")})).toEqual(
|
||||
registry
|
||||
);
|
||||
});
|
||||
it("adding already-existing repoId shifts it to the end", () => {
|
||||
const registry = [makeRepoId("zoo", "zod"), makeRepoId("foo", "bar")];
|
||||
expect(addRepoId(makeRepoId("zoo", "zod"), registry)).toEqual([
|
||||
makeRepoId("foo", "bar"),
|
||||
makeRepoId("zoo", "zod"),
|
||||
const registry = [
|
||||
{repoId: makeRepoId("zoo", "zod")},
|
||||
{repoId: makeRepoId("foo", "bar")},
|
||||
];
|
||||
expect(addRepoId(registry, {repoId: makeRepoId("zoo", "zod")})).toEqual([
|
||||
{repoId: makeRepoId("foo", "bar")},
|
||||
{repoId: makeRepoId("zoo", "zod")},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,8 +26,8 @@ export default function makePrototypesPage(
|
|||
<ul>
|
||||
{registry.map((x) => (
|
||||
<li key={stringify(x)}>
|
||||
<Link to={`/prototypes/${x.owner}/${x.name}/`}>
|
||||
{`${x.owner}/${x.name}`}
|
||||
<Link to={`/prototypes/${x.repoId.owner}/${x.repoId.name}/`}>
|
||||
{`${x.repoId.owner}/${x.repoId.name}`}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
|
|
@ -47,13 +47,13 @@ function makeRouteData(registry /*: RepoIdRegistry */) /*: RouteData */ {
|
|||
title: "SourceCred prototype",
|
||||
navTitle: "Prototype",
|
||||
},
|
||||
...registry.map((repo) => ({
|
||||
path: `/prototypes/${repo.owner}/${repo.name}/`,
|
||||
...registry.map((entry) => ({
|
||||
path: `/prototypes/${entry.repoId.owner}/${entry.repoId.name}/`,
|
||||
contents: {
|
||||
type: "PAGE",
|
||||
component: () => require("./ProjectPage").default(repo),
|
||||
component: () => require("./ProjectPage").default(entry.repoId),
|
||||
},
|
||||
title: `${repo.owner}/${repo.name} • SourceCred`,
|
||||
title: `${entry.repoId.owner}/${entry.repoId.name} • SourceCred`,
|
||||
navTitle: null,
|
||||
})),
|
||||
{
|
||||
|
|
|
@ -6,8 +6,8 @@ import {makeRouteData} from "./routeData";
|
|||
describe("homepage/routeData", () => {
|
||||
function routeData() {
|
||||
return makeRouteData([
|
||||
stringToRepoId("sourcecred/example-github"),
|
||||
stringToRepoId("sourcecred/sourcecred"),
|
||||
{repoId: stringToRepoId("sourcecred/example-github")},
|
||||
{repoId: stringToRepoId("sourcecred/sourcecred")},
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue