Added: custom variable

This commit is contained in:
zhenorzz 2024-05-14 15:28:48 +08:00
parent 68b5d2082e
commit e2cf9c6b11
25 changed files with 482 additions and 373 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ tmp
goploy
goploy_arm64
goploy_arm64.mac
goploy.exe*
goploy.mac
goploy.pid

View File

@ -4,6 +4,20 @@ All notable changes to the "goploy" extension will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
## [1.17.0] - 2024-05-14
### Added
- [custom variable](https://github.com/zhenorzz/goploy/issues/101)
- custom login lock time
### Changed
- change deploy dialog ui
### Bug fixed
- [fix quote in rsync remote shell](https://github.com/zhenorzz/goploy/pull/107)
## [1.16.3] - 2024-03-29
### Bug fixed

View File

@ -29,6 +29,8 @@ env GOOS=linux go build -o goploy cmd/server/main.go
env GOOS=linux GOARCH=arm64 go build -o goploy_arm64 cmd/server/main.go
env GOOS=darwin GOARCH=arm64 go build -o goploy_arm64.mac cmd/server/main.go
env GOOS=darwin go build -o goploy.mac cmd/server/main.go
env GOOS=windows go build -o goploy.exe cmd/server/main.go

View File

@ -539,9 +539,11 @@ func (Deploy) ManageProcess(gp *server.Goploy) server.Response {
// @Router /deploy/publish [post]
func (Deploy) Publish(gp *server.Goploy) server.Response {
type ReqData struct {
ProjectID int64 `json:"projectId" validate:"required,gt=0"`
Commit string `json:"commit"`
Branch string `json:"branch"`
ProjectID int64 `json:"projectId" validate:"required,gt=0"`
Commit string `json:"commit"`
Branch string `json:"branch"`
ServerIDs []int64 `json:"serverIds"`
CustomVariables []model.ProjectScriptCustomVariable `json:"customVariables"`
}
var reqData ReqData
if err := gp.Decode(&reqData); err != nil {
@ -554,11 +556,11 @@ func (Deploy) Publish(gp *server.Goploy) server.Response {
token := ""
if project.DeployState == model.ProjectNotDeploy {
token, err = projectDeploy(gp, project, "", "")
token, err = projectDeploy(gp, project, "", "", reqData.ServerIDs, reqData.CustomVariables)
} else if project.Review == model.Enable {
err = projectReview(gp, project, reqData.Commit, reqData.Branch)
} else {
token, err = projectDeploy(gp, project, reqData.Commit, reqData.Branch)
token, err = projectDeploy(gp, project, reqData.Commit, reqData.Branch, reqData.ServerIDs, reqData.CustomVariables)
}
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
@ -617,7 +619,17 @@ func (Deploy) Rebuild(gp *server.Goploy) server.Response {
break
}
if publishTrace.Type == model.Pull {
if publishTrace.Type == model.Queue {
var queueExt model.PublishTraceQueueExt
if publishTrace.Ext != "" {
err := json.Unmarshal([]byte(publishTrace.Ext), &queueExt)
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
// set the token script
project.Script = queueExt.Script
}
} else if publishTrace.Type == model.Pull {
err := json.Unmarshal([]byte(publishTrace.Ext), &commitInfo)
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
@ -647,6 +659,7 @@ func (Deploy) Rebuild(gp *server.Goploy) server.Response {
if project.Script.AfterDeploy.Content != "" {
scriptContent := project.ReplaceVars(project.Script.AfterDeploy.Content)
scriptContent = project.ReplaceCustomVars(scriptContent)
scriptContent = projectServer.ReplaceVars(scriptContent)
if project.Script.AfterDeploy.Mode == "yaml" {
@ -815,56 +828,8 @@ func (Deploy) Rebuild(gp *server.Goploy) server.Response {
// @Param request body deploy.GreyPublish.ReqData true "body params"
// @Success 200 {object} response.JSON
// @Router /deploy/greyPublish [post]
func (Deploy) GreyPublish(gp *server.Goploy) server.Response {
type ReqData struct {
ProjectID int64 `json:"projectId" validate:"required,gt=0"`
Commit string `json:"commit"`
Branch string `json:"branch"`
ServerIDs []int64 `json:"serverIds"`
}
var reqData ReqData
if err := gp.Decode(&reqData); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
project, err := model.Project{ID: reqData.ProjectID}.GetData()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
bindProjectServers, err := model.ProjectServer{ProjectID: project.ID}.GetBindServerListByProjectID()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
projectServers := model.ProjectServers{}
for _, projectServer := range bindProjectServers {
for _, serverID := range reqData.ServerIDs {
if projectServer.ServerID == serverID {
projectServers = append(projectServers, projectServer)
}
}
}
project.PublisherID = gp.UserInfo.ID
project.PublisherName = gp.UserInfo.Name
project.DeployState = model.ProjectDeploying
project.LastPublishToken = uuid.New().String()
err = project.Publish()
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
task.AddDeployTask(task.Gsync{
UserInfo: gp.UserInfo,
Project: project,
ProjectServers: projectServers,
CommitID: reqData.Commit,
Branch: reqData.Branch,
})
return response.JSON{}
func (d Deploy) GreyPublish(gp *server.Goploy) server.Response {
return d.Publish(gp)
}
// Review reviews the project
@ -906,7 +871,7 @@ func (Deploy) Review(gp *server.Goploy) server.Response {
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
if _, err := projectDeploy(gp, project, pr.CommitID, pr.Branch); err != nil {
if _, err := projectDeploy(gp, project, pr.CommitID, pr.Branch, nil, nil); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
}
@ -1005,7 +970,7 @@ func (Deploy) Callback(gp *server.Goploy) server.Response {
if err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
if _, err := projectDeploy(gp, project, pr.CommitID, pr.Branch); err != nil {
if _, err := projectDeploy(gp, project, pr.CommitID, pr.Branch, nil, nil); err != nil {
return response.JSON{Code: response.Error, Message: err.Error()}
}
@ -1016,11 +981,32 @@ func (Deploy) Callback(gp *server.Goploy) server.Response {
return response.JSON{}
}
func projectDeploy(gp *server.Goploy, project model.Project, commitID string, branch string) (string, error) {
projectServers, err := model.ProjectServer{ProjectID: project.ID}.GetBindServerListByProjectID()
func projectDeploy(gp *server.Goploy, project model.Project, commitID string, branch string, serverIDs []int64, customVariables []model.ProjectScriptCustomVariable) (string, error) {
bindProjectServers, err := model.ProjectServer{ProjectID: project.ID}.GetBindServerListByProjectID()
if err != nil {
return "", err
}
projectServers := bindProjectServers
if len(serverIDs) > 0 {
projectServers = model.ProjectServers{}
for _, projectServer := range bindProjectServers {
for _, serverID := range serverIDs {
if projectServer.ServerID == serverID {
projectServers = append(projectServers, projectServer)
}
}
}
}
if len(customVariables) > 0 {
project.Script.CustomVariables = customVariables
} else {
project.Script.CustomVariables = []model.ProjectScriptCustomVariable{}
}
project.PublisherID = gp.UserInfo.ID
project.PublisherName = gp.UserInfo.Name
project.DeployState = model.ProjectDeploying

View File

@ -49,7 +49,7 @@ var (
s string
)
const appVersion = "1.16.3"
const appVersion = "1.17.0"
func init() {
flag.StringVar(&config.AssetDir, "asset-dir", "", "default: ./")
@ -64,7 +64,7 @@ func init() {
}
// @title Goploy
// @version 1.16.3
// @version 1.17.0
// @description A web deployment system tool!
// @contact.name zhenorzz
// @contact.url https://github.com/zhenorzz/goploy

View File

@ -117,12 +117,18 @@ func AddDeployTask(gsync Gsync) {
}{gsync.Project.LastPublishToken},
},
})
queueExt := model.PublishTraceQueueExt{
Script: gsync.Project.Script,
}
ext, _ := json.Marshal(queueExt)
gsync.PublishTrace = model.PublishTrace{
Token: gsync.Project.LastPublishToken,
ProjectID: gsync.Project.ID,
ProjectName: gsync.Project.Name,
PublisherID: gsync.UserInfo.ID,
PublisherName: gsync.UserInfo.Name,
Ext: string(ext),
InsertTime: time.Now().Format("20060102150405"),
Type: model.Queue,
State: model.Success,
@ -208,9 +214,9 @@ func (gsync *Gsync) repoStage() error {
var err error
r, _ := repo.GetRepo(gsync.Project.RepoType)
if len(gsync.CommitID) == 0 {
err = r.Follow(gsync.Project, "origin/"+gsync.Project.Branch)
err = r.Follow(gsync.Project.ID, "origin/"+gsync.Project.Branch, gsync.Project.URL, gsync.Project.Branch)
} else {
err = r.Follow(gsync.Project, gsync.CommitID)
err = r.Follow(gsync.Project.ID, gsync.CommitID, gsync.Project.URL, gsync.Project.Branch)
}
if err != nil {
@ -286,6 +292,7 @@ func (gsync *Gsync) serverStage() error {
scriptContent := ""
if project.Script.AfterDeploy.Content != "" {
scriptContent = project.ReplaceVars(project.Script.AfterDeploy.Content)
scriptContent = project.ReplaceCustomVars(scriptContent)
scriptContent = projectServer.ReplaceVars(scriptContent)
scriptContent = strings.Replace(scriptContent, "${SERVER_TOTAL_NUMBER}", strconv.Itoa(len(gsync.ProjectServers)), -1)
scriptContent = strings.Replace(scriptContent, "${SERVER_SERIAL_NUMBER}", strconv.Itoa(index), -1)
@ -575,7 +582,9 @@ func (gsync *Gsync) runLocalScript() error {
if mode != "" {
scriptMode = mode
}
scriptText := project.ReplaceVars(commitInfo.ReplaceVars(content))
scriptText := commitInfo.ReplaceVars(content)
scriptText = project.ReplaceVars(scriptText)
scriptText = project.ReplaceCustomVars(scriptText)
// run yaml script by docker
if mode == "yaml" {

View File

@ -392,7 +392,7 @@ CREATE TABLE IF NOT EXISTS `terminal_log` (
INSERT IGNORE INTO `user`(`id`, `account`, `password`, `name`, `contact`, `state`, `super_manager`) VALUES (1, 'admin', '$2a$10$89ZJ2xeJj35GOw11Qiucr.phaEZP4.kBX6aKTs7oWFp1xcGBBgijm', '超管', '', 1, 1);
INSERT IGNORE INTO `namespace`(`id`, `name`) VALUES (1, 'goploy');
INSERT IGNORE INTO `namespace_user`(`id`, `namespace_id`, `user_id`, `role_id`) VALUES (1, 1, 1, 0);
INSERT IGNORE INTO `system_config` (`id`, `key`, `value`) VALUES (1, 'version', '1.16.3');
INSERT IGNORE INTO `system_config` (`id`, `key`, `value`) VALUES (1, 'version', '1.17.0');
INSERT IGNORE INTO `role`(`id`, `name`, `description`) VALUES (1, 'manager', '');
INSERT IGNORE INTO `role`(`id`, `name`, `description`) VALUES (2, 'member', '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (1, 0, 'Log', 0, '');
@ -457,7 +457,6 @@ INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALU
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (60, 56, 'DeployDetail', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (61, 56, 'DeployProject', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (62, 56, 'DeployResetState', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (63, 56, 'GreyDeploy', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (64, 56, 'DeployRollback', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (65, 56, 'DeployReview', 0, '');
INSERT IGNORE INTO `permission`(`id`, `pid`, `name`, `sort`, `description`) VALUES (66, 56, 'DeployTask', 0, '');
@ -525,7 +524,6 @@ INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 59);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 60);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 61);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 62);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 63);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 64);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 65);
INSERT IGNORE INTO `role_permission`(`role_id`, `permission_id`) VALUES (1, 66);

View File

@ -1,7 +1,7 @@
# Import sql manually https://github.com/zhenorzz/goploy/blob/master/model/sql/goploy.sql
FROM alpine
LABEL maintainer="zhenorzz@gmail.com"
ARG GOPLOY_VER=v1.16.3
ARG GOPLOY_VER=v1.17.0
ENV GOPLOY_VER=${GOPLOY_VER}
RUN echo "https://mirrors.aliyun.com/alpine/latest-stable/main/" > /etc/apk/repositories

View File

@ -30,6 +30,13 @@ type ProjectScript struct {
Mode string `json:"mode"`
Content string `json:"content"`
} `json:"deployFinish"`
CustomVariables []ProjectScriptCustomVariable `json:"customVariables"`
}
type ProjectScriptCustomVariable struct {
Name string `json:"name"`
Value string `json:"value"`
Type string `json:"type"`
}
type Project struct {
@ -588,3 +595,11 @@ func (p Project) ReplaceVars(script string) string {
}
return script
}
func (p Project) ReplaceCustomVars(script string) string {
for _, variable := range p.Script.CustomVariables {
key := fmt.Sprintf("${%s}", variable.Name)
script = strings.Replace(script, key, variable.Value, -1)
}
return script
}

View File

@ -28,6 +28,10 @@ type PublishTrace struct {
UpdateTime string `json:"updateTime"`
}
type PublishTraceQueueExt struct {
Script ProjectScript `json:"script"`
}
// PublishTraces -
type PublishTraces []PublishTrace

View File

@ -13,10 +13,8 @@ import (
type Repo interface {
Ping(url string) error
// Create one repository
Create(projectID int64) error
// Follow the repository code and update to latest
Follow(project model.Project, target string) error
Follow(projectID int64, target string, url string, branch string) error
// RemoteBranchList list remote branches in the url
RemoteBranchList(url string) ([]string, error)
// BranchList list the local repository's branches

View File

@ -10,7 +10,6 @@ import (
"github.com/jlaffaye/ftp"
log "github.com/sirupsen/logrus"
"github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model"
"io"
"net/url"
"os"
@ -34,18 +33,7 @@ func (ftpRepo FtpRepo) Ping(url string) error {
return nil
}
// Create -
func (ftpRepo FtpRepo) Create(projectID int64) error {
project, err := model.Project{ID: projectID}.GetData()
if err != nil {
log.Error(fmt.Sprintf("The project does not exist, projectID:%d", projectID))
return err
}
return ftpRepo.Follow(project, "")
}
func (ftpRepo FtpRepo) Follow(project model.Project, _ string) error {
projectID := project.ID
func (ftpRepo FtpRepo) Follow(projectID int64, _ string, projectURL string, _ string) error {
srcPath := config.GetProjectPath(projectID)
_ = os.RemoveAll(srcPath)
if err := os.MkdirAll(srcPath, 0755); err != nil {
@ -53,7 +41,7 @@ func (ftpRepo FtpRepo) Follow(project model.Project, _ string) error {
return err
}
c, err := ftpRepo.dial(project.URL)
c, err := ftpRepo.dial(projectURL)
if err != nil {
log.Error(fmt.Sprintf("The project fail to connect ftp, projectID:%d, error:%s", projectID, err.Error()))
return err

View File

@ -9,7 +9,6 @@ import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pkg"
"os"
"strconv"
@ -31,22 +30,18 @@ func (GitRepo) Ping(url string) error {
return nil
}
func (GitRepo) Create(projectID int64) error {
func (GitRepo) create(projectID int64, url string, branch string) error {
srcPath := config.GetProjectPath(projectID)
if _, err := os.Stat(srcPath); err == nil {
return nil
}
project, err := model.Project{ID: projectID}.GetData()
if err != nil {
log.Error(fmt.Sprintf("The project does not exist, projectID:%d", projectID))
return err
}
if err := os.RemoveAll(srcPath); err != nil {
log.Error(fmt.Sprintf("The project fail to remove, projectID:%d, error: %s", projectID, err.Error()))
return err
}
git := pkg.GIT{}
if err := git.Clone(project.URL, srcPath); err != nil {
if err := git.Clone(url, srcPath); err != nil {
log.Error(fmt.Sprintf("The project fail to initialize, projectID:%d, error:%s, detail:%s", projectID, err.Error(), git.Err.String()))
return err
}
@ -57,30 +52,30 @@ func (GitRepo) Create(projectID int64) error {
return err
}
currentBranch := pkg.ClearNewline(git.Output.String())
if project.Branch != currentBranch {
if err := git.Checkout("-b", project.Branch, "origin/"+project.Branch); err != nil {
log.Error(fmt.Sprintf("The project fail to switch branch, projectID:%d, error:%s, detail:%s", projectID, err.Error(), git.Err.String()))
_ = os.RemoveAll(srcPath)
return err
}
}
//currentBranch := pkg.ClearNewline(git.Output.String())
//if branch != currentBranch {
// if err := git.Checkout("-b", branch, "origin/"+branch); err != nil {
// log.Error(fmt.Sprintf("The project fail to switch branch, projectID:%d, error:%s, detail:%s", projectID, err.Error(), git.Err.String()))
// _ = os.RemoveAll(srcPath)
// return err
// }
//}
log.Trace(fmt.Sprintf("The project success to initialize, projectID:%d", projectID))
return nil
}
func (gitRepo GitRepo) Follow(project model.Project, target string) error {
if err := gitRepo.Create(project.ID); err != nil {
func (gitRepo GitRepo) Follow(projectID int64, target string, url string, branch string) error {
if err := gitRepo.create(projectID, url, branch); err != nil {
return err
}
git := pkg.GIT{Dir: config.GetProjectPath(project.ID)}
log.Trace("projectID: " + strconv.FormatInt(project.ID, 10) + " git add .")
git := pkg.GIT{Dir: config.GetProjectPath(projectID)}
log.Trace("projectID: " + strconv.FormatInt(projectID, 10) + " git add .")
if err := git.Add("."); err != nil {
log.Error(err.Error() + ", detail: " + git.Err.String())
return err
}
log.Trace("projectID: " + strconv.FormatInt(project.ID, 10) + " git reset --hard")
log.Trace("projectID: " + strconv.FormatInt(projectID, 10) + " git reset --hard")
if err := git.Reset("--hard"); err != nil {
log.Error(err.Error() + ", detail: " + git.Err.String())
return err
@ -88,14 +83,14 @@ func (gitRepo GitRepo) Follow(project model.Project, target string) error {
// the length of commit id is 40
if len(target) != 40 {
log.Trace("projectID: " + strconv.FormatInt(project.ID, 10) + " git fetch")
log.Trace("projectID: " + strconv.FormatInt(projectID, 10) + " git fetch")
if err := git.Fetch(); err != nil {
log.Error(err.Error() + ", detail: " + git.Err.String())
return err
}
}
log.Trace("projectID: " + strconv.FormatInt(project.ID, 10) + " git checkout -B goploy " + target)
log.Trace("projectID: " + strconv.FormatInt(projectID, 10) + " git checkout -B goploy " + target)
if err := git.Checkout("-B", "goploy", target); err != nil {
log.Error(err.Error() + ", detail: " + git.Err.String())
return err

View File

@ -9,7 +9,6 @@ import (
"github.com/pkg/sftp"
log "github.com/sirupsen/logrus"
"github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pkg"
"golang.org/x/crypto/ssh"
"io"
@ -36,17 +35,7 @@ func (sftpRepo SftpRepo) Ping(url string) error {
return nil
}
func (sftpRepo SftpRepo) Create(projectID int64) error {
project, err := model.Project{ID: projectID}.GetData()
if err != nil {
log.Error(fmt.Sprintf("The project does not exist, projectID:%d", projectID))
return err
}
return sftpRepo.Follow(project, "")
}
func (sftpRepo SftpRepo) Follow(project model.Project, _ string) error {
projectID := project.ID
func (sftpRepo SftpRepo) Follow(projectID int64, _ string, projectURL string, _ string) error {
srcPath := config.GetProjectPath(projectID)
_ = os.RemoveAll(srcPath)
if err := os.MkdirAll(srcPath, 0755); err != nil {
@ -54,7 +43,7 @@ func (sftpRepo SftpRepo) Follow(project model.Project, _ string) error {
return err
}
sshClient, err := sftpRepo.dial(project.URL)
sshClient, err := sftpRepo.dial(projectURL)
if err != nil {
log.Error(fmt.Sprintf("The project fail to connect ftp, projectID:%d, error:%s", projectID, err.Error()))
return err
@ -110,7 +99,7 @@ func (sftpRepo SftpRepo) Follow(project model.Project, _ string) error {
}
return nil
}
_url, _, _ := sftpRepo.parseURL(project.URL)
_url, _, _ := sftpRepo.parseURL(projectURL)
u, err := url.Parse(_url)
if err != nil {
log.Error(fmt.Sprintf("The project fail to parse url, projectID:%d, error:%s", projectID, err.Error()))

View File

@ -10,7 +10,6 @@ import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/zhenorzz/goploy/config"
"github.com/zhenorzz/goploy/internal/model"
"github.com/zhenorzz/goploy/internal/pkg"
"os"
"strconv"
@ -33,40 +32,35 @@ func (SvnRepo) Ping(url string) error {
return nil
}
// Create -
func (SvnRepo) Create(projectID int64) error {
func (SvnRepo) create(projectID int64, url string) error {
srcPath := config.GetProjectPath(projectID)
if _, err := os.Stat(srcPath); err == nil {
return nil
}
project, err := model.Project{ID: projectID}.GetData()
if err != nil {
log.Trace("The project does not exist, projectID:" + strconv.FormatInt(projectID, 10))
return err
}
if err := os.RemoveAll(srcPath); err != nil {
log.Trace("The project fail to remove, projectID:" + strconv.FormatInt(project.ID, 10) + " ,error: " + err.Error())
log.Trace("The project fail to remove, projectID:" + strconv.FormatInt(projectID, 10) + " ,error: " + err.Error())
return err
}
svn := pkg.SVN{}
options := strings.Split(project.URL, " ")
options := strings.Split(url, " ")
options = append(options, srcPath)
if err := svn.Clone(options...); err != nil {
log.Error("The project fail to initialize, projectID:" + strconv.FormatInt(project.ID, 10) + " ,error: " + err.Error() + ", detail: " + svn.Err.String())
log.Error("The project fail to initialize, projectID:" + strconv.FormatInt(projectID, 10) + " ,error: " + err.Error() + ", detail: " + svn.Err.String())
return err
}
log.Trace("The project success to initialize, projectID:" + strconv.FormatInt(project.ID, 10))
log.Trace("The project success to initialize, projectID:" + strconv.FormatInt(projectID, 10))
return nil
}
func (svnRepo SvnRepo) Follow(project model.Project, target string) error {
if err := svnRepo.Create(project.ID); err != nil {
func (svnRepo SvnRepo) Follow(projectID int64, target string, url string, _ string) error {
if err := svnRepo.create(projectID, url); err != nil {
return err
}
svn := pkg.SVN{Dir: config.GetProjectPath(project.ID)}
svn := pkg.SVN{Dir: config.GetProjectPath(projectID)}
// the length of commit id is 40
log.Trace("projectID:" + strconv.FormatInt(project.ID, 10) + " svn up")
log.Trace("projectID:" + strconv.FormatInt(projectID, 10) + " svn up")
if strings.Index(target, "r") == 0 {
if err := svn.Pull("-r", target); err != nil {
log.Error(err.Error() + ", detail: " + svn.Err.String())

1
web/components.d.ts vendored
View File

@ -39,6 +39,7 @@ declare module '@vue/runtime-core' {
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']

View File

@ -1,6 +1,6 @@
{
"name": "goploy",
"version": "1.16.3",
"version": "1.17.0",
"license": "GPL-3.0-or-later",
"scripts": {
"dev": "vite",

View File

@ -138,6 +138,8 @@ export class DeployPublish extends Request {
projectId: number
branch: string
commit: string
serverIds?: number[]
customVariables?: { name: string; value: string; type: string }[]
}
constructor(param: DeployPublish['param']) {
super()

View File

@ -6,6 +6,7 @@ export interface ProjectScript {
afterPull: { mode: string; content: string }
afterDeploy: { mode: string; content: string }
deployFinish: { mode: string; content: string }
customVariables: { name: string; value: string; type: string }[]
}
export interface ProjectData {
@ -25,10 +26,6 @@ export interface ProjectData {
review: number
reviewURL: string
script: ProjectScript
afterPullScriptMode: string
afterPullScript: string
afterDeployScriptMode: string
afterDeployScript: string
transferType: string
transferOption: string
deployServerMode: string

View File

@ -1,5 +1,6 @@
{
"default": "Default",
"select": "Select",
"name": "Name",
"signIn": "Sign in",
"tag": "Tag",
@ -408,7 +409,7 @@
"Rejected"
],
"removeProjectTaskTips": "This action will delete the crontab task in {projectName}, continue?",
"publishCommitTips": "This action will rebuild {commit}, continue?"
"publishCommitTips": "This action will publish {commit}, continue?"
},
"loginPage": {
"captchaDefault": "Click on the button for check captcha",

View File

@ -1,5 +1,6 @@
{
"default": "默认",
"select": "选择",
"name": "名称",
"signIn": "登录",
"tag": "标签",
@ -354,6 +355,8 @@
"afterDeployScriptTips": "部署后在目标服务器运行的脚本\n运行方式打包成一份脚本文件\n如需重启服务请注意是否需要nohup",
"deployFinishScriptLabel": "部署完成运行脚本",
"deployFinishScriptTips": "部署完成后在宿主服务器运行的脚本\n运行方式打包成一份脚本文件\n检查服务器是否安装该脚本类型(默认以bash运行)",
"customVariableLabel": "自定义变量",
"customVariableTips": "可用在每个脚本中,构建时可选择传入参数",
"predefinedVar": "预定义变量",
"autoDeployTitle": "构建触发器:达成某种条件后自动构建发布项目",
"autoDeployGitTips": "填入连接http(s)://域名(IP)/deploy/webhook?project_id={projectId}\n勾选push event即可, (Gitlab可以选对应的分支)",
@ -379,7 +382,7 @@
"reviewTips": "此操作将通过该次提交, 是否继续?",
"reviewStateOption": ["待审", "已审", "拒审"],
"removeProjectTaskTips": "此操作删除{projectName}的定时任务, 是否继续?",
"publishCommitTips": "此操作将重新构建{commit}, 是否继续?"
"publishCommitTips": "此操作将发布\n{commit}"
},
"loginPage": {
"captchaDefault": "点击按键进行人机验证",

View File

@ -3,8 +3,19 @@
v-model="dialogVisible"
title="Commit"
:fullscreen="$store.state.app.device === 'mobile'"
:show-close="false"
:close-on-press-escape="false"
:close-on-click-modal="false"
class="commit-dialog"
>
<el-row type="flex" justify="end" @change="handleChangeType">
<el-radio-group v-model="type" style="margin-bottom: 10px">
<el-radio-button label="Commit" value="Commit" />
<el-radio-button label="Tag" value="Tag" />
</el-radio-group>
</el-row>
<el-select
v-if="type == 'Commit'"
v-model="branch"
v-loading="branchLoading"
filterable
@ -36,6 +47,17 @@
</div>
</template>
</el-table-column>
<el-table-column v-if="type == 'Tag'" prop="tag" label="tag">
<template #default="scope">
<RepoURL
style="font-size: 12px"
:url="projectRow.url"
:suffix="'/tree/' + scope.row.tag"
:text="scope.row.tag"
>
</RepoURL>
</template>
</el-table-column>
<el-table-column
prop="message"
width="155"
@ -77,7 +99,7 @@
</el-table-column>
</el-table>
<template #footer>
<el-button @click="dialogVisible = false">
<el-button @click="cancel">
{{ $t('cancel') }}
</el-button>
</template>
@ -85,7 +107,11 @@
</template>
<script lang="ts" setup>
import RepoURL from '@/components/RepoURL/index.vue'
import { RepositoryBranchList, RepositoryCommitList } from '@/api/repository'
import {
RepositoryBranchList,
RepositoryCommitList,
RepositoryTagList,
} from '@/api/repository'
import { ProjectData } from '@/api/project'
import { parseTime } from '@/utils'
import { PropType, computed, watch, ref } from 'vue'
@ -99,13 +125,16 @@ const props = defineProps({
required: true,
},
})
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(['update:modelValue', 'cancel'])
const dialogVisible = computed({
get: () => props.modelValue,
set: (val) => {
emit('update:modelValue', val)
},
})
const type = ref('Commit')
const branchLoading = ref(false)
const branchOption = ref<RepositoryBranchList['datagram']['list']>([])
const branch = ref('')
@ -152,4 +181,35 @@ const getCommitList = () => {
tableLoading.value = false
})
}
const getTagList = () => {
tableLoading.value = true
new RepositoryTagList({ id: props.projectRow.id })
.request()
.then((response) => {
tableData.value = response.data.list
})
.finally(() => {
tableLoading.value = false
})
}
function handleChangeType() {
tableData.value = []
if (type.value == 'Tag') {
getTagList()
}
}
function cancel() {
emit('cancel')
dialogVisible.value = false
}
</script>
<style lang="scss">
.commit-dialog {
.el-dialog__header {
display: none;
}
}
</style>

View File

@ -3,6 +3,9 @@
v-model="dialogVisible"
title="Tag"
:fullscreen="$store.state.app.device === 'mobile'"
:show-close="false"
:close-on-press-escape="false"
:close-on-click-modal="false"
>
<el-table
v-loading="tableLoading"
@ -76,7 +79,7 @@
</el-table-column>
</el-table>
<template #footer>
<el-button @click="dialogVisible = false">
<el-button @click="cancel">
{{ $t('cancel') }}
</el-button>
</template>
@ -97,7 +100,7 @@ const props = defineProps({
required: true,
},
})
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(['update:modelValue', 'cancel'])
const dialogVisible = computed({
get: () => props.modelValue,
set: (val) => {
@ -122,4 +125,9 @@ watch(
}
}
)
function cancel() {
emit('cancel')
dialogVisible.value = false
}
</script>

View File

@ -170,16 +170,7 @@
<el-row style="margin-top: 10px" justify="space-between">
<div>
<Button
v-if="row.deployState === DeployState.Uninitialized"
:permissions="[pms.DeployProject]"
type="primary"
size="small"
@click="publish(row)"
>
{{ $t('initial') }}
</Button>
<Button
v-else-if="row.deployState === DeployState.Deploying"
v-if="row.deployState === DeployState.Deploying"
:permissions="[pms.DeployResetState]"
type="primary"
size="small"
@ -187,38 +178,15 @@
>
{{ $t('deployPage.resetState') }}
</Button>
<Dropdown
<Button
v-else
:permissions="[pms.DeployProject]"
:split-button="row.review === 1 ? false : true"
trigger="click"
type="primary"
size="small"
@click="publish(row)"
@command="(funcName: string) => commandFunc[funcName](row)"
>
<el-button
v-if="row.review === 1"
size="small"
type="primary"
>
{{ $t('submit') }}
<el-icon class="el-icon--right">
<arrow-down />
</el-icon>
</el-button>
<span v-else>{{ $t('deploy') }}</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :command="'handleCommitCommand'">
Commit list
</el-dropdown-item>
<el-dropdown-item :command="'handleTagCommand'">
Tag list
</el-dropdown-item>
</el-dropdown-menu>
</template>
</Dropdown>
{{ $t('deploy') }}
</Button>
<el-dropdown
trigger="click"
style="margin-left: 5px"
@ -296,72 +264,110 @@
<TheCommitListDialog
v-model="commitDialogVisible"
:project-row="selectedItem"
@cancel="handleCancelSelectCommit"
>
<template #tableOP="scope">
<Button
type="primary"
:permissions="[pms.DeployProject]"
@click="publishByCommit(scope.row)"
@click="selectCommit(scope.row)"
>
{{ $t('deploy') }}
</Button>
<Button
type="warning"
:permissions="[pms.GreyDeploy]"
@click="handleGreyPublish(scope.row)"
>
{{ $t('grey') }}
{{ $t('select') }}
</Button>
</template>
</TheCommitListDialog>
<TheTagListDialog v-model="tagDialogVisible" :project-row="selectedItem">
<template #tableOP="scope">
<Button
type="primary"
:permissions="[pms.DeployProject]"
@click="publishByCommit(scope.row)"
>
{{ $t('deploy') }}
</Button>
<Button
type="warning"
:permissions="[pms.GreyDeploy]"
@click="handleGreyPublish(scope.row)"
>
{{ $t('grey') }}
</Button>
</template>
</TheTagListDialog>
<TheTaskListDialog
v-model="taskListDialogVisible"
:project-row="selectedItem"
/>
<el-dialog v-model="greyServerDialogVisible" :title="$t('deploy')">
<el-form
ref="greyServerForm"
:rules="greyServerFormRules"
:model="greyServerFormData"
>
<el-form-item :label="$t('server')" label-width="80px" prop="serverIds">
<el-checkbox-group v-model="greyServerFormData.serverIds">
<el-checkbox
v-for="(item, index) in greyServerFormProps.serverOption"
:key="index"
:label="item.serverId"
>
{{ item.server.name + '(' + item.server.description + ')' }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-form>
<el-dialog
v-model="publishDialogVisible"
:title="publishFormProps.title"
class="publish-dialog"
align-center
width="450px"
:fullscreen="$store.state.app.device === 'mobile'"
>
<template #header>
<el-row style="white-space: pre-wrap" v-html="publishFormProps.title" />
</template>
<el-row>
<el-row
v-for="(variable, index) in publishFormProps.customVariables"
:key="index"
type="flex"
align="middle"
style="width: 100%; margin-bottom: 10px"
>
<el-row style="margin-right: 10px">
<span>${</span>{{ variable.name }}<span>}</span>
</el-row>
<el-select
v-if="variable.type == 'list'"
v-model="variable.value"
style="flex: 1"
>
<el-option
v-for="item in selectedItem.script.customVariables[index].value.split(',')"
:key="item"
:label="item"
:value="item"
/>
</el-select>
<el-input
v-else
v-model.trim="variable.value"
style="flex: 1"
autocomplete="off"
placeholder="variable value"
>
</el-input>
</el-row>
<el-row style="width: 100%">
<el-checkbox
v-model="publishFormProps.selectCommit"
:label="`Select Commit (default lastest ${selectedItem.branch})`"
:disabled="publishFormProps.selectTag"
@change="handleSelectCommit"
/>
<el-row
v-show="publishFormProps.selectCommit"
style="width: 100%; padding-left: 20px"
>
{{ publishFormProps.branch }}
{{ publishFormProps.commit }}
</el-row>
</el-row>
<el-row style="width: 100%; margin-top: 10px">
<el-checkbox
v-model="publishFormProps.selectServer"
:label="`Select Server (default all)`"
@change="handleSelectServer"
/>
<el-row
v-show="publishFormProps.selectServer"
style="width: 100%; padding-left: 20px"
>
<el-checkbox-group v-model="publishFormProps.serverIds">
<el-checkbox
v-for="(item, index) in publishFormProps.serverOption"
:key="index"
:label="item.serverId"
>
{{ item.server.name + '(' + item.server.description + ')' }}
</el-checkbox>
</el-checkbox-group>
</el-row>
</el-row>
</el-row>
<template #footer>
<el-button @click="greyServerDialogVisible = false">
<el-button @click="publishDialogVisible = false">
{{ $t('cancel') }}
</el-button>
<el-button
:disabled="greyServerFormProps.disabled"
:disabled="publishFormProps.disabled"
type="primary"
@click="greyPublish"
@click="publishFormProps.func"
>
{{ $t('confirm') }}
</el-button>
@ -397,20 +403,17 @@ import {
DeployList,
DeployPublish,
DeployResetState,
DeployGreyPublish,
} from '@/api/deploy'
import { ProjectServerList, ProjectData, LabelList } from '@/api/project'
import RepoURL from '@/components/RepoURL/index.vue'
import { isLink, parseTime } from '@/utils'
import { isLink, parseTime, deepClone } from '@/utils'
import TheDetailDialog from './TheDetailDialog.vue'
import TheCommitListDialog from './TheCommitListDialog.vue'
import TheTagListDialog from './TheTagListDialog.vue'
import TheTaskListDialog from './TheTaskListDialog.vue'
import TheReviewListDialog from './TheReviewListDialog.vue'
import TheProcessManagerDialog from './TheProcessManagerDialog.vue'
import TheFileCompareDialog from './TheFileCompareDialog.vue'
import TheFileSyncDialog from './TheFileSyncDialog.vue'
import type { ElForm } from 'element-plus'
import { computed, watch, h, ref } from 'vue'
import { CommitData } from '@/api/repository'
import { useStore } from 'vuex'
@ -418,13 +421,12 @@ import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const store = useStore()
const commitDialogVisible = ref(false)
const tagDialogVisible = ref(false)
const greyServerDialogVisible = ref(false)
const taskListDialogVisible = ref(false)
const fileSyncDialogVisible = ref(false)
const fileCompareDialogVisible = ref(false)
const processManagerDialogVisible = ref(false)
const reviewListDialogVisible = ref(false)
const publishDialogVisible = ref(false)
const dialogVisible = ref(false)
const stickList = ref(getStick())
const searchProject = ref({
@ -459,26 +461,23 @@ const disabled = computed(() => noMore.value)
const tableData = ref<any[]>([])
const labelList = ref<string[]>([])
const pagination = ref({ page: 0, rows: 24 })
const greyServerForm = ref<InstanceType<typeof ElForm>>()
const greyServerFormProps = ref({
const tempPublishFormProps = {
disabled: false,
serverOption: [] as ProjectServerList['datagram']['list'],
})
const greyServerFormData = ref({
projectId: 0,
title: '',
customVariables: [],
commit: '',
branch: '',
serverIds: [],
})
const greyServerFormRules: InstanceType<typeof ElForm>['rules'] = {
serverIds: [
{
type: 'array',
required: true,
message: 'Server required',
trigger: 'change',
},
],
selectCommit: false,
selectServer: false,
serverOption: [] as ProjectServerList['datagram']['list'],
func: () => {
ElMessage.error('Undefined function')
},
}
const publishFormProps = ref(tempPublishFormProps)
const tablePage = computed(() => {
let _tableData = tableData.value
if (searchProject.value.name !== '') {
@ -663,16 +662,27 @@ function handleRebuilt() {
tableData.value[projectIndex].deployState = 1
}
function handleGreyPublish(data: CommitData) {
function handleSelectCommit(state) {
if (state == false) {
publishFormProps.value.branch = ''
publishFormProps.value.commit = ''
return
}
commitDialogVisible.value = true
}
function handleSelectServer() {
new ProjectServerList({ id: selectedItem.value.id })
.request()
.then((response) => {
greyServerFormProps.value.serverOption = response.data.list
publishFormProps.value.serverOption = response.data.list
})
// add projectID to server form
greyServerFormData.value.projectId = selectedItem.value.id
greyServerFormData.value.commit = data.commit
greyServerDialogVisible.value = true
}
function handleCancelSelectCommit(state) {
publishFormProps.value.branch = ''
publishFormProps.value.commit = ''
publishFormProps.value.selectCommit = false
}
const cardMoreFunc: { [K: string]: (data: ProjectData) => void } = {
@ -696,8 +706,6 @@ function handleUnpinCard(data: ProjectData) {
}
const commandFunc: { [K: string]: (data: ProjectData) => void } = {
handleCommitCommand,
handleTagCommand,
handleTaskCommand,
handleFileCompareCommand,
handleFileSyncCommand,
@ -705,16 +713,6 @@ const commandFunc: { [K: string]: (data: ProjectData) => void } = {
handleReviewCommand,
}
function handleCommitCommand(data: ProjectData) {
selectedItem.value = data
commitDialogVisible.value = true
}
function handleTagCommand(data: ProjectData) {
selectedItem.value = data
tagDialogVisible.value = true
}
function handleTaskCommand(data: ProjectData) {
selectedItem.value = data
taskListDialogVisible.value = true
@ -740,8 +738,14 @@ function handleReviewCommand(data: ProjectData) {
reviewListDialogVisible.value = true
}
function selectCommit(data: CommitData) {
publishFormProps.value.branch = data.branch
publishFormProps.value.commit = data.commit
commitDialogVisible.value = false
}
function publish(data: ProjectData) {
const id = data.id
restorePublishForm()
let color = ''
if (data.environment === 1) {
color = 'color: var(--el-color-danger)'
@ -750,63 +754,41 @@ function publish(data: ProjectData) {
} else {
color = 'color: var(--el-color-info)'
}
ElMessageBox.confirm('', t('tips'), {
message: h('p', null, [
h('span', null, 'Deploy: '),
h(
'b',
{ style: color },
data.name + ' - ' + t(`envOption[${data.environment}]`)
),
]),
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
})
.then(() => {
new DeployPublish({ projectId: id, commit: '', branch: '' })
.request()
.then(() => {
const projectIndex = tableData.value.findIndex(
(element) => element.id === id
)
tableData.value[projectIndex].deployState = 1
})
selectedItem.value = deepClone(data)
const customVariables = deepClone(data.script.customVariables)
publishFormProps.value.customVariables =
customVariables &&
customVariables.map((item) => {
if (item.type == 'list') {
item.value = ''
}
return item
})
.catch(() => {
ElMessage.info('Cancel')
})
}
publishDialogVisible.value = true
function publishByCommit(data: CommitData) {
ElMessageBox.confirm(
t('deployPage.publishCommitTips', { commit: data.commit }),
t('tips'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
)
.then(() => {
new DeployPublish({
projectId: selectedItem.value.id,
branch: data.branch,
commit: data.commit,
let env = t(`envOption[${data.environment}]`)
publishFormProps.value.title = `<span style="${color}; font-weight: 600; font-size: 15px">${data.name} - ${env}</span>`
publishFormProps.value.func = () => {
publishFormProps.value.disabled = true
new DeployPublish({
projectId: data.id,
commit: publishFormProps.value.commit,
branch: publishFormProps.value.branch,
customVariables: publishFormProps.value.customVariables,
serverIds: publishFormProps.value.serverIds,
})
.request()
.then(() => {
publishDialogVisible.value = false
const projectIndex = tableData.value.findIndex(
(element) => element.id === data.id
)
tableData.value[projectIndex].deployState = 1
})
.request()
.then(() => {
const projectIndex = tableData.value.findIndex(
(element) => element.id === selectedItem.value.id
)
tableData.value[projectIndex].deployState = 1
commitDialogVisible.value = false
tagDialogVisible.value = false
})
})
.catch(() => {
ElMessage.info('Cancel')
})
.finally(() => {
publishFormProps.value.disabled = false
})
}
}
function resetState(data: ProjectData) {
@ -831,48 +813,6 @@ function resetState(data: ProjectData) {
})
}
function greyPublish() {
greyServerForm.value?.validate((valid) => {
if (valid) {
const data = greyServerFormData.value
ElMessageBox.confirm(
t('deployPage.publishCommitTips', {
commit: data.commit,
}),
t('tips'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning',
}
)
.then(() => {
new DeployGreyPublish({
projectId: data.projectId,
commit: data.commit,
serverIds: data.serverIds,
})
.request()
.then(() => {
const projectIndex = tableData.value.findIndex(
(element) => element.id === data.projectId
)
tableData.value[projectIndex].deployState = 1
commitDialogVisible.value = false
tagDialogVisible.value = false
greyServerDialogVisible.value = false
})
})
.catch(() => {
ElMessage.info('Cancel')
})
return Promise.resolve(true)
} else {
return Promise.reject(false)
}
})
}
function enterToBR(detail: string) {
return detail ? detail.replace(/\n|(\r\n)/g, '<br>') : ''
}
@ -900,8 +840,28 @@ function getStick(): number[] {
function setStick(value: string) {
localStorage.setItem('deploy-stick', value)
}
</script>
function restorePublishForm() {
publishFormProps.value = { ...tempPublishFormProps }
console.log(publishFormProps.value)
}
</script>
<style lang="scss">
.publish-dialog {
.el-dialog__header {
padding: 20px 15px 10px 15px;
margin-right: 0px;
}
.el-dialog__body {
padding-top: 10px;
padding-left: 15px;
padding-bottom: 10px;
}
.el-dialog__footer {
padding: 10px 15px;
}
}
</style>
<style lang="scss" scoped>
.card {
border: none;

View File

@ -1096,6 +1096,72 @@
/>
</el-form-item>
</el-tab-pane>
<el-tab-pane name="customVariable">
<template #label>
<span style="vertical-align: middle; padding-right: 4px">
{{ $t('projectPage.customVariableLabel') }}
</span>
<el-tooltip class="item" effect="dark" placement="bottom">
<template #content>
<div style="white-space: pre-line">
{{ $t('projectPage.customVariableTips') }}
</div>
</template>
<el-icon style="vertical-align: middle" :size="16">
<question-filled />
</el-icon>
</el-tooltip>
</template>
<el-row type="flex" justify="end" style="margin-bottom: 10px">
<el-button
type="primary"
:icon="Plus"
@click="handleCusotmVariableAdd"
/>
</el-row>
<el-form-item prop="customVariableScript" label-width="0px">
<el-row
v-for="(variable, index) in formData.script.customVariables"
:key="index"
type="flex"
style="width: 100%"
>
<el-input
v-model.trim="variable.name"
style="flex: 1"
autocomplete="off"
placeholder="variable name"
>
<template #prepend>${</template>
<template #append>}</template>
</el-input>
<el-select v-model="variable.type" style="width: 200px">
<el-option
v-for="item in formProps.customVariablesType"
:key="item"
:label="item"
:value="item"
/>
</el-select>
<el-input
v-model.trim="variable.value"
style="flex: 1"
autocomplete="off"
:placeholder="
variable.type == 'list'
? 'value split by comma'
: 'default value'
"
/>
<el-button
type="warning"
:icon="Minus"
plain
@click="handleCusotmVariableDelete(index)"
/>
</el-row>
</el-form-item>
</el-tab-pane>
</el-tabs>
</el-form>
<template #footer>
@ -1208,6 +1274,7 @@ import {
View,
Link,
Plus,
Minus,
Edit,
QuestionFilled,
Files,
@ -1315,6 +1382,7 @@ const formProps = ref({
pinging: false,
lsBranchLoading: false,
tab: 'base',
customVariablesType: ['string', 'list'],
})
const tempFormData = {
id: 0,
@ -1329,6 +1397,7 @@ const tempFormData = {
afterPull: { mode: '', content: '' },
afterDeploy: { mode: '', content: '' },
deployFinish: { mode: '', content: '' },
customVariables: [] as { name: string; value: string; type: string }[],
},
environment: 1,
branch: '',
@ -1509,6 +1578,21 @@ function handleAutoDeploy(data: ProjectData) {
autoDeployFormData.value.autoDeploy = data.autoDeploy
}
function handleCusotmVariableAdd() {
if (!formData.value.script.customVariables) {
formData.value.script.customVariables = []
}
formData.value.script.customVariables.push({
name: '',
value: '',
type: 'string',
})
}
function handleCusotmVariableDelete(index: number) {
formData.value.script.customVariables.splice(index, 1)
}
enum ScriptKey {
AfterPull = 'afterPull',
AfterDeploy = 'afterDeploy',