diff --git a/integration-tests/testkit/flow.ts b/integration-tests/testkit/flow.ts index c442cf16a..c2b821085 100644 --- a/integration-tests/testkit/flow.ts +++ b/integration-tests/testkit/flow.ts @@ -104,9 +104,10 @@ export function createProject(input: CreateProjectInput, authToken: string) { id cleanId } - createdTarget { + createdTargets { id cleanId + name } } } diff --git a/integration-tests/tests/api/persisted-operations/publish.spec.ts b/integration-tests/tests/api/persisted-operations/publish.spec.ts index 099b0eaf1..06419f7a9 100644 --- a/integration-tests/tests/api/persisted-operations/publish.spec.ts +++ b/integration-tests/tests/api/persisted-operations/publish.spec.ts @@ -22,7 +22,7 @@ test('can publish persisted operations only with project:operations-store:write' ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with no rights const noAccessTokenResult = await createToken( @@ -127,7 +127,7 @@ test('should skip on already persisted operations', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( diff --git a/integration-tests/tests/api/project/create.spec.ts b/integration-tests/tests/api/project/create.spec.ts new file mode 100644 index 000000000..5e85d1e51 --- /dev/null +++ b/integration-tests/tests/api/project/create.spec.ts @@ -0,0 +1,45 @@ +import { ProjectType } from '@app/gql/graphql'; +import { createOrganization, createProject } from '../../../testkit/flow'; +import { authenticate } from '../../../testkit/auth'; + +test('creating a project should result in creating the development, staging and production targets', async () => { + const { access_token } = await authenticate('main'); + const orgResult = await createOrganization( + { + name: 'foo', + }, + access_token + ); + const org = orgResult.body.data!.createOrganization.ok!.createdOrganizationPayload.organization; + + const projectResult = await createProject( + { + organization: org.cleanId, + type: ProjectType.Single, + name: 'foo', + }, + access_token + ); + + const targets = projectResult.body.data!.createProject.ok!.createdTargets; + + expect(targets).toHaveLength(3); + expect(targets).toContainEqual( + expect.objectContaining({ + cleanId: 'development', + name: 'development', + }) + ); + expect(targets).toContainEqual( + expect.objectContaining({ + cleanId: 'staging', + name: 'staging', + }) + ); + expect(targets).toContainEqual( + expect.objectContaining({ + cleanId: 'production', + name: 'production', + }) + ); +}); diff --git a/integration-tests/tests/api/schema/check.spec.ts b/integration-tests/tests/api/schema/check.spec.ts index ab2609840..b0a3f75a5 100644 --- a/integration-tests/tests/api/schema/check.spec.ts +++ b/integration-tests/tests/api/schema/check.spec.ts @@ -34,7 +34,7 @@ test('can check a schema with target:registry:read access', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -145,7 +145,7 @@ test('should match indentation of previous description', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( diff --git a/integration-tests/tests/api/schema/publish.spec.ts b/integration-tests/tests/api/schema/publish.spec.ts index eea36fc79..f3875fd14 100644 --- a/integration-tests/tests/api/schema/publish.spec.ts +++ b/integration-tests/tests/api/schema/publish.spec.ts @@ -43,7 +43,7 @@ test('cannot publish a schema without target:registry:write access', async () => ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { @@ -98,7 +98,7 @@ test('can publish a schema with target:registry:write access', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { @@ -175,7 +175,7 @@ test('base schema should not affect the output schema persisted in db', async () ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -276,7 +276,7 @@ test('directives should not be removed (federation)', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -352,7 +352,7 @@ test('should allow to update the URL of a Federated service without changing the ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -443,7 +443,7 @@ test('should allow to update the URL of a Federated service while also changing ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -532,7 +532,7 @@ test('directives should not be removed (stitching)', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -608,7 +608,7 @@ test('directives should not be removed (single)', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -684,7 +684,7 @@ test('share publication of schema using redis', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -758,7 +758,7 @@ test("Two targets with the same commit id shouldn't return an error", async () = owner_access_token ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const writeTokenResult = await createToken( { name: 'test', @@ -843,7 +843,7 @@ test('marking versions as valid', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { @@ -987,7 +987,7 @@ test('marking only the most recent version as valid result in an update of CDN', ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { @@ -1133,7 +1133,7 @@ test('CDN data can not be fetched with an invalid access token', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { @@ -1215,7 +1215,7 @@ test('CDN data can be fetched with an valid access token', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { diff --git a/integration-tests/tests/api/schema/sync.spec.ts b/integration-tests/tests/api/schema/sync.spec.ts index 96303725f..733085fde 100644 --- a/integration-tests/tests/api/schema/sync.spec.ts +++ b/integration-tests/tests/api/schema/sync.spec.ts @@ -35,7 +35,7 @@ test('marking only the most recent version as valid result in an update of CDN', ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { diff --git a/integration-tests/tests/api/target/tokens.spec.ts b/integration-tests/tests/api/target/tokens.spec.ts index 7a2f1d66f..0be812224 100644 --- a/integration-tests/tests/api/target/tokens.spec.ts +++ b/integration-tests/tests/api/target/tokens.spec.ts @@ -38,7 +38,7 @@ test('cannot set a scope on a token if user has no access to that scope', async const member = joinResult.body.data!.joinOrganization.organization.me; const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Give access to tokens await updateMemberAccess( diff --git a/integration-tests/tests/api/target/usage.spec.ts b/integration-tests/tests/api/target/usage.spec.ts index 0fb1acc62..805d3379e 100644 --- a/integration-tests/tests/api/target/usage.spec.ts +++ b/integration-tests/tests/api/target/usage.spec.ts @@ -53,7 +53,7 @@ test('collect operation', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const settingsTokenResult = await createToken( { @@ -216,7 +216,7 @@ test('normalize and collect operation without breaking its syntax', async () => ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const settingsTokenResult = await createToken( { @@ -393,7 +393,7 @@ test('number of produced and collected operations should match (no errors)', asy ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { @@ -491,7 +491,7 @@ test('check usage from two selected targets', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const staging = projectResult.body.data!.createProject.ok!.createdTarget; + const staging = projectResult.body.data!.createProject.ok!.createdTargets[0]; const productionTargetResult = await createTarget( { @@ -685,7 +685,7 @@ test('number of produced and collected operations should match', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; const tokenResult = await createToken( { diff --git a/integration-tests/tests/cli/schema.spec.ts b/integration-tests/tests/cli/schema.spec.ts index f7ed7e142..8af93c7ce 100644 --- a/integration-tests/tests/cli/schema.spec.ts +++ b/integration-tests/tests/cli/schema.spec.ts @@ -34,7 +34,7 @@ test('can publish and check a schema with target:registry:read access', async () ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -94,7 +94,7 @@ test('service url should be available in supergraph', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -163,7 +163,7 @@ test('service url should be required in Federation', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -221,7 +221,7 @@ test('schema:check should notify user when registry is empty', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( @@ -267,7 +267,7 @@ test('schema:check should throw on corrupted schema', async () => { ); const project = projectResult.body.data!.createProject.ok!.createdProject; - const target = projectResult.body.data!.createProject.ok!.createdTarget; + const target = projectResult.body.data!.createProject.ok!.createdTargets[0]; // Create a token with write rights const writeTokenResult = await createToken( diff --git a/packages/services/api/src/modules/project/module.graphql.ts b/packages/services/api/src/modules/project/module.graphql.ts index 74ab5cee8..8a29e9ed2 100644 --- a/packages/services/api/src/modules/project/module.graphql.ts +++ b/packages/services/api/src/modules/project/module.graphql.ts @@ -48,7 +48,7 @@ export default gql` type CreateProjectOk { selector: ProjectSelector! createdProject: Project! - createdTarget: Target! + createdTargets: [Target!]! } type CreateProjectInputErrors { diff --git a/packages/services/api/src/modules/project/resolvers.ts b/packages/services/api/src/modules/project/resolvers.ts index fa63081ac..125e340ac 100644 --- a/packages/services/api/src/modules/project/resolvers.ts +++ b/packages/services/api/src/modules/project/resolvers.ts @@ -62,11 +62,26 @@ export const resolvers: ProjectModule.Resolvers & { ProjectType: any } = { ...input, organization, }); - const target = await injector.get(TargetManager).createTarget({ - name: 'experiment', - project: project.id, - organization, - }); + + const targetManager = injector.get(TargetManager); + + const targets = await Promise.all([ + targetManager.createTarget({ + name: 'production', + project: project.id, + organization, + }), + targetManager.createTarget({ + name: 'staging', + project: project.id, + organization, + }), + targetManager.createTarget({ + name: 'development', + project: project.id, + organization, + }), + ]); return { ok: { @@ -75,7 +90,7 @@ export const resolvers: ProjectModule.Resolvers & { ProjectType: any } = { project: project.cleanId, }, createdProject: project, - createdTarget: target, + createdTargets: targets, }, }; }, diff --git a/packages/web/app/src/components/v2/modals/create-project.tsx b/packages/web/app/src/components/v2/modals/create-project.tsx index 4457b044b..f5ffeb40b 100644 --- a/packages/web/app/src/components/v2/modals/create-project.tsx +++ b/packages/web/app/src/components/v2/modals/create-project.tsx @@ -19,7 +19,7 @@ const CreateProjectMutation = gql(/* GraphQL */ ` createdProject { ...ProjectFields } - createdTarget { + createdTargets { ...TargetFields } } @@ -95,7 +95,8 @@ export const CreateProjectModal = ({ Create a project

A project is built on top of Targets, which are just your environments. We will also create a default - stack named experiment for you (don't worry, you can change it later). + stacks named production, staging and development for you (don't worry, you can change it + later).

diff --git a/packages/web/app/src/graphql/mutation.create-project.graphql b/packages/web/app/src/graphql/mutation.create-project.graphql index bc11b300c..c8559387d 100644 --- a/packages/web/app/src/graphql/mutation.create-project.graphql +++ b/packages/web/app/src/graphql/mutation.create-project.graphql @@ -8,7 +8,7 @@ mutation createProject($input: CreateProjectInput!) { createdProject { ...ProjectFields } - createdTarget { + createdTargets { ...TargetFields } }