From 9fd84abaa54ae468de14ce5fc8c46d961af2fee7 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Wed, 15 Mar 2023 12:28:06 +0100 Subject: [PATCH] feat: Default project mode open (#3316) --- src/lib/db/project-store.ts | 13 +++++++++---- src/lib/openapi/spec/project-schema.ts | 8 ++++++++ src/lib/types/model.ts | 3 +++ .../__snapshots__/openapi.e2e.test.ts.snap | 10 ++++++++++ .../e2e/services/project-service.e2e.test.ts | 19 ++++++++++--------- src/test/fixtures/fake-project-store.ts | 16 +++++++++------- 6 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/lib/db/project-store.ts b/src/lib/db/project-store.ts index a45d6e5682..962bc91386 100644 --- a/src/lib/db/project-store.ts +++ b/src/lib/db/project-store.ts @@ -133,8 +133,11 @@ class ProjectStore implements IProjectStore { const memberMap = new Map( memberCount.map((c) => [c.project, Number(c.count)]), ); - return projectsWithFeatureCount.map((r) => { - return { ...r, memberCount: memberMap.get(r.id) }; + return projectsWithFeatureCount.map((projectWithCount) => { + return { + ...projectWithCount, + memberCount: memberMap.get(projectWithCount.id) || 0, + }; }); } @@ -149,6 +152,7 @@ class ProjectStore implements IProjectStore { featureCount: Number(row.number_of_features) || 0, memberCount: Number(row.number_of_users) || 0, updatedAt: row.updated_at, + mode: 'open', }; } @@ -224,8 +228,8 @@ class ProjectStore implements IProjectStore { } async addDefaultEnvironment(projects: any[]): Promise { - const environments = projects.map((p) => ({ - project_id: p.id, + const environments = projects.map((project) => ({ + project_id: project.id, environment_name: DEFAULT_ENV, })); await this.db('project_environments') @@ -456,6 +460,7 @@ class ProjectStore implements IProjectStore { createdAt: row.created_at, health: row.health ?? 100, updatedAt: row.updated_at || new Date(), + mode: 'open', }; } } diff --git a/src/lib/openapi/spec/project-schema.ts b/src/lib/openapi/spec/project-schema.ts index b81512188b..2e85f018d4 100644 --- a/src/lib/openapi/spec/project-schema.ts +++ b/src/lib/openapi/spec/project-schema.ts @@ -55,6 +55,14 @@ export const projectSchema = { description: '`true` if the project was favorited, otherwise `false`.', }, + mode: { + type: 'string', + enum: ['open', 'protected'], + example: 'open', + nullable: true, + description: + 'A mode of the project affecting what actions are possible in this project. During a rollout of project modes this feature can be optional or `null`', + }, }, components: {}, } as const; diff --git a/src/lib/types/model.ts b/src/lib/types/model.ts index 4c7575b135..8cb90abe81 100644 --- a/src/lib/types/model.ts +++ b/src/lib/types/model.ts @@ -366,7 +366,10 @@ export interface IProject { createdAt?: Date; updatedAt?: Date; changeRequestsEnabled?: boolean; + mode: ProjectMode; } +export type ProjectMode = 'open' | 'protected'; + export interface ICustomRole { id: number; name: string; diff --git a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap index 80068eb061..777073ea10 100644 --- a/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap +++ b/src/test/e2e/api/openapi/__snapshots__/openapi.e2e.test.ts.snap @@ -2836,6 +2836,16 @@ exports[`should serve the OpenAPI spec 1`] = ` "example": 4, "type": "number", }, + "mode": { + "description": "A mode of the project affecting what actions are possible in this project. During a rollout of project modes this feature can be optional or \`null\`", + "enum": [ + "open", + "protected", + ], + "example": "open", + "nullable": true, + "type": "string", + }, "name": { "description": "The name of this project", "example": "DX-Squad", diff --git a/src/test/e2e/services/project-service.e2e.test.ts b/src/test/e2e/services/project-service.e2e.test.ts index 439f5f438b..94dbbed19e 100644 --- a/src/test/e2e/services/project-service.e2e.test.ts +++ b/src/test/e2e/services/project-service.e2e.test.ts @@ -206,6 +206,7 @@ test('should update project', async () => { id: 'test-update', name: 'New name', description: 'Blah longer desc', + mode: 'open' as const, }; await projectService.createProject(project, user); @@ -655,14 +656,14 @@ test('should add a user to the project with a custom role', async () => { { id: 2, name: 'CREATE_FEATURE', - environment: null, + environment: undefined, displayName: 'Create Feature Toggles', type: 'project', }, { id: 8, name: 'DELETE_FEATURE', - environment: null, + environment: undefined, displayName: 'Delete Feature Toggles', type: 'project', }, @@ -711,14 +712,14 @@ test('should delete role entries when deleting project', async () => { { id: 2, name: 'CREATE_FEATURE', - environment: null, + environment: undefined, displayName: 'Create Feature Toggles', type: 'project', }, { id: 8, name: 'DELETE_FEATURE', - environment: null, + environment: undefined, displayName: 'Delete Feature Toggles', type: 'project', }, @@ -757,14 +758,14 @@ test('should change a users role in the project', async () => { { id: 2, name: 'CREATE_FEATURE', - environment: null, + environment: undefined, displayName: 'Create Feature Toggles', type: 'project', }, { id: 8, name: 'DELETE_FEATURE', - environment: null, + environment: undefined, displayName: 'Delete Feature Toggles', type: 'project', }, @@ -940,7 +941,7 @@ test('Should allow bulk update of group permissions', async () => { { id: 2, name: 'CREATE_FEATURE', - environment: null, + environment: undefined, displayName: 'Create Feature Toggles', type: 'project', }, @@ -973,7 +974,7 @@ test('Should bulk update of only users', async () => { { id: 2, name: 'CREATE_FEATURE', - environment: null, + environment: undefined, displayName: 'Create Feature Toggles', type: 'project', }, @@ -1012,7 +1013,7 @@ test('Should allow bulk update of only groups', async () => { { id: 2, name: 'CREATE_FEATURE', - environment: null, + environment: undefined, displayName: 'Create Feature Toggles', type: 'project', }, diff --git a/src/test/fixtures/fake-project-store.ts b/src/test/fixtures/fake-project-store.ts index b0033cf923..bf453e635d 100644 --- a/src/test/fixtures/fake-project-store.ts +++ b/src/test/fixtures/fake-project-store.ts @@ -42,8 +42,8 @@ export default class FakeProjectStore implements IProjectStore { } async getProjectsWithCounts(): Promise { - return this.projects.map((p) => { - return { ...p, memberCount: 0, featureCount: 0 }; + return this.projects.map((project) => { + return { ...project, memberCount: 0, featureCount: 0 }; }); } @@ -52,6 +52,7 @@ export default class FakeProjectStore implements IProjectStore { ...project, health: 100, createdAt: new Date(), + mode: 'open', }; this.projects.push(newProj); return newProj; @@ -63,7 +64,7 @@ export default class FakeProjectStore implements IProjectStore { async delete(key: string): Promise { this.projects.splice( - this.projects.findIndex((p) => p.id === key), + this.projects.findIndex((project) => project.id === key), 1, ); } @@ -90,7 +91,7 @@ export default class FakeProjectStore implements IProjectStore { } async exists(key: string): Promise { - return this.projects.some((p) => p.id === key); + return this.projects.some((project) => project.id === key); } async get(key: string): Promise { @@ -120,7 +121,7 @@ export default class FakeProjectStore implements IProjectStore { // eslint-disable-next-line @typescript-eslint/no-unused-vars environments?: IEnvironment[], ): Promise { - return projects.map((p) => this.createInternal(p)); + return projects.map((project) => this.createInternal(project)); } async update(update: IProjectInsert): Promise { @@ -129,8 +130,9 @@ export default class FakeProjectStore implements IProjectStore { } async updateHealth(healthUpdate: IProjectHealthUpdate): Promise { - this.projects.find((p) => p.id === healthUpdate.id).health = - healthUpdate.health; + this.projects.find( + (project) => project.id === healthUpdate.id, + )!.health = healthUpdate.health; } getMembersCount(): Promise {