From 8bd395e622a6c6fc8883d0ba957766725b36414f Mon Sep 17 00:00:00 2001 From: Justin Brooks Date: Mon, 28 Oct 2024 00:29:10 -0400 Subject: [PATCH 1/6] init eph envs --- packages/db/src/schema/environment.ts | 68 +++++++++++++++++++++++---- packages/db/src/schema/release.ts | 12 +++++ 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/packages/db/src/schema/environment.ts b/packages/db/src/schema/environment.ts index b4cbf03c6..ae6925db3 100644 --- a/packages/db/src/schema/environment.ts +++ b/packages/db/src/schema/environment.ts @@ -1,4 +1,3 @@ -import type { ReleaseCondition } from "@ctrlplane/validators/releases"; import type { TargetCondition } from "@ctrlplane/validators/targets"; import type { InferSelectModel } from "drizzle-orm"; import type { z } from "zod"; @@ -16,11 +15,11 @@ import { } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; -import { releaseCondition } from "@ctrlplane/validators/releases"; import { targetCondition } from "@ctrlplane/validators/targets"; import { user } from "./auth.js"; -import { release } from "./release.js"; +import { deployment } from "./deployment.js"; +import { release, releaseChannel } from "./release.js"; import { system } from "./system.js"; import { variableSetEnvironment } from "./variable-sets.js"; @@ -37,7 +36,11 @@ export const environment = pgTable("environment", { targetFilter: jsonb("target_filter") .$type() .default(sql`NULL`), + deletedAt: timestamp("deleted_at", { withTimezone: true }), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), }); export type Environment = InferSelectModel; @@ -90,11 +93,16 @@ export const environmentPolicy = pgTable("environment_policy", { concurrencyType: concurrencyType("concurrency_type").notNull().default("all"), concurrencyLimit: integer("concurrency_limit").notNull().default(1), - duration: bigint("duration", { mode: "number" }).notNull().default(0), + // Duration in milliseconds over which to gradually roll out releases to this + // environment + rolloutDuration: bigint("rollout_duration", { mode: "number" }) + .notNull() + .default(0), - releaseFilter: jsonb("release_filter") - .$type() - .default(sql`NULL`), + // Duration in milliseconds after which deployment delete hooks will be called + ephemeralDuration: bigint("ephemeral_duration", { mode: "number" }) + .notNull() + .default(0), releaseSequencing: releaseSequencingType("release_sequencing") .notNull() @@ -103,9 +111,9 @@ export const environmentPolicy = pgTable("environment_policy", { export type EnvironmentPolicy = InferSelectModel; -export const createEnvironmentPolicy = createInsertSchema(environmentPolicy, { - releaseFilter: releaseCondition.nullable(), -}).omit({ id: true }); +export const createEnvironmentPolicy = createInsertSchema( + environmentPolicy, +).omit({ id: true }); export const updateEnvironmentPolicy = createEnvironmentPolicy.partial(); @@ -190,3 +198,43 @@ export const environmentPolicyApproval = pgTable( export type EnvironmentPolicyApproval = InferSelectModel< typeof environmentPolicyApproval >; + +export const environmentPolicyReleaseChannel = pgTable( + "environment_policy_release_channel", + { + id: uuid("id").primaryKey().defaultRandom(), + policyId: uuid("policy_id") + .notNull() + .references(() => environmentPolicy.id, { onDelete: "cascade" }), + channelId: uuid("channel_id") + .notNull() + .references(() => releaseChannel.id, { onDelete: "cascade" }), + }, + (t) => ({ + uniq: uniqueIndex().on(t.policyId, t.channelId), + deploymentUniq: uniqueIndex().on( + t.policyId, + sql`(SELECT ${deployment.id} FROM ${releaseChannel} WHERE id = ${t.channelId})`, + ), + }), +); + +export const environmentReleaseChannel = pgTable( + "environment_release_channel", + { + id: uuid("id").primaryKey().defaultRandom(), + environmentId: uuid("environment_id") + .notNull() + .references(() => environment.id, { onDelete: "cascade" }), + channelId: uuid("channel_id") + .notNull() + .references(() => releaseChannel.id, { onDelete: "cascade" }), + }, + (t) => ({ + uniq: uniqueIndex().on(t.environmentId, t.channelId), + deploymentUniq: uniqueIndex().on( + t.environmentId, + sql`(SELECT ${deployment.id} FROM ${releaseChannel} WHERE id = ${t.channelId})`, + ), + }), +); diff --git a/packages/db/src/schema/release.ts b/packages/db/src/schema/release.ts index 8e8e2ea7e..0ea07f14b 100644 --- a/packages/db/src/schema/release.ts +++ b/packages/db/src/schema/release.ts @@ -48,6 +48,18 @@ import { environment } from "./environment.js"; import { job } from "./job.js"; import { target } from "./target.js"; +export const releaseChannel = pgTable("release_channel", { + id: uuid("id").primaryKey().defaultRandom(), + name: text("name").notNull(), + description: text("description").default(""), + deploymentId: uuid("deployment_id") + .notNull() + .references(() => deployment.id, { onDelete: "cascade" }), + releaseFilter: jsonb("release_filter") + .$type() + .default(sql`NULL`), +}); + export const releaseDependency = pgTable( "release_dependency", { From 94d6f2552e5daaa1b4726cc3731cd42676b0f8ec Mon Sep 17 00:00:00 2001 From: Justin Brooks Date: Mon, 28 Oct 2024 00:35:39 -0400 Subject: [PATCH 2/6] add default ref --- packages/db/src/schema/deployment-variables.ts | 6 +++++- packages/db/src/schema/deployment.ts | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/db/src/schema/deployment-variables.ts b/packages/db/src/schema/deployment-variables.ts index 6017c52dc..0bfcfcc58 100644 --- a/packages/db/src/schema/deployment-variables.ts +++ b/packages/db/src/schema/deployment-variables.ts @@ -29,7 +29,11 @@ export const deploymentVariable = pgTable( deploymentId: uuid("deployment_id") .notNull() .references(() => deployment.id), - defaultValueId: uuid("default_value_id").default(sql`NULL`), + defaultValueId: uuid("default_value_id") + .references((): any => deploymentVariableValue.id, { + onDelete: "set null", + }) + .default(sql`NULL`), config: jsonb("schema").$type(), }, (t) => ({ diff --git a/packages/db/src/schema/deployment.ts b/packages/db/src/schema/deployment.ts index 7ba409aaf..e858210ee 100644 --- a/packages/db/src/schema/deployment.ts +++ b/packages/db/src/schema/deployment.ts @@ -1,9 +1,11 @@ import type { InferSelectModel } from "drizzle-orm"; +import { sql } from "drizzle-orm"; import { jsonb, pgTable, text, uniqueIndex, uuid } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { z } from "zod"; import { jobAgent } from "./job-agent.js"; +import { releaseChannel } from "./release.js"; import { system } from "./system.js"; export const deploymentSchema = z.object({ @@ -33,6 +35,11 @@ export const deployment = pgTable( id: uuid("id").primaryKey().defaultRandom(), name: text("name").notNull(), slug: text("slug").notNull(), + + defaultReleaseChannelId: uuid("default_release_channel_id") + .references((): any => releaseChannel.id, { onDelete: "set null" }) + .default(sql`NULL`), + description: text("description").notNull(), systemId: uuid("system_id") .notNull() @@ -45,7 +52,9 @@ export const deployment = pgTable( .$type>() .notNull(), }, - (t) => ({ uniq: uniqueIndex().on(t.systemId, t.slug) }), + (t) => ({ + uniq: uniqueIndex().on(t.systemId, t.slug), + }), ); const deploymentInsert = createInsertSchema(deployment, { From 4291287a936a8215c5a500f818cd792afeffa672 Mon Sep 17 00:00:00 2001 From: Justin Brooks Date: Mon, 28 Oct 2024 00:37:23 -0400 Subject: [PATCH 3/6] add env metadata --- packages/db/src/schema/environment.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/db/src/schema/environment.ts b/packages/db/src/schema/environment.ts index ae6925db3..fcf29a010 100644 --- a/packages/db/src/schema/environment.ts +++ b/packages/db/src/schema/environment.ts @@ -238,3 +238,16 @@ export const environmentReleaseChannel = pgTable( ), }), ); + +export const environmentMetadata = pgTable( + "environment_metadata", + { + id: uuid("id").primaryKey().defaultRandom().notNull(), + environmentId: uuid("environment_id") + .references(() => environment.id, { onDelete: "cascade" }) + .notNull(), + key: text("key").notNull(), + value: text("value").notNull(), + }, + (t) => ({ uniq: uniqueIndex().on(t.key, t.environmentId) }), +); From 973914f764394323e3a4a16f9552e7da694c6d76 Mon Sep 17 00:00:00 2001 From: Justin Brooks Date: Mon, 28 Oct 2024 00:40:32 -0400 Subject: [PATCH 4/6] remove nl --- packages/db/src/schema/deployment.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/db/src/schema/deployment.ts b/packages/db/src/schema/deployment.ts index e858210ee..0caa906da 100644 --- a/packages/db/src/schema/deployment.ts +++ b/packages/db/src/schema/deployment.ts @@ -52,9 +52,7 @@ export const deployment = pgTable( .$type>() .notNull(), }, - (t) => ({ - uniq: uniqueIndex().on(t.systemId, t.slug), - }), + (t) => ({ uniq: uniqueIndex().on(t.systemId, t.slug) }), ); const deploymentInsert = createInsertSchema(deployment, { From d7ff09d7feb7cb4568b2449a67454fbbacba3936 Mon Sep 17 00:00:00 2001 From: Aditya Choudhari Date: Mon, 28 Oct 2024 15:01:37 -0700 Subject: [PATCH 5/6] more changes --- .../DeploymentControl.tsx | 37 +- .../RolloutAndTiming.tsx | 14 +- .../releases/[versionId]/FlowPolicyNode.tsx | 83 +- packages/api/src/router/job.ts | 2 +- packages/api/src/router/release.ts | 140 +- packages/db/drizzle/0026_blushing_kang.sql | 86 + packages/db/drizzle/meta/0026_snapshot.json | 4044 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/src/schema/deployment.ts | 6 - packages/db/src/schema/environment.ts | 24 +- packages/db/src/schema/release.ts | 1 + .../__test__/job-variables-deployment.test.ts | 7 + .../src/policies/gradual-rollout.ts | 2 +- .../src/policies/release-string-check.ts | 159 +- 14 files changed, 4414 insertions(+), 198 deletions(-) create mode 100644 packages/db/drizzle/0026_blushing_kang.sql create mode 100644 packages/db/drizzle/meta/0026_snapshot.json diff --git a/apps/webservice/src/app/[workspaceSlug]/_components/environment-policy-drawer/DeploymentControl.tsx b/apps/webservice/src/app/[workspaceSlug]/_components/environment-policy-drawer/DeploymentControl.tsx index 9cb69dd9e..a6387fa6e 100644 --- a/apps/webservice/src/app/[workspaceSlug]/_components/environment-policy-drawer/DeploymentControl.tsx +++ b/apps/webservice/src/app/[workspaceSlug]/_components/environment-policy-drawer/DeploymentControl.tsx @@ -1,6 +1,5 @@ import type * as SCHEMA from "@ctrlplane/db/schema"; import React from "react"; -import _ from "lodash"; import { z } from "zod"; import { Button } from "@ctrlplane/ui/button"; @@ -11,24 +10,16 @@ import { FormField, FormItem, FormLabel, - FormMessage, useForm, } from "@ctrlplane/ui/form"; import { Input } from "@ctrlplane/ui/input"; import { RadioGroup, RadioGroupItem } from "@ctrlplane/ui/radio-group"; -import { - defaultCondition, - isEmptyCondition, - releaseCondition, -} from "@ctrlplane/validators/releases"; import { api } from "~/trpc/react"; -import { ReleaseConditionRender } from "../release-condition/ReleaseConditionRender"; const schema = z.object({ concurrencyType: z.enum(["all", "some"]), concurrencyLimit: z.number().min(1, "Must be a positive number"), - releaseFilter: releaseCondition.nullable(), }); export const DeploymentControl: React.FC<{ @@ -41,12 +32,8 @@ export const DeploymentControl: React.FC<{ const { id, systemId } = environmentPolicy; const onSubmit = form.handleSubmit((data) => { - const releaseFilter = - data.releaseFilter != null && isEmptyCondition(data.releaseFilter) - ? null - : data.releaseFilter; updatePolicy - .mutateAsync({ id, data: { ...data, releaseFilter } }) + .mutateAsync({ id, data }) .then(() => form.reset(data)) .then(() => utils.environment.policy.byId.invalidate(id)) .then(() => utils.environment.policy.bySystemId.invalidate(systemId)); @@ -118,28 +105,6 @@ export const DeploymentControl: React.FC<{ )} /> - ( - - Filter - - - - - {form.formState.isDirty && ( - - Save to apply - - )} - - )} - /> -