feat: simpleDockerfile deployment
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Application" ADD COLUMN "simpleDockerfile" TEXT;
|
@@ -131,15 +131,17 @@ model Application {
|
||||
gitCommitHash String?
|
||||
baseImage String?
|
||||
baseBuildImage String?
|
||||
gitSource GitSource? @relation(fields: [gitSourceId], references: [id])
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
persistentStorage ApplicationPersistentStorage[]
|
||||
settings ApplicationSettings?
|
||||
dockerRegistryId String?
|
||||
simpleDockerfile String?
|
||||
|
||||
persistentStorage ApplicationPersistentStorage[]
|
||||
secrets Secret[]
|
||||
teams Team[]
|
||||
connectedDatabase ApplicationConnectedDatabase?
|
||||
previewApplication PreviewApplication[]
|
||||
dockerRegistryId String?
|
||||
gitSource GitSource? @relation(fields: [gitSourceId], references: [id])
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
dockerRegistry DockerRegistry? @relation(fields: [dockerRegistryId], references: [id])
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ import crypto from 'crypto';
|
||||
import fs from 'fs/promises';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
import { copyBaseConfigurationFiles, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common';
|
||||
import { copyBaseConfigurationFiles, makeLabelForSimpleDockerfile, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common';
|
||||
import { createDirectories, decrypt, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma, decryptApplication, isDev } from '../lib/common';
|
||||
import * as importers from '../lib/importers';
|
||||
import * as buildpacks from '../lib/buildPacks';
|
||||
@@ -39,10 +39,155 @@ import * as buildpacks from '../lib/buildPacks';
|
||||
actions.push(async () => {
|
||||
let application = await prisma.application.findUnique({ where: { id: queueBuild.applicationId }, include: { destinationDocker: true, gitSource: { include: { githubApp: true, gitlabApp: true } }, persistentStorage: true, secrets: true, settings: true, teams: true } })
|
||||
|
||||
let { id: buildId, type, sourceBranch = null, pullmergeRequestId = null, previewApplicationId = null, forceRebuild, sourceRepository = null } = queueBuild
|
||||
|
||||
let { id: buildId, type, gitSourceId, sourceBranch = null, pullmergeRequestId = null, previewApplicationId = null, forceRebuild, sourceRepository = null } = queueBuild
|
||||
application = decryptApplication(application)
|
||||
|
||||
if (!gitSourceId && application.simpleDockerfile) {
|
||||
const {
|
||||
id: applicationId,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
secrets,
|
||||
port,
|
||||
persistentStorage,
|
||||
exposePort,
|
||||
simpleDockerfile
|
||||
} = application
|
||||
const { workdir } = await createDirectories({ repository: applicationId, buildId });
|
||||
try {
|
||||
if (queueBuild.status === 'running') {
|
||||
await saveBuildLog({ line: 'Building halted, restarting...', buildId, applicationId: application.id });
|
||||
}
|
||||
const volumes =
|
||||
persistentStorage?.map((storage) => {
|
||||
if (storage.oldPath) {
|
||||
return `${applicationId}${storage.path.replace(/\//gi, '-').replace('-app', '')}:${storage.path}`;
|
||||
}
|
||||
return `${applicationId}${storage.path.replace(/\//gi, '-')}:${storage.path}`;
|
||||
}) || [];
|
||||
|
||||
if (destinationDockerId) {
|
||||
await prisma.build.update({ where: { id: buildId }, data: { status: 'running' } });
|
||||
try {
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker ps -a --filter 'label=com.docker.compose.service=${applicationId}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0`
|
||||
})
|
||||
await executeDockerCmd({
|
||||
dockerId: destinationDockerId,
|
||||
command: `docker ps -a --filter 'label=com.docker.compose.service=${applicationId}' --format {{.ID}}|xargs -r -n 1 docker rm --force`
|
||||
})
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
const envs = [
|
||||
`PORT=${port}`
|
||||
];
|
||||
if (secrets.length > 0) {
|
||||
secrets.forEach((secret) => {
|
||||
if (pullmergeRequestId) {
|
||||
const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
|
||||
if (isSecretFound.length > 0) {
|
||||
envs.push(`${secret.name}=${isSecretFound[0].value}`);
|
||||
} else {
|
||||
envs.push(`${secret.name}=${secret.value}`);
|
||||
}
|
||||
} else {
|
||||
if (!secret.isPRMRSecret) {
|
||||
envs.push(`${secret.name}=${secret.value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
await fs.writeFile(`${workdir}/.env`, envs.join('\n'));
|
||||
|
||||
let envFound = false;
|
||||
try {
|
||||
envFound = !!(await fs.stat(`${workdir}/.env`));
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
|
||||
await fs.writeFile(`${workdir}/Dockerfile`, simpleDockerfile);
|
||||
const labels = makeLabelForSimpleDockerfile({
|
||||
applicationId,
|
||||
type,
|
||||
port: exposePort ? `${exposePort}:${port}` : port,
|
||||
});
|
||||
try {
|
||||
await saveBuildLog({ line: 'Deployment initiated', buildId, applicationId });
|
||||
const composeVolumes = volumes.map((volume) => {
|
||||
return {
|
||||
[`${volume.split(':')[0]}`]: {
|
||||
name: volume.split(':')[0]
|
||||
}
|
||||
};
|
||||
});
|
||||
const composeFile = {
|
||||
version: '3.8',
|
||||
services: {
|
||||
[applicationId]: {
|
||||
build: {
|
||||
context: workdir,
|
||||
},
|
||||
image: `${applicationId}:${buildId}`,
|
||||
container_name: applicationId,
|
||||
volumes,
|
||||
labels,
|
||||
env_file: envFound ? [`${workdir}/.env`] : [],
|
||||
depends_on: [],
|
||||
expose: [port],
|
||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||
...defaultComposeConfiguration(destinationDocker.network),
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[destinationDocker.network]: {
|
||||
external: true
|
||||
}
|
||||
},
|
||||
volumes: Object.assign({}, ...composeVolumes)
|
||||
};
|
||||
await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(composeFile));
|
||||
await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` })
|
||||
await saveBuildLog({ line: 'Deployed successfully 🎉', buildId, applicationId });
|
||||
} catch (error) {
|
||||
await saveBuildLog({ line: error, buildId, applicationId });
|
||||
const foundBuild = await prisma.build.findUnique({ where: { id: buildId } })
|
||||
if (foundBuild) {
|
||||
await prisma.build.update({
|
||||
where: { id: buildId },
|
||||
data: {
|
||||
status: 'failed'
|
||||
}
|
||||
});
|
||||
}
|
||||
throw new Error(error);
|
||||
}
|
||||
await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } });
|
||||
}
|
||||
} catch (error) {
|
||||
const foundBuild = await prisma.build.findUnique({ where: { id: buildId } })
|
||||
if (foundBuild) {
|
||||
await prisma.build.update({
|
||||
where: { id: buildId },
|
||||
data: {
|
||||
status: 'failed'
|
||||
}
|
||||
});
|
||||
}
|
||||
if (error !== 1) {
|
||||
await saveBuildLog({ line: error, buildId, applicationId: application.id });
|
||||
}
|
||||
} finally {
|
||||
if (!isDev) {
|
||||
await fs.rm(workdir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const originalApplicationId = application.id
|
||||
const {
|
||||
id: applicationId,
|
||||
@@ -415,8 +560,7 @@ import * as buildpacks from '../lib/buildPacks';
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
const foundBuild = await prisma.build.findUnique({ where: { id: buildId } })
|
||||
if (foundBuild) {
|
||||
await prisma.build.update({
|
||||
|
@@ -675,7 +675,14 @@ export async function buildImage({
|
||||
await saveBuildLog({ line: `Building production image built successful 🎉`, buildId, applicationId });
|
||||
}
|
||||
}
|
||||
|
||||
export function makeLabelForSimpleDockerfile({ applicationId, port, type }) {
|
||||
return [
|
||||
'coolify.managed=true',
|
||||
`coolify.version=${version}`,
|
||||
`coolify.applicationId=${applicationId}`,
|
||||
`coolify.type=standalone-application`
|
||||
];
|
||||
}
|
||||
export function makeLabelForStandaloneApplication({
|
||||
applicationId,
|
||||
fqdn,
|
||||
|
@@ -1091,7 +1091,7 @@ export const createDirectories = async ({
|
||||
repository: string;
|
||||
buildId: string;
|
||||
}): Promise<{ workdir: string; repodir: string }> => {
|
||||
repository = repository.replaceAll(' ', '')
|
||||
if (repository) repository = repository.replaceAll(' ', '')
|
||||
const repodir = `/tmp/build-sources/${repository}/`;
|
||||
const workdir = `/tmp/build-sources/${repository}/${buildId}`;
|
||||
let workdirFound = false;
|
||||
|
@@ -48,7 +48,6 @@ export async function checkContainer({ dockerId, container, remove = false }: {
|
||||
isRunning,
|
||||
isRestarting,
|
||||
isExited
|
||||
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
|
@@ -334,7 +334,8 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
baseDatabaseBranch,
|
||||
dockerComposeFile,
|
||||
dockerComposeFileLocation,
|
||||
dockerComposeConfiguration
|
||||
dockerComposeConfiguration,
|
||||
simpleDockerfile
|
||||
} = request.body
|
||||
if (port) port = Number(port);
|
||||
if (exposePort) {
|
||||
@@ -373,6 +374,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
dockerComposeFile,
|
||||
dockerComposeFileLocation,
|
||||
dockerComposeConfiguration,
|
||||
simpleDockerfile,
|
||||
...defaultConfiguration,
|
||||
connectedDatabase: { update: { hostedDatabaseDBName: baseDatabaseBranch } }
|
||||
}
|
||||
@@ -395,6 +397,7 @@ export async function saveApplication(request: FastifyRequest<SaveApplication>,
|
||||
dockerComposeFile,
|
||||
dockerComposeFileLocation,
|
||||
dockerComposeConfiguration,
|
||||
simpleDockerfile,
|
||||
...defaultConfiguration
|
||||
}
|
||||
});
|
||||
@@ -770,6 +773,7 @@ export async function deployApplication(request: FastifyRequest<DeployApplicatio
|
||||
await prisma.application.update({ where: { id }, data: { configHash } });
|
||||
}
|
||||
await prisma.application.update({ where: { id }, data: { updatedAt: new Date() } });
|
||||
if (application.gitSourceId) {
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
id: buildId,
|
||||
@@ -786,6 +790,20 @@ export async function deployApplication(request: FastifyRequest<DeployApplicatio
|
||||
type: pullmergeRequestId ? application.gitSource?.githubApp?.id ? 'manual_pr' : 'manual_mr' : 'manual'
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
id: buildId,
|
||||
applicationId: id,
|
||||
branch: 'latest',
|
||||
forceRebuild,
|
||||
destinationDockerId: application.destinationDocker?.id,
|
||||
status: 'queued',
|
||||
type: 'manual'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
buildId
|
||||
};
|
||||
@@ -800,20 +818,29 @@ export async function deployApplication(request: FastifyRequest<DeployApplicatio
|
||||
export async function saveApplicationSource(request: FastifyRequest<SaveApplicationSource>, reply: FastifyReply) {
|
||||
try {
|
||||
const { id } = request.params
|
||||
const { gitSourceId, forPublic, type } = request.body
|
||||
const { gitSourceId, forPublic, type, simpleDockerfile } = request.body
|
||||
if (forPublic) {
|
||||
if (gitSourceId) {
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: { gitSource: { connect: { id: gitSourceId } } }
|
||||
});
|
||||
} else {
|
||||
const publicGit = await prisma.gitSource.findFirst({ where: { type, forPublic } });
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: { gitSource: { connect: { id: publicGit.id } } }
|
||||
});
|
||||
} else {
|
||||
}
|
||||
}
|
||||
if (simpleDockerfile) {
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: { gitSource: { connect: { id: gitSourceId } } }
|
||||
data: { simpleDockerfile }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return reply.code(201).send()
|
||||
} catch ({ status, message }) {
|
||||
return errorHandler({ status, message })
|
||||
@@ -916,11 +943,11 @@ export async function getBuildPack(request) {
|
||||
const teamId = request.user?.teamId;
|
||||
const application: any = await getApplicationFromDB(id, teamId);
|
||||
return {
|
||||
type: application.gitSource.type,
|
||||
type: application.gitSource?.type || 'dockerRegistry',
|
||||
projectId: application.projectId,
|
||||
repository: application.repository,
|
||||
branch: application.branch,
|
||||
apiUrl: application.gitSource.apiUrl,
|
||||
apiUrl: application.gitSource?.apiUrl || null,
|
||||
isPublicRepository: application.settings.isPublicRepository
|
||||
}
|
||||
} catch ({ status, message }) {
|
||||
|
@@ -25,7 +25,8 @@ export interface SaveApplication extends OnlyId {
|
||||
baseDatabaseBranch: string,
|
||||
dockerComposeFile: string,
|
||||
dockerComposeFileLocation: string,
|
||||
dockerComposeConfiguration: string
|
||||
dockerComposeConfiguration: string,
|
||||
simpleDockerfile: string
|
||||
}
|
||||
}
|
||||
export interface SaveApplicationSettings extends OnlyId {
|
||||
@@ -56,7 +57,7 @@ export interface GetImages {
|
||||
Body: { buildPack: string, deploymentType: string }
|
||||
}
|
||||
export interface SaveApplicationSource extends OnlyId {
|
||||
Body: { gitSourceId?: string | null, forPublic?: boolean, type?: string }
|
||||
Body: { gitSourceId?: string | null, forPublic?: boolean, type?: string, simpleDockerfile?: string }
|
||||
}
|
||||
export interface CheckRepository extends OnlyId {
|
||||
Querystring: { repository: string, branch: string }
|
||||
|
@@ -190,7 +190,7 @@ export async function showDashboard(request: FastifyRequest) {
|
||||
|
||||
let foundUnconfiguredApplication = false;
|
||||
for (const application of applications) {
|
||||
if (!application.buildPack || !application.destinationDockerId || !application.branch || (!application.settings?.isBot && !application?.fqdn) && application.buildPack !== "compose") {
|
||||
if (((!application.buildPack || !application.branch) && !application.simpleDockerfile) || !application.destinationDockerId || (!application.settings?.isBot && !application?.fqdn) && application.buildPack !== "compose") {
|
||||
foundUnconfiguredApplication = true
|
||||
}
|
||||
}
|
||||
|
@@ -42,4 +42,6 @@
|
||||
<Icons.Heroku {isAbsolute} />
|
||||
{:else if application.buildPack?.toLowerCase() === 'compose'}
|
||||
<Icons.Compose {isAbsolute} />
|
||||
{:else if application.simpleDockerfile}
|
||||
<Icons.Docker {isAbsolute} />
|
||||
{/if}
|
||||
|
@@ -19,14 +19,14 @@ export async function refreshStatus(list: Array<any>) {
|
||||
}
|
||||
|
||||
export async function getStatus(resource: any, force: boolean = false) {
|
||||
const { id, buildPack, dualCerts, engine } = resource;
|
||||
const { id, buildPack, dualCerts, engine, simpleDockerfile } = resource;
|
||||
let newStatus = 'stopped';
|
||||
|
||||
// Already set and we're not forcing
|
||||
if (getStore(containerStatus)[id] && !force) return getStore(containerStatus)[id];
|
||||
|
||||
try {
|
||||
if (buildPack) { // Application
|
||||
if (buildPack || simpleDockerfile) { // Application
|
||||
const response = await get(`/applications/${id}/status`);
|
||||
newStatus = parseApplicationsResponse(response);
|
||||
} else if (typeof dualCerts !== 'undefined') { // Service
|
||||
|
@@ -57,14 +57,15 @@ export const appSession: Writable<AppSession> = writable({
|
||||
export const disabledButton: Writable<boolean> = writable(false);
|
||||
export const isDeploymentEnabled: Writable<boolean> = writable(false);
|
||||
export function checkIfDeploymentEnabledApplications(isAdmin: boolean, application: any) {
|
||||
return (
|
||||
return !!(
|
||||
isAdmin &&
|
||||
(application.buildPack === 'compose') ||
|
||||
(application.fqdn || application.settings.isBot) &&
|
||||
application.gitSource &&
|
||||
((application.gitSource &&
|
||||
application.repository &&
|
||||
application.destinationDocker &&
|
||||
application.buildPack
|
||||
application.buildPack) || application.simpleDockerfile) &&
|
||||
application.destinationDocker
|
||||
|
||||
);
|
||||
}
|
||||
export function checkIfDeploymentEnabledServices(isAdmin: boolean, service: any) {
|
||||
|
@@ -218,6 +218,7 @@
|
||||
<li class="menu-title">
|
||||
<span>Advanced</span>
|
||||
</li>
|
||||
{#if !application.simpleDockerfile}
|
||||
<li
|
||||
class="rounded"
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/revert`}
|
||||
@@ -240,6 +241,7 @@
|
||||
Revert</a
|
||||
>
|
||||
</li>
|
||||
{/if}
|
||||
<li
|
||||
class="rounded"
|
||||
class:text-stone-600={$status.application.overallStatus !== 'healthy'}
|
||||
@@ -265,7 +267,7 @@
|
||||
</svg>Monitoring</a
|
||||
>
|
||||
</li>
|
||||
{#if !application.settings.isBot}
|
||||
{#if !application.settings.isBot && !application.simpleDockerfile}
|
||||
<li
|
||||
class="rounded"
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/previews`}
|
||||
|
@@ -2,8 +2,14 @@
|
||||
import type { Load } from '@sveltejs/kit';
|
||||
function checkConfiguration(application: any): string | null {
|
||||
let configurationPhase = null;
|
||||
if (!application.gitSourceId) {
|
||||
configurationPhase = 'source';
|
||||
if (!application.gitSourceId && !application.simpleDockerfile) {
|
||||
return (configurationPhase = 'source');
|
||||
}
|
||||
if (application.simpleDockerfile) {
|
||||
if (!application.destinationDockerId) {
|
||||
configurationPhase = 'destination';
|
||||
}
|
||||
return configurationPhase;
|
||||
} else if (!application.repository && !application.branch) {
|
||||
configurationPhase = 'repository';
|
||||
} else if (!application.destinationDockerId) {
|
||||
|
@@ -9,6 +9,12 @@
|
||||
redirect: `/applications/${params.id}`
|
||||
};
|
||||
}
|
||||
if (application.simpleDockerfile) {
|
||||
return {
|
||||
status: 302,
|
||||
redirect: `/applications/${params.id}`
|
||||
};
|
||||
}
|
||||
const response = await get(`/applications/${params.id}/configuration/buildpack`);
|
||||
return {
|
||||
props: {
|
||||
@@ -47,7 +53,7 @@
|
||||
|
||||
const { id } = $page.params;
|
||||
|
||||
let htmlUrl = application.gitSource.htmlUrl;
|
||||
let htmlUrl = application.gitSource?.htmlUrl || null;
|
||||
|
||||
let scanning: boolean = true;
|
||||
let foundConfig: any = null;
|
||||
|
@@ -25,6 +25,8 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let sources: any;
|
||||
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { get, post } from '$lib/api';
|
||||
@@ -33,11 +35,12 @@
|
||||
import { appSession } from '$lib/store';
|
||||
import PublicRepository from './_PublicRepository.svelte';
|
||||
import DocLink from '$lib/components/DocLink.svelte';
|
||||
import Beta from '$lib/components/Beta.svelte';
|
||||
|
||||
const { id } = $page.params;
|
||||
const from = $page.url.searchParams.get('from');
|
||||
let simpleDockerfile: any = null;
|
||||
|
||||
export let sources: any;
|
||||
const filteredSources = sources.filter(
|
||||
(source: any) =>
|
||||
(source.type === 'github' && source.githubAppId && source.githubApp.installationId) ||
|
||||
@@ -61,18 +64,20 @@
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function newSource() {
|
||||
const { id } = await post('/sources/new', {});
|
||||
return await goto(`/sources/${id}`, { replaceState: true });
|
||||
async function handleDockerImage() {
|
||||
try {
|
||||
await post(`/applications/${id}/configuration/source`, { simpleDockerfile });
|
||||
return await goto(from || `/applications/${id}/configuration/destination`);
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="max-w-screen-2xl mx-auto px-9">
|
||||
{#if !filteredSources}
|
||||
<div class="title pb-8">Git App</div>
|
||||
{/if}
|
||||
<div class="flex flex-wrap justify-center">
|
||||
{#if !filteredSources}
|
||||
<div class="flex-col">
|
||||
<div class="pb-2 text-center font-bold">
|
||||
{$t('application.configuration.no_configurable_git')}
|
||||
@@ -95,7 +100,13 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
</div>
|
||||
{/if}
|
||||
{#if ownSources.length > 0 || otherSources.length > 0}
|
||||
<div class="title pb-8">Integrated with Git App</div>
|
||||
{/if}
|
||||
{#if ownSources.length > 0}
|
||||
<div class="flex flex-wrap justify-center">
|
||||
<div class="flex flex-col lg:flex-row lg:flex-wrap justify-center">
|
||||
{#each ownSources as source}
|
||||
<div class="p-2 relative">
|
||||
@@ -240,11 +251,25 @@
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="title py-4 pr-4">Public Repository</div>
|
||||
<div class="title py-4 pr-4">Public Repository from Git</div>
|
||||
<DocLink url="https://docs.coollabs.io/coolify/applications/#public-repository" />
|
||||
</div>
|
||||
<PublicRepository />
|
||||
<div class="flex flex-row items-center pt-10">
|
||||
<div class="title py-4 pr-4">Simple Dockerfile <Beta /></div>
|
||||
<DocLink url="https://docs.coollabs.io/coolify/applications/#dockerfile" />
|
||||
</div>
|
||||
<div class="mx-auto max-w-screen-2xl">
|
||||
<form class="flex flex-col" on:submit|preventDefault={handleDockerImage}>
|
||||
<div class="flex flex-col space-y-2 w-full">
|
||||
<div class="flex flex-row space-x-2">
|
||||
<textarea required class="w-full" rows="10" bind:value={simpleDockerfile} />
|
||||
<button class="btn btn-primary" type="submit">Deploy Dockerfile</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -124,7 +124,7 @@
|
||||
description={$t('application.enable_auto_deploy_webhooks')}
|
||||
/>
|
||||
</div>
|
||||
{#if !application.settings.isBot}
|
||||
{#if !application.settings.isBot && !application.simpleDockerfile}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<Setting
|
||||
id="previews"
|
||||
|
@@ -66,6 +66,7 @@
|
||||
save: false,
|
||||
reloadCompose: false
|
||||
};
|
||||
let isSimpleDockerfile = !!application.simpleDockerfile;
|
||||
let fqdnEl: any = null;
|
||||
let forceSave = false;
|
||||
let isPublicRepository = application.settings?.isPublicRepository;
|
||||
@@ -492,6 +493,7 @@
|
||||
<label for="name">{$t('forms.name')}</label>
|
||||
<input name="name" id="name" class="w-full" bind:value={application.name} required />
|
||||
</div>
|
||||
{#if !isSimpleDockerfile}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="gitSource">{$t('application.git_source')}</label>
|
||||
{#if isDisabled || application.settings.isPublicRepository}
|
||||
@@ -512,6 +514,7 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">Git commit</label>
|
||||
<div class="flex gap-2">
|
||||
@@ -565,6 +568,9 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="registry">Docker Registry</label>
|
||||
{#if isDisabled}
|
||||
@@ -586,10 +592,15 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !isSimpleDockerfile}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="buildPack">{$t('application.build_pack')} </label>
|
||||
{#if isDisabled}
|
||||
<input class="capitalize w-full" disabled={isDisabled} value={application.buildPack} />
|
||||
<input
|
||||
class="capitalize w-full"
|
||||
disabled={isDisabled}
|
||||
value={application.buildPack}
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/buildpack?from=/applications/${id}`}
|
||||
@@ -603,6 +614,7 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="destination">{$t('application.destination')}</label>
|
||||
<div class="no-underline">
|
||||
@@ -712,7 +724,44 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if application.buildPack !== 'compose'}
|
||||
{#if isSimpleDockerfile}
|
||||
<div class="title font-bold pb-3 pt-10 border-b border-coolgray-500 mb-6">
|
||||
Configuration
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row gap-2 px-4 pr-5">
|
||||
<div class="grid grid-cols-2 items-center pt-4">
|
||||
<label for="simpleDockerfile">Dockerfile</label>
|
||||
<div class="flex gap-2">
|
||||
<textarea
|
||||
rows=10
|
||||
id="simpleDockerfile"
|
||||
name="simpleDockerfile"
|
||||
class="w-full"
|
||||
disabled={isDisabled}
|
||||
bind:value={application.simpleDockerfile}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="port"
|
||||
>{$t('forms.port')}
|
||||
<Explainer
|
||||
explanation={'The port your application listens inside the docker container.'}
|
||||
/></label
|
||||
>
|
||||
<input
|
||||
class="w-full"
|
||||
disabled={isDisabled}
|
||||
readonly={!$appSession.isAdmin}
|
||||
name="port"
|
||||
id="port"
|
||||
bind:value={application.port}
|
||||
placeholder="{$t('forms.default')}: 3000"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{:else if application.buildPack !== 'compose'}
|
||||
<div class="title font-bold pb-3 pt-10 border-b border-coolgray-500 mb-6">
|
||||
Configuration
|
||||
</div>
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let secrets: any;
|
||||
export let application: any;
|
||||
export let previewSecrets: any;
|
||||
import pLimit from 'p-limit';
|
||||
import { page } from '$app/stores';
|
||||
@@ -28,7 +29,6 @@
|
||||
import Secret from './_Secret.svelte';
|
||||
import PreviewSecret from './_PreviewSecret.svelte';
|
||||
import { errorNotification } from '$lib/common';
|
||||
import { t } from '$lib/translations';
|
||||
import Explainer from '$lib/components/Explainer.svelte';
|
||||
|
||||
const limit = pLimit(1);
|
||||
@@ -110,6 +110,7 @@
|
||||
<div class="lg:pt-0 pt-10">
|
||||
<Secret on:refresh={refreshSecrets} length={secrets.length} isNewSecret />
|
||||
</div>
|
||||
{#if !application.settings.isBot && !application.simpleDockerfile}
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
|
||||
<div class="title font-bold pb-3 pt-8">
|
||||
Preview Secrets <Explainer
|
||||
@@ -133,6 +134,7 @@
|
||||
{:else}
|
||||
Add secrets first to see Preview Secrets.
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<form on:submit|preventDefault={getValues} class="mb-12 w-full">
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2 pt-10">
|
||||
|
@@ -86,7 +86,7 @@
|
||||
<Storage on:refresh={refreshStorage} {storage} />
|
||||
{/key}
|
||||
{/each}
|
||||
<div class="title pt-10">
|
||||
<div class="Preview Secrets" class:pt-10={predefinedVolumes.length > 0}>
|
||||
Add New Volume <Explainer
|
||||
position="dropdown-bottom"
|
||||
explanation={$t('application.storage.persistent_storage_explainer')}
|
||||
|
@@ -151,7 +151,7 @@
|
||||
}
|
||||
|
||||
async function getStatus(resources: any, force: boolean = false) {
|
||||
const { id, buildPack, dualCerts, type } = resources;
|
||||
const { id, buildPack, dualCerts, type, simpleDockerfile } = resources;
|
||||
if (buildPack && applications.length + filtered.otherApplications.length > 10 && !force) {
|
||||
noInitialStatus.applications = true;
|
||||
return;
|
||||
@@ -172,7 +172,7 @@
|
||||
numberOfGetStatus++;
|
||||
let isRunning = false;
|
||||
let isDegraded = false;
|
||||
if (buildPack) {
|
||||
if (buildPack || simpleDockerfile) {
|
||||
const response = await get(`/applications/${id}/status`);
|
||||
if (response.length === 0) {
|
||||
isRunning = false;
|
||||
|
Reference in New Issue
Block a user