diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx
index edb1dad8e..1212e5af1 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx
@@ -1,10 +1,4 @@
import { Button } from "@ctrlplane/ui/button";
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@ctrlplane/ui/tooltip";
import { ApprovalDialog } from "~/app/[workspaceSlug]/(app)/(deploy)/_components/deployment-version/ApprovalDialog";
import { api } from "~/trpc/react";
@@ -16,16 +10,24 @@ export const ApprovalCheck: React.FC<{
versionId: string;
versionTag: string;
}> = (props) => {
- const { data, isLoading } =
- api.deployment.version.checks.approval.status.useQuery(props);
+ const { data, isLoading } = api.policy.evaluate.useQuery(props);
const utils = api.useUtils();
- const invalidate = () =>
- utils.deployment.version.checks.approval.status.invalidate(props);
+ const invalidate = () => utils.policy.evaluate.invalidate(props);
- const isApproved = data?.approved ?? false;
- const rejectionReasonEntries = Array.from(
- data?.rejectionReasons.entries() ?? [],
- );
+ const isAnyApprovalSatisfied = Object.values(
+ data?.rules.anyApprovals ?? {},
+ ).every((reasons) => reasons.length === 0);
+ const isUserApprovalSatisfied = Object.values(
+ data?.rules.userApprovals ?? {},
+ ).every((reasons) => reasons.length === 0);
+ const isRoleApprovalSatisfied = Object.values(
+ data?.rules.roleApprovals ?? {},
+ ).every((reasons) => reasons.length === 0);
+
+ const isApproved =
+ isAnyApprovalSatisfied &&
+ isUserApprovalSatisfied &&
+ isRoleApprovalSatisfied;
if (isLoading)
return (
@@ -41,35 +43,6 @@ export const ApprovalCheck: React.FC<{
);
- if (rejectionReasonEntries.length > 0)
- return (
-
-
-
-
-
- Not enough approvals
-
-
-
-
-
-
-
-
- {rejectionReasonEntries.map(([reason, comment]) => (
- -
- {reason}: {comment}
-
- ))}
-
-
-
-
- );
-
return (
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/DenyWindow.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/DenyWindow.tsx
deleted file mode 100644
index 7e2f54af1..000000000
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/DenyWindow.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@ctrlplane/ui/tooltip";
-
-import { api } from "~/trpc/react";
-import { Loading, Passing, Waiting } from "../StatusIcons";
-
-export const DenyWindowCheck: React.FC<{
- workspaceId: string;
- environmentId: string;
- versionId: string;
-}> = ({ workspaceId, environmentId, versionId }) => {
- const { data, isLoading } =
- api.deployment.version.checks.denyWindow.status.useQuery({
- workspaceId,
- environmentId,
- versionId,
- });
-
- const isBlocked = data ?? false;
- const rejectionReasonEntries: Array<[string, string]> = [];
-
- if (isLoading)
- return (
-
- Loading deny windows
-
- );
-
- if (!isBlocked)
- return (
-
-
no active deny windows
-
- );
-
- if (rejectionReasonEntries.length > 0) {
- return (
-
-
-
-
- deny window is active
-
-
-
-
- {rejectionReasonEntries.map(([reason, comment]) => (
- -
- {reason}: {comment}
-
- ))}
-
-
-
-
- );
- }
-
- return (
-
- currently in deny window
-
- );
-};
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/VersionSelector.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/VersionSelector.tsx
index e8a47135a..458faccd7 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/VersionSelector.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/VersionSelector.tsx
@@ -5,13 +5,14 @@ export const VersionSelectorCheck: React.FC<{
versionId: string;
environmentId: string;
}> = ({ versionId, environmentId }) => {
- const { data, isLoading } =
- api.deployment.version.checks.versionSelector.useQuery({
- versionId,
- environmentId,
- });
+ const { data, isLoading } = api.policy.evaluate.useQuery({
+ environmentId,
+ versionId,
+ });
- const isPassingVersionSelector = data ?? false;
+ const isPassingVersionSelector = Object.values(
+ data?.rules.versionSelector ?? {},
+ ).every((isPassing) => isPassing);
if (isLoading)
return (
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/nodes/EnvironmentNode.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/nodes/EnvironmentNode.tsx
index a996f81ad..93b494ffb 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/nodes/EnvironmentNode.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/nodes/EnvironmentNode.tsx
@@ -8,7 +8,6 @@ import { cn } from "@ctrlplane/ui";
import { Separator } from "@ctrlplane/ui/separator";
import { ApprovalCheck } from "../checks/Approval";
-import { DenyWindowCheck } from "../checks/DenyWindow";
import { VersionSelectorCheck } from "../checks/VersionSelector";
type EnvironmentNodeProps = NodeProps<{
@@ -35,7 +34,6 @@ export const EnvironmentNode: React.FC
= ({ data }) => (
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/page.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/page.tsx
index 1172d2dd9..57200446c 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/page.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/page.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { IconMenu2 } from "@tabler/icons-react";
+import _ from "lodash";
import { SidebarTrigger } from "@ctrlplane/ui/sidebar";
@@ -44,9 +45,15 @@ export default async function ChecksPage(props: PageProps) {
if (deploymentVersion == null || deployment == null) return notFound();
const { system } = deployment;
- const environments = await api.deployment.version.checks.environmentsToCheck(
- deployment.id,
+ const releaseTargets = await api.releaseTarget.list({
+ deploymentId: deployment.id,
+ });
+
+ const environments = _.uniqBy(
+ releaseTargets.map((r) => r.environment),
+ (env) => env.id,
);
+
return (
void;
}> = ({ versionId, versionTag, environmentId, children, onSubmit }) => {
const [open, setOpen] = useState(false);
- const addRecord =
- api.deployment.version.checks.approval.addRecord.useMutation();
+ const addRecord = api.deployment.version.addApprovalRecord.useMutation();
const router = useRouter();
diff --git a/packages/api/src/router/deployment-version-checks/approvals.ts b/packages/api/src/router/deployment-version-checks/approvals.ts
deleted file mode 100644
index 60650345a..000000000
--- a/packages/api/src/router/deployment-version-checks/approvals.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-import { z } from "zod";
-
-import { and, eq } from "@ctrlplane/db";
-import * as SCHEMA from "@ctrlplane/db/schema";
-import { Channel, getQueue } from "@ctrlplane/events";
-import {
- getVersionApprovalRules,
- mergePolicies,
- VersionReleaseManager,
-} from "@ctrlplane/rule-engine";
-import { Permission } from "@ctrlplane/validators/auth";
-
-import { createTRPCRouter, protectedProcedure } from "../../trpc";
-import {
- getAnyReleaseTargetForDeploymentAndEnvironment,
- getApplicablePoliciesWithoutResourceScope,
- getVersionWithMetadata,
-} from "./utils";
-
-export const approvalRouter = createTRPCRouter({
- status: protectedProcedure
- .input(
- z.object({
- workspaceId: z.string().uuid(),
- versionId: z.string().uuid(),
- environmentId: z.string().uuid(),
- }),
- )
- .meta({
- authorizationCheck: ({ canUser, input }) =>
- canUser.perform(Permission.DeploymentVersionGet).on({
- type: "deploymentVersion",
- id: input.versionId,
- }),
- })
- .query(
- async ({ ctx, input: { versionId, environmentId, workspaceId } }) => {
- const version = await getVersionWithMetadata(ctx.db, versionId);
- const { deploymentId } = version;
-
- const releaseTarget =
- await getAnyReleaseTargetForDeploymentAndEnvironment(
- ctx.db,
- deploymentId,
- environmentId,
- workspaceId,
- );
- const policies = await getApplicablePoliciesWithoutResourceScope(
- ctx.db,
- releaseTarget.id,
- );
- const mergedPolicy = mergePolicies(policies);
- const manager = new VersionReleaseManager(ctx.db, releaseTarget);
- const result = await manager.evaluate({
- policy: mergedPolicy ?? undefined,
- versions: [version],
- rules: getVersionApprovalRules,
- });
-
- return {
- approved: result.chosenCandidate != null,
- rejectionReasons: result.rejectionReasons,
- };
- },
- ),
-
- addRecord: protectedProcedure
- .input(
- z.object({
- deploymentVersionId: z.string().uuid(),
- environmentId: z.string().uuid(),
- status: z.nativeEnum(SCHEMA.ApprovalStatus),
- reason: z.string().optional(),
- }),
- )
- .meta({
- authorizationCheck: ({ canUser, input }) =>
- canUser.perform(Permission.DeploymentVersionGet).on({
- type: "deploymentVersion",
- id: input.deploymentVersionId,
- }),
- })
- .mutation(async ({ ctx, input }) => {
- const { deploymentVersionId, environmentId, status, reason } = input;
-
- const record = await ctx.db
- .insert(SCHEMA.policyRuleAnyApprovalRecord)
- .values({
- deploymentVersionId,
- userId: ctx.session.user.id,
- status,
- reason,
- approvedAt:
- status === SCHEMA.ApprovalStatus.Approved ? new Date() : null,
- })
- .returning();
-
- const rows = await ctx.db
- .select()
- .from(SCHEMA.deploymentVersion)
- .innerJoin(
- SCHEMA.releaseTarget,
- eq(
- SCHEMA.deploymentVersion.deploymentId,
- SCHEMA.releaseTarget.deploymentId,
- ),
- )
- .where(
- and(
- eq(SCHEMA.deploymentVersion.id, deploymentVersionId),
- eq(SCHEMA.releaseTarget.environmentId, environmentId),
- ),
- );
-
- const targets = rows.map((row) => row.release_target);
- if (targets.length > 0)
- await getQueue(Channel.EvaluateReleaseTarget).addBulk(
- targets.map((rt) => ({
- name: `${rt.resourceId}-${rt.environmentId}-${rt.deploymentId}`,
- data: rt,
- })),
- );
-
- return record;
- }),
-});
diff --git a/packages/api/src/router/deployment-version-checks/deny-window.ts b/packages/api/src/router/deployment-version-checks/deny-window.ts
deleted file mode 100644
index ee16ede2a..000000000
--- a/packages/api/src/router/deployment-version-checks/deny-window.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { z } from "zod";
-
-import { Permission } from "@ctrlplane/validators/auth";
-
-import { createTRPCRouter, protectedProcedure } from "../../trpc";
-
-export const denyWindowRouter = createTRPCRouter({
- status: protectedProcedure
- .input(
- z.object({
- workspaceId: z.string().uuid(),
- versionId: z.string().uuid(),
- environmentId: z.string().uuid(),
- }),
- )
- .meta({
- authorizationCheck: ({ canUser, input }) =>
- canUser.perform(Permission.DeploymentVersionGet).on({
- type: "deploymentVersion",
- id: input.versionId,
- }),
- })
- .query(() => false),
-});
diff --git a/packages/api/src/router/deployment-version-checks/router.ts b/packages/api/src/router/deployment-version-checks/router.ts
deleted file mode 100644
index 03b652003..000000000
--- a/packages/api/src/router/deployment-version-checks/router.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { z } from "zod";
-
-import { eq } from "@ctrlplane/db";
-import * as SCHEMA from "@ctrlplane/db/schema";
-import { Permission } from "@ctrlplane/validators/auth";
-
-import { createTRPCRouter, protectedProcedure } from "../../trpc";
-import { approvalRouter } from "./approvals";
-import { denyWindowRouter } from "./deny-window";
-import { versionSelector } from "./version-selector";
-
-export const deploymentVersionChecksRouter = createTRPCRouter({
- environmentsToCheck: protectedProcedure
- .input(z.string().uuid())
- .meta({
- authorizationCheck: async ({ ctx, canUser, input }) => {
- const deployment = await ctx.db.query.deployment.findFirst({
- where: eq(SCHEMA.deployment.id, input),
- });
- if (deployment == null) return false;
- return canUser
- .perform(Permission.EnvironmentList)
- .on({ type: "system", id: deployment.systemId });
- },
- })
- .query(async ({ ctx, input: deploymentId }) => {
- const rows = await ctx.db
- .selectDistinctOn([SCHEMA.environment.id])
- .from(SCHEMA.releaseTarget)
- .innerJoin(
- SCHEMA.environment,
- eq(SCHEMA.releaseTarget.environmentId, SCHEMA.environment.id),
- )
- .where(eq(SCHEMA.releaseTarget.deploymentId, deploymentId))
- .orderBy(SCHEMA.environment.id);
- return rows.map((r) => r.environment);
- }),
- approval: approvalRouter,
- denyWindow: denyWindowRouter,
- versionSelector,
-});
diff --git a/packages/api/src/router/deployment-version-checks/utils.ts b/packages/api/src/router/deployment-version-checks/utils.ts
deleted file mode 100644
index 0fec22a1e..000000000
--- a/packages/api/src/router/deployment-version-checks/utils.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import type { Tx } from "@ctrlplane/db";
-import { TRPCError } from "@trpc/server";
-
-import { and, eq, inArray, isNull } from "@ctrlplane/db";
-import * as SCHEMA from "@ctrlplane/db/schema";
-
-export const getApplicablePoliciesWithoutResourceScope = async (
- db: Tx,
- releaseTargetId: string,
-) => {
- const rows = await db
- .select()
- .from(SCHEMA.computedPolicyTargetReleaseTarget)
- .innerJoin(
- SCHEMA.policyTarget,
- eq(
- SCHEMA.computedPolicyTargetReleaseTarget.policyTargetId,
- SCHEMA.policyTarget.id,
- ),
- )
- .where(
- and(
- eq(
- SCHEMA.computedPolicyTargetReleaseTarget.releaseTargetId,
- releaseTargetId,
- ),
- isNull(SCHEMA.policyTarget.resourceSelector),
- ),
- );
-
- const policyIds = rows.map((r) => r.policy_target.policyId);
- return db.query.policy.findMany({
- where: inArray(SCHEMA.policy.id, policyIds),
- with: {
- denyWindows: true,
- deploymentVersionSelector: true,
- versionAnyApprovals: true,
- versionRoleApprovals: true,
- versionUserApprovals: true,
- },
- });
-};
-
-export const getVersionWithMetadata = async (db: Tx, versionId: string) => {
- const v = await db.query.deploymentVersion.findFirst({
- where: eq(SCHEMA.deploymentVersion.id, versionId),
- with: { metadata: true },
- });
- if (v == null)
- throw new TRPCError({
- code: "NOT_FOUND",
- message: `Deployment version not found: ${versionId}`,
- });
- const metadata = Object.fromEntries(v.metadata.map((m) => [m.key, m.value]));
- return { ...v, metadata };
-};
-
-export const getAnyReleaseTargetForDeploymentAndEnvironment = async (
- db: Tx,
- deploymentId: string,
- environmentId: string,
- workspaceId: string,
-) => {
- const rt = await db.query.releaseTarget.findFirst({
- where: and(
- eq(SCHEMA.releaseTarget.deploymentId, deploymentId),
- eq(SCHEMA.releaseTarget.environmentId, environmentId),
- ),
- });
- if (rt == null)
- throw new TRPCError({
- code: "NOT_FOUND",
- message: `Release target not found: ${deploymentId} ${environmentId}`,
- });
- return { ...rt, workspaceId };
-};
diff --git a/packages/api/src/router/deployment-version-checks/version-selector.ts b/packages/api/src/router/deployment-version-checks/version-selector.ts
deleted file mode 100644
index 4f87bb95d..000000000
--- a/packages/api/src/router/deployment-version-checks/version-selector.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { TRPCError } from "@trpc/server";
-import { z } from "zod";
-
-import { and, eq, selector } from "@ctrlplane/db";
-import * as SCHEMA from "@ctrlplane/db/schema";
-import { mergePolicies } from "@ctrlplane/rule-engine";
-import { Permission } from "@ctrlplane/validators/auth";
-
-import { protectedProcedure } from "../../trpc";
-import {
- getAnyReleaseTargetForDeploymentAndEnvironment,
- getApplicablePoliciesWithoutResourceScope,
- getVersionWithMetadata,
-} from "./utils";
-
-export const versionSelector = protectedProcedure
- .input(
- z.object({
- versionId: z.string().uuid(),
- environmentId: z.string().uuid(),
- }),
- )
- .meta({
- authorizationCheck: ({ canUser, input }) =>
- canUser.perform(Permission.DeploymentVersionGet).on({
- type: "deploymentVersion",
- id: input.versionId,
- }),
- })
- .query(async ({ ctx, input }) => {
- const { versionId, environmentId } = input;
- const version = await getVersionWithMetadata(ctx.db, versionId);
- const { deploymentId } = version;
-
- const environment = await ctx.db.query.environment.findFirst({
- where: eq(SCHEMA.environment.id, environmentId),
- with: { system: true },
- });
- if (environment == null)
- throw new TRPCError({
- code: "NOT_FOUND",
- message: `Environment not found: ${environmentId}`,
- });
-
- const { system } = environment;
- const { workspaceId } = system;
-
- const releaseTarget = await getAnyReleaseTargetForDeploymentAndEnvironment(
- ctx.db,
- deploymentId,
- environmentId,
- workspaceId,
- );
- const policies = await getApplicablePoliciesWithoutResourceScope(
- ctx.db,
- releaseTarget.id,
- );
- const mergedPolicy = mergePolicies(policies);
- const versionSelector =
- mergedPolicy?.deploymentVersionSelector?.deploymentVersionSelector;
- if (versionSelector == null) return true;
-
- const matchedVersion = await ctx.db.query.deploymentVersion.findFirst({
- where: and(
- eq(SCHEMA.deploymentVersion.id, versionId),
- selector().query().deploymentVersions().where(versionSelector).sql(),
- ),
- });
-
- return matchedVersion != null;
- });
diff --git a/packages/api/src/router/deployment-version.ts b/packages/api/src/router/deployment-version.ts
index 1b78c6427..94d4613e2 100644
--- a/packages/api/src/router/deployment-version.ts
+++ b/packages/api/src/router/deployment-version.ts
@@ -45,7 +45,6 @@ import {
} from "@ctrlplane/validators/releases";
import { createTRPCRouter, protectedProcedure } from "../trpc";
-import { deploymentVersionChecksRouter } from "./deployment-version-checks/router";
import { deploymentVersionJobsRouter } from "./deployment-version-jobs";
import { deploymentVersionMetadataKeysRouter } from "./version-metadata-keys";
@@ -379,6 +378,66 @@ export const versionRouter = createTRPCRouter({
),
),
+ addApprovalRecord: protectedProcedure
+ .input(
+ z.object({
+ deploymentVersionId: z.string().uuid(),
+ environmentId: z.string().uuid(),
+ status: z.nativeEnum(SCHEMA.ApprovalStatus),
+ reason: z.string().optional(),
+ }),
+ )
+ .meta({
+ authorizationCheck: ({ canUser, input }) =>
+ canUser.perform(Permission.DeploymentVersionGet).on({
+ type: "deploymentVersion",
+ id: input.deploymentVersionId,
+ }),
+ })
+ .mutation(async ({ ctx, input }) => {
+ const { deploymentVersionId, environmentId, status, reason } = input;
+
+ const record = await ctx.db
+ .insert(SCHEMA.policyRuleAnyApprovalRecord)
+ .values({
+ deploymentVersionId,
+ userId: ctx.session.user.id,
+ status,
+ reason,
+ approvedAt:
+ status === SCHEMA.ApprovalStatus.Approved ? new Date() : null,
+ })
+ .returning();
+
+ const rows = await ctx.db
+ .select()
+ .from(SCHEMA.deploymentVersion)
+ .innerJoin(
+ SCHEMA.releaseTarget,
+ eq(
+ SCHEMA.deploymentVersion.deploymentId,
+ SCHEMA.releaseTarget.deploymentId,
+ ),
+ )
+ .where(
+ and(
+ eq(SCHEMA.deploymentVersion.id, deploymentVersionId),
+ eq(SCHEMA.releaseTarget.environmentId, environmentId),
+ ),
+ );
+
+ const targets = rows.map((row) => row.release_target);
+ if (targets.length > 0)
+ await getQueue(Channel.EvaluateReleaseTarget).addBulk(
+ targets.map((rt) => ({
+ name: `${rt.resourceId}-${rt.environmentId}-${rt.deploymentId}`,
+ data: rt,
+ })),
+ );
+
+ return record;
+ }),
+
/**
* Lists all environments where a deployment version is blocked from being deployed based on policy rules.
* This is crucial for determining where a version cannot be released due to environment-specific policies and deployment rules.
@@ -834,5 +893,4 @@ export const versionRouter = createTRPCRouter({
}),
metadataKeys: deploymentVersionMetadataKeysRouter,
- checks: deploymentVersionChecksRouter,
});