From 34f20e02aee1369e73e89984952b55a7f5cd0b62 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Thu, 3 Oct 2024 20:59:18 +0800 Subject: [PATCH] :sparkles: Post deploy script --- cli/src/cmd/deploy.ts | 16 ++++++++++++++-- cli/src/utils/config-local.ts | 9 ++++++++- pkg/navi/struct.go | 2 +- pkg/sideload/publish.go | 15 ++++++++++++++- pkg/sideload/regions.go | 2 +- pkg/warden/executor.go | 11 +++-------- 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/cli/src/cmd/deploy.ts b/cli/src/cmd/deploy.ts index 7994187..50ad9b4 100644 --- a/cli/src/cmd/deploy.ts +++ b/cli/src/cmd/deploy.ts @@ -6,7 +6,7 @@ import * as fs from "node:fs" import * as child_process from "node:child_process" import * as path from "node:path" import { createAuthHeader } from "../utils/auth.ts" -import { RsLocalConfig } from "../utils/config-local.ts" +import { RsLocalConfig, type RsLocalConfigDeploymentPostActionData } from "../utils/config-local.ts" import * as os from "node:os" export class DeployCommand extends Command { @@ -26,7 +26,7 @@ export class DeployCommand extends Command { site = Option.String({ required: false }) input = Option.String({ required: false }) - async deploy(serverLabel: string, region: string, site: string, input: string) { + async deploy(serverLabel: string, region: string, site: string, input: string, postDeploy: RsLocalConfigDeploymentPostActionData | null = null) { const cfg = await RsConfig.getInstance() const server = cfg.config.servers.find(item => item.label === serverLabel) if (server == null) { @@ -59,6 +59,18 @@ export class DeployCommand extends Command { try { const payload = new FormData() payload.set("attachments", await fs.openAsBlob(input), isDirectory ? "dist.zip" : path.basename(input)) + + if(postDeploy) { + if(postDeploy.command) { + payload.set("post-deploy-script", postDeploy.command) + } else if(postDeploy.scriptPath) { + payload.set("post-deploy-script", fs.readFileSync(postDeploy.scriptPath, "utf8")) + } else { + this.context.stdout.write(chalk.yellow(`Configured post deploy action but no script provided, skip performing post deploy action...\n`)) + } + payload.set("post-deploy-environment", postDeploy.environment?.join("\n") ?? "") + } + const res = await fetch(`${server.url}/webhooks/publish/${region}/${site}?mimetype=application/zip`, { method: "PUT", body: payload, diff --git a/cli/src/utils/config-local.ts b/cli/src/utils/config-local.ts index ed3c10b..e87a94b 100644 --- a/cli/src/utils/config-local.ts +++ b/cli/src/utils/config-local.ts @@ -15,6 +15,7 @@ interface RsLocalConfigDeploymentData { path: string region: string site: string + postDeploy?: RsLocalConfigDeploymentPostActionData autoBuild?: RsLocalConfigDeploymentAutoBuildData } @@ -23,6 +24,12 @@ interface RsLocalConfigDeploymentAutoBuildData { environment?: string[] } +interface RsLocalConfigDeploymentPostActionData { + command?: string + scriptPath?: string + environment?: string[] +} + class RsLocalConfig { private static instance: RsLocalConfig @@ -57,4 +64,4 @@ class RsLocalConfig { } } -export { RsLocalConfig, type RsLocalConfigData } \ No newline at end of file +export { RsLocalConfig, type RsLocalConfigData, type RsLocalConfigDeploymentPostActionData } \ No newline at end of file diff --git a/pkg/navi/struct.go b/pkg/navi/struct.go index 2dea59c..68fe0a8 100644 --- a/pkg/navi/struct.go +++ b/pkg/navi/struct.go @@ -60,7 +60,7 @@ func (v *Destination) GetType() DestinationType { func (v *Destination) GetRawUri() (string, url.Values) { uri := strings.SplitN(v.Uri, "://", 2)[1] data := strings.SplitN(uri, "?", 2) - data = append(data, " ") // Make the data array least have two elements + data = append(data, " ") // Make the data array at least have two elements qs, _ := url.ParseQuery(data[1]) return data[0], qs diff --git a/pkg/sideload/publish.go b/pkg/sideload/publish.go index 59bcae1..71a3ea0 100644 --- a/pkg/sideload/publish.go +++ b/pkg/sideload/publish.go @@ -2,9 +2,12 @@ package sideload import ( "context" + "fmt" "git.solsynth.dev/goatworks/roadsign/pkg/warden" "os" + "os/exec" "path/filepath" + "strings" "git.solsynth.dev/goatworks/roadsign/pkg/navi" "github.com/gofiber/fiber/v2" @@ -50,7 +53,7 @@ func doPublish(c *fiber.Ctx) error { return fiber.ErrNotFound } - if c.Query("overwrite", "yes") == "yes" { + if c.QueryBool("overwrite", true) { files, _ := filepath.Glob(filepath.Join(workdir, "*")) for _, file := range files { _ = os.Remove(file) @@ -74,6 +77,7 @@ func doPublish(c *fiber.Ctx) error { return err } } + _ = os.Remove(dst) default: dst := filepath.Join(workdir, file.Filename) if err := c.SaveFile(file, dst); err != nil { @@ -83,6 +87,15 @@ func doPublish(c *fiber.Ctx) error { } } + if postScript := c.FormValue("post-deploy-script", ""); len(postScript) > 0 { + cmd := exec.Command("sh", "-c", postScript) + cmd.Dir = filepath.Join(workdir) + cmd.Env = append(cmd.Env, strings.Split(c.FormValue("post-deploy-environment", ""), "\n")...) + if err := cmd.Run(); err != nil { + return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("post deploy script runs failed: %v", err)) + } + } + if instance != nil { _ = instance.Wake() } diff --git a/pkg/sideload/regions.go b/pkg/sideload/regions.go index dba4f44..6bfc207 100644 --- a/pkg/sideload/regions.go +++ b/pkg/sideload/regions.go @@ -77,7 +77,7 @@ func doSync(c *fiber.Ctx) error { _ = instance.Stop() } for _, instance := range startQueue { - _ = instance.Start() + _ = instance.Wake() } return c.SendStatus(fiber.StatusOK) diff --git a/pkg/warden/executor.go b/pkg/warden/executor.go index ef5cf0f..cdd64f2 100644 --- a/pkg/warden/executor.go +++ b/pkg/warden/executor.go @@ -62,14 +62,8 @@ func (v *AppInstance) Wake() error { } if v.Cmd.ProcessState.Exited() { return v.Start() - } else if v.Cmd.ProcessState.Exited() { - return fmt.Errorf("process already dead") - } - if v.Cmd.ProcessState.Exited() { - return fmt.Errorf("cannot start process") - } else { - return nil } + return nil } func (v *AppInstance) Start() error { @@ -93,7 +87,7 @@ func (v *AppInstance) Start() error { } else if v.Cmd != nil && v.Cmd.ProcessState == nil { v.Status = AppStarted } else { - v.Status = lo.Ternary(v.Cmd == nil, AppExited, AppFailure) + v.Status = AppFailure v.Cmd = nil return } @@ -119,6 +113,7 @@ func (v *AppInstance) Stop() error { } } + v.Status = AppExited return nil }