mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-25 05:02:09 +00:00
feat: specific git commit deployment
feat: revert to specific image fix: no system wide docker registries
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
<a
|
||||
id="git"
|
||||
href="{application.gitSource.htmlUrl}/{application.repository}/tree/{application.branch}"
|
||||
target="_blank"
|
||||
target="_blank noreferrer"
|
||||
class="no-underline"
|
||||
>
|
||||
{#if application.gitSource?.type === 'gitlab'}
|
||||
@@ -165,7 +165,9 @@
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/logs`}
|
||||
>
|
||||
<a
|
||||
href={$status.application.overallStatus !== 'stopped' ? `/applications/${$page.params.id}/logs` : ''}
|
||||
href={$status.application.overallStatus !== 'stopped'
|
||||
? `/applications/${$page.params.id}/logs`
|
||||
: ''}
|
||||
class="no-underline w-full"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -216,12 +218,38 @@
|
||||
<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
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
class="rounded"
|
||||
class:text-stone-600={$status.application.overallStatus !== 'healthy'}
|
||||
class:bg-coollabs={$page.url.pathname === `/applications/${$page.params.id}/usage`}
|
||||
>
|
||||
<a href={$status.application.overallStatus === 'healthy' ? `/applications/${$page.params.id}/usage` : ''} class="no-underline w-full"
|
||||
<a
|
||||
href={$status.application.overallStatus === 'healthy'
|
||||
? `/applications/${$page.params.id}/usage`
|
||||
: ''}
|
||||
class="no-underline w-full"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6"
|
||||
|
||||
@@ -96,6 +96,18 @@
|
||||
|
||||
async function handleDeploySubmit(forceRebuild = false) {
|
||||
if (!$isDeploymentEnabled) return;
|
||||
if (application.gitCommitHash && !application.settings.isPublicRepository) {
|
||||
const sure = await confirm(
|
||||
`Are you sure you want to deploy a specific commit (${application.gitCommitHash})? This will disable the "Automatic Deployment" feature to prevent accidental overwrites of incoming commits.`
|
||||
);
|
||||
if (!sure) {
|
||||
return;
|
||||
} else {
|
||||
await post(`/applications/${id}/settings`, {
|
||||
autodeploy: false
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!statusInterval) {
|
||||
statusInterval = setInterval(async () => {
|
||||
await getStatus();
|
||||
|
||||
@@ -46,73 +46,48 @@
|
||||
|
||||
<div class="flex flex-col justify-center w-full">
|
||||
<div class="flex flex-col flex-wrap justify-center px-2 md:flex-row mx-auto gap-4">
|
||||
{#each registries.public as registry}
|
||||
<button
|
||||
on:click={() => handleSubmit(registry.id)}
|
||||
class="box-selection hover:bg-primary relative"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="absolute top-0 left-0 -m-4 h-12 w-12 text-sky-500"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
{#if registries.length > 0}
|
||||
{#each registries as registry}
|
||||
<button
|
||||
on:click={() => handleSubmit(registry.id)}
|
||||
class="box-selection hover:bg-primary relative"
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1.002 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z"
|
||||
/>
|
||||
<path d="M5 10h3v3h-3z" />
|
||||
<path d="M8 10h3v3h-3z" />
|
||||
<path d="M11 10h3v3h-3z" />
|
||||
<path d="M8 7h3v3h-3z" />
|
||||
<path d="M11 7h3v3h-3z" />
|
||||
<path d="M11 4h3v3h-3z" />
|
||||
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
|
||||
<line x1="10" y1="16" x2="10" y2="16.01" />
|
||||
</svg>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="absolute top-0 left-0 -m-4 h-12 w-12 text-sky-500"
|
||||
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="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1.002 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z"
|
||||
/>
|
||||
<path d="M5 10h3v3h-3z" />
|
||||
<path d="M8 10h3v3h-3z" />
|
||||
<path d="M11 10h3v3h-3z" />
|
||||
<path d="M8 7h3v3h-3z" />
|
||||
<path d="M11 7h3v3h-3z" />
|
||||
<path d="M11 4h3v3h-3z" />
|
||||
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
|
||||
<line x1="10" y1="16" x2="10" y2="16.01" />
|
||||
</svg>
|
||||
|
||||
<div class="font-bold text-xl text-center truncate">{registry.name}</div>
|
||||
<div class="text-center truncate">{registry.url}</div>
|
||||
<div>public</div>
|
||||
</button>
|
||||
{/each}
|
||||
{#each registries.private as registry}
|
||||
<button
|
||||
on:click={() => handleSubmit(registry.id)}
|
||||
class="box-selection hover:bg-primary relative"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="absolute top-0 left-0 -m-4 h-12 w-12 text-sky-500"
|
||||
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="M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1.002 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z"
|
||||
/>
|
||||
<path d="M5 10h3v3h-3z" />
|
||||
<path d="M8 10h3v3h-3z" />
|
||||
<path d="M11 10h3v3h-3z" />
|
||||
<path d="M8 7h3v3h-3z" />
|
||||
<path d="M11 7h3v3h-3z" />
|
||||
<path d="M11 4h3v3h-3z" />
|
||||
<path d="M4.571 18c1.5 0 2.047 -.074 2.958 -.78" />
|
||||
<line x1="10" y1="16" x2="10" y2="16.01" />
|
||||
</svg>
|
||||
|
||||
<div class="font-bold text-xl text-center truncate">{registry.name}</div>
|
||||
<div class="text-center truncate">{registry.url}</div>
|
||||
<div>private</div>
|
||||
</button>
|
||||
{/each}
|
||||
<div class="font-bold text-xl text-center truncate">{registry.name}</div>
|
||||
<div class="text-center truncate">{registry.url}</div>
|
||||
</button>
|
||||
{/each}
|
||||
{:else}
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<div class="text-center text-xl font-bold pb-4">No registries found.</div>
|
||||
<div class="flex gap-2">
|
||||
<a class="btn btn-sm" href={from || `/applications/${id}`}>Go back</a>
|
||||
<a class="btn btn-sm btn-primary" href={`/settings/docker`}>Add a Docker Registry</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -515,40 +515,37 @@
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{#if application.settings.isPublicRepository}
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">Git commit</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
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"
|
||||
rel="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 class="grid grid-cols-2 items-center">
|
||||
<label for="repository">Git commit</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
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"
|
||||
>
|
||||
</div>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M4.5 19.5l15-15m0 0H8.25m11.25 0v11.25"
|
||||
/>
|
||||
</svg></a
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<label for="repository">{$t('application.git_repository')}</label>
|
||||
{#if isDisabled || application.settings.isPublicRepository}
|
||||
@@ -575,7 +572,7 @@
|
||||
<input
|
||||
class="capitalize w-full"
|
||||
disabled={isDisabled}
|
||||
value={application.dockerRegistry.name}
|
||||
value={application.dockerRegistry?.name || 'DockerHub (unauthenticated)'}
|
||||
/>
|
||||
{:else}
|
||||
<a
|
||||
@@ -583,7 +580,7 @@
|
||||
class="no-underline"
|
||||
>
|
||||
<input
|
||||
value={application.dockerRegistry.name}
|
||||
value={application.dockerRegistry?.name || 'DockerHub (unauthenticated)'}
|
||||
id="registry"
|
||||
class="cursor-pointer hover:bg-coolgray-500 capitalize w-full"
|
||||
/></a
|
||||
|
||||
119
apps/ui/src/routes/applications/[id]/revert.svelte
Normal file
119
apps/ui/src/routes/applications/[id]/revert.svelte
Normal file
@@ -0,0 +1,119 @@
|
||||
<script context="module" lang="ts">
|
||||
import type { Load } from '@sveltejs/kit';
|
||||
export const load: Load = async ({ fetch, params, stuff, url }) => {
|
||||
try {
|
||||
const response = await get(`/applications/${params.id}/images`);
|
||||
return {
|
||||
props: {
|
||||
application: stuff.application,
|
||||
...response
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 500,
|
||||
error: new Error(`Could not load ${url}`)
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let application: any;
|
||||
export let imagesAvailables: any;
|
||||
export let runningImage: any;
|
||||
import { page } from '$app/stores';
|
||||
import { get, post } from '$lib/api';
|
||||
import { status, addToast } from '$lib/store';
|
||||
import { errorNotification } from '$lib/common';
|
||||
|
||||
const { id } = $page.params;
|
||||
|
||||
async function revertApplication(image: any) {
|
||||
const sure = confirm(`Are you sure you want to revert to ${image.tag} ?`);
|
||||
if (sure) {
|
||||
try {
|
||||
$status.application.initialLoading = true;
|
||||
$status.application.loading = true;
|
||||
const imageId = `${image.repository}:${image.tag}`;
|
||||
await post(`/applications/${id}/restart`, { imageId });
|
||||
addToast({
|
||||
type: 'success',
|
||||
message: 'Revert successful.'
|
||||
});
|
||||
} catch (error) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
$status.application.initialLoading = false;
|
||||
$status.application.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="w-full">
|
||||
<div class="mx-auto w-full">
|
||||
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
|
||||
<div class="title font-bold pb-3">Revert Application</div>
|
||||
</div>
|
||||
<div>
|
||||
You can revert application to a previously built image. Currently only locally stored images
|
||||
supported.
|
||||
</div>
|
||||
<br />
|
||||
<div class="pb-4">
|
||||
If you do not want the next commit to overwrite the reverted application, temporary disable <span
|
||||
class="text-yellow-400 font-bold">Automatic Deployment</span
|
||||
>
|
||||
feature <a href={`/applications/${id}/features`}>here</a>.
|
||||
</div>
|
||||
<div
|
||||
class="px-4 lg:pb-10 pb-6 flex flex-wrap items-center justify-center lg:justify-start gap-8"
|
||||
>
|
||||
{#each imagesAvailables as image}
|
||||
<div class="gap-2 py-4 m-2">
|
||||
<div class="flex flex-col justify-center items-center">
|
||||
<div class="text-xl font-bold">
|
||||
{image.tag}
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
class="flex no-underline text-xs my-4"
|
||||
href="{application.gitSource.htmlUrl}/{application.repository}/commit/{image.tag}"
|
||||
target="_blank noreferrer"
|
||||
>
|
||||
<button class="btn btn-sm">
|
||||
Check Commit
|
||||
<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>
|
||||
</button></a
|
||||
>
|
||||
{#if image.repository + ':' + image.tag !== runningImage}
|
||||
<button
|
||||
class="btn btn-sm btn-primary w-full"
|
||||
on:click={() => revertApplication(image)}>Revert Now</button
|
||||
>
|
||||
{:else}
|
||||
<button class="btn btn-sm btn-primary w-full btn-disabled bg-transparent underline"
|
||||
>Currently Used</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user