feat: simpleDockerfile deployment
This commit is contained in:
parent
a129be0dbd
commit
2e56086661
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Application" ADD COLUMN "simpleDockerfile" TEXT;
|
@ -98,7 +98,7 @@ model TeamInvitation {
|
||||
}
|
||||
|
||||
model Application {
|
||||
id String @id @default(cuid())
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
fqdn String?
|
||||
repository String?
|
||||
@ -124,23 +124,25 @@ model Application {
|
||||
dockerComposeFile String?
|
||||
dockerComposeFileLocation String?
|
||||
dockerComposeConfiguration String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
destinationDockerId String?
|
||||
gitSourceId String?
|
||||
gitCommitHash String?
|
||||
baseImage String?
|
||||
baseBuildImage String?
|
||||
gitSource GitSource? @relation(fields: [gitSourceId], references: [id])
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
persistentStorage ApplicationPersistentStorage[]
|
||||
settings ApplicationSettings?
|
||||
secrets Secret[]
|
||||
teams Team[]
|
||||
connectedDatabase ApplicationConnectedDatabase?
|
||||
previewApplication PreviewApplication[]
|
||||
dockerRegistryId String?
|
||||
dockerRegistry DockerRegistry? @relation(fields: [dockerRegistryId], references: [id])
|
||||
simpleDockerfile String?
|
||||
|
||||
persistentStorage ApplicationPersistentStorage[]
|
||||
secrets Secret[]
|
||||
teams Team[]
|
||||
connectedDatabase ApplicationConnectedDatabase?
|
||||
previewApplication PreviewApplication[]
|
||||
gitSource GitSource? @relation(fields: [gitSourceId], references: [id])
|
||||
destinationDocker DestinationDocker? @relation(fields: [destinationDockerId], references: [id])
|
||||
dockerRegistry DockerRegistry? @relation(fields: [dockerRegistryId], references: [id])
|
||||
}
|
||||
|
||||
model PreviewApplication {
|
||||
|
@ -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;
|
||||
|
@ -41,14 +41,13 @@ export async function checkContainer({ dockerId, container, remove = false }: {
|
||||
`docker rm ${container}`
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
found: containerFound,
|
||||
status: {
|
||||
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,22 +773,37 @@ 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() } });
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
id: buildId,
|
||||
applicationId: id,
|
||||
sourceBranch: branch,
|
||||
branch: application.branch,
|
||||
pullmergeRequestId: pullmergeRequestId?.toString(),
|
||||
forceRebuild,
|
||||
destinationDockerId: application.destinationDocker?.id,
|
||||
gitSourceId: application.gitSource?.id,
|
||||
githubAppId: application.gitSource?.githubApp?.id,
|
||||
gitlabAppId: application.gitSource?.gitlabApp?.id,
|
||||
status: 'queued',
|
||||
type: pullmergeRequestId ? application.gitSource?.githubApp?.id ? 'manual_pr' : 'manual_mr' : 'manual'
|
||||
}
|
||||
});
|
||||
if (application.gitSourceId) {
|
||||
await prisma.build.create({
|
||||
data: {
|
||||
id: buildId,
|
||||
applicationId: id,
|
||||
sourceBranch: branch,
|
||||
branch: application.branch,
|
||||
pullmergeRequestId: pullmergeRequestId?.toString(),
|
||||
forceRebuild,
|
||||
destinationDockerId: application.destinationDocker?.id,
|
||||
gitSourceId: application.gitSource?.id,
|
||||
githubAppId: application.gitSource?.githubApp?.id,
|
||||
gitlabAppId: application.gitSource?.gitlabApp?.id,
|
||||
status: 'queued',
|
||||
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) {
|
||||
const publicGit = await prisma.gitSource.findFirst({ where: { type, 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 } } }
|
||||
});
|
||||
}
|
||||
}
|
||||
if (simpleDockerfile) {
|
||||
await prisma.application.update({
|
||||
where: { id },
|
||||
data: { gitSource: { connect: { id: publicGit.id } } }
|
||||
});
|
||||
} else {
|
||||
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,28 +218,30 @@
|
||||
<li class="menu-title">
|
||||
<span>Advanced</span>
|
||||
</li>
|
||||
<li
|
||||
class="rounded"
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/revert`}
|
||||
>
|
||||
<a href={`/applications/${$page.params.id}/revert`} class="no-underline w-full">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M20 5v14l-12 -7z" />
|
||||
<line x1="4" y1="5" x2="4" y2="19" />
|
||||
</svg>
|
||||
Revert</a
|
||||
{#if !application.simpleDockerfile}
|
||||
<li
|
||||
class="rounded"
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/revert`}
|
||||
>
|
||||
</li>
|
||||
<a href={`/applications/${$page.params.id}/revert`} class="no-underline w-full">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M20 5v14l-12 -7z" />
|
||||
<line x1="4" y1="5" x2="4" y2="19" />
|
||||
</svg>
|
||||
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 flex-wrap justify-center">
|
||||
<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>
|
||||
</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;
|
||||
@ -268,7 +269,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
await saveForm(id, application,baseDatabaseBranch, dockerComposeConfiguration);
|
||||
await saveForm(id, application, baseDatabaseBranch, dockerComposeConfiguration);
|
||||
setLocation(application, settings);
|
||||
$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
|
||||
|
||||
@ -492,79 +493,84 @@
|
||||
<label for="name">{$t('forms.name')}</label>
|
||||
<input name="name" id="name" class="w-full" bind:value={application.name} required />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="gitSource">{$t('application.git_source')}</label>
|
||||
{#if isDisabled || application.settings.isPublicRepository}
|
||||
<input
|
||||
disabled={isDisabled || application.settings.isPublicRepository}
|
||||
class="w-full"
|
||||
value={application.gitSource?.name}
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/source?from=/applications/${id}`}
|
||||
class="no-underline"
|
||||
><input
|
||||
{#if !isSimpleDockerfile}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="gitSource">{$t('application.git_source')}</label>
|
||||
{#if isDisabled || application.settings.isPublicRepository}
|
||||
<input
|
||||
disabled={isDisabled || application.settings.isPublicRepository}
|
||||
class="w-full"
|
||||
value={application.gitSource?.name}
|
||||
id="gitSource"
|
||||
class="cursor-pointer hover:bg-coolgray-500 w-full"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">Git commit</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
id="commit"
|
||||
name="commit"
|
||||
class="w-full"
|
||||
disabled={isDisabled}
|
||||
placeholder="default: latest commit"
|
||||
bind:value={application.gitCommitHash}
|
||||
/>
|
||||
<a
|
||||
href="{application.gitSource
|
||||
.htmlUrl}/{application.repository}/commits/{application.branch}"
|
||||
target="_blank noreferrer"
|
||||
class="btn btn-primary text-xs"
|
||||
>Commits<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="3"
|
||||
stroke="currentColor"
|
||||
class="w-3 h-3 text-white ml-2"
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/source?from=/applications/${id}`}
|
||||
class="no-underline"
|
||||
><input
|
||||
value={application.gitSource?.name}
|
||||
id="gitSource"
|
||||
class="cursor-pointer hover:bg-coolgray-500 w-full"
|
||||
/></a
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M4.5 19.5l15-15m0 0H8.25m11.25 0v11.25"
|
||||
/>
|
||||
</svg></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">{$t('application.git_repository')}</label>
|
||||
{#if isDisabled || application.settings.isPublicRepository}
|
||||
<input
|
||||
class="w-full"
|
||||
disabled={isDisabled || application.settings.isPublicRepository}
|
||||
value="{application.repository}/{application.branch}"
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
|
||||
class="no-underline"
|
||||
><input
|
||||
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">Git commit</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
id="commit"
|
||||
name="commit"
|
||||
class="w-full"
|
||||
disabled={isDisabled}
|
||||
placeholder="default: latest commit"
|
||||
bind:value={application.gitCommitHash}
|
||||
/>
|
||||
<a
|
||||
href="{application.gitSource
|
||||
.htmlUrl}/{application.repository}/commits/{application.branch}"
|
||||
target="_blank noreferrer"
|
||||
class="btn btn-primary text-xs"
|
||||
>Commits<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="3"
|
||||
stroke="currentColor"
|
||||
class="w-3 h-3 text-white ml-2"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M4.5 19.5l15-15m0 0H8.25m11.25 0v11.25"
|
||||
/>
|
||||
</svg></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">{$t('application.git_repository')}</label>
|
||||
{#if isDisabled || application.settings.isPublicRepository}
|
||||
<input
|
||||
class="w-full"
|
||||
disabled={isDisabled || application.settings.isPublicRepository}
|
||||
value="{application.repository}/{application.branch}"
|
||||
id="repository"
|
||||
class="cursor-pointer hover:bg-coolgray-500 w-full"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
|
||||
class="no-underline"
|
||||
><input
|
||||
value="{application.repository}/{application.branch}"
|
||||
id="repository"
|
||||
class="cursor-pointer hover:bg-coolgray-500 w-full"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
{/if}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="registry">Docker Registry</label>
|
||||
{#if isDisabled}
|
||||
@ -586,23 +592,29 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<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} />
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/buildpack?from=/applications/${id}`}
|
||||
class="no-underline"
|
||||
>
|
||||
{#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}
|
||||
id="buildPack"
|
||||
class="cursor-pointer hover:bg-coolgray-500 capitalize w-full"
|
||||
/></a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
href={`/applications/${id}/configuration/buildpack?from=/applications/${id}`}
|
||||
class="no-underline"
|
||||
>
|
||||
<input
|
||||
value={application.buildPack}
|
||||
id="buildPack"
|
||||
class="cursor-pointer hover:bg-coolgray-500 capitalize w-full"
|
||||
/></a
|
||||
>
|
||||
{/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')}
|
||||
|
@ -29,7 +29,7 @@
|
||||
export let settings: any;
|
||||
export let gitSources: any;
|
||||
export let destinations: any;
|
||||
|
||||
|
||||
let filtered: any = setInitials();
|
||||
import { get, post } from '$lib/api';
|
||||
import { t } from '$lib/translations';
|
||||
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user