@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "coolify",
|
"name": "coolify",
|
||||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||||
"version": "2.4.3",
|
"version": "2.4.4",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev",
|
"dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev",
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"db:seed": "prisma db seed",
|
"db:seed": "prisma db seed",
|
||||||
"db:migrate": "COOLIFY_DATABASE_URL=file:../db/migration.db prisma migrate dev --skip-seed --name",
|
"db:migrate": "COOLIFY_DATABASE_URL=file:../db/migration.db prisma migrate dev --skip-seed --name",
|
||||||
"release:production:all": "cross-var docker build --platform linux/amd64,linux/arm64 -t coollabsio/coolify:$npm_package_version -t coollabsio/coolify:latest --push .",
|
"release:production:all": "cross-var docker build --platform linux/amd64,linux/arm64 -t coollabsio/coolify:$npm_package_version -t coollabsio/coolify:latest --push .",
|
||||||
|
"release:production:amd": "cross-var docker build --platform linux/amd64 -t coollabsio/coolify:$npm_package_version -t coollabsio/coolify:latest --push .",
|
||||||
"release:staging:all": "cross-var docker build --platform linux/amd64,linux/arm64 -t coollabsio/coolify:$npm_package_version --push .",
|
"release:staging:all": "cross-var docker build --platform linux/amd64,linux/arm64 -t coollabsio/coolify:$npm_package_version --push .",
|
||||||
"release:staging:amd": "cross-var docker build --platform linux/amd64 -t coollabsio/coolify:$npm_package_version --push .",
|
"release:staging:amd": "cross-var docker build --platform linux/amd64 -t coollabsio/coolify:$npm_package_version --push .",
|
||||||
"release:haproxy": "docker build --platform linux/amd64,linux/arm64 -t coollabsio/coolify-haproxy-alpine:latest -t coollabsio/coolify-haproxy-alpine:1.1.0 -f data/haproxy.Dockerfile --push .",
|
"release:haproxy": "docker build --platform linux/amd64,linux/arm64 -t coollabsio/coolify-haproxy-alpine:latest -t coollabsio/coolify-haproxy-alpine:1.1.0 -f data/haproxy.Dockerfile --push .",
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
"@prisma/client": "3.11.1",
|
"@prisma/client": "3.11.1",
|
||||||
"@sentry/node": "6.19.6",
|
"@sentry/node": "6.19.6",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bullmq": "1.79.0",
|
"bullmq": "1.80.0",
|
||||||
"compare-versions": "4.1.3",
|
"compare-versions": "4.1.3",
|
||||||
"cookie": "0.4.2",
|
"cookie": "0.4.2",
|
||||||
"cuid": "2.1.8",
|
"cuid": "2.1.8",
|
||||||
|
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -5,7 +5,7 @@ specifiers:
|
|||||||
'@prisma/client': 3.11.1
|
'@prisma/client': 3.11.1
|
||||||
'@sentry/node': 6.19.6
|
'@sentry/node': 6.19.6
|
||||||
'@sveltejs/adapter-node': 1.0.0-next.73
|
'@sveltejs/adapter-node': 1.0.0-next.73
|
||||||
'@sveltejs/kit': 1.0.0-next.310
|
'@sveltejs/kit': 1.0.0-next.303
|
||||||
'@types/js-cookie': 3.0.1
|
'@types/js-cookie': 3.0.1
|
||||||
'@types/js-yaml': 4.0.5
|
'@types/js-yaml': 4.0.5
|
||||||
'@types/node': 17.0.23
|
'@types/node': 17.0.23
|
||||||
@@ -15,7 +15,7 @@ specifiers:
|
|||||||
'@zerodevx/svelte-toast': 0.7.1
|
'@zerodevx/svelte-toast': 0.7.1
|
||||||
autoprefixer: 10.4.4
|
autoprefixer: 10.4.4
|
||||||
bcryptjs: ^2.4.3
|
bcryptjs: ^2.4.3
|
||||||
bullmq: 1.79.0
|
bullmq: 1.78.1
|
||||||
compare-versions: 4.1.3
|
compare-versions: 4.1.3
|
||||||
cookie: 0.4.2
|
cookie: 0.4.2
|
||||||
cross-env: 7.0.3
|
cross-env: 7.0.3
|
||||||
@@ -60,7 +60,7 @@ dependencies:
|
|||||||
'@prisma/client': 3.11.1_prisma@3.11.1
|
'@prisma/client': 3.11.1_prisma@3.11.1
|
||||||
'@sentry/node': 6.19.6
|
'@sentry/node': 6.19.6
|
||||||
bcryptjs: 2.4.3
|
bcryptjs: 2.4.3
|
||||||
bullmq: 1.79.0
|
bullmq: 1.78.1
|
||||||
compare-versions: 4.1.3
|
compare-versions: 4.1.3
|
||||||
cookie: 0.4.2
|
cookie: 0.4.2
|
||||||
cuid: 2.1.8
|
cuid: 2.1.8
|
||||||
@@ -82,7 +82,7 @@ dependencies:
|
|||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/adapter-node': 1.0.0-next.73
|
'@sveltejs/adapter-node': 1.0.0-next.73
|
||||||
'@sveltejs/kit': 1.0.0-next.310_svelte@3.47.0
|
'@sveltejs/kit': 1.0.0-next.303_svelte@3.47.0
|
||||||
'@types/js-cookie': 3.0.1
|
'@types/js-cookie': 3.0.1
|
||||||
'@types/js-yaml': 4.0.5
|
'@types/js-yaml': 4.0.5
|
||||||
'@types/node': 17.0.23
|
'@types/node': 17.0.23
|
||||||
@@ -374,10 +374,10 @@ packages:
|
|||||||
tiny-glob: 0.2.9
|
tiny-glob: 0.2.9
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@sveltejs/kit/1.0.0-next.310_svelte@3.47.0:
|
/@sveltejs/kit/1.0.0-next.303_svelte@3.47.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-pTyMyaoyHS+V5cQZIQMfQXmLkhw1VaRwT9avOSgwDc0QBpnNw2LdzwoPYsUr96ca5B6cfT3SMUNolxErTNHmPQ==
|
integrity: sha512-WdxDc8OiF1WEd/bEza7CBdzA+3qIcCi1GKBj/gieKX9I3N8iDJt/Cg2POrLo9wQoJ47nZcAd1eOhfr7XEX1aIQ==
|
||||||
}
|
}
|
||||||
engines: { node: '>=14.13' }
|
engines: { node: '>=14.13' }
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1669,10 +1669,10 @@ packages:
|
|||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/bullmq/1.79.0:
|
/bullmq/1.78.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-rVtNCDpcWdc+U1MinRtvhJv+GBFNkz0Q3Unf20010qIC6Pj+O2kkIUeepBkCmMNz6G9abrhsee2PheGRJ32+sw==
|
integrity: sha512-er45mM8nGhgA83EVCJ4PNxPyDSzakvoxeFGU4vdSgYeB+SbeFQAlJYmAC50Ms7YFPstm1LeinbVZ+oX/BmBzOg==
|
||||||
}
|
}
|
||||||
dependencies:
|
dependencies:
|
||||||
cron-parser: 4.2.1
|
cron-parser: 4.2.1
|
||||||
|
@@ -69,7 +69,7 @@ export function del(
|
|||||||
export function post(
|
export function post(
|
||||||
path: string,
|
path: string,
|
||||||
data: Record<string, unknown>,
|
data: Record<string, unknown>,
|
||||||
headers: Record<string, unknown>
|
headers?: Record<string, unknown>
|
||||||
): Promise<Record<string, unknown>> {
|
): Promise<Record<string, unknown>> {
|
||||||
return send({ method: 'POST', path, data, headers });
|
return send({ method: 'POST', path, data, headers });
|
||||||
}
|
}
|
||||||
|
@@ -18,18 +18,10 @@ export async function listSources(
|
|||||||
|
|
||||||
export async function newSource({
|
export async function newSource({
|
||||||
name,
|
name,
|
||||||
teamId,
|
teamId
|
||||||
type,
|
|
||||||
htmlUrl,
|
|
||||||
apiUrl,
|
|
||||||
organization
|
|
||||||
}: {
|
}: {
|
||||||
name: string;
|
name: string;
|
||||||
teamId: string;
|
teamId: string;
|
||||||
type: string;
|
|
||||||
htmlUrl: string;
|
|
||||||
apiUrl: string;
|
|
||||||
organization: string;
|
|
||||||
}): Promise<GitSource> {
|
}): Promise<GitSource> {
|
||||||
return await prisma.gitSource.create({
|
return await prisma.gitSource.create({
|
||||||
data: {
|
data: {
|
||||||
@@ -74,8 +66,11 @@ export async function getSource({
|
|||||||
if (body?.gitlabApp?.appSecret) body.gitlabApp.appSecret = decrypt(body.gitlabApp.appSecret);
|
if (body?.gitlabApp?.appSecret) body.gitlabApp.appSecret = decrypt(body.gitlabApp.appSecret);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
export async function addGitHubSource({ id, teamId, type, name, htmlUrl, apiUrl }) {
|
export async function addGitHubSource({ id, teamId, type, name, htmlUrl, apiUrl, organization }) {
|
||||||
await prisma.gitSource.update({ where: { id }, data: { type, name, htmlUrl, apiUrl } });
|
await prisma.gitSource.update({
|
||||||
|
where: { id },
|
||||||
|
data: { type, name, htmlUrl, apiUrl, organization }
|
||||||
|
});
|
||||||
return await prisma.githubApp.create({
|
return await prisma.githubApp.create({
|
||||||
data: {
|
data: {
|
||||||
teams: { connect: { id: teamId } },
|
teams: { connect: { id: teamId } },
|
||||||
@@ -123,10 +118,14 @@ export async function configureGitsource({
|
|||||||
}
|
}
|
||||||
export async function updateGitsource({
|
export async function updateGitsource({
|
||||||
id,
|
id,
|
||||||
name
|
name,
|
||||||
|
htmlUrl,
|
||||||
|
apiUrl
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
htmlUrl: string;
|
||||||
|
apiUrl: string;
|
||||||
}): Promise<GitSource> {
|
}): Promise<GitSource> {
|
||||||
return await prisma.gitSource.update({
|
return await prisma.gitSource.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import { dev } from '$app/env';
|
import { dev } from '$app/env';
|
||||||
import got, { type Got } from 'got';
|
import got, { type Got } from 'got';
|
||||||
import * as db from '$lib/database';
|
import * as db from '$lib/database';
|
||||||
|
import mustache from 'mustache';
|
||||||
|
import crypto from 'crypto';
|
||||||
import { checkContainer, checkHAProxy } from '.';
|
import { checkContainer, checkHAProxy } from '.';
|
||||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||||
import { supportedServiceTypesAndVersions } from '$lib/components/common';
|
import { supportedServiceTypesAndVersions } from '$lib/components/common';
|
||||||
@@ -262,36 +264,20 @@ export async function configureHAProxy(): Promise<void> {
|
|||||||
redirectValue,
|
redirectValue,
|
||||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain
|
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain
|
||||||
});
|
});
|
||||||
for (const service of services) {
|
}
|
||||||
const { fqdn, id, type, destinationDocker, destinationDockerId, updatedAt } = service;
|
const output = mustache.render(template, data);
|
||||||
if (destinationDockerId) {
|
const newHash = crypto.createHash('md5').update(output).digest('hex');
|
||||||
const { engine } = destinationDocker;
|
const { proxyHash, id } = await db.listSettings();
|
||||||
const found = supportedServiceTypesAndVersions.find((a) => a.name === type);
|
if (proxyHash !== newHash) {
|
||||||
if (found) {
|
await db.prisma.setting.update({ where: { id }, data: { proxyHash: newHash } });
|
||||||
const port = found.ports.main;
|
await haproxy.post(`v2/services/haproxy/configuration/raw`, {
|
||||||
const publicPort = service[type]?.publicPort;
|
searchParams: {
|
||||||
const isRunning = await checkContainer(engine, id);
|
skip_version: true
|
||||||
if (fqdn) {
|
},
|
||||||
const domain = getDomain(fqdn);
|
body: output,
|
||||||
const isHttps = fqdn.startsWith('https://');
|
headers: {
|
||||||
const isWWW = fqdn.includes('www.');
|
'Content-Type': 'text/plain'
|
||||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
}
|
||||||
if (isRunning) {
|
|
||||||
data.services.push({
|
|
||||||
id,
|
|
||||||
port,
|
|
||||||
publicPort,
|
|
||||||
domain,
|
|
||||||
isRunning,
|
|
||||||
isHttps,
|
|
||||||
redirectValue,
|
|
||||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain,
|
|
||||||
updatedAt: updatedAt.getTime()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,9 @@ import * as Bullmq from 'bullmq';
|
|||||||
import { default as ProdBullmq, QueueScheduler } from 'bullmq';
|
import { default as ProdBullmq, QueueScheduler } from 'bullmq';
|
||||||
import { dev } from '$app/env';
|
import { dev } from '$app/env';
|
||||||
import { prisma } from '$lib/database';
|
import { prisma } from '$lib/database';
|
||||||
|
|
||||||
import builder from './builder';
|
import builder from './builder';
|
||||||
|
import logger from './logger';
|
||||||
import cleanup from './cleanup';
|
import cleanup from './cleanup';
|
||||||
import proxy from './proxy';
|
import proxy from './proxy';
|
||||||
import ssl from './ssl';
|
import ssl from './ssl';
|
||||||
@@ -142,5 +144,9 @@ buildWorker.on('failed', async (job: Bullmq.Job, failedReason) => {
|
|||||||
|
|
||||||
const buildLogQueueName = 'log_queue';
|
const buildLogQueueName = 'log_queue';
|
||||||
const buildLogQueue = new Queue(buildLogQueueName, connectionOptions);
|
const buildLogQueue = new Queue(buildLogQueueName, connectionOptions);
|
||||||
|
const buildLogWorker = new Worker(buildLogQueueName, async (job) => await logger(job), {
|
||||||
|
concurrency: 1,
|
||||||
|
...connectionOptions
|
||||||
|
});
|
||||||
|
|
||||||
export { buildQueue, buildLogQueue };
|
export { buildQueue, buildLogQueue };
|
||||||
|
@@ -8,7 +8,6 @@ import type { RequestHandler } from '@sveltejs/kit';
|
|||||||
export const get: RequestHandler = async (event) => {
|
export const get: RequestHandler = async (event) => {
|
||||||
const { teamId, status, body } = await getUserDetails(event);
|
const { teamId, status, body } = await getUserDetails(event);
|
||||||
if (status === 401) return { status, body };
|
if (status === 401) return { status, body };
|
||||||
console.log(teamId);
|
|
||||||
const { id } = event.params;
|
const { id } = event.params;
|
||||||
try {
|
try {
|
||||||
const destination = await db.getDestination({ id, teamId });
|
const destination = await db.getDestination({ id, teamId });
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
export let source;
|
export let source;
|
||||||
import { page, session } from '$app/stores';
|
import { page, session } from '$app/stores';
|
||||||
import { post } from '$lib/api';
|
import { post } from '$lib/api';
|
||||||
|
import Explainer from '$lib/components/Explainer.svelte';
|
||||||
import { errorNotification } from '$lib/form';
|
import { errorNotification } from '$lib/form';
|
||||||
import { toast } from '@zerodevx/svelte-toast';
|
import { toast } from '@zerodevx/svelte-toast';
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
@@ -51,7 +52,8 @@
|
|||||||
type: 'github',
|
type: 'github',
|
||||||
name: source.name,
|
name: source.name,
|
||||||
htmlUrl: source.htmlUrl.replace(/\/$/, ''),
|
htmlUrl: source.htmlUrl.replace(/\/$/, ''),
|
||||||
apiUrl: source.apiUrl.replace(/\/$/, '')
|
apiUrl: source.apiUrl.replace(/\/$/, ''),
|
||||||
|
organization: source.organization
|
||||||
});
|
});
|
||||||
} catch ({ error }) {
|
} catch ({ error }) {
|
||||||
return errorNotification(error);
|
return errorNotification(error);
|
||||||
@@ -97,6 +99,22 @@
|
|||||||
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label>
|
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label>
|
||||||
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
|
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-2">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label for="organization" class="pt-2 text-base font-bold text-stone-100"
|
||||||
|
>Organization</label
|
||||||
|
>
|
||||||
|
<Explainer
|
||||||
|
text="Fill it if you would like to use an organization's as your Git Source. Otherwise your user will be used."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
name="organization"
|
||||||
|
id="organization"
|
||||||
|
placeholder="eg: coollabsio"
|
||||||
|
bind:value={source.organization}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if source.apiUrl && source.htmlUrl && source.name}
|
{#if source.apiUrl && source.htmlUrl && source.name}
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
@@ -135,6 +153,21 @@
|
|||||||
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label>
|
<label for="apiUrl" class="text-base font-bold text-stone-100">API URL</label>
|
||||||
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
|
<input name="apiUrl" id="apiUrl" required bind:value={source.apiUrl} />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-2">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<label for="organization" class="pt-2 text-base font-bold text-stone-100"
|
||||||
|
>Organization</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
readonly
|
||||||
|
disabled
|
||||||
|
name="organization"
|
||||||
|
id="organization"
|
||||||
|
placeholder="eg: coollabsio"
|
||||||
|
bind:value={source.organization}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{:else}
|
{:else}
|
||||||
|
@@ -9,8 +9,8 @@ export const post: RequestHandler = async (event) => {
|
|||||||
const { id } = event.params;
|
const { id } = event.params;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let { type, name, htmlUrl, apiUrl } = await event.request.json();
|
let { type, name, htmlUrl, apiUrl, organization } = await event.request.json();
|
||||||
await db.addGitHubSource({ id, teamId, type, name, htmlUrl, apiUrl });
|
await db.addGitHubSource({ id, teamId, type, name, htmlUrl, apiUrl, organization });
|
||||||
return { status: 201 };
|
return { status: 201 };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return ErrorHandler(error);
|
return ErrorHandler(error);
|
||||||
|
@@ -36,7 +36,6 @@
|
|||||||
export let settings;
|
export let settings;
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const { organization, id, htmlUrl } = source;
|
const { organization, id, htmlUrl } = source;
|
||||||
console.log(source);
|
|
||||||
const { fqdn } = settings;
|
const { fqdn } = settings;
|
||||||
const host = dev
|
const host = dev
|
||||||
? 'http://localhost:3000'
|
? 'http://localhost:3000'
|
||||||
|
Reference in New Issue
Block a user