Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish tracking #1726

Merged
merged 9 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add latestBuild
  • Loading branch information
istarkov committed Jun 6, 2023
commit 05f610533b4e95155d7e24a1151641390b84c19a
21 changes: 17 additions & 4 deletions packages/domain/src/db/domain.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { v4 as uuid } from "uuid";
import { prisma, type Project, type Domain } from "@webstudio-is/prisma-client";
import {
prisma,
type Project,
type Domain,
type ProjectWithDomain,
type LatestBuildPerProjectDomain,
} from "@webstudio-is/prisma-client";
import {
authorizeProject,
type AppContext,
Expand All @@ -8,13 +14,21 @@ import {
import { validateDomain } from "./validate";
import { cnameFromUserId } from "./cname-from-user-id";

const getProjectDomains = async (projectId: Project["id"]) =>
export type ProjectDomain = ProjectWithDomain & {
domain: Domain;
latestBuid: null | LatestBuildPerProjectDomain;
};

const getProjectDomains = async (
projectId: Project["id"]
): Promise<ProjectDomain[]> =>
await prisma.projectWithDomain.findMany({
where: {
projectId,
},
include: {
domain: true,
latestBuid: true,
},
orderBy: [
{
Expand All @@ -27,8 +41,7 @@ export const findMany = async (
props: { projectId: Project["id"] },
context: AppContext
): Promise<
| { success: false; error: string }
| { success: true; data: Awaited<ReturnType<typeof getProjectDomains>> }
{ success: false; error: string } | { success: true; data: ProjectDomain[] }
> => {
// Only builder of the project can list domains
const canList = await authorizeProject.hasProjectPermit(
Expand Down
6 changes: 4 additions & 2 deletions packages/domain/src/trpc/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const domainRouter = router({
.query(async ({ input, ctx }) => {
try {
const project = await projectDb.project.loadById(input.projectId, ctx);

return {
success: true,
project,
Expand All @@ -28,18 +29,19 @@ export const domainRouter = router({
.input(z.object({ projectId: z.string(), domains: z.array(z.string()) }))
.mutation(async ({ input, ctx }) => {
try {
const project = await projectDb.project.loadById(input.projectId, ctx);

const build = await createProductionBuild(
{
projectId: input.projectId,
deployment: {
domains: input.domains,
projectDomain: project.domain,
},
},
ctx
);

const project = await projectDb.project.loadById(input.projectId, ctx);

const { deploymentTrpc, env } = ctx.deployment;

const result = deploymentTrpc.publish.mutate({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
UPDATE
"Build"
SET
deployment = deployment::jsonb ||('{"projectDomain": "' || "Project".domain || '" }')::jsonb
FROM
"Project"
WHERE
"Project".id = "Build"."projectId"
AND "Build".deployment IS NOT NULL;

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
-- CreateEnum
CREATE TYPE "PublishStatus" AS ENUM ('PENDING', 'PUBLISHED', 'FAILED');

-- AlterTable
ALTER TABLE "Build" ADD COLUMN "publishStatus" "PublishStatus" NOT NULL DEFAULT 'PENDING';

-- CreateIndex
CREATE UNIQUE INDEX "Project_id_domain_key" ON "Project"("id", "domain");


CREATE OR REPLACE VIEW "LatestBuildPerProjectDomain" AS
WITH lbd AS (
SELECT DISTINCT ON ("projectId",
"domain")
jsonb_array_elements_text(deployment::jsonb -> 'domains') AS "domain",
bld.id AS "buildId",
bld."projectId",
bld."updatedAt",
bld."publishStatus"
FROM
"Build" bld
WHERE
bld.deployment IS NOT NULL
ORDER BY
bld."projectId",
"domain",
bld."createdAt" DESC,
"buildId"
),
lb AS (
SELECT DISTINCT ON ("projectId")
bld.id AS "buildId",
bld."projectId",
bld."updatedAt",
bld."publishStatus"
FROM
"Build" bld
WHERE
bld.deployment IS NOT NULL
ORDER BY
bld."projectId",
bld."createdAt" DESC,
"buildId"
)
SELECT
d.id AS "domainId",
lbd."projectId",
lbd."buildId",
coalesce(lbd."updatedAt" = lb."updatedAt", FALSE) AS "isLatestBuild",
lbd."publishStatus",
lbd."updatedAt"
FROM
lbd,
lb,
"Domain" d
WHERE
lbd.domain = d.domain
AND lb."projectId" = lbd."projectId";

CREATE OR REPLACE VIEW "LatestBuildPerProject" AS
WITH lb AS (
SELECT DISTINCT ON ("projectId")
bld.id AS "buildId",
bld."projectId",
bld."updatedAt"
FROM
"Build" bld
WHERE
bld.deployment IS NOT NULL
ORDER BY
bld."projectId",
bld."createdAt" DESC,
"buildId"
)
SELECT DISTINCT ON ("projectId", "domain")
bld.id AS "buildId",
bld."projectId",
deployment::jsonb ->> 'projectDomain' AS domain,
coalesce(bld."updatedAt" = lb."updatedAt", FALSE) AS "isLatestBuild",
bld."updatedAt",
bld."publishStatus"
FROM
"Build" bld,
lb
WHERE
bld.deployment IS NOT NULL
AND lb."projectId" = bld."projectId"
ORDER BY
bld."projectId",
"domain",
bld."createdAt" DESC,
"buildId";
62 changes: 51 additions & 11 deletions packages/prisma-client/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,27 @@ model User {
}

model Project {
id String @id @default(uuid())
createdAt DateTime @default(now())
id String @id @default(uuid())
createdAt DateTime @default(now())
title String
domain String @unique
user User? @relation(fields: [userId], references: [id])
domain String @unique
user User? @relation(fields: [userId], references: [id])
userId String?
build Build[]
isDeleted Boolean @default(false)
isDeleted Boolean @default(false)
files File[]
ProjectDomain ProjectDomain[]
projectDomain ProjectDomain[]
latestBuild LatestBuildPerProject?

@@unique([id, isDeleted])
@@unique([domain, isDeleted])
@@unique([id, domain])
}

enum PublishStatus {
PENDING
PUBLISHED
FAILED
}

model Build {
Expand All @@ -94,7 +102,8 @@ model Build {
props String @default("[]")
instances String @default("[]")

deployment String?
deployment String?
publishStatus PublishStatus @default(PENDING)

@@id([id, projectId])
}
Expand Down Expand Up @@ -132,13 +141,14 @@ model Domain {
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt

ProjectDomain ProjectDomain[]
ProjectDomain ProjectDomain[]
// Last known txtRecord of the domain (to check domain ownership)
txtRecord String?
txtRecord String?
// create, init, pending, active, error
status DomainStatus @default(INITIALIZING)
status DomainStatus @default(INITIALIZING)
// In case of status="error", this will contain the error message
error String?
error String?

projectWithDomain ProjectWithDomain[]
}

Expand Down Expand Up @@ -174,9 +184,39 @@ view ProjectWithDomain {
// To count statistics per user
userId String?

// We can deploy on per domain basis, here for each project domain we have latest build
latestBuid LatestBuildPerProjectDomain?

@@id([projectId, domainId])
}

view LatestBuildPerProjectDomain {
domainId String
buildId String
projectId String
projectWithDomain ProjectWithDomain @relation(fields: [projectId, domainId], references: [projectId, domainId])

isLatestBuild Boolean
publishStatus PublishStatus
updatedAt DateTime

@@id([projectId, domainId])
}

view LatestBuildPerProject {
buildId String

projectId String
domain String
project Project @relation(fields: [projectId, domain], references: [id, domain])

isLatestBuild Boolean
publishStatus PublishStatus
updatedAt DateTime

@@id([projectId, domain])
}

// Dashboard
view DashboardProject {
id String @id @default(uuid())
Expand Down
2 changes: 1 addition & 1 deletion packages/prisma-client/src/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ prisma.$on("query", (e) => {
);

// eslint-disable-next-line no-console
console.log("Params: " + e.params.slice(0, 100));
console.log("Params: " + e.params.slice(0, 200));
// eslint-disable-next-line no-console
console.log("Duration: " + e.duration + "ms");
});
Expand Down
3 changes: 3 additions & 0 deletions packages/prisma-client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ export type {
AuthorizationToken,
DomainStatus,
Domain,
ProjectWithDomain,
LatestBuildPerProjectDomain,
LatestBuildPerProject,
} from "./__generated__";
1 change: 1 addition & 0 deletions packages/project-build/src/schema/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { z } from "zod";

export const Deployment = z.object({
domains: z.array(z.string()),
projectDomain: z.string(),
});

export type Deployment = z.infer<typeof Deployment>;
3 changes: 3 additions & 0 deletions packages/project/src/db/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export const loadById = async (

const data = await prisma.project.findUnique({
where: { id_isDeleted: { id: projectId, isDeleted: false } },
include: {
latestBuild: true,
},
});

return Project.parse(data);
Expand Down
8 changes: 8 additions & 0 deletions packages/project/src/shared/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ export const Project = z.object({
userId: z.string().nullable(),
isDeleted: z.boolean(),
domain: z.string(),
latestBuild: z
.object({
buildId: z.string(),
isLatestBuild: z.boolean(),
publishStatus: z.enum(["PENDING", "PUBLISHED", "FAILED"]),
updatedAt: z.date().transform((date) => date.toISOString()),
})
.nullable(),
});
export type Project = z.infer<typeof Project>;

Expand Down