Merge pull request #611 from coollabsio/next

v3.10.1
This commit is contained in:
Andras Bacsai 2022-09-10 10:47:47 +02:00 committed by GitHub
commit 0a68a48fc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 159 additions and 74 deletions

View File

@ -261,7 +261,10 @@ import * as buildpacks from '../lib/buildPacks';
if (secrets.length > 0) { if (secrets.length > 0) {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { 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}`); envs.push(`${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -556,7 +556,6 @@ export function checkPnpm(installCommand = null, buildCommand = null, startComma
); );
} }
export async function buildImage({ export async function buildImage({
applicationId, applicationId,
tag, tag,
@ -677,8 +676,6 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
secrets, secrets,
pullmergeRequestId pullmergeRequestId
} = data; } = data;
const isPnpm = checkPnpm(installCommand, buildCommand); const isPnpm = checkPnpm(installCommand, buildCommand);
const Dockerfile: Array<string> = []; const Dockerfile: Array<string> = [];
Dockerfile.push(`FROM ${imageForBuild}`); Dockerfile.push(`FROM ${imageForBuild}`);
@ -688,7 +685,10 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {
@ -707,6 +707,7 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
Dockerfile.push(`RUN ${installCommand}`); Dockerfile.push(`RUN ${installCommand}`);
} }
Dockerfile.push(`RUN ${buildCommand}`); Dockerfile.push(`RUN ${buildCommand}`);
console.log(Dockerfile.join('\n'))
await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n'));
await buildImage({ ...data, isCache: true }); await buildImage({ ...data, isCache: true });
} }
@ -722,7 +723,10 @@ export async function buildCacheImageForLaravel(data, imageForBuild) {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -27,7 +27,10 @@ const createDockerfile = async (data, image): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -28,6 +28,7 @@ export default async function (data) {
if (secrets.length > 0) { if (secrets.length > 0) {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
// TODO: fix secrets
if ( if (
(pullmergeRequestId && secret.isPRMRSecret) || (pullmergeRequestId && secret.isPRMRSecret) ||
(!pullmergeRequestId && !secret.isPRMRSecret) (!pullmergeRequestId && !secret.isPRMRSecret)

View File

@ -27,7 +27,10 @@ const createDockerfile = async (data, image): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -23,7 +23,10 @@ const createDockerfile = async (data, image): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -27,7 +27,10 @@ const createDockerfile = async (data, image): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -16,7 +16,10 @@ const createDockerfile = async (data, image, htaccessFound): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -21,7 +21,10 @@ const createDockerfile = async (data, image): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -24,7 +24,10 @@ const createDockerfile = async (data, image): Promise<void> => {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (secret.isBuildSecret) { if (secret.isBuildSecret) {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { const isSecretFound = secrets.filter(s => s.name === secret.name && s.isPRMRSecret)
if (isSecretFound.length > 0) {
Dockerfile.push(`ARG ${secret.name}=${isSecretFound[0].value}`);
} else {
Dockerfile.push(`ARG ${secret.name}=${secret.value}`); Dockerfile.push(`ARG ${secret.name}=${secret.value}`);
} }
} else { } else {

View File

@ -21,7 +21,7 @@ import { scheduler } from './scheduler';
import { supportedServiceTypesAndVersions } from './services/supportedVersions'; import { supportedServiceTypesAndVersions } from './services/supportedVersions';
import { includeServices } from './services/common'; import { includeServices } from './services/common';
export const version = '3.10.0'; export const version = '3.10.1';
export const isDev = process.env.NODE_ENV === 'development'; export const isDev = process.env.NODE_ENV === 'development';
const algorithm = 'aes-256-ctr'; const algorithm = 'aes-256-ctr';
@ -537,7 +537,7 @@ export async function executeDockerCmd({ debug, buildId, applicationId, dockerId
} }
export async function startTraefikProxy(id: string): Promise<void> { export async function startTraefikProxy(id: string): Promise<void> {
const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } }) const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } })
const found = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true }); const { found } = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true });
const { id: settingsId, ipv4, ipv6 } = await listSettings(); const { id: settingsId, ipv4, ipv6 } = await listSettings();
if (!found) { if (!found) {
@ -621,7 +621,7 @@ export async function configureNetworkTraefikProxy(destination: any): Promise<vo
export async function stopTraefikProxy( export async function stopTraefikProxy(
id: string id: string
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const found = await checkContainer({ dockerId: id, container: 'coolify-proxy' }); const { found } = await checkContainer({ dockerId: id, container: 'coolify-proxy' });
await prisma.destinationDocker.update({ await prisma.destinationDocker.update({
where: { id }, where: { id },
data: { isCoolifyProxyUsed: false } data: { isCoolifyProxyUsed: false }
@ -1062,7 +1062,7 @@ export async function stopTcpHttpProxy(
const { id: dockerId } = destinationDocker; const { id: dockerId } = destinationDocker;
let container = `${id}-${publicPort}`; let container = `${id}-${publicPort}`;
if (forceName) container = forceName; if (forceName) container = forceName;
const found = await checkContainer({ dockerId, container }); const { found } = await checkContainer({ dockerId, container });
try { try {
if (found) { if (found) {
return await executeDockerCmd({ return await executeDockerCmd({
@ -1284,7 +1284,7 @@ export async function startTraefikTCPProxy(
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const { network, id: dockerId, remoteEngine } = destinationDocker; const { network, id: dockerId, remoteEngine } = destinationDocker;
const container = `${id}-${publicPort}`; const container = `${id}-${publicPort}`;
const found = await checkContainer({ dockerId, container, remove: true }); const { found } = await checkContainer({ dockerId, container, remove: true });
const { ipv4, ipv6 } = await listSettings(); const { ipv4, ipv6 } = await listSettings();
let dependentId = id; let dependentId = id;

View File

@ -13,7 +13,7 @@ export function formatLabelsOnDocker(data) {
return container return container
}) })
} }
export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<boolean> { export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<{ found: boolean, status?: { isExited: boolean, isRunning: boolean, isRestarting: boolean } }> {
let containerFound = false; let containerFound = false;
try { try {
const { stdout } = await executeDockerCmd({ const { stdout } = await executeDockerCmd({
@ -21,10 +21,12 @@ export async function checkContainer({ dockerId, container, remove = false }: {
command: command:
`docker inspect --format '{{json .State}}' ${container}` `docker inspect --format '{{json .State}}' ${container}`
}); });
containerFound = true
const parsedStdout = JSON.parse(stdout); const parsedStdout = JSON.parse(stdout);
const status = parsedStdout.Status; const status = parsedStdout.Status;
const isRunning = status === 'running'; const isRunning = status === 'running';
const isRestarting = status === 'restarting'
const isExited = status === 'exited'
if (status === 'created') { if (status === 'created') {
await executeDockerCmd({ await executeDockerCmd({
dockerId, dockerId,
@ -39,13 +41,23 @@ export async function checkContainer({ dockerId, container, remove = false }: {
`docker rm ${container}` `docker rm ${container}`
}); });
} }
if (isRunning) {
containerFound = true; return {
} found: containerFound,
status: {
isRunning,
isRestarting,
isExited
}
};
} catch (err) { } catch (err) {
// Container not found // Container not found
} }
return containerFound; return {
found: false
};
} }
export async function isContainerExited(dockerId: string, containerName: string): Promise<boolean> { export async function isContainerExited(dockerId: string, containerName: string): Promise<boolean> {

View File

@ -10,7 +10,8 @@ export default async function ({
branch, branch,
buildId, buildId,
privateSshKey, privateSshKey,
customPort customPort,
forPublic
}: { }: {
applicationId: string; applicationId: string;
workdir: string; workdir: string;
@ -21,11 +22,15 @@ export default async function ({
repodir: string; repodir: string;
privateSshKey: string; privateSshKey: string;
customPort: number; customPort: number;
forPublic: boolean;
}): Promise<string> { }): Promise<string> {
const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, ''); const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, '');
await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId }); await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId });
await asyncExecShell(`echo '${privateSshKey}' > ${repodir}/id.rsa`);
await asyncExecShell(`chmod 600 ${repodir}/id.rsa`); if (!forPublic) {
await asyncExecShell(`echo '${privateSshKey}' > ${repodir}/id.rsa`);
await asyncExecShell(`chmod 600 ${repodir}/id.rsa`);
}
await saveBuildLog({ await saveBuildLog({
line: `Cloning ${repository}:${branch} branch.`, line: `Cloning ${repository}:${branch} branch.`,
@ -33,9 +38,16 @@ export default async function ({
applicationId applicationId
}); });
await asyncExecShell( if (forPublic) {
`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. ` await asyncExecShell(
); `git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. `
);
} else {
await asyncExecShell(
`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git submodule update --init --recursive && git lfs pull && cd .. `
);
}
const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`);
return commit.replace('\n', ''); return commit.replace('\n', '');
} }

View File

@ -655,7 +655,7 @@ async function startLanguageToolService(request: FastifyRequest<ServiceStartStop
image: config.languagetool.image, image: config.languagetool.image,
environment: config.languagetool.environmentVariables, environment: config.languagetool.environmentVariables,
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
volumes: config.languagetool, volumes: config.languagetool.volumes,
labels: makeLabelForServices('languagetool'), labels: makeLabelForServices('languagetool'),
...defaultComposeConfiguration(network), ...defaultComposeConfiguration(network),
} }
@ -710,7 +710,7 @@ async function startN8nService(request: FastifyRequest<ServiceStartStop>) {
[id]: { [id]: {
container_name: id, container_name: id,
image: config.n8n.image, image: config.n8n.image,
volumes: config.n8n, volumes: config.n8n.volumes,
environment: config.n8n.environmentVariables, environment: config.n8n.environmentVariables,
labels: makeLabelForServices('n8n'), labels: makeLabelForServices('n8n'),
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
@ -1116,7 +1116,6 @@ async function startUmamiService(request: FastifyRequest<ServiceStartStop>) {
}, },
volumes: volumeMounts volumes: volumeMounts
}; };
console.log(composeFile)
const composeFileDestination = `${workdir}/docker-compose.yaml`; const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
await startServiceContainers(destinationDocker.id, composeFileDestination) await startServiceContainers(destinationDocker.id, composeFileDestination)

View File

@ -74,14 +74,21 @@ export async function getApplicationStatus(request: FastifyRequest<OnlyId>) {
const { teamId } = request.user const { teamId } = request.user
let isRunning = false; let isRunning = false;
let isExited = false; let isExited = false;
let isRestarting = false;
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application?.destinationDockerId) { if (application?.destinationDockerId) {
isRunning = await checkContainer({ dockerId: application.destinationDocker.id, container: id }); const status = await checkContainer({ dockerId: application.destinationDocker.id, container: id });
isExited = await isContainerExited(application.destinationDocker.id, id); if (status?.found) {
isRunning = status.status.isRunning;
isExited = status.status.isExited;
isRestarting = status.status.isRestarting
}
// isExited = await isContainerExited(application.destinationDocker.id, id);
} }
return { return {
isRunning, isRunning,
isRestarting,
isExited, isExited,
}; };
} catch ({ status, message }) { } catch ({ status, message }) {
@ -339,7 +346,7 @@ export async function stopPreviewApplication(request: FastifyRequest<StopPreview
if (application?.destinationDockerId) { if (application?.destinationDockerId) {
const container = `${id}-${pullmergeRequestId}` const container = `${id}-${pullmergeRequestId}`
const { id: dockerId } = application.destinationDocker; const { id: dockerId } = application.destinationDocker;
const found = await checkContainer({ dockerId, container }); const { found } = await checkContainer({ dockerId, container });
if (found) { if (found) {
await removeContainer({ id: container, dockerId: application.destinationDocker.id }); await removeContainer({ id: container, dockerId: application.destinationDocker.id });
} }
@ -366,7 +373,10 @@ export async function restartApplication(request: FastifyRequest<OnlyId>, reply:
if (secrets.length > 0) { if (secrets.length > 0) {
secrets.forEach((secret) => { secrets.forEach((secret) => {
if (pullmergeRequestId) { if (pullmergeRequestId) {
if (secret.isPRMRSecret) { 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}`); envs.push(`${secret.name}=${secret.value}`);
} }
} else { } else {
@ -463,7 +473,7 @@ export async function stopApplication(request: FastifyRequest<OnlyId>, reply: Fa
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application?.destinationDockerId) { if (application?.destinationDockerId) {
const { id: dockerId } = application.destinationDocker; const { id: dockerId } = application.destinationDocker;
const found = await checkContainer({ dockerId, container: id }); const { found } = await checkContainer({ dockerId, container: id });
if (found) { if (found) {
await removeContainer({ id, dockerId: application.destinationDocker.id }); await removeContainer({ id, dockerId: application.destinationDocker.id });
} }

View File

@ -229,7 +229,7 @@ export async function getDestinationStatus(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params const { id } = request.params
const destination = await prisma.destinationDocker.findUnique({ where: { id } }) const destination = await prisma.destinationDocker.findUnique({ where: { id } })
const isRunning = await checkContainer({ dockerId: destination.id, container: 'coolify-proxy', remove: true }) const { found: isRunning } = await checkContainer({ dockerId: destination.id, container: 'coolify-proxy', remove: true })
return { return {
isRunning isRunning
} }

View File

@ -26,7 +26,7 @@ export async function cleanupManually(request: FastifyRequest) {
} }
export async function checkUpdate(request: FastifyRequest) { export async function checkUpdate(request: FastifyRequest) {
try { try {
const isStaging = request.hostname === 'staging.coolify.io' const isStaging = request.hostname === 'staging.coolify.io' || request.hostname === 'arm.coolify.io'
const currentVersion = version; const currentVersion = version;
const { data: versions } = await axios.get( const { data: versions } = await axios.get(
`https://get.coollabs.io/versions.json?appId=${process.env['COOLIFY_APP_ID']}&version=${currentVersion}` `https://get.coollabs.io/versions.json?appId=${process.env['COOLIFY_APP_ID']}&version=${currentVersion}`

View File

@ -43,13 +43,17 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
let isRunning = false; let isRunning = false;
let isExited = false let isExited = false
let isRestarting = false;
const service = await getServiceFromDB({ id, teamId }); const service = await getServiceFromDB({ id, teamId });
const { destinationDockerId, settings } = service; const { destinationDockerId, settings } = service;
if (destinationDockerId) { if (destinationDockerId) {
isRunning = await checkContainer({ dockerId: service.destinationDocker.id, container: id }); const status = await checkContainer({ dockerId: service.destinationDocker.id, container: id });
isExited = await isContainerExited(service.destinationDocker.id, id); if (status?.found) {
isRunning = status.status.isRunning;
isExited = status.status.isExited;
isRestarting = status.status.isRestarting
}
} }
return { return {
isRunning, isRunning,
@ -554,7 +558,7 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp
}); });
try { try {
const isRunning = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` }); const { found: isRunning } = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` });
if (isRunning) { if (isRunning) {
await executeDockerCmd({ await executeDockerCmd({
dockerId: destinationDocker.id, dockerId: destinationDocker.id,

View File

@ -154,7 +154,7 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
if (application.settings.previews) { if (application.settings.previews) {
if (application.destinationDockerId) { if (application.destinationDockerId) {
const isRunning = await checkContainer( const { found: isRunning } = await checkContainer(
{ {
dockerId: application.destinationDocker.id, dockerId: application.destinationDocker.id,
container: application.id container: application.id

View File

@ -107,7 +107,7 @@ export async function gitLabEvents(request: FastifyRequest<GitLabEvents>) {
const buildId = cuid(); const buildId = cuid();
if (application.settings.previews) { if (application.settings.previews) {
if (application.destinationDockerId) { if (application.destinationDockerId) {
const isRunning = await checkContainer( const { found: isRunning } = await checkContainer(
{ {
dockerId: application.destinationDocker.id, dockerId: application.destinationDocker.id,
container: application.id container: application.id

View File

@ -73,6 +73,7 @@ export const status: Writable<any> = writable({
application: { application: {
isRunning: false, isRunning: false,
isExited: false, isExited: false,
isRestarting: false,
loading: false, loading: false,
initialLoading: true initialLoading: true
}, },

View File

@ -107,7 +107,7 @@
$status.application.initialLoading = true; $status.application.initialLoading = true;
try { try {
await del(`/applications/${id}`, { id, force }); await del(`/applications/${id}`, { id, force });
return await goto(`/`, { replaceState: true }); return await window.location.assign(`/`);
} catch (error) { } catch (error) {
if (error.message.startsWith(`Command failed: SSH_AUTH_SOCK=/tmp/coolify-ssh-agent.pid`)) { if (error.message.startsWith(`Command failed: SSH_AUTH_SOCK=/tmp/coolify-ssh-agent.pid`)) {
forceDelete = true; forceDelete = true;
@ -154,6 +154,7 @@
const data = await get(`/applications/${id}/status`); const data = await get(`/applications/${id}/status`);
$status.application.isRunning = data.isRunning; $status.application.isRunning = data.isRunning;
$status.application.isExited = data.isExited; $status.application.isExited = data.isExited;
$status.application.isRestarting = data.isRestarting;
$status.application.loading = false; $status.application.loading = false;
$status.application.initialLoading = false; $status.application.initialLoading = false;
} }
@ -162,6 +163,7 @@
$status.application.initialLoading = true; $status.application.initialLoading = true;
$status.application.isRunning = false; $status.application.isRunning = false;
$status.application.isExited = false; $status.application.isExited = false;
$status.application.isRestarting = false;
$status.application.loading = false; $status.application.loading = false;
$location = null; $location = null;
$isDeploymentEnabled = false; $isDeploymentEnabled = false;
@ -171,6 +173,7 @@
setLocation(application, settings); setLocation(application, settings);
$status.application.isRunning = false; $status.application.isRunning = false;
$status.application.isExited = false; $status.application.isExited = false;
$status.application.isRestarting = false;
$status.application.loading = false; $status.application.loading = false;
if ( if (
application.gitSourceId && application.gitSourceId &&
@ -215,7 +218,7 @@
<div class="border border-coolgray-500 h-8" /> <div class="border border-coolgray-500 h-8" />
{/if} {/if}
{#if $status.application.isExited} {#if $status.application.isExited || $status.application.isRestarting}
<a <a
id="applicationerror" id="applicationerror"
href={$isDeploymentEnabled ? `/applications/${id}/logs` : null} href={$isDeploymentEnabled ? `/applications/${id}/logs` : null}
@ -240,7 +243,30 @@
<line x1="12" y1="16" x2="12.01" y2="16" /> <line x1="12" y1="16" x2="12.01" y2="16" />
</svg> </svg>
</a> </a>
<Tooltip triggeredBy="#applicationerror">Application exited with an error!</Tooltip> <Tooltip triggeredBy="#applicationerror">Application exited or restarting!</Tooltip>
<button
id="stop"
on:click={stopApplication}
type="submit"
disabled={!$isDeploymentEnabled}
class="icons bg-transparent text-sm flex items-center space-x-2 text-error"
>
<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" />
<rect x="6" y="5" width="4" height="14" rx="1" />
<rect x="14" y="5" width="4" height="14" rx="1" />
</svg>
</button>
<Tooltip triggeredBy="#stop">Stop</Tooltip>
{/if} {/if}
{#if $status.application.initialLoading} {#if $status.application.initialLoading}
<button <button

View File

@ -220,7 +220,6 @@
loading = true; loading = true;
try { try {
nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, ''); nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
console.log({debug: nonWWWDomain})
if (application.deploymentType) if (application.deploymentType)
application.deploymentType = application.deploymentType.toLowerCase(); application.deploymentType = application.deploymentType.toLowerCase();
!isBot && !isBot &&

View File

@ -103,7 +103,7 @@
<button <button
id="follow" id="follow"
on:click={followBuild} on:click={followBuild}
class="bg-transparent btn btn-sm btn-linkhover:text-green-500 hover:bg-coolgray-500" class="bg-transparent btn btn-sm btn-link hover:text-green-500 hover:bg-coolgray-500"
class:text-green-500={followingBuild} class:text-green-500={followingBuild}
> >
<svg <svg

View File

@ -6,7 +6,8 @@
import LoadingLogs from '$lib/components/LoadingLogs.svelte'; import LoadingLogs from '$lib/components/LoadingLogs.svelte';
import { onMount, onDestroy } from 'svelte'; import { onMount, onDestroy } from 'svelte';
import Tooltip from '$lib/components/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip.svelte';
import { status } from '$lib/store';
import { goto } from '$app/navigation';
let application: any = {}; let application: any = {};
let logsLoading = false; let logsLoading = false;
let loadLogsInterval: any = null; let loadLogsInterval: any = null;
@ -16,7 +17,13 @@
let followingLogs: any; let followingLogs: any;
let logsEl: any; let logsEl: any;
let position = 0; let position = 0;
if (
!$status.application.isExited &&
!$status.application.isRestarting &&
!$status.application.isRunning
) {
goto(`/applications/${$page.params.id}/`, { replaceState: true });
}
const { id } = $page.params; const { id } = $page.params;
onMount(async () => { onMount(async () => {
const response = await get(`/applications/${id}`); const response = await get(`/applications/${id}`);

View File

@ -76,7 +76,7 @@
$status.database.initialLoading = true; $status.database.initialLoading = true;
try { try {
await del(`/databases/${database.id}`, { id: database.id, force }); await del(`/databases/${database.id}`, { id: database.id, force });
return await goto('/', { replaceState: true }); return await window.location.assign('/');
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} finally { } finally {

View File

@ -112,7 +112,7 @@
<button <button
id="follow" id="follow"
on:click={followBuild} on:click={followBuild}
class="bg-transparent btn btn-sm" class="bg-transparent btn btn-sm btn-link"
class:text-green-500={followingLogs} class:text-green-500={followingLogs}
> >
<svg <svg

View File

@ -188,6 +188,7 @@
return ( return (
(service.name && service.name.toLowerCase().includes($search.toLowerCase())) || (service.name && service.name.toLowerCase().includes($search.toLowerCase())) ||
(service.type && service.type.toLowerCase().includes($search.toLowerCase())) || (service.type && service.type.toLowerCase().includes($search.toLowerCase())) ||
(service.fqdn && service.fqdn.toLowerCase().includes($search.toLowerCase())) ||
(service.version && service.version.toLowerCase().includes($search.toLowerCase())) || (service.version && service.version.toLowerCase().includes($search.toLowerCase())) ||
(service.destinationDockerId && (service.destinationDockerId &&
service.destinationDocker.name.toLowerCase().includes($search.toLowerCase())) service.destinationDocker.name.toLowerCase().includes($search.toLowerCase()))

View File

@ -85,7 +85,7 @@
if (service.type && $status.service.isRunning) if (service.type && $status.service.isRunning)
await post(`/services/${service.id}/${service.type}/stop`, {}); await post(`/services/${service.id}/${service.type}/stop`, {});
await del(`/services/${service.id}`, { id: service.id }); await del(`/services/${service.id}`, { id: service.id });
return await goto(`/`, { replaceState: true }); return await window.location.assign(`/`);
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} finally { } finally {

View File

@ -128,7 +128,7 @@
<button <button
id="follow" id="follow"
on:click={followBuild} on:click={followBuild}
class="bg-transparent btn btn-sm" class="bg-transparent btn btn-sm btn-link"
class:text-green-500={followingLogs} class:text-green-500={followingLogs}
> >
<svg <svg

View File

@ -200,21 +200,6 @@
<input name="name" id="name" required bind:value={source.name} /> <input name="name" id="name" required bind:value={source.name} />
</div> </div>
</div> </div>
{#if source.gitlabApp.groupName}
<div class="grid grid-cols-2 items-center">
<label for="groupName" class="text-base font-bold text-stone-100"
>{$t('source.group_name')}</label
>
<input
name="groupName"
id="groupName"
disabled={source.gitlabAppId}
readonly={source.gitlabAppId}
required
bind:value={source.gitlabApp.groupName}
/>
</div>
{/if}
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<label for="htmlUrl" class="text-base font-bold text-stone-100">HTML URL</label> <label for="htmlUrl" class="text-base font-bold text-stone-100">HTML URL</label>
<input <input

View File

@ -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": "3.10.0", "version": "3.10.1",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": "github:coollabsio/coolify", "repository": "github:coollabsio/coolify",
"scripts": { "scripts": {