Add params field to Project type (#1801)

* Add params field to Project type

This will allow SourceCred instances to override the default alpha and interval decay parameters by adding an optional "params" field in their project.json file. If they don't include any of the fields, it will just fallback to use the default params.

Test Plan: Add params field in project.json file and see if the resulting SourceCred instance correctly picks up the custom alpha value.

* Rename params field in project to timelineCredParams

Makes the field more descriptive and allows it to be nullable

Test Plan: Ensure all usages of Project type are updated to use timelineCredParams field instead of params

* Update Snapshots

Update snapshots for new project version file

Test Plan: Ensure sharness tests pass in CI
This commit is contained in:
Hammad Jutt 2020-06-04 18:23:06 -06:00 committed by GitHub
parent a8a83c4a86
commit 1abed5f0ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 11 deletions

View File

@ -1 +1 @@
[{"type":"sourcecred/project","version":"0.5.0"},{"discourseServer":null,"id":"sourcecred-test/example-github","identities":[],"initiatives":null,"repoIds":[{"name":"example-github","owner":"sourcecred-test"}]}]
[{"type":"sourcecred/project","version":"0.5.1"},{"discourseServer":null,"id":"sourcecred-test/example-github","identities":[],"initiatives":null,"repoIds":[{"name":"example-github","owner":"sourcecred-test"}],"timelineCredParams":null}]

View File

@ -62,7 +62,7 @@ export function defaultParams(): TimelineCredParameters {
* Fill in default values for timeline cred parameters.
*/
export function partialParams(
partial: $Shape<TimelineCredParameters>
partial: $Shape<TimelineCredParameters> | null
): TimelineCredParameters {
return {...defaultParams(), ...partial};
}

View File

@ -6,7 +6,7 @@ import {LoggingTaskReporter} from "../util/taskReporter";
import type {Command} from "./command";
import * as Common from "./common";
import * as Weights from "../core/weights";
import {projectFromJSON} from "../core/project";
import {projectFromJSON, type Project} from "../core/project";
import {load} from "../api/load";
import {specToProject} from "../plugins/github/specToProject";
import fs from "fs-extra";
@ -14,7 +14,7 @@ import {type PluginDeclaration} from "../analysis/pluginDeclaration";
import {declaration as discourseDeclaration} from "../plugins/discourse/declaration";
import {declaration as githubDeclaration} from "../plugins/github/declaration";
import {declaration as identityDeclaration} from "../plugins/identity/declaration";
import {defaultParams} from "../analysis/timeline/params";
import {partialParams} from "../analysis/timeline/params";
function usage(print: (string) => void): void {
print(
@ -126,7 +126,7 @@ const loadCommand: Command = async (args, std) => {
const taskReporter = new LoggingTaskReporter();
const specProjects = await Promise.all(
const specProjects: $ReadOnlyArray<Project> = await Promise.all(
projectSpecs.map((s) => specToProject(s, githubToken))
);
const manualProjects = await Promise.all(projectPaths.map(loadProject));
@ -142,9 +142,11 @@ const loadCommand: Command = async (args, std) => {
if (project.identities.length) {
plugins.push(identityDeclaration);
}
const params = partialParams(project.timelineCredParams);
return {
project,
params: defaultParams(),
params,
weightsOverrides: weights,
plugins,
sourcecredDirectory: Common.sourcecredDirectory(),

View File

@ -6,6 +6,7 @@ import {toCompat, fromCompat, type Compatible} from "../util/compat";
import {type ProjectParameters as Initiatives} from "../plugins/initiatives/params";
import {type Identity} from "../plugins/identity/identity";
import {type DiscourseServer} from "../plugins/discourse/server";
import type {TimelineCredParameters} from "../analysis/timeline/params";
export type ProjectId = string;
@ -25,22 +26,24 @@ export type ProjectId = string;
* the future (e.g. showing the last update time for each of the project's data
* dependencies).
*/
export type Project = ProjectV050;
export type Project = ProjectV051;
export type SupportedProject =
| ProjectV030
| ProjectV031
| ProjectV040
| ProjectV051
| ProjectV050;
export type ProjectV050 = {|
export type ProjectV051 = {|
+id: ProjectId,
+initiatives: Initiatives | null,
+repoIds: $ReadOnlyArray<RepoId>,
+discourseServer: DiscourseServer | null,
+identities: $ReadOnlyArray<Identity>,
+timelineCredParams: $Shape<TimelineCredParameters> | null,
|};
const COMPAT_INFO = {type: "sourcecred/project", version: "0.5.0"};
const COMPAT_INFO = {type: "sourcecred/project", version: "0.5.1"};
/**
* Creates a new Project instance with default values.
@ -57,6 +60,7 @@ export function createProject(p: $Shape<Project>): Project {
identities: [],
discourseServer: null,
initiatives: null,
timelineCredParams: null,
...p,
};
}
@ -79,11 +83,25 @@ export function encodeProjectId(id: ProjectId): string {
return base64url.encode(id);
}
const upgradeFrom040 = (p: ProjectV040): ProjectV050 => ({
const upgradeFrom050 = (p: ProjectV050): ProjectV051 => ({
...p,
initiatives: null,
timelineCredParams: {},
});
export type ProjectV050 = {|
+id: ProjectId,
+initiatives: Initiatives | null,
+repoIds: $ReadOnlyArray<RepoId>,
+discourseServer: DiscourseServer | null,
+identities: $ReadOnlyArray<Identity>,
|};
const upgradeFrom040 = (p: ProjectV040) =>
upgradeFrom050({
...p,
initiatives: null,
});
export type ProjectV040 = {|
+id: ProjectId,
+repoIds: $ReadOnlyArray<RepoId>,
@ -124,4 +142,5 @@ const upgrades = {
"0.3.0": upgradeFrom030,
"0.3.1": upgradeFrom030,
"0.4.0": upgradeFrom040,
"0.5.0": upgradeFrom050,
};

View File

@ -15,6 +15,7 @@ import {
import {makeRepoId} from "../plugins/github/repoId";
import {toCompat} from "../util/compat";
import type {ProjectV050} from "./project";
describe("core/project", () => {
const foobar = deepFreeze(makeRepoId("foo", "bar"));
@ -25,6 +26,7 @@ describe("core/project", () => {
discourseServer: null,
initiatives: null,
identities: [],
timelineCredParams: null,
});
const p2: Project = deepFreeze({
id: "@foo",
@ -37,6 +39,7 @@ describe("core/project", () => {
aliases: ["github/example"],
},
],
timelineCredParams: null,
});
describe("to/from JSON", () => {
it("round trip is identity", () => {
@ -74,6 +77,7 @@ describe("core/project", () => {
// It should strip the apiUsername field, keeping just serverUrl.
discourseServer: {serverUrl: "https://example.com"},
initiatives: null,
timelineCredParams: {},
}: Project)
);
});
@ -103,6 +107,7 @@ describe("core/project", () => {
// It should strip the apiUsername field, keeping just serverUrl.
discourseServer: {serverUrl: "https://example.com"},
initiatives: null,
timelineCredParams: {},
}: Project)
);
});
@ -128,6 +133,33 @@ describe("core/project", () => {
...body,
// It should add a default initiatives field.
initiatives: null,
timelineCredParams: {},
}: Project)
);
});
it("should upgrade from 0.5.0 formatting", () => {
// Given
const body: ProjectV050 = {
id: "example-050",
repoIds: [foobar, foozod],
discourseServer: {serverUrl: "https://example.com"},
identities: [],
initiatives: null,
};
const compat = toCompat(
{type: "sourcecred/project", version: "0.5.0"},
body
);
// When
const project = projectFromJSON(compat);
// Then
expect(project).toEqual(
({
...body,
// It should add default params field.
timelineCredParams: {},
}: Project)
);
});
@ -169,6 +201,7 @@ describe("core/project", () => {
initiatives: null,
repoIds: [],
identities: [],
timelineCredParams: null,
});
});
it("treats input shape as overrides", () => {
@ -185,6 +218,7 @@ describe("core/project", () => {
aliases: ["github/example"],
},
],
timelineCredParams: {alpha: 0.2, intervalDecay: 0.5},
};
// When

View File

@ -38,6 +38,7 @@ describe("core/project_io", () => {
discourseServer: {serverUrl: "https://example.com"},
identities: [{username: "foo", aliases: ["github/foo", "discourse/foo"]}],
initiatives: {remoteUrl: "https://example.com/initiatives"},
timelineCredParams: {alpha: 0.2, intervalDecay: 0.5},
});
it("setupProjectDirectory results in a loadable project", async () => {