From a42e94c75f08fa77902f312952fc6d752d2c2cfd Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Wed, 27 Sep 2023 18:17:15 +0100 Subject: [PATCH] Add the STAGING environment by default --- .../helpContent/HelpContentText.tsx | 15 +++++ apps/webapp/app/models/organization.server.ts | 5 +- apps/webapp/app/models/project.server.ts | 1 + .../EnvironmentsPresenter.server.ts | 21 +++++- .../route.tsx | 18 ++++- apps/webapp/prisma/seed.ts | 67 +++++++++++++++++++ .../concepts/environments-endpoints.mdx | 4 ++ .../migration.sql | 13 ++++ packages/database/prisma/schema.prisma | 9 +++ 9 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 packages/database/prisma/migrations/20230927160010_add_data_migrations/migration.sql diff --git a/apps/webapp/app/components/helpContent/HelpContentText.tsx b/apps/webapp/app/components/helpContent/HelpContentText.tsx index 9b7adb3e4..8e9a45871 100644 --- a/apps/webapp/app/components/helpContent/HelpContentText.tsx +++ b/apps/webapp/app/components/helpContent/HelpContentText.tsx @@ -272,6 +272,21 @@ export function HowToUseApiKeysAndEndpoints() { you should use the Test feature to trigger any scheduled Jobs. + + Staging + + + } + /> + + + The STAGING environment is where your Jobs will run in a staging + environment, meant to mirror your production environment. + + environment.type === "STAGING"); + const productionEnvironment = filtered.find( (environment) => environment.type === "PRODUCTION" ); @@ -151,6 +153,9 @@ export class EnvironmentsPresenter { state: "unconfigured", environment: productionEnvironment, }, + STAGING: stagingEnvironment + ? { state: "unconfigured", environment: stagingEnvironment } + : undefined, }, }; @@ -161,6 +166,16 @@ export class EnvironmentsPresenter { client.endpoints.DEVELOPMENT = endpointClient(devEndpoint, developmentEnvironment, baseUrl); } + if (stagingEnvironment) { + const stagingEndpoint = stagingEnvironment.endpoints.find( + (endpoint) => endpoint.slug === slug + ); + + if (stagingEndpoint) { + client.endpoints.STAGING = endpointClient(stagingEndpoint, stagingEnvironment, baseUrl); + } + } + const prodEndpoint = productionEnvironment.endpoints.find( (endpoint) => endpoint.slug === slug ); diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.environments/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.environments/route.tsx index 7d3a2fcaa..a335b1411 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.environments/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.environments/route.tsx @@ -85,8 +85,8 @@ export default function Page() { const client = clients.find((c) => c.slug === selected.client); if (!client) return undefined; - if (selected.type === "PREVIEW" || selected.type === "STAGING") { - throw new Error("PREVIEW/STAGING is not yet supported"); + if (selected.type === "PREVIEW") { + throw new Error("PREVIEW is not yet supported"); } return { @@ -195,6 +195,18 @@ export default function Page() { }) } /> + {client.endpoints.STAGING && ( + + setSelected({ + client: client.slug, + type: "STAGING", + }) + } + /> + )} )} - {selectedEndpoint && ( + {selectedEndpoint && selectedEndpoint.endpoint && ( { + const existingDataMigration = await tx.dataMigration.findUnique({ + where: { + name: "2023-09-27-AddStagingEnvironments", + }, + }); + + if (existingDataMigration) { + return; + } + + await tx.dataMigration.create({ + data: { + name: "2023-09-27-AddStagingEnvironments", + }, + }); + + console.log("Running data migration 2023-09-27-AddStagingEnvironments"); + + const projectsWithoutStagingEnvironments = await tx.project.findMany({ + where: { + environments: { + none: { + type: "STAGING", + }, + }, + }, + include: { + organization: true, + }, + }); + + for (const project of projectsWithoutStagingEnvironments) { + try { + console.log( + `Creating staging environment for project ${project.slug} on org ${project.organization.slug}` + ); + + await createEnvironment(project.organization, project, "STAGING", undefined, tx); + } catch (error) { + console.error(error); + } + } + + await tx.dataMigration.update({ + where: { + name: "2023-09-27-AddStagingEnvironments", + }, + data: { + completedAt: new Date(), + }, + }); + }); + } catch (error) { + console.error(error); + } +} + async function seed() { await seedIntegrationAuthMethods(); if (process.env.NODE_ENV === "development" && process.env.SEED_CLOUD === "enabled") { await seedCloud(prisma); } + + await runDataMigrations(); } seed() diff --git a/docs/documentation/concepts/environments-endpoints.mdx b/docs/documentation/concepts/environments-endpoints.mdx index 689cf7cdd..09239616d 100644 --- a/docs/documentation/concepts/environments-endpoints.mdx +++ b/docs/documentation/concepts/environments-endpoints.mdx @@ -27,6 +27,10 @@ The `DEV` environment should only be used for local development. It's where you +### Staging + +The `STAGING` environment is useful for testing your Jobs against your staging server, if you have one. STAGING works identically to PROD. + ### Production The `PROD` environment is where your Jobs will run in production. It's where you can run your Jobs against real data. diff --git a/packages/database/prisma/migrations/20230927160010_add_data_migrations/migration.sql b/packages/database/prisma/migrations/20230927160010_add_data_migrations/migration.sql new file mode 100644 index 000000000..349fcebaa --- /dev/null +++ b/packages/database/prisma/migrations/20230927160010_add_data_migrations/migration.sql @@ -0,0 +1,13 @@ +-- CreateTable +CREATE TABLE "DataMigration" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "completedAt" TIMESTAMP(3), + + CONSTRAINT "DataMigration_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "DataMigration_name_key" ON "DataMigration"("name"); diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma index 86757f86d..9e8b66da8 100644 --- a/packages/database/prisma/schema.prisma +++ b/packages/database/prisma/schema.prisma @@ -1091,3 +1091,12 @@ model ApiIntegrationVote { @@unique([apiIdentifier, userId]) } + +model DataMigration { + id String @id @default(cuid()) + name String @unique + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + completedAt DateTime? +}