From 4565b3d7a2af0681f7e8a419e12a0910c529b99c Mon Sep 17 00:00:00 2001 From: UndefinedPony Date: Fri, 20 Dec 2024 18:26:54 +0100 Subject: [PATCH] refactor: add latestVersion information to update data --- .../settings/web-server/update-server.tsx | 8 ++--- apps/dokploy/components/layouts/navbar.tsx | 6 ++-- apps/dokploy/server/api/routers/settings.ts | 8 ++--- packages/server/src/services/settings.ts | 35 +++++++++++++++---- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx index 14a66749..1b8798e4 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx @@ -20,16 +20,16 @@ export const UpdateServer = () => { const [isUpdateAvailable, setIsUpdateAvailable] = useState( null, ); - const { mutateAsync: checkForUpdate, isLoading } = - api.settings.checkForUpdate.useMutation(); + const { mutateAsync: getUpdateData, isLoading } = + api.settings.getUpdateData.useMutation(); const [isOpen, setIsOpen] = useState(false); const handleCheckUpdates = async () => { try { - const updateAvailable = await checkForUpdate(); + const { updateAvailable, latestVersion } = await getUpdateData(); setIsUpdateAvailable(updateAvailable); if (updateAvailable) { - toast.success("Update is available!"); + toast.success(`${latestVersion} update is available!`); } else { toast.info("No updates available"); } diff --git a/apps/dokploy/components/layouts/navbar.tsx b/apps/dokploy/components/layouts/navbar.tsx index b0836939..a5a8b74c 100644 --- a/apps/dokploy/components/layouts/navbar.tsx +++ b/apps/dokploy/components/layouts/navbar.tsx @@ -34,8 +34,8 @@ export const Navbar = () => { }, ); const { mutateAsync } = api.auth.logout.useMutation(); - const { mutateAsync: checkForUpdate } = - api.settings.checkForUpdate.useMutation(); + const { mutateAsync: getUpdateData } = + api.settings.getUpdateData.useMutation(); const checkUpdatesIntervalRef = useRef(null); @@ -58,7 +58,7 @@ export const Navbar = () => { return; } - const updateAvailable = await checkForUpdate(); + const { updateAvailable } = await getUpdateData(); if (updateAvailable) { // Stop interval when update is available diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 001da65e..2861511e 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -45,7 +45,7 @@ import { stopService, stopServiceRemote, updateAdmin, - checkIsUpdateAvailable, + getUpdateData, updateLetsEncryptEmail, updateServerById, updateServerTraefik, @@ -343,12 +343,12 @@ export const settingsRouter = createTRPCRouter({ writeConfig("middlewares", input.traefikConfig); return true; }), - checkForUpdate: adminProcedure.mutation(async () => { + getUpdateData: adminProcedure.mutation(async () => { if (IS_CLOUD) { - return true; + return { latestVersion: null, updateAvailable: false }; } - return await checkIsUpdateAvailable(); + return await getUpdateData(); }), updateServer: adminProcedure.mutation(async () => { if (IS_CLOUD) { diff --git a/packages/server/src/services/settings.ts b/packages/server/src/services/settings.ts index fb8e6a65..3000f832 100644 --- a/packages/server/src/services/settings.ts +++ b/packages/server/src/services/settings.ts @@ -1,7 +1,6 @@ import { readdirSync } from "node:fs"; import { join } from "node:path"; import { docker } from "@dokploy/server/constants"; -import { getServiceContainer } from "@dokploy/server/utils/docker/utils"; import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync"; import { spawnAsync } from "../utils/process/spawnAsync"; // import packageInfo from "../../../package.json"; @@ -11,8 +10,11 @@ export const getDokployImageTag = () => { return process.env.RELEASE_TAG || "latest"; }; -/** Checks if server update is available by comparing current image's digest against digest for provided image tag via Docker hub API */ -export const checkIsUpdateAvailable = async () => { +/** Returns latest version number and information whether server update is available by comparing current image's digest against digest for provided image tag via Docker hub API. */ +export const getUpdateData = async (): Promise<{ + latestVersion: string | null; + updateAvailable: boolean; +}> => { const commandResult = await spawnAsync("docker", [ "inspect", "--format={{index .RepoDigests 0}}", @@ -21,16 +23,35 @@ export const checkIsUpdateAvailable = async () => { const currentDigest = commandResult.toString().trim().split("@")[1]; - const url = `https://hub.docker.com/v2/repositories/dokploy/dokploy/tags/${getDokployImageTag()}`; + const url = "https://hub.docker.com/v2/repositories/dokploy/dokploy/tags"; const response = await fetch(url, { method: "GET", headers: { "Content-Type": "application/json" }, }); - const data = (await response.json()) as { digest: string }; - const { digest } = data; + const data = (await response.json()) as { + results: [{ digest: string; name: string }]; + }; + const { results } = data; + const latestTagDigest = results.find((t) => t.name === "latest")?.digest; - return digest !== currentDigest; + if (!latestTagDigest) { + return { latestVersion: null, updateAvailable: false }; + } + + const versionedTag = results.find( + (t) => t.digest === latestTagDigest && t.name.startsWith("v"), + ); + + if (!versionedTag) { + return { latestVersion: null, updateAvailable: false }; + } + + const { name: latestVersion, digest } = versionedTag; + + const updateAvailable = digest !== currentDigest; + + return { latestVersion, updateAvailable }; }; export const getDokployImage = () => {