feat: Webhooks inititate all applications with the correct branch

This commit is contained in:
Andras Bacsai 2022-03-11 21:18:12 +01:00
parent 16ea9a3e07
commit c5c9f84503
7 changed files with 256 additions and 231 deletions

View File

@ -11,6 +11,7 @@ import { version as currentVersion } from '../../package.json';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import Cookie from 'cookie'; import Cookie from 'cookie';
import os from 'os'; import os from 'os';
import cuid from 'cuid';
try { try {
if (!dev) { if (!dev) {

View File

@ -58,15 +58,6 @@ export async function removeApplication({ id, teamId }) {
const id = containerObj.ID; const id = containerObj.ID;
const preview = containerObj.Image.split('-')[1]; const preview = containerObj.Image.split('-')[1];
await removeDestinationDocker({ id, engine: destinationDocker.engine }); await removeDestinationDocker({ id, engine: destinationDocker.engine });
try {
if (preview) {
await removeProxyConfiguration({ domain: `${preview}.${domain}` });
} else {
await removeProxyConfiguration({ domain });
}
} catch (error) {
console.log(error);
}
} }
} }
} }
@ -79,7 +70,7 @@ export async function removeApplication({ id, teamId }) {
export async function getApplicationWebhook({ projectId, branch }) { export async function getApplicationWebhook({ projectId, branch }) {
try { try {
let body = await prisma.application.findFirst({ let applications = await prisma.application.findMany({
where: { projectId, branch }, where: { projectId, branch },
include: { include: {
destinationDocker: true, destinationDocker: true,
@ -88,30 +79,40 @@ export async function getApplicationWebhook({ projectId, branch }) {
secrets: true secrets: true
} }
}); });
for (const application of applications) {
if (body.gitSource?.githubApp?.clientSecret) { if (application.gitSource?.githubApp?.clientSecret) {
body.gitSource.githubApp.clientSecret = decrypt(body.gitSource.githubApp.clientSecret); application.gitSource.githubApp.clientSecret = decrypt(
application.gitSource.githubApp.clientSecret
);
} }
if (body.gitSource?.githubApp?.webhookSecret) { if (application.gitSource?.githubApp?.webhookSecret) {
body.gitSource.githubApp.webhookSecret = decrypt(body.gitSource.githubApp.webhookSecret); application.gitSource.githubApp.webhookSecret = decrypt(
application.gitSource.githubApp.webhookSecret
);
} }
if (body.gitSource?.githubApp?.privateKey) { if (application.gitSource?.githubApp?.privateKey) {
body.gitSource.githubApp.privateKey = decrypt(body.gitSource.githubApp.privateKey); application.gitSource.githubApp.privateKey = decrypt(
application.gitSource.githubApp.privateKey
);
} }
if (body?.gitSource?.gitlabApp?.appSecret) { if (application?.gitSource?.gitlabApp?.appSecret) {
body.gitSource.gitlabApp.appSecret = decrypt(body.gitSource.gitlabApp.appSecret); application.gitSource.gitlabApp.appSecret = decrypt(
application.gitSource.gitlabApp.appSecret
);
} }
if (body?.gitSource?.gitlabApp?.webhookToken) { if (application?.gitSource?.gitlabApp?.webhookToken) {
body.gitSource.gitlabApp.webhookToken = decrypt(body.gitSource.gitlabApp.webhookToken); application.gitSource.gitlabApp.webhookToken = decrypt(
application.gitSource.gitlabApp.webhookToken
);
} }
if (body?.secrets.length > 0) { if (application?.secrets.length > 0) {
body.secrets = body.secrets.map((s) => { application.secrets = application.secrets.map((s) => {
s.value = decrypt(s.value); s.value = decrypt(s.value);
return s; return s;
}); });
} }
}
return { ...body }; return [...applications];
} catch (e) { } catch (e) {
throw { status: 404, body: { message: e.message } }; throw { status: 404, body: { message: e.message } };
} }

View File

@ -120,7 +120,7 @@ buildWorker.on('completed', async (job: Bullmq.Job) => {
} catch (err) { } catch (err) {
console.log(err); console.log(err);
} finally { } finally {
const workdir = `/tmp/build-sources/${job.data.repository}/`; const workdir = `/tmp/build-sources/${job.data.repository}/${job.data.build_id}`;
await asyncExecShell(`rm -fr ${workdir}`); await asyncExecShell(`rm -fr ${workdir}`);
} }
return; return;

View File

@ -172,7 +172,7 @@
class="w-96" class="w-96"
disabled={!selected.repository} disabled={!selected.repository}
bind:value={selected.branch} bind:value={selected.branch}
on:change={isBranchAlreadyUsed} on:change={() => (showSave = true)}
> >
{#if !selected.repository} {#if !selected.repository}
<option value="" disabled selected>Select a repository first</option> <option value="" disabled selected>Select a repository first</option>

View File

@ -305,7 +305,7 @@
name="branch" name="branch"
class="w-96" class="w-96"
bind:value={selected.branch} bind:value={selected.branch}
on:change={isBranchAlreadyUsed} on:change={() => (showSave = true)}
disabled={!selected.project} disabled={!selected.project}
> >
<option value="" disabled selected>Please select a branch</option> <option value="" disabled selected>Please select a branch</option>

View File

@ -20,7 +20,6 @@ export const options: RequestHandler = async () => {
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
try { try {
const buildId = cuid();
const allowedGithubEvents = ['push', 'pull_request']; const allowedGithubEvents = ['push', 'pull_request'];
const allowedActions = ['opened', 'reopened', 'synchronize', 'closed']; const allowedActions = ['opened', 'reopened', 'synchronize', 'closed'];
const githubEvent = event.request.headers.get('x-github-event')?.toLowerCase(); const githubEvent = event.request.headers.get('x-github-event')?.toLowerCase();
@ -45,9 +44,12 @@ export const post: RequestHandler = async (event) => {
branch = body.pull_request.head.ref.split('/')[2]; branch = body.pull_request.head.ref.split('/')[2];
} }
const applicationFound = await db.getApplicationWebhook({ projectId, branch }); const applications = await db.getApplicationWebhook({ projectId, branch });
if (applicationFound) { if (applications.length > 0) {
const webhookSecret = applicationFound.gitSource.githubApp.webhookSecret; for (const application of applications) {
const buildId = cuid();
const webhookSecret = application.gitSource.githubApp.webhookSecret;
const hmac = crypto.createHmac('sha256', webhookSecret); const hmac = crypto.createHmac('sha256', webhookSecret);
const digest = Buffer.from( const digest = Buffer.from(
'sha256=' + hmac.update(JSON.stringify(body)).digest('hex'), 'sha256=' + hmac.update(JSON.stringify(body)).digest('hex'),
@ -66,16 +68,16 @@ export const post: RequestHandler = async (event) => {
} }
if (githubEvent === 'push') { if (githubEvent === 'push') {
if (!applicationFound.configHash) { if (!application.configHash) {
const configHash = crypto const configHash = crypto
.createHash('sha256') .createHash('sha256')
.update( .update(
JSON.stringify({ JSON.stringify({
buildPack: applicationFound.buildPack, buildPack: application.buildPack,
port: applicationFound.port, port: application.port,
installCommand: applicationFound.installCommand, installCommand: application.installCommand,
buildCommand: applicationFound.buildCommand, buildCommand: application.buildCommand,
startCommand: applicationFound.startCommand startCommand: application.startCommand
}) })
) )
.digest('hex'); .digest('hex');
@ -85,13 +87,13 @@ export const post: RequestHandler = async (event) => {
}); });
} }
await db.prisma.application.update({ await db.prisma.application.update({
where: { id: applicationFound.id }, where: { id: application.id },
data: { updatedAt: new Date() } data: { updatedAt: new Date() }
}); });
await buildQueue.add(buildId, { await buildQueue.add(buildId, {
build_id: buildId, build_id: buildId,
type: 'webhook_commit', type: 'webhook_commit',
...applicationFound ...application
}); });
return { return {
status: 200, status: 200,
@ -112,11 +114,11 @@ export const post: RequestHandler = async (event) => {
}; };
} }
if (applicationFound.settings.previews) { if (application.settings.previews) {
if (applicationFound.destinationDockerId) { if (application.destinationDockerId) {
const isRunning = await checkContainer( const isRunning = await checkContainer(
applicationFound.destinationDocker.engine, application.destinationDocker.engine,
applicationFound.id application.id
); );
if (!isRunning) { if (!isRunning) {
return { return {
@ -133,13 +135,13 @@ export const post: RequestHandler = async (event) => {
pullmergeRequestAction === 'synchronize' pullmergeRequestAction === 'synchronize'
) { ) {
await db.prisma.application.update({ await db.prisma.application.update({
where: { id: applicationFound.id }, where: { id: application.id },
data: { updatedAt: new Date() } data: { updatedAt: new Date() }
}); });
await buildQueue.add(buildId, { await buildQueue.add(buildId, {
build_id: buildId, build_id: buildId,
type: 'webhook_pr', type: 'webhook_pr',
...applicationFound, ...application,
sourceBranch, sourceBranch,
pullmergeRequestId pullmergeRequestId
}); });
@ -150,9 +152,9 @@ export const post: RequestHandler = async (event) => {
} }
}; };
} else if (pullmergeRequestAction === 'closed') { } else if (pullmergeRequestAction === 'closed') {
if (applicationFound.destinationDockerId) { if (application.destinationDockerId) {
const id = `${applicationFound.id}-${pullmergeRequestId}`; const id = `${application.id}-${pullmergeRequestId}`;
const engine = applicationFound.destinationDocker.engine; const engine = application.destinationDocker.engine;
await removeDestinationDocker({ id, engine }); await removeDestinationDocker({ id, engine });
} }
return { return {
@ -178,6 +180,13 @@ export const post: RequestHandler = async (event) => {
message: 'Not handled event.' message: 'Not handled event.'
} }
}; };
}
return {
status: 500,
body: {
message: 'No applications configured in Coolify.'
}
};
} catch (err) { } catch (err) {
console.log(err); console.log(err);
return { return {

View File

@ -21,25 +21,27 @@ export const options: RequestHandler = async () => {
export const post: RequestHandler = async (event) => { export const post: RequestHandler = async (event) => {
const allowedActions = ['opened', 'reopen', 'close', 'open', 'update']; const allowedActions = ['opened', 'reopen', 'close', 'open', 'update'];
const body = await event.request.json(); const body = await event.request.json();
const buildId = cuid();
try { try {
const { object_kind: objectKind } = body; const { object_kind: objectKind } = body;
if (objectKind === 'push') { if (objectKind === 'push') {
const { ref } = body; const { ref } = body;
const projectId = Number(body['project_id']); const projectId = Number(body['project_id']);
const branch = ref.split('/')[2]; const branch = ref.split('/')[2];
const applicationFound = await db.getApplicationWebhook({ projectId, branch }); const applications = await db.getApplicationWebhook({ projectId, branch });
if (applicationFound) { if (applications.length > 0) {
if (!applicationFound.configHash) { for (const application of applications) {
const buildId = cuid();
if (!application.configHash) {
const configHash = crypto const configHash = crypto
.createHash('sha256') .createHash('sha256')
.update( .update(
JSON.stringify({ JSON.stringify({
buildPack: applicationFound.buildPack, buildPack: application.buildPack,
port: applicationFound.port, port: application.port,
installCommand: applicationFound.installCommand, installCommand: application.installCommand,
buildCommand: applicationFound.buildCommand, buildCommand: application.buildCommand,
startCommand: applicationFound.startCommand startCommand: application.startCommand
}) })
) )
.digest('hex'); .digest('hex');
@ -49,14 +51,16 @@ export const post: RequestHandler = async (event) => {
}); });
} }
await db.prisma.application.update({ await db.prisma.application.update({
where: { id: applicationFound.id }, where: { id: application.id },
data: { updatedAt: new Date() } data: { updatedAt: new Date() }
}); });
await buildQueue.add(buildId, { await buildQueue.add(buildId, {
build_id: buildId, build_id: buildId,
type: 'webhook_commit', type: 'webhook_commit',
...applicationFound ...application
}); });
}
return { return {
status: 200, status: 200,
body: { body: {
@ -64,6 +68,12 @@ export const post: RequestHandler = async (event) => {
} }
}; };
} }
return {
status: 500,
body: {
message: 'No applications configured in Coolify.'
}
};
} else if (objectKind === 'merge_request') { } else if (objectKind === 'merge_request') {
const webhookToken = event.request.headers.get('x-gitlab-token'); const webhookToken = event.request.headers.get('x-gitlab-token');
if (!webhookToken) { if (!webhookToken) {
@ -98,13 +108,15 @@ export const post: RequestHandler = async (event) => {
}; };
} }
const applicationFound = await db.getApplicationWebhook({ projectId, branch: targetBranch }); const applications = await db.getApplicationWebhook({ projectId, branch: targetBranch });
if (applicationFound) { if (applications.length > 0) {
if (applicationFound.settings.previews) { for (const application of applications) {
if (applicationFound.destinationDockerId) { const buildId = cuid();
if (application.settings.previews) {
if (application.destinationDockerId) {
const isRunning = await checkContainer( const isRunning = await checkContainer(
applicationFound.destinationDocker.engine, application.destinationDocker.engine,
applicationFound.id application.id
); );
if (!isRunning) { if (!isRunning) {
return { return {
@ -115,7 +127,7 @@ export const post: RequestHandler = async (event) => {
}; };
} }
} }
if (!dev && applicationFound.gitSource.gitlabApp.webhookToken !== webhookToken) { if (!dev && application.gitSource.gitlabApp.webhookToken !== webhookToken) {
return { return {
status: 500, status: 500,
body: { body: {
@ -130,13 +142,13 @@ export const post: RequestHandler = async (event) => {
action === 'update' action === 'update'
) { ) {
await db.prisma.application.update({ await db.prisma.application.update({
where: { id: applicationFound.id }, where: { id: application.id },
data: { updatedAt: new Date() } data: { updatedAt: new Date() }
}); });
await buildQueue.add(buildId, { await buildQueue.add(buildId, {
build_id: buildId, build_id: buildId,
type: 'webhook_mr', type: 'webhook_mr',
...applicationFound, ...application,
sourceBranch, sourceBranch,
pullmergeRequestId pullmergeRequestId
}); });
@ -147,9 +159,9 @@ export const post: RequestHandler = async (event) => {
} }
}; };
} else if (action === 'close') { } else if (action === 'close') {
if (applicationFound.destinationDockerId) { if (application.destinationDockerId) {
const id = `${applicationFound.id}-${pullmergeRequestId}`; const id = `${application.id}-${pullmergeRequestId}`;
const engine = applicationFound.destinationDocker.engine; const engine = application.destinationDocker.engine;
await removeDestinationDocker({ id, engine }); await removeDestinationDocker({ id, engine });
} }
@ -161,6 +173,8 @@ export const post: RequestHandler = async (event) => {
}; };
} }
} }
}
return { return {
status: 500, status: 500,
body: { body: {