diff --git a/prisma/migrations/20220311213422_autodeploy/migration.sql b/prisma/migrations/20220311213422_autodeploy/migration.sql new file mode 100644 index 000000000..d534d9372 --- /dev/null +++ b/prisma/migrations/20220311213422_autodeploy/migration.sql @@ -0,0 +1,19 @@ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_ApplicationSettings" ( + "id" TEXT NOT NULL PRIMARY KEY, + "applicationId" TEXT NOT NULL, + "dualCerts" BOOLEAN NOT NULL DEFAULT false, + "debug" BOOLEAN NOT NULL DEFAULT false, + "previews" BOOLEAN NOT NULL DEFAULT false, + "autodeploy" BOOLEAN NOT NULL DEFAULT true, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_ApplicationSettings" ("applicationId", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt") SELECT "applicationId", "createdAt", "debug", "dualCerts", "id", "previews", "updatedAt" FROM "ApplicationSettings"; +DROP TABLE "ApplicationSettings"; +ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings"; +CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId"); +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 8c4fdab53..85b78fdc4 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -104,6 +104,7 @@ model ApplicationSettings { dualCerts Boolean @default(false) debug Boolean @default(false) previews Boolean @default(false) + autodeploy Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts index 43bacd46a..60d58f27f 100644 --- a/src/lib/database/applications.ts +++ b/src/lib/database/applications.ts @@ -71,7 +71,7 @@ export async function removeApplication({ id, teamId }) { export async function getApplicationWebhook({ projectId, branch }) { try { let applications = await prisma.application.findMany({ - where: { projectId, branch }, + where: { projectId, branch, settings: { autodeploy: true } }, include: { destinationDocker: true, settings: true, @@ -158,24 +158,41 @@ export async function getApplication({ id, teamId }) { return { ...body }; } -export async function configureGitRepository({ id, repository, branch, projectId, webhookToken }) { +export async function configureGitRepository({ + id, + repository, + branch, + projectId, + webhookToken, + autodeploy +}) { if (webhookToken) { const encryptedWebhookToken = encrypt(webhookToken); - return await prisma.application.update({ + await prisma.application.update({ where: { id }, data: { repository, branch, projectId, - gitSource: { update: { gitlabApp: { update: { webhookToken: encryptedWebhookToken } } } } + gitSource: { update: { gitlabApp: { update: { webhookToken: encryptedWebhookToken } } } }, + settings: { update: { autodeploy } } } }); } else { - return await prisma.application.update({ + await prisma.application.update({ where: { id }, - data: { repository, branch, projectId } + data: { repository, branch, projectId, settings: { update: { autodeploy } } } }); } + if (!autodeploy) { + const applications = await prisma.application.findMany({ where: { branch, projectId } }); + for (const application of applications) { + await prisma.applicationSettings.updateMany({ + where: { applicationId: application.id }, + data: { autodeploy: false } + }); + } + } } export async function configureBuildPack({ id, buildPack }) { @@ -210,10 +227,14 @@ export async function configureApplication({ }); } -export async function setApplicationSettings({ id, debug, previews, dualCerts }) { +export async function checkDoubleBranch(branch, projectId) { + const applications = await prisma.application.findMany({ where: { branch, projectId } }); + return applications.length > 1; +} +export async function setApplicationSettings({ id, debug, previews, dualCerts, autodeploy }) { return await prisma.application.update({ where: { id }, - data: { settings: { update: { debug, previews, dualCerts } } }, + data: { settings: { update: { debug, previews, dualCerts, autodeploy } } }, include: { destinationDocker: true } }); } diff --git a/src/routes/applications/[id]/configuration/_GithubRepositories.svelte b/src/routes/applications/[id]/configuration/_GithubRepositories.svelte index 776f719a3..9ba619d64 100644 --- a/src/routes/applications/[id]/configuration/_GithubRepositories.svelte +++ b/src/routes/applications/[id]/configuration/_GithubRepositories.svelte @@ -28,6 +28,8 @@ branch: undefined }; let showSave = false; + let autodeploy = application.settings.autodeploy || true; + async function loadRepositoriesByPage(page = 0) { return await get(`${apiUrl}/installation/repositories?per_page=100&page=${page}`, { Authorization: `token ${$gitTokens.githubToken}` @@ -69,7 +71,14 @@ `/applications/${id}/configuration/repository.json?repository=${selected.repository}&branch=${selected.branch}` ); if (data.used) { - errorNotification('This branch is already used by another application.'); + const sure = confirm( + `This branch is already used by another application. Webhooks won't work in this case for both applications. Are you sure you want to use it?` + ); + if (sure) { + autodeploy = false; + showSave = true; + return true; + } showSave = false; return true; } @@ -172,7 +181,7 @@ class="w-96" disabled={!selected.repository} bind:value={selected.branch} - on:change={() => (showSave = true)} + on:change={isBranchAlreadyUsed} > {#if !selected.repository} diff --git a/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte b/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte index 737d08c04..e3a26a38d 100644 --- a/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte +++ b/src/routes/applications/[id]/configuration/_GitlabRepositories.svelte @@ -30,6 +30,7 @@ let projects = []; let branches = []; let showSave = false; + let autodeploy = application.settings.autodeploy || true; let selected = { group: undefined, @@ -138,7 +139,14 @@ `/applications/${id}/configuration/repository.json?repository=${selected.project.path_with_namespace}&branch=${selected.branch.name}` ); if (data.used) { - errorNotification('This branch is already used by another application.'); + const sure = confirm( + `This branch is already used by another application. Webhooks won't work in this case for both applications. Are you sure you want to use it?` + ); + if (sure) { + autodeploy = false; + showSave = true; + return true; + } showSave = false; return true; } @@ -242,6 +250,7 @@ repository, branch: selected.branch.name, projectId: selected.project.id, + autodeploy, webhookToken }); return await goto(from || `/applications/${id}/configuration/buildpack`); @@ -305,7 +314,7 @@ name="branch" class="w-96" bind:value={selected.branch} - on:change={() => (showSave = true)} + on:change={isBranchAlreadyUsed} disabled={!selected.project} > diff --git a/src/routes/applications/[id]/configuration/repository.json.ts b/src/routes/applications/[id]/configuration/repository.json.ts index 6d133f29f..38987c4c6 100644 --- a/src/routes/applications/[id]/configuration/repository.json.ts +++ b/src/routes/applications/[id]/configuration/repository.json.ts @@ -30,14 +30,21 @@ export const post: RequestHandler = async (event) => { if (status === 401) return { status, body }; const { id } = event.params; - let { repository, branch, projectId, webhookToken } = await event.request.json(); + let { repository, branch, projectId, webhookToken, autodeploy } = await event.request.json(); repository = repository.toLowerCase(); branch = branch.toLowerCase(); projectId = Number(projectId); try { - await db.configureGitRepository({ id, repository, branch, projectId, webhookToken }); + await db.configureGitRepository({ + id, + repository, + branch, + projectId, + webhookToken, + autodeploy + }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte index 35af22c4d..a0ccec921 100644 --- a/src/routes/applications/[id]/index.svelte +++ b/src/routes/applications/[id]/index.svelte @@ -56,6 +56,7 @@ let debug = application.settings.debug; let previews = application.settings.previews; let dualCerts = application.settings.dualCerts; + let autodeploy = application.settings.autodeploy; if (browser && window.location.hostname === 'demo.coolify.io' && !application.fqdn) { application.fqdn = `http://${cuid()}.demo.coolify.io`; @@ -75,10 +76,32 @@ if (name === 'dualCerts') { dualCerts = !dualCerts; } + if (name === 'autodeploy') { + autodeploy = !autodeploy; + } try { - await post(`/applications/${id}/settings.json`, { previews, debug, dualCerts }); + await post(`/applications/${id}/settings.json`, { + previews, + debug, + dualCerts, + autodeploy, + branch: application.branch, + projectId: application.projectId + }); return toast.push('Settings saved.'); } catch ({ error }) { + if (name === 'debug') { + debug = !debug; + } + if (name === 'previews') { + previews = !previews; + } + if (name === 'dualCerts') { + dualCerts = !dualCerts; + } + if (name === 'autodeploy') { + autodeploy = !autodeploy; + } return errorNotification(error); } } @@ -383,22 +406,23 @@