Merge pull request #67 from mc0814/master

project script yaml mode
This commit is contained in:
zhenorzz 2023-12-21 10:46:08 +08:00 committed by GitHub
commit 018c54daf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 921 additions and 312 deletions

View File

@ -20,11 +20,14 @@ import (
"github.com/zhenorzz/goploy/cmd/server/task" "github.com/zhenorzz/goploy/cmd/server/task"
"github.com/zhenorzz/goploy/config" "github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model" "github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pipeline/docker"
"github.com/zhenorzz/goploy/internal/pkg" "github.com/zhenorzz/goploy/internal/pkg"
"github.com/zhenorzz/goploy/internal/pkg/cmd" "github.com/zhenorzz/goploy/internal/pkg/cmd"
"github.com/zhenorzz/goploy/internal/repo" "github.com/zhenorzz/goploy/internal/repo"
"github.com/zhenorzz/goploy/internal/server" "github.com/zhenorzz/goploy/internal/server"
"github.com/zhenorzz/goploy/internal/server/response" "github.com/zhenorzz/goploy/internal/server/response"
"github.com/zhenorzz/goploy/internal/transmitter"
"gopkg.in/yaml.v3"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -628,23 +631,51 @@ func (Deploy) Rebuild(gp *server.Goploy) server.Response {
ch := make(chan bool, len(projectServers)) ch := make(chan bool, len(projectServers))
for _, projectServer := range projectServers { for _, projectServer := range projectServers {
go func(projectServer model.ProjectServer) { go func(projectServer model.ProjectServer) {
var dockerScript docker.Script
destDir := path.Join(project.SymlinkPath, project.LastPublishToken) destDir := path.Join(project.SymlinkPath, project.LastPublishToken)
cmdEntity := cmd.New(projectServer.Server.OS) cmdEntity := cmd.New(projectServer.Server.OS)
afterDeployCommands := []string{cmdEntity.Symlink(destDir, project.Path), cmdEntity.ChangeDirTime(destDir)} scriptName := fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, projectServer.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode))
if project.Script.AfterDeploy.Content != "" { if project.Script.AfterDeploy.Content != "" {
scriptName := fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, projectServer.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode))
scriptContent := project.ReplaceVars(project.Script.AfterDeploy.Content) scriptContent := project.ReplaceVars(project.Script.AfterDeploy.Content)
scriptContent = projectServer.ReplaceVars(scriptContent) scriptContent = projectServer.ReplaceVars(scriptContent)
err = os.WriteFile(path.Join(config.GetProjectPath(project.ID), scriptName), []byte(project.ReplaceVars(project.Script.AfterDeploy.Content)), 0755)
if err != nil { if project.Script.AfterDeploy.Mode == "yaml" {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " write file err: " + err.Error()) if err := yaml.Unmarshal([]byte(scriptContent), &dockerScript); err != nil {
ch <- false log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " unmarshal yaml script fail err: " + err.Error())
return ch <- false
return
}
for stepIndex, step := range dockerScript.Steps {
scriptName = fmt.Sprintf("goploy-after-deploy-p%d-s%d-y%d", project.ID, projectServer.ServerID, stepIndex)
// delete the script
step.Commands = append(step.Commands, fmt.Sprintf("rm -f %s", docker.GetDockerProjectScriptPath(project.ID, scriptName)))
scriptContent = strings.Join(step.Commands, "\n")
err = os.WriteFile(path.Join(config.GetProjectPath(project.ID), scriptName), []byte(scriptContent), 0755)
if err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " write file err: " + err.Error())
ch <- false
return
}
}
} else {
err = os.WriteFile(path.Join(config.GetProjectPath(project.ID), scriptName), []byte(scriptContent), 0755)
if err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " write file err: " + err.Error())
ch <- false
return
}
} }
afterDeployScriptPath := path.Join(project.Path, scriptName)
afterDeployCommands = append(afterDeployCommands, cmdEntity.Script(project.Script.AfterDeploy.Mode, afterDeployScriptPath))
afterDeployCommands = append(afterDeployCommands, cmdEntity.Remove(afterDeployScriptPath))
} }
transmitterEntity := transmitter.New(project, projectServer)
if transmitterOutput, err := transmitterEntity.Exec(); err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " transmit exec err: " + err.Error() + ", output: " + transmitterOutput)
ch <- false
return
}
client, err := projectServer.ToSSHConfig().Dial() client, err := projectServer.ToSSHConfig().Dial()
if err != nil { if err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " dial err: " + err.Error()) log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " dial err: " + err.Error())
@ -652,12 +683,14 @@ func (Deploy) Rebuild(gp *server.Goploy) server.Response {
return return
} }
defer client.Close() defer client.Close()
session, err := client.NewSession() session, err := client.NewSession()
if err != nil { if err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " new session err: " + err.Error()) log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " new session err: " + err.Error())
ch <- false ch <- false
return return
} }
defer session.Close()
// check if the path is existed or not // check if the path is existed or not
if output, err := session.CombinedOutput("cd " + destDir); err != nil { if output, err := session.CombinedOutput("cd " + destDir); err != nil {
@ -665,19 +698,55 @@ func (Deploy) Rebuild(gp *server.Goploy) server.Response {
ch <- false ch <- false
return return
} }
session, err = client.NewSession()
if err != nil { if project.Script.AfterDeploy.Mode == "yaml" && len(dockerScript.Steps) > 0 {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " new session err: " + err.Error()) dockerConfig := docker.Config{
ch <- false ProjectID: project.ID,
return ProjectPath: project.Path,
Server: projectServer.Server,
}
if err := dockerConfig.Setup(); err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " setup docker err: " + err.Error())
ch <- false
return
}
for stepIndex, step := range dockerScript.Steps {
step.ScriptName = fmt.Sprintf("goploy-after-deploy-p%d-s%d-y%d", project.ID, projectServer.ServerID, stepIndex)
dockerOutput, dockerErr := dockerConfig.Run(step)
scriptFullName := path.Join(config.GetProjectPath(project.ID), step.ScriptName)
_ = os.Remove(scriptFullName)
if dockerErr != "" {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " run docker script err: " + err.Error() + ", detail: " + string(dockerOutput))
ch <- false
return
}
}
} else {
afterDeployCommands := []string{cmdEntity.Symlink(destDir, project.Path), cmdEntity.ChangeDirTime(destDir)}
afterDeployScriptPath := path.Join(project.Path, scriptName)
afterDeployCommands = append(afterDeployCommands, cmdEntity.Script(project.Script.AfterDeploy.Mode, afterDeployScriptPath))
afterDeployCommands = append(afterDeployCommands, cmdEntity.Remove(afterDeployScriptPath))
session, err = client.NewSession()
defer session.Close()
if err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " new session err: " + err.Error())
ch <- false
return
}
// redirect to project path
if output, err := session.CombinedOutput(strings.Join(afterDeployCommands, "&&")); err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " symlink err: " + err.Error() + ", detail: " + string(output))
ch <- false
return
}
} }
// redirect to project path
if output, err := session.CombinedOutput(strings.Join(afterDeployCommands, "&&")); err != nil {
log.Error("projectID:" + strconv.FormatInt(project.ID, 10) + " symlink err: " + err.Error() + ", detail: " + string(output))
ch <- false
return
}
ch <- true ch <- true
}(projectServer) }(projectServer)
} }

View File

@ -597,7 +597,7 @@ func (Project) Edit(gp *server.Goploy) server.Response {
func (Project) SetAutoDeploy(gp *server.Goploy) server.Response { func (Project) SetAutoDeploy(gp *server.Goploy) server.Response {
type ReqData struct { type ReqData struct {
ID int64 `json:"id" validate:"required,gt=0"` ID int64 `json:"id" validate:"required,gt=0"`
AutoDeploy uint8 `json:"autoDeploy" validate:"required,gte=0"` AutoDeploy uint8 `json:"autoDeploy" validate:"oneof=0 1"`
} }
var reqData ReqData var reqData ReqData
if err := gp.Decode(&reqData); err != nil { if err := gp.Decode(&reqData); err != nil {

View File

@ -14,10 +14,12 @@ import (
"github.com/zhenorzz/goploy/cmd/server/ws" "github.com/zhenorzz/goploy/cmd/server/ws"
"github.com/zhenorzz/goploy/config" "github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model" "github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pipeline/docker"
"github.com/zhenorzz/goploy/internal/pkg" "github.com/zhenorzz/goploy/internal/pkg"
"github.com/zhenorzz/goploy/internal/pkg/cmd" "github.com/zhenorzz/goploy/internal/pkg/cmd"
"github.com/zhenorzz/goploy/internal/repo" "github.com/zhenorzz/goploy/internal/repo"
"github.com/zhenorzz/goploy/internal/transmitter" "github.com/zhenorzz/goploy/internal/transmitter"
"gopkg.in/yaml.v3"
"io" "io"
"net/http" "net/http"
"os" "os"
@ -261,10 +263,6 @@ func (gsync *Gsync) afterPullScriptStage() error {
} }
gsync.PublishTrace.Type = model.AfterPull gsync.PublishTrace.Type = model.AfterPull
ext, _ := json.Marshal(struct {
Script string `json:"script"`
}{gsync.Project.Script.AfterPull.Content})
gsync.PublishTrace.Ext = string(ext)
return gsync.runLocalScript() return gsync.runLocalScript()
} }
@ -279,13 +277,45 @@ func (gsync *Gsync) serverStage() error {
project := gsync.Project project := gsync.Project
publishTraceModel := gsync.PublishTrace publishTraceModel := gsync.PublishTrace
// write after deploy script for rsync // write after deploy script for rsync
var dockerScript docker.Script
scriptName := fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, projectServer.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode)) scriptName := fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, projectServer.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode))
scriptContent := ""
if project.Script.AfterDeploy.Content != "" { if project.Script.AfterDeploy.Content != "" {
scriptContent := project.ReplaceVars(project.Script.AfterDeploy.Content) scriptContent = project.ReplaceVars(project.Script.AfterDeploy.Content)
scriptContent = projectServer.ReplaceVars(scriptContent) scriptContent = projectServer.ReplaceVars(scriptContent)
scriptContent = strings.Replace(scriptContent, "${SERVER_TOTAL_NUMBER}", strconv.Itoa(len(gsync.ProjectServers)), -1) scriptContent = strings.Replace(scriptContent, "${SERVER_TOTAL_NUMBER}", strconv.Itoa(len(gsync.ProjectServers)), -1)
scriptContent = strings.Replace(scriptContent, "${SERVER_SERIAL_NUMBER}", strconv.Itoa(index), -1) scriptContent = strings.Replace(scriptContent, "${SERVER_SERIAL_NUMBER}", strconv.Itoa(index), -1)
_ = os.WriteFile(path.Join(config.GetProjectPath(project.ID), scriptName), []byte(scriptContent), 0755)
if project.Script.AfterDeploy.Mode == "yaml" {
if err := yaml.Unmarshal([]byte(scriptContent), &dockerScript); err != nil {
log.Error(fmt.Sprintf("projectID: %d unmarshal yaml script fail err: %s", project.ID, err))
publishTraceModel.Detail = fmt.Sprintf("err: %s", err)
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: err.Error(),
state: model.ProjectFail,
}
return
}
for stepIndex, step := range dockerScript.Steps {
scriptName = fmt.Sprintf("goploy-after-deploy-p%d-s%d-y%d", project.ID, projectServer.ServerID, stepIndex)
// delete the script
step.Commands = append(step.Commands, fmt.Sprintf("rm -f %s", docker.GetDockerProjectScriptPath(project.ID, scriptName)))
scriptContent = strings.Join(step.Commands, "\n")
project.Script.AfterDeploy.ScriptNames = append(project.Script.AfterDeploy.ScriptNames, scriptName)
_ = os.WriteFile(path.Join(config.GetProjectPath(project.ID), scriptName), []byte(scriptContent), 0755)
}
} else {
project.Script.AfterDeploy.ScriptNames = append(project.Script.AfterDeploy.ScriptNames, scriptName)
_ = os.WriteFile(path.Join(config.GetProjectPath(project.ID), scriptName), []byte(scriptContent), 0755)
}
} }
transmitterEntity := transmitter.New(project, projectServer) transmitterEntity := transmitter.New(project, projectServer)
@ -321,95 +351,162 @@ func (gsync *Gsync) serverStage() error {
} }
} }
var afterDeployCommands []string if project.Script.AfterDeploy.Mode == "yaml" && len(dockerScript.Steps) > 0 {
cmdEntity := cmd.New(projectServer.Server.OS) dockerConfig := docker.Config{
if len(project.SymlinkPath) != 0 { ProjectID: project.ID,
destDir := path.Join(project.SymlinkPath, project.LastPublishToken) ProjectPath: project.Path,
afterDeployCommands = append(afterDeployCommands, cmdEntity.Symlink(destDir, project.Path)) Server: projectServer.Server,
}
if project.Script.AfterDeploy.Content != "" {
afterDeployScriptPath := path.Join(project.Path, scriptName)
afterDeployCommands = append(afterDeployCommands, cmdEntity.Script(project.Script.AfterDeploy.Mode, afterDeployScriptPath))
afterDeployCommands = append(afterDeployCommands, cmdEntity.Remove(afterDeployScriptPath))
}
// no symlink and deploy script
if len(afterDeployCommands) == 0 {
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
state: model.ProjectSuccess,
} }
return
}
completeAfterDeployCmd := strings.Join(afterDeployCommands, "&&")
publishTraceModel.Type = model.AfterDeploy
ext, _ = json.Marshal(struct {
ServerID int64 `json:"serverId"`
ServerName string `json:"serverName"`
Script string `json:"script"`
}{projectServer.ServerID, projectServer.Server.Name, completeAfterDeployCmd})
publishTraceModel.Ext = string(ext)
client, err := projectServer.ToSSHConfig().Dial() if err := dockerConfig.Setup(); err != nil {
if err != nil { log.Error(fmt.Sprintf("projectID: %d err: %s", project.ID, err))
log.Error(err.Error()) publishTraceModel.Detail = err.Error()
publishTraceModel.Detail = err.Error() publishTraceModel.State = model.Fail
publishTraceModel.State = model.Fail if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: err.Error(),
state: model.ProjectFail,
}
return
}
for stepIndex, step := range dockerScript.Steps {
step.ScriptName = fmt.Sprintf("goploy-after-deploy-p%d-s%d-y%d", project.ID, projectServer.ServerID, stepIndex)
dockerOutput, dockerErr := dockerConfig.Run(step)
scriptContent = strings.Join(step.Commands, "\n")
publishTraceModel.Type = model.AfterDeploy
ext, _ = json.Marshal(struct {
ServerID int64 `json:"serverId"`
ServerName string `json:"serverName"`
Script string `json:"script"`
Step string `json:"step"`
}{projectServer.ServerID, projectServer.Server.Name, scriptContent, step.Name})
publishTraceModel.Ext = string(ext)
scriptFullName := path.Join(config.GetProjectPath(project.ID), step.ScriptName)
_ = os.Remove(scriptFullName)
if dockerErr != "" {
log.Error(fmt.Sprintf("projectID: %d run docker script err: %s", project.ID, dockerErr))
publishTraceModel.Detail = fmt.Sprintf("err: %s\noutput: %s", dockerErr, dockerOutput)
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: fmt.Sprintf("err: %s\noutput: %s", dockerErr, dockerOutput),
state: model.ProjectFail,
}
return
} else {
publishTraceModel.Detail = dockerOutput
publishTraceModel.State = model.Success
if _, err := publishTraceModel.AddRow(); err != nil {
log.Error("projectID: " + strconv.FormatInt(project.ID, 10) + " " + err.Error())
}
}
}
} else {
var afterDeployCommands []string
cmdEntity := cmd.New(projectServer.Server.OS)
if len(project.SymlinkPath) != 0 {
destDir := path.Join(project.SymlinkPath, project.LastPublishToken)
afterDeployCommands = append(afterDeployCommands, cmdEntity.Symlink(destDir, project.Path))
}
if project.Script.AfterDeploy.Content != "" {
afterDeployScriptPath := path.Join(project.Path, scriptName)
afterDeployCommands = append(afterDeployCommands, cmdEntity.Script(project.Script.AfterDeploy.Mode, afterDeployScriptPath))
afterDeployCommands = append(afterDeployCommands, cmdEntity.Remove(afterDeployScriptPath))
}
// no symlink and deploy script
if len(afterDeployCommands) == 0 {
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
state: model.ProjectSuccess,
}
return
}
completeAfterDeployCmd := strings.Join(afterDeployCommands, "&&")
publishTraceModel.Type = model.AfterDeploy
ext, _ = json.Marshal(struct {
ServerID int64 `json:"serverId"`
ServerName string `json:"serverName"`
Script string `json:"script"`
}{projectServer.ServerID, projectServer.Server.Name, scriptContent})
publishTraceModel.Ext = string(ext)
client, err := projectServer.ToSSHConfig().Dial()
if err != nil {
log.Error(err.Error())
publishTraceModel.Detail = err.Error()
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: err.Error(),
state: model.ProjectFail,
}
return
}
defer client.Close()
session, sessionErr := client.NewSession()
if sessionErr != nil {
log.Error(sessionErr.Error())
publishTraceModel.Detail = sessionErr.Error()
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: sessionErr.Error(),
state: model.ProjectFail,
}
return
}
defer session.Close()
log.Trace(fmt.Sprintf("projectID: %d ssh exec: %s", project.ID, completeAfterDeployCmd))
output, err := session.CombinedOutput(completeAfterDeployCmd)
if err != nil {
log.Error(fmt.Sprintf("projectID: %d ssh exec err: %s, output: %s", project.ID, err, output))
publishTraceModel.Detail = fmt.Sprintf("err: %s\noutput: %s", err, output)
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: fmt.Sprintf("%s\noutput: %s", err.Error(), output),
state: model.ProjectFail,
}
return
}
publishTraceModel.Detail = string(output)
publishTraceModel.State = model.Success
if _, err := publishTraceModel.AddRow(); err != nil { if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err) log.Error("projectID: " + strconv.FormatInt(project.ID, 10) + " " + err.Error())
} }
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: err.Error(),
state: model.ProjectFail,
}
return
}
defer client.Close()
session, sessionErr := client.NewSession()
if sessionErr != nil {
log.Error(sessionErr.Error())
publishTraceModel.Detail = sessionErr.Error()
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: sessionErr.Error(),
state: model.ProjectFail,
}
return
}
defer session.Close()
log.Trace(fmt.Sprintf("projectID: %d ssh exec: %s", project.ID, completeAfterDeployCmd))
output, err := session.CombinedOutput(completeAfterDeployCmd)
if err != nil {
log.Error(fmt.Sprintf("projectID: %d ssh exec err: %s, output: %s", project.ID, err, output))
publishTraceModel.Detail = fmt.Sprintf("err: %s\noutput: %s", err, output)
publishTraceModel.State = model.Fail
if _, err := publishTraceModel.AddRow(); err != nil {
log.Errorf(projectLogFormat, project.ID, err)
}
ch <- syncMessage{
serverName: projectServer.Server.Name,
projectID: project.ID,
detail: fmt.Sprintf("%s\noutput: %s", err.Error(), output),
state: model.ProjectFail,
}
return
} }
publishTraceModel.Detail = string(output)
publishTraceModel.State = model.Success
if _, err := publishTraceModel.AddRow(); err != nil {
log.Error("projectID: " + strconv.FormatInt(project.ID, 10) + " " + err.Error())
}
ch <- syncMessage{ ch <- syncMessage{
serverName: projectServer.Server.Name, serverName: projectServer.Server.Name,
projectID: project.ID, projectID: project.ID,
@ -446,11 +543,6 @@ func (gsync *Gsync) deployFinishScriptStage() error {
} }
gsync.PublishTrace.Type = model.DeployFinish gsync.PublishTrace.Type = model.DeployFinish
ext, _ := json.Marshal(struct {
Script string `json:"script"`
}{gsync.Project.Script.DeployFinish.Content})
gsync.PublishTrace.Ext = string(ext)
return gsync.runLocalScript() return gsync.runLocalScript()
} }
@ -467,7 +559,7 @@ func (gsync *Gsync) runLocalScript() error {
}) })
mode = project.Script.AfterPull.Mode mode = project.Script.AfterPull.Mode
content = project.Script.AfterPull.Content content = project.Script.AfterPull.Content
scriptName = "goploy-after-pull." + pkg.GetScriptExt(project.Script.AfterPull.Mode) scriptName = "goploy-after-pull"
case model.DeployFinish: case model.DeployFinish:
ws.Send(ws.Data{ ws.Send(ws.Data{
@ -476,7 +568,7 @@ func (gsync *Gsync) runLocalScript() error {
}) })
mode = project.Script.DeployFinish.Mode mode = project.Script.DeployFinish.Mode
content = project.Script.DeployFinish.Content content = project.Script.DeployFinish.Content
scriptName = "goploy-deploy-finish." + pkg.GetScriptExt(project.Script.DeployFinish.Mode) scriptName = "goploy-deploy-finish"
default: default:
return errors.New("not support stage") return errors.New("not support stage")
@ -486,39 +578,109 @@ func (gsync *Gsync) runLocalScript() error {
commitInfo := gsync.CommitInfo commitInfo := gsync.CommitInfo
srcPath := config.GetProjectPath(project.ID) srcPath := config.GetProjectPath(project.ID)
scriptFullName := path.Join(srcPath, scriptName)
scriptMode := "bash" scriptMode := "bash"
if mode != "" { if mode != "" {
scriptMode = mode scriptMode = mode
} }
scriptText := project.ReplaceVars(commitInfo.ReplaceVars(content)) scriptText := project.ReplaceVars(commitInfo.ReplaceVars(content))
_ = os.WriteFile(scriptFullName, []byte(scriptText), 0755)
var commandOptions []string
if scriptMode == "cmd" {
commandOptions = append(commandOptions, "/C")
scriptFullName, _ = filepath.Abs(scriptFullName)
}
commandOptions = append(commandOptions, scriptFullName)
handler := exec.Command(scriptMode, commandOptions...) // run yaml script by docker
handler.Dir = srcPath if mode == "yaml" {
var dockerScript docker.Script
if output, err := handler.CombinedOutput(); err != nil { err := yaml.Unmarshal([]byte(scriptText), &dockerScript)
gsync.PublishTrace.Detail = fmt.Sprintf("err: %s\noutput: %s", err, string(output)) if err != nil {
gsync.PublishTrace.State = model.Fail return errors.New("unmarshal yaml script fail")
if _, err := gsync.PublishTrace.AddRow(); err != nil { }
log.Errorf(projectLogFormat, gsync.Project.ID, err)
projectPath, err := filepath.Abs(config.GetProjectPath(project.ID))
if err != nil {
return fmt.Errorf("get repository abs path err: %s", err)
}
if len(dockerScript.Steps) == 0 {
return nil
}
dockerConfig := docker.Config{
ProjectID: project.ID,
ProjectPath: projectPath,
}
if err = dockerConfig.Setup(); err != nil {
return err
}
for stepIndex, step := range dockerScript.Steps {
scriptText = strings.Join(step.Commands, "\n")
tmpScriptName := scriptName + fmt.Sprintf("-y%d", stepIndex)
scriptFullName := path.Join(srcPath, tmpScriptName)
step.ScriptName = tmpScriptName
_ = os.WriteFile(scriptFullName, []byte(scriptText), 0755)
dockerOutput, dockerErr := dockerConfig.Run(step)
ext, _ := json.Marshal(struct {
Script string `json:"script"`
Step string `json:"step"`
}{scriptText, step.Name})
gsync.PublishTrace.Ext = string(ext)
_ = os.Remove(scriptFullName)
if dockerErr != "" {
gsync.PublishTrace.Detail = dockerErr
gsync.PublishTrace.State = model.Fail
if _, err := gsync.PublishTrace.AddRow(); err != nil {
log.Errorf(projectLogFormat, gsync.Project.ID, err)
}
return fmt.Errorf("run docker script err: %s", dockerErr)
} else {
gsync.PublishTrace.Detail = dockerOutput
gsync.PublishTrace.State = model.Success
if _, err := gsync.PublishTrace.AddRow(); err != nil {
log.Errorf(projectLogFormat, gsync.Project.ID, err)
}
}
} }
return fmt.Errorf("err: %s, output: %s", err, string(output))
} else { } else {
_ = os.Remove(scriptFullName) scriptName += fmt.Sprintf(".%s", pkg.GetScriptExt(mode))
gsync.PublishTrace.Detail = string(output) scriptFullName := path.Join(srcPath, scriptName)
gsync.PublishTrace.State = model.Success _ = os.WriteFile(scriptFullName, []byte(scriptText), 0755)
if _, err := gsync.PublishTrace.AddRow(); err != nil {
log.Errorf(projectLogFormat, gsync.Project.ID, err) var commandOptions []string
if scriptMode == "cmd" {
commandOptions = append(commandOptions, "/C")
scriptFullName, _ = filepath.Abs(scriptFullName)
}
commandOptions = append(commandOptions, scriptFullName)
ext, _ := json.Marshal(struct {
Script string `json:"script"`
}{Script: scriptText})
gsync.PublishTrace.Ext = string(ext)
handler := exec.Command(scriptMode, commandOptions...)
handler.Dir = srcPath
if output, err := handler.CombinedOutput(); err != nil {
gsync.PublishTrace.Detail = fmt.Sprintf("err: %s\noutput: %s", err, string(output))
gsync.PublishTrace.State = model.Fail
if _, err := gsync.PublishTrace.AddRow(); err != nil {
log.Errorf(projectLogFormat, gsync.Project.ID, err)
}
return fmt.Errorf("err: %s, output: %s", err, string(output))
} else {
_ = os.Remove(scriptFullName)
gsync.PublishTrace.Detail = string(output)
gsync.PublishTrace.State = model.Success
if _, err := gsync.PublishTrace.AddRow(); err != nil {
log.Errorf(projectLogFormat, gsync.Project.ID, err)
}
} }
return nil
} }
return nil
} }
// commit id // commit id

28
go.mod
View File

@ -4,12 +4,13 @@ go 1.18
require ( require (
github.com/Masterminds/squirrel v1.4.0 github.com/Masterminds/squirrel v1.4.0
github.com/docker/docker v24.0.7+incompatible
github.com/go-ldap/ldap/v3 v3.4.1 github.com/go-ldap/ldap/v3 v3.4.1
github.com/go-playground/locales v0.13.0 github.com/go-playground/locales v0.13.0
github.com/go-playground/universal-translator v0.17.0 github.com/go-playground/universal-translator v0.17.0
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.5.0
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.1.1 github.com/google/uuid v1.3.0
github.com/gorilla/schema v1.2.0 github.com/gorilla/schema v1.2.0
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/hashicorp/go-version v1.3.0 github.com/hashicorp/go-version v1.3.0
@ -19,22 +20,43 @@ require (
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/vearutop/statigz v1.1.8 github.com/vearutop/statigz v1.1.8
github.com/wenlng/go-captcha v1.2.5 github.com/wenlng/go-captcha v1.2.5
golang.org/x/crypto v0.1.0 golang.org/x/crypto v0.14.0
gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/go-playground/validator.v9 v9.31.0
gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/containerd/containerd v1.7.9 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/klauspost/compress v1.17.3 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/leodido/go-urn v1.2.0 // indirect github.com/leodido/go-urn v1.2.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
github.com/opencontainers/runc v1.1.10 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
golang.org/x/image v0.10.0 // indirect golang.org/x/image v0.10.0 // indirect
golang.org/x/sys v0.5.0 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/time v0.4.0 // indirect
golang.org/x/tools v0.10.0 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
) )

84
go.sum
View File

@ -1,13 +1,30 @@
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ= github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ=
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/Masterminds/squirrel v1.4.0 h1:he5i/EXixZxrBUWcxzDYMiju9WZ3ld/l7QBNuo/eN3w= github.com/Masterminds/squirrel v1.4.0 h1:he5i/EXixZxrBUWcxzDYMiju9WZ3ld/l7QBNuo/eN3w=
github.com/Masterminds/squirrel v1.4.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= github.com/Masterminds/squirrel v1.4.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/bool64/dev v0.2.9 h1:efyGf5pgx4CYWQpCzPEX8a1PgewaCGaEexXa+IYHT/8= github.com/bool64/dev v0.2.9 h1:efyGf5pgx4CYWQpCzPEX8a1PgewaCGaEexXa+IYHT/8=
github.com/containerd/containerd v1.7.9 h1:KOhK01szQbM80YfW1H6RZKh85PHGqY/9OcEZ35Je8sc=
github.com/containerd/containerd v1.7.9/go.mod h1:0/W44LWEYfSHoxBtsHIiNU/duEkgpMokemafHVCpq9Y=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag= github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag=
github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
@ -19,12 +36,15 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
@ -38,6 +58,10 @@ github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/jlaffaye/ftp v0.0.0-20220301181425-a81b090061fa h1:Cv45cONl1gg0QBv5rvDBrZycQtJtEJlEloN4IIeVhxg= github.com/jlaffaye/ftp v0.0.0-20220301181425-a81b090061fa h1:Cv45cONl1gg0QBv5rvDBrZycQtJtEJlEloN4IIeVhxg=
github.com/jlaffaye/ftp v0.0.0-20220301181425-a81b090061fa/go.mod h1:oZaomI+9/et52UBjvNU9LCIqmgt816+7ljXCx0EIPzo= github.com/jlaffaye/ftp v0.0.0-20220301181425-a81b090061fa/go.mod h1:oZaomI+9/et52UBjvNU9LCIqmgt816+7ljXCx0EIPzo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
@ -46,6 +70,20 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40=
github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M=
github.com/pelletier/go-toml/v2 v2.0.0-beta.4 h1:GCs8ebsDtEH3RiO78+BvhHqj65d/I6tjESitJZc07Rc= github.com/pelletier/go-toml/v2 v2.0.0-beta.4 h1:GCs8ebsDtEH3RiO78+BvhHqj65d/I6tjESitJZc07Rc=
github.com/pelletier/go-toml/v2 v2.0.0-beta.4/go.mod h1:ke6xncR3W76Ba8xnVxkrZG0js6Rd2BsQEAYrfgJ6eQA= github.com/pelletier/go-toml/v2 v2.0.0-beta.4/go.mod h1:ke6xncR3W76Ba8xnVxkrZG0js6Rd2BsQEAYrfgJ6eQA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -60,47 +98,64 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942 h1:t0lM6y/M5IiUZyvbBTcngso8SZEZICH7is9B6g/obVU=
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/vearutop/statigz v1.1.8 h1:IJgQHx6EomuYOYd2TzFt3haP+BIzV471zn7aepRiLHA= github.com/vearutop/statigz v1.1.8 h1:IJgQHx6EomuYOYd2TzFt3haP+BIzV471zn7aepRiLHA=
github.com/vearutop/statigz v1.1.8/go.mod h1:pfzrpvgLRnFeSVZd9iUYrpYDLqbV+RgeCfizr3ZFf44= github.com/vearutop/statigz v1.1.8/go.mod h1:pfzrpvgLRnFeSVZd9iUYrpYDLqbV+RgeCfizr3ZFf44=
github.com/wenlng/go-captcha v1.2.5 h1:zA0/fovEl9oAhSg+KwHBwmq99GeeAXknWx6wYKjhjTg= github.com/wenlng/go-captcha v1.2.5 h1:zA0/fovEl9oAhSg+KwHBwmq99GeeAXknWx6wYKjhjTg=
github.com/wenlng/go-captcha v1.2.5/go.mod h1:QgPgpEURSa37gF3GtojNoNRwbMwuatSBx5NXrzASOb0= github.com/wenlng/go-captcha v1.2.5/go.mod h1:QgPgpEURSa37gF3GtojNoNRwbMwuatSBx5NXrzASOb0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.10.0 h1:gXjUUtwtx5yOE0VKWq1CH4IJAClq4UGgUA3i+rpON9M= golang.org/x/image v0.10.0 h1:gXjUUtwtx5yOE0VKWq1CH4IJAClq4UGgUA3i+rpON9M=
golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0= golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -108,16 +163,29 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

View File

@ -22,8 +22,9 @@ type ProjectScript struct {
Content string `json:"content"` Content string `json:"content"`
} `json:"afterPull"` } `json:"afterPull"`
AfterDeploy struct { AfterDeploy struct {
Mode string `json:"mode"` Mode string `json:"mode"`
Content string `json:"content"` Content string `json:"content"`
ScriptNames []string `json:"scriptNames"`
} `json:"afterDeploy"` } `json:"afterDeploy"`
DeployFinish struct { DeployFinish struct {
Mode string `json:"mode"` Mode string `json:"mode"`
@ -407,7 +408,8 @@ func (p Project) GetDeployList() (Projects, error) {
project.environment, project.environment,
project.branch, project.branch,
project.symlink_path, project.symlink_path,
project.review, project.review,
project.script,
project.last_publish_token, project.last_publish_token,
project.auto_deploy, project.auto_deploy,
project.deploy_state, project.deploy_state,
@ -436,7 +438,7 @@ func (p Project) GetDeployList() (Projects, error) {
projects := Projects{} projects := Projects{}
for rows.Next() { for rows.Next() {
var project Project var project Project
var script []byte
if err := rows.Scan( if err := rows.Scan(
&project.ID, &project.ID,
&project.Name, &project.Name,
@ -451,12 +453,18 @@ func (p Project) GetDeployList() (Projects, error) {
&project.Branch, &project.Branch,
&project.SymlinkPath, &project.SymlinkPath,
&project.Review, &project.Review,
&script,
&project.LastPublishToken, &project.LastPublishToken,
&project.AutoDeploy, &project.AutoDeploy,
&project.DeployState, &project.DeployState,
&project.UpdateTime); err != nil { &project.UpdateTime); err != nil {
return projects, err return projects, err
} }
if err = json.Unmarshal(script, &project.Script); err != nil {
return nil, err
}
projects = append(projects, project) projects = append(projects, project)
} }

View File

@ -0,0 +1,212 @@
package docker
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stdcopy"
"github.com/google/uuid"
"github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model"
"path"
"path/filepath"
)
type Script struct {
Steps []Step `yaml:"steps"`
}
type Step struct {
Name string `yaml:"name"`
Commands []string `yaml:"commands"`
Image string `yaml:"image"`
ImageOptions struct {
Registry string `yaml:"registry"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Dockerfile string `yaml:"dockerfile"`
} `yaml:"imageOptions"`
ScriptName string
ContainerName string
}
type Config struct {
ProjectID int64
ProjectPath string
Server model.Server
Client client.APIClient
}
func GetDockerProjectPath(projectID int64) string {
return fmt.Sprintf("/data/www/repository/project_%d", projectID)
}
func GetDockerProjectScriptPath(projectID int64, scriptName string) string {
return path.Join(GetDockerProjectPath(projectID), scriptName)
}
func (c *Config) Setup() (err error) {
if c.Server.IP != "" {
c.Client, err = client.NewClientWithOpts(client.WithHost(fmt.Sprintf("tcp://%s:2375", c.Server.IP)), client.WithAPIVersionNegotiation())
} else {
c.Client, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
}
if err != nil {
return fmt.Errorf("connect docker err: %s", err)
}
return nil
}
func (c *Config) Run(step Step) (outStr string, errStr string) {
defer func() {
c.Destroy(step)
}()
step.ContainerName = uuid.New().String()
ctx := context.Background()
pullOptions := types.ImagePullOptions{}
if step.ImageOptions.Registry != "" {
step.Image = fmt.Sprintf("%s%s", step.ImageOptions.Registry, step.Image)
}
// build image by dockerfile
if step.ImageOptions.Dockerfile != "" {
localProjectPath, err := filepath.Abs(config.GetProjectPath(c.ProjectID))
if err != nil {
errStr = fmt.Sprintf("get local repository abs path err: %s", err)
return
}
tar, err := archive.TarWithOptions(filepath.Join(localProjectPath, step.ImageOptions.Dockerfile), &archive.TarOptions{})
_, err = c.Client.ImageBuild(ctx, tar, types.ImageBuildOptions{
Tags: []string{step.Image},
Dockerfile: "Dockerfile",
Remove: true,
ForceRemove: true,
})
if err != nil {
errStr = fmt.Sprintf("build image err: %s", err)
return
}
} else {
// pull image from private registry
if step.ImageOptions.Username != "" && step.ImageOptions.Password != "" {
authConfig := registry.AuthConfig{
Username: step.ImageOptions.Username,
Password: step.ImageOptions.Password,
}
authConfigBytes, _ := json.Marshal(authConfig)
authConfigEncoded := base64.URLEncoding.EncodeToString(authConfigBytes)
pullOptions.RegistryAuth = authConfigEncoded
}
_, err := c.Client.ImagePull(ctx, step.Image, pullOptions)
if err != nil {
errStr = fmt.Sprintf("pull docker image err: %s", err)
return
}
}
dockerProjectPath := GetDockerProjectPath(c.ProjectID)
hostConfig := &container.HostConfig{
Mounts: []mount.Mount{
{
Type: mount.TypeBind,
Source: c.ProjectPath,
Target: dockerProjectPath,
},
},
}
_, err := c.Client.ContainerCreate(ctx, &container.Config{
Image: step.Image,
Cmd: []string{GetDockerProjectScriptPath(c.ProjectID, step.ScriptName)},
Entrypoint: []string{"/bin/sh"},
WorkingDir: dockerProjectPath,
AttachStdin: false,
AttachStdout: true,
AttachStderr: true,
}, hostConfig, nil, nil, step.ContainerName)
// if err is image does not exist, re-pull image and re-create container
if client.IsErrNotFound(err) && step.ImageOptions.Dockerfile == "" {
_, err = c.Client.ImagePull(ctx, step.Image, pullOptions)
if err != nil {
errStr = fmt.Sprintf("pull docker image twice err: %s", err)
return
}
_, err = c.Client.ContainerCreate(ctx, &container.Config{
Image: step.Image,
Cmd: []string{GetDockerProjectScriptPath(c.ProjectID, step.ScriptName)},
Entrypoint: []string{"/bin/sh"},
WorkingDir: dockerProjectPath,
AttachStdin: false,
AttachStdout: true,
AttachStderr: true,
}, hostConfig, nil, nil, step.ContainerName)
}
if err != nil {
errStr = fmt.Sprintf("create docker container err: %s", err)
return
}
if err := c.Client.ContainerStart(ctx, step.ContainerName, types.ContainerStartOptions{}); err != nil {
errStr = fmt.Sprintf("start docker container err: %s", err)
return
}
statusCh, errCh := c.Client.ContainerWait(ctx, step.ContainerName, container.WaitConditionNotRunning)
select {
case err := <-errCh:
if err != nil {
errStr = fmt.Sprintf("wait docker container err: %s", err)
break
}
case <-statusCh:
}
if errStr != "" {
return
}
out, err := c.Client.ContainerLogs(ctx, step.ContainerName, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
if err != nil {
errStr = fmt.Sprintf("logs docker container err: %s", err)
return
}
var dockerOutbuf, dockerErrbuf bytes.Buffer
stdcopy.StdCopy(&dockerOutbuf, &dockerErrbuf, out)
defer out.Close()
if dockerErrbuf.Len() > 0 {
errStr = fmt.Sprintf("run docker script err: %s", dockerErrbuf.String())
return
}
return dockerOutbuf.String(), errStr
}
func (c *Config) Destroy(step Step) {
ctx := context.Background()
_ = c.Client.ContainerKill(ctx, step.ContainerName, "9")
_ = c.Client.ContainerRemove(ctx, step.ContainerName, types.ContainerRemoveOptions{
RemoveVolumes: true,
RemoveLinks: false,
Force: true,
})
}

View File

@ -24,6 +24,9 @@ func (ct customTransmitter) String() string {
scriptVars := map[string]string{ scriptVars := map[string]string{
"${AFTER_DEPLOY_FILENAME}": fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, server.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode)), "${AFTER_DEPLOY_FILENAME}": fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, server.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode)),
} }
for index, scriptName := range project.Script.AfterDeploy.ScriptNames {
scriptVars[fmt.Sprintf("${AFTER_DEPLOY_FILENAME_YAML_%d}", index)] = scriptName
}
for key, value := range scriptVars { for key, value := range scriptVars {
script = strings.Replace(script, key, value, -1) script = strings.Replace(script, key, value, -1)
} }

View File

@ -5,7 +5,6 @@
package transmitter package transmitter
import ( import (
"fmt"
"github.com/zhenorzz/goploy/config" "github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model" "github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pkg" "github.com/zhenorzz/goploy/internal/pkg"
@ -36,10 +35,12 @@ func (rt rsyncTransmitter) args() []string {
} }
rsyncOption, _ := pkg.ParseCommandLine(projectServer.ReplaceVars(project.ReplaceVars(project.TransferOption))) rsyncOption, _ := pkg.ParseCommandLine(projectServer.ReplaceVars(project.ReplaceVars(project.TransferOption)))
rsyncOption = append([]string{ var includes []string
"--include", for _, scriptName := range project.Script.AfterDeploy.ScriptNames {
fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, projectServer.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode)), includes = append(includes, "--include", scriptName)
}, rsyncOption...) }
rsyncOption = append(includes, rsyncOption...)
rsyncOption = append(rsyncOption, "-e", projectServer.ToSSHOption()) rsyncOption = append(rsyncOption, "-e", projectServer.ToSSHOption())
if projectServer.Server.OS == model.ServerOSLinux { if projectServer.Server.OS == model.ServerOSLinux {

View File

@ -5,7 +5,6 @@
package transmitter package transmitter
import ( import (
"fmt"
"github.com/pkg/sftp" "github.com/pkg/sftp"
"github.com/zhenorzz/goploy/config" "github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model" "github.com/zhenorzz/goploy/internal/model"
@ -97,7 +96,7 @@ func (st sftpTransmitter) Exec() (string, error) {
} }
nextItem = "" nextItem = ""
} }
includes = append(includes, fmt.Sprintf("goploy-after-deploy-p%d-s%d.%s", project.ID, st.ProjectServer.ServerID, pkg.GetScriptExt(project.Script.AfterDeploy.Mode))) includes = append(includes, project.Script.AfterDeploy.ScriptNames...)
srcPath := config.GetProjectPath(project.ID) + "/" srcPath := config.GetProjectPath(project.ID) + "/"
destPath := project.Path destPath := project.Path

View File

@ -45,6 +45,7 @@ export interface PublishTraceExt {
diff: string diff: string
script: string script: string
command: string command: string
step: string
} }
export class DeployList extends Request { export class DeployList extends Request {

View File

@ -6,6 +6,7 @@ const scriptLang = {
{ label: 'python', value: 'python', lang: 'python' }, { label: 'python', value: 'python', lang: 'python' },
{ label: 'php', value: 'php', lang: 'php' }, { label: 'php', value: 'php', lang: 'php' },
{ label: 'bat', value: 'cmd', lang: 'batchfile' }, { label: 'bat', value: 'cmd', lang: 'batchfile' },
{ label: 'yaml', value: 'yaml', lang: 'yaml' },
], ],
getScriptLang: function (mode = '') { getScriptLang: function (mode = '') {
if (mode !== '') { if (mode !== '') {

View File

@ -245,7 +245,7 @@
{{ projectRow.repoType }} {{ projectRow.repoType }}
</span> </span>
<span <span
v-if="localTraceList[PublishTraceType.Pull].state === 1" v-if="localTraceList[PublishTraceType.Pull][0].state === 1"
class="icon-success" class="icon-success"
></span> ></span>
<span v-else class="icon-fail"></span> <span v-else class="icon-fail"></span>
@ -253,51 +253,51 @@
</el-row> </el-row>
<el-row> <el-row>
Time: Time:
{{ localTraceList[PublishTraceType.Pull].updateTime }} {{ localTraceList[PublishTraceType.Pull][0].updateTime }}
</el-row> </el-row>
<template v-if="localTraceList[PublishTraceType.Pull].state !== 0"> <template v-if="localTraceList[PublishTraceType.Pull][0].state !== 0">
<el-row> <el-row>
Branch: Branch:
{{ localTraceList[PublishTraceType.Pull]['branch'] }} {{ localTraceList[PublishTraceType.Pull][0]['branch'] }}
</el-row> </el-row>
<el-row> <el-row>
Commit: Commit:
<RepoURL <RepoURL
:url="projectRow.url" :url="projectRow.url"
:suffix="`/commit/${ :suffix="`/commit/${
localTraceList[PublishTraceType.Pull]['commit'] localTraceList[PublishTraceType.Pull][0]['commit']
}`" }`"
:text="localTraceList[PublishTraceType.Pull]['commit']" :text="localTraceList[PublishTraceType.Pull][0]['commit']"
> >
</RepoURL> </RepoURL>
</el-row> </el-row>
<el-row> <el-row>
Message: Message:
{{ localTraceList[PublishTraceType.Pull]['message'] }} {{ localTraceList[PublishTraceType.Pull][0]['message'] }}
</el-row> </el-row>
<el-row> <el-row>
Author: Author:
{{ localTraceList[PublishTraceType.Pull]['author'] }} {{ localTraceList[PublishTraceType.Pull][0]['author'] }}
</el-row> </el-row>
<el-row> <el-row>
Datetime: Datetime:
{{ {{
localTraceList[PublishTraceType.Pull]['timestamp'] localTraceList[PublishTraceType.Pull][0]['timestamp']
? parseTime( ? parseTime(
localTraceList[PublishTraceType.Pull]['timestamp'] localTraceList[PublishTraceType.Pull][0]['timestamp']
) )
: '' : ''
}} }}
</el-row> </el-row>
<el-row> <el-row>
<span style="white-space: pre-line"> <span style="white-space: pre-line">
{{ localTraceList[PublishTraceType.Pull]['diff'] }} {{ localTraceList[PublishTraceType.Pull][0]['diff'] }}
</span> </span>
</el-row> </el-row>
</template> </template>
<el-row v-else style="margin: 5px 0"> <el-row v-else style="margin: 5px 0">
<span style="white-space: pre-line; padding: 5px 0"> <span style="white-space: pre-line; padding: 5px 0">
{{ localTraceList[PublishTraceType.Pull].detail }} {{ localTraceList[PublishTraceType.Pull][0].detail }}
</span> </span>
</el-row> </el-row>
</div> </div>
@ -308,45 +308,54 @@
<el-row style="margin: 5px 0" class="project-title"> <el-row style="margin: 5px 0" class="project-title">
<span style="margin-right: 5px">After Pull</span> <span style="margin-right: 5px">After Pull</span>
<span <span
v-if="localTraceList[PublishTraceType.AfterPull].state === 1" v-if="
!localTraceList[PublishTraceType.AfterPull]
.map((localTrace) => localTrace.state)
.includes(0)
"
class="icon-success" class="icon-success"
></span> ></span>
<span v-else class="icon-fail"></span> <span v-else class="icon-fail"></span>
</el-row> </el-row>
<el-row>
Time: {{ localTraceList[PublishTraceType.AfterPull].updateTime }}
</el-row>
<el-row style="width: 100%">
<div>Script:</div>
<pre style="white-space: pre-line">
{{ localTraceList[PublishTraceType.AfterPull].script }}
</pre>
</el-row>
<div <div
v-loading=" v-for="(trace, traceKey) in localTraceList[
traceDetail[localTraceList[PublishTraceType.AfterPull].id] === '' PublishTraceType.AfterPull
" ]"
style="margin: 5px 0" :key="traceKey"
> >
<span>[goploy ~]#</span> <el-divider
<el-button v-if="traceKey !== 0"
v-if=" border-style="dashed"
localTraceList[PublishTraceType.AfterPull].state === 1 && style="margin: 0"
!(localTraceList[PublishTraceType.AfterPull].id in traceDetail) />
" <el-row
type="primary" v-if="trace.step && trace.step !== ''"
link style="margin-top: 5px"
@click="
getPublishTraceDetail(
localTraceList[PublishTraceType.AfterPull]
)
"
> >
{{ $t('deployPage.showDetail') }} Step: {{ trace.step }}
</el-button> </el-row>
<span v-else style="white-space: pre-line; padding: 5px 0"> <el-row> Time: {{ trace.updateTime }} </el-row>
{{ traceDetail[localTraceList[PublishTraceType.AfterPull].id] }} <el-row style="width: 100%">
</span> <div>Script:</div>
<pre style="white-space: pre-line">
{{ trace.script }}
</pre
>
</el-row>
<div v-loading="traceDetail[trace.id] === ''" style="margin: 5px 0">
<span>[goploy ~]#</span>
<el-button
v-if="trace.state === 1 && !(trace.id in traceDetail)"
type="primary"
link
@click="getPublishTraceDetail(trace)"
>
{{ $t('deployPage.showDetail') }}
</el-button>
<span v-else style="white-space: pre-line; padding: 5px 0">
{{ traceDetail[trace.id] }}
</span>
</div>
</div> </div>
</div> </div>
<el-tabs v-model="activeRomoteTracePane" style="width: 100%"> <el-tabs v-model="activeRomoteTracePane" style="width: 100%">
@ -356,87 +365,131 @@
:label="serverName" :label="serverName"
:name="serverName" :name="serverName"
> >
<div v-for="(trace, key) in item" :key="key"> <div v-for="(traceList, key) in item" :key="key">
<template v-if="trace.type === PublishTraceType.BeforeDeploy"> <template v-if="Number(key) === PublishTraceType.BeforeDeploy">
<el-row style="margin: 5px 0" class="project-title"> <el-row style="margin: 5px 0" class="project-title">
<span style="margin-right: 5px">Before deploy</span> <span style="margin-right: 5px">Before deploy</span>
<span v-if="trace.state === 1" class="icon-success"></span> <span
v-if="!traceList.map((trace) => trace.state).includes(0)"
class="icon-success"
></span>
<span v-else class="icon-fail"></span> <span v-else class="icon-fail"></span>
</el-row> </el-row>
<el-row style="margin: 5px 0"> <div v-for="(trace, traceKey) in traceList" :key="traceKey">
Time: {{ trace.updateTime }} <el-divider
</el-row> v-if="traceKey !== 0"
<el-row> border-style="dashed"
Script: style="margin: 0"
<pre style="white-space: pre-line">{{ trace.script }}</pre> />
</el-row> <el-row
<div v-loading="traceDetail[trace.id] === ''"> v-if="trace.step && trace.step !== ''"
<span style="padding: 5px 0">[goploy ~]#</span> style="margin-top: 5px"
<el-button
v-if="trace.state === 1 && !(trace.id in traceDetail)"
type="primary"
link
@click="getPublishTraceDetail(trace)"
> >
{{ $t('deployPage.showDetail') }} Step: {{ trace.step }}
</el-button> </el-row>
<div v-else style="white-space: pre-line; padding: 5px 0"> <el-row style="margin: 5px 0">
{{ traceDetail[trace.id] }} Time: {{ trace.updateTime }}
</el-row>
<el-row>
Script:
<pre style="white-space: pre-line">{{ trace.script }}</pre>
</el-row>
<div v-loading="traceDetail[trace.id] === ''">
<span style="padding: 5px 0">[goploy ~]#</span>
<el-button
v-if="trace.state === 1 && !(trace.id in traceDetail)"
type="primary"
link
@click="getPublishTraceDetail(trace)"
>
{{ $t('deployPage.showDetail') }}
</el-button>
<div v-else style="white-space: pre-line; padding: 5px 0">
{{ traceDetail[trace.id] }}
</div>
</div> </div>
</div> </div>
</template> </template>
<template v-else-if="trace.type === PublishTraceType.Deploy"> <template v-else-if="Number(key) === PublishTraceType.Deploy">
<el-row style="margin: 5px 0" class="project-title"> <el-row style="margin: 5px 0" class="project-title">
<span style="margin-right: 5px; text-transform: capitalize"> <span style="margin-right: 5px; text-transform: capitalize">
{{ projectRow.transferType }} {{ projectRow.transferType }}
</span> </span>
<span v-if="trace.state === 1" class="icon-success"></span> <span
v-if="!traceList.map((trace) => trace.state).includes(0)"
class="icon-success"
></span>
<span v-else class="icon-fail"></span> <span v-else class="icon-fail"></span>
</el-row> </el-row>
<el-row style="margin: 5px 0"> <div v-for="(trace, traceKey) in traceList" :key="traceKey">
Time: {{ trace.updateTime }} <el-row style="margin: 5px 0">
</el-row> Time: {{ trace.updateTime }}
<el-row>Command: {{ trace.command }}</el-row> </el-row>
<div v-loading="traceDetail[trace.id] === ''"> <el-row>Command: {{ trace.command }}</el-row>
<span style="padding: 5px 0">[goploy ~]#</span> <div v-loading="traceDetail[trace.id] === ''">
<el-button <span style="padding: 5px 0">[goploy ~]#</span>
v-if="trace.state === 1 && !(trace.id in traceDetail)" <el-button
type="primary" v-if="trace.state === 1 && !(trace.id in traceDetail)"
link type="primary"
@click="getPublishTraceDetail(trace)" link
> @click="getPublishTraceDetail(trace)"
{{ $t('deployPage.showDetail') }} >
</el-button> {{ $t('deployPage.showDetail') }}
<div v-else style="white-space: pre-line; padding: 5px 0"> </el-button>
{{ traceDetail[trace.id] }} <div v-else style="white-space: pre-line; padding: 5px 0">
{{ traceDetail[trace.id] }}
</div>
</div> </div>
</div> </div>
</template> </template>
<template v-else-if="trace.type === PublishTraceType.AfterDeploy"> <template
v-else-if="Number(key) === PublishTraceType.AfterDeploy"
>
<el-row style="margin: 5px 0" class="project-title"> <el-row style="margin: 5px 0" class="project-title">
<span style="margin-right: 5px">After deploy</span> <span style="margin-right: 5px">After deploy</span>
<span v-if="trace.state === 1" class="icon-success"></span> <span
v-if="!traceList.map((trace) => trace.state).includes(0)"
class="icon-success"
></span>
<span v-else class="icon-fail"></span> <span v-else class="icon-fail"></span>
</el-row> </el-row>
<el-row style="margin: 5px 0"> <div v-for="(trace, traceKey) in traceList" :key="traceKey">
Time: {{ trace.updateTime }} <el-divider
</el-row> v-if="traceKey !== 0"
<el-row>Script: {{ trace.script }}</el-row> border-style="dashed"
<div style="margin: 0"
v-loading="traceDetail[trace.id] === ''" />
style="margin: 5px 0" <el-row
> v-if="trace.step && trace.step !== ''"
<span>[goploy ~]#</span> style="margin-top: 5px"
<el-button
v-if="trace.state === 1 && !(trace.id in traceDetail)"
type="primary"
link
@click="getPublishTraceDetail(trace)"
> >
{{ $t('deployPage.showDetail') }} Step: {{ trace.step }}
</el-button> </el-row>
<div v-else style="white-space: pre-line; padding: 5px 0"> <el-row style="margin: 5px 0">
{{ traceDetail[trace.id] }} Time: {{ trace.updateTime }}
</el-row>
<el-row>
Script:
<pre style="white-space: pre-line">
{{ trace.script }}
</pre>
</el-row>
<div
v-loading="traceDetail[trace.id] === ''"
style="margin: 5px 0"
>
<span>[goploy ~]#</span>
<el-button
v-if="trace.state === 1 && !(trace.id in traceDetail)"
type="primary"
link
@click="getPublishTraceDetail(trace)"
>
{{ $t('deployPage.showDetail') }}
</el-button>
<div v-else style="white-space: pre-line; padding: 5px 0">
{{ traceDetail[trace.id] }}
</div>
</div> </div>
</div> </div>
</template> </template>
@ -450,51 +503,52 @@
<el-row style="margin: 5px 0" class="project-title"> <el-row style="margin: 5px 0" class="project-title">
<span style="margin-right: 5px">Deploy Finish</span> <span style="margin-right: 5px">Deploy Finish</span>
<span <span
v-if="localTraceList[PublishTraceType.DeployFinish].state === 1" v-if="
!localTraceList[PublishTraceType.DeployFinish]
.map((localTrace) => localTrace.state)
.includes(0)
"
class="icon-success" class="icon-success"
></span> ></span>
<span v-else class="icon-fail"></span> <span v-else class="icon-fail"></span>
</el-row> </el-row>
<el-row>
Time: {{ localTraceList[PublishTraceType.DeployFinish].updateTime }}
</el-row>
<el-row style="width: 100%">
<div>Script:</div>
<pre style="white-space: pre-line">
{{ localTraceList[PublishTraceType.DeployFinish].script }}
</pre>
</el-row>
<div <div
v-loading=" v-for="(trace, traceKey) in localTraceList[
traceDetail[localTraceList[PublishTraceType.DeployFinish].id] === PublishTraceType.DeployFinish
'' ]"
" :key="traceKey"
style="margin: 5px 0"
> >
<span>[goploy ~]#</span> <el-row
<el-button v-if="trace.step && trace.step !== ''"
v-if=" style="margin-top: 5px"
localTraceList[PublishTraceType.DeployFinish].state === 1 &&
!(
localTraceList[PublishTraceType.DeployFinish].id in
traceDetail
)
"
type="primary"
link
@click="
getPublishTraceDetail(
localTraceList[PublishTraceType.DeployFinish]
)
"
> >
{{ $t('deployPage.showDetail') }} Step: {{ trace.step }}
</el-button> </el-row>
<span v-else style="white-space: pre-line; padding: 5px 0"> <el-row>
{{ Time:
traceDetail[localTraceList[PublishTraceType.DeployFinish].id] {{ trace.updateTime }}
}} </el-row>
</span> <el-row style="width: 100%">
<div>Script:</div>
<pre style="white-space: pre-line">
{{ trace.script }}
</pre
>
</el-row>
<div v-loading="traceDetail[trace.id] === ''" style="margin: 5px 0">
<span>[goploy ~]#</span>
<el-button
v-if="trace.state === 1 && !(trace.id in traceDetail)"
type="primary"
link
@click="getPublishTraceDetail(trace)"
>
{{ $t('deployPage.showDetail') }}
</el-button>
<span v-else style="white-space: pre-line; padding: 5px 0">
{{ traceDetail[trace.id] }}
</span>
</div>
</div> </div>
</div> </div>
</el-row> </el-row>
@ -581,7 +635,7 @@ const shortcuts = [
const userOption = ref<NamespaceUserOption['datagram']['list']>([]) const userOption = ref<NamespaceUserOption['datagram']['list']>([])
watch( watch(
() => props.modelValue, () => props.modelValue,
(val: typeof props['modelValue']) => { (val: (typeof props)['modelValue']) => {
if (val === true) { if (val === true) {
clearFilterParams() clearFilterParams()
getPreviewList(props.projectRow.id) getPreviewList(props.projectRow.id)
@ -607,9 +661,11 @@ const gitTraceList = ref<(PublishTraceData & PublishTraceExt)[]>([])
const pagination = reactive({ page: 1, rows: 11, total: 0 }) const pagination = reactive({ page: 1, rows: 11, total: 0 })
const traceDetail = ref<Record<number, string>>({}) const traceDetail = ref<Record<number, string>>({})
const publishToken = ref('') const publishToken = ref('')
const localTraceList = ref<(PublishTraceData & PublishTraceExt)[]>([]) const localTraceList = ref<
Record<number, (PublishTraceData & PublishTraceExt)[]>
>({})
const remoteTraceList = ref< const remoteTraceList = ref<
Record<string, (PublishTraceData & PublishTraceExt)[]> Record<string, Record<number, (PublishTraceData & PublishTraceExt)[]>>
>({}) >({})
const filterlength = computed(() => { const filterlength = computed(() => {
let number = 0 let number = 0
@ -671,7 +727,7 @@ const getPreviewList = (projectId: number) => {
publishToken.value = gitTraceList.value[0].token publishToken.value = gitTraceList.value[0].token
getPublishTrace(publishToken.value) getPublishTrace(publishToken.value)
} else { } else {
localTraceList.value = [] localTraceList.value = {}
remoteTraceList.value = {} remoteTraceList.value = {}
} }
pagination.total = response.data.pagination.total pagination.total = response.data.pagination.total
@ -705,7 +761,7 @@ function getPublishTrace(publishToken: string) {
} }
return element as PublishTraceData & PublishTraceExt return element as PublishTraceData & PublishTraceExt
}) })
localTraceList.value = [] localTraceList.value = {}
remoteTraceList.value = {} remoteTraceList.value = {}
for (const trace of publishTraceList) { for (const trace of publishTraceList) {
if (trace.detail !== '') { if (trace.detail !== '') {
@ -720,7 +776,10 @@ function getPublishTrace(publishToken: string) {
PublishTraceType.DeployFinish, PublishTraceType.DeployFinish,
].includes(trace.type) ].includes(trace.type)
) { ) {
localTraceList.value[trace.type] = trace if (!localTraceList.value[trace.type]) {
localTraceList.value[trace.type] = []
}
localTraceList.value[trace.type].push(trace)
} else if ( } else if (
[ [
PublishTraceType.BeforeDeploy, PublishTraceType.BeforeDeploy,
@ -729,9 +788,13 @@ function getPublishTrace(publishToken: string) {
].includes(trace.type) ].includes(trace.type)
) { ) {
if (!remoteTraceList.value[trace.serverName]) { if (!remoteTraceList.value[trace.serverName]) {
remoteTraceList.value[trace.serverName] = [] remoteTraceList.value[trace.serverName] = {}
} }
remoteTraceList.value[trace.serverName].push(trace) if (!remoteTraceList.value[trace.serverName][trace.type]) {
remoteTraceList.value[trace.serverName][trace.type] = []
}
remoteTraceList.value[trace.serverName][trace.type].push(trace)
} }
} }
activeRomoteTracePane.value = Object.keys(remoteTraceList.value)[0] activeRomoteTracePane.value = Object.keys(remoteTraceList.value)[0]