diff --git a/routes/applications.update.ts b/routes/applications.update.ts index 1e159dd..d4e08b1 100644 --- a/routes/applications.update.ts +++ b/routes/applications.update.ts @@ -21,12 +21,23 @@ const UpdateForm = (application: Application, latestVersions: string[]) => { `; }; -const PendingUpdates = (pendingUpdates: UpdateDefinition[]) => { +const FreeUpdateForm = (application: Application) => { + return html`
+ + + +
`; +}; + +const PendingUpdates = (pendingUpdates: UpdateDefinition[], logs: string) => { if (pendingUpdates.length === 0) { return ""; } - return html`
+ return html`

Pending updates

-
`; + +
${logs}
+ + `; }; const Page = ( application: Application, latestVersions: string[], - pendingUpdates: UpdateDefinition[] + pendingUpdates: UpdateDefinition[], + logs: string ) => { return html`

Updating ${application.name}

- ${PendingUpdates(pendingUpdates)} + ${PendingUpdates(pendingUpdates, logs)} -
-
Last deployment
-
${application.lastDeployedAt.toLocaleString("fr-FR")}
+
+
+
Last deployment
+
${application.lastDeployedAt.toLocaleString("fr-FR")}
-
Current version
-
- ${application.dockerImage - ? `Docker hub +
Current version
+
+ ${application.dockerImage + ? `Docker hub ${application.dockerImage.name}:${application.dockerImage.tag} ` - : `${application.imageName}… check yourself!`} -
- -
Latest versions
-
- ${latestVersions.length === 0 - ? "No version found" - : UpdateForm(application, latestVersions)} -
-
+ : `${application.imageName}… check yourself!`} + + +
Latest versions
+
+ ${latestVersions.length === 0 + ? "No version found" + : UpdateForm(application, latestVersions)} +
+
Manual update
+
${FreeUpdateForm(application)}
+
+
`; }; @@ -108,9 +132,13 @@ export default async ( ); const pendingUpdates = queries.pendingApplicationUpdates(appToUpdate.name); + let logs = ""; + if (pendingUpdates.length > 0) { + logs = await caprover.getLogs(appToUpdate.name); + } return new Response( - Layout(Page(appToUpdate, latestVersions, pendingUpdates)), + Layout(Page(appToUpdate, latestVersions, pendingUpdates, logs)), { headers: { "Content-Type": "text/html" }, } diff --git a/services/Caprover.test.ts b/services/Caprover.test.ts index 32c68e3..f4e9bbd 100644 --- a/services/Caprover.test.ts +++ b/services/Caprover.test.ts @@ -134,5 +134,19 @@ describe("Caprover", () => { expect(events).toBeArrayOfSize(0); }); }); + + describe("getLogs", () => { + it("should return the logs of the application when it exists", async () => { + const logs = await caprover.getLogs("mysql"); + expect(logs).toBe("mysql logs"); + }); + + it("should throw an error when the application does not exist", async () => { + await expect( + caprover.getLogs("unknown") + // @ts-ignore toThrowError exists¯\_(ツ)_/¯ + ).rejects.toThrowError(/Failed to fetch logs for application unknown/); + }); + }); }); }); diff --git a/services/Caprover.ts b/services/Caprover.ts index eef782f..e0ba49f 100644 --- a/services/Caprover.ts +++ b/services/Caprover.ts @@ -79,21 +79,23 @@ class Caprover { async updateApplication(appName: string, version: string): Promise { console.debug("Caprover: Updating application", appName, "to", version); - const response = await this.fetch(`/user/apps/appData/${appName}`, { - method: "POST", - body: JSON.stringify({ - captainDefinitionContent: JSON.stringify({ - schemaVersion: 2, - imageName: version, + try { + const response = await this.fetch(`/user/apps/appData/${appName}`, { + method: "POST", + body: JSON.stringify({ + captainDefinitionContent: JSON.stringify({ + schemaVersion: 2, + imageName: version, + }), + gitHash: "", }), - gitHash: "", - }), - }); - - console.debug("update application response", response); - if (response.status !== 100) { + }); + if (response.status !== 100) { + throw new Error(response.description); + } + } catch (error) { throw new Error( - `Failed to update application ${appName} to ${version}: ${response.description}.` + `Failed to update application ${appName} to ${version}: ${error ?? ""}.` ); } @@ -105,6 +107,18 @@ class Caprover { ); } + async getLogs(appName: string): Promise { + console.debug("Caprover: Fetching logs for", appName); + const response = await this.fetch(`/user/apps/appData/${appName}/logs`); + if (response.status !== 100) { + throw new Error( + `Failed to fetch logs for application ${appName}: ${response.description}` + ); + } + + return response.data.logs; + } + private async authenticate() { if (this.authToken) { return; diff --git a/services/mocks/caproverServer.ts b/services/mocks/caproverServer.ts index c59a414..d986487 100644 --- a/services/mocks/caproverServer.ts +++ b/services/mocks/caproverServer.ts @@ -1,9 +1,4 @@ -import { - http, - HttpResponse, - HttpResponseResolver, - PathParams -} from "msw"; +import { http, HttpResponse, HttpResponseResolver, PathParams } from "msw"; import { setupServer } from "msw/node"; import appsFixtures from "./apps.fixtures.json"; @@ -97,6 +92,27 @@ const handlers = [ data: {}, }); }), + http.get( + `${BASE_URI}/user/apps/appData/:name/logs`, + withAuth(({ params }) => { + const app = appsFixtures.find((app) => app.appName === params.name); + if (!app) { + return HttpResponse.json({ + status: 1000, + description: `App (${params.name}) could not be found. Make sure that you have created the app.`, + data: {}, + }); + } + + return HttpResponse.json({ + status: 100, + description: "App runtime logs are retrieved", + data: { + logs: `${params.name} logs`, + }, + }); + }) + ), ]; const server = setupServer(...handlers);