mirror of
https://gitee.com/goploy/goploy.git
synced 2024-11-30 11:17:50 +08:00
A 灰度发布
This commit is contained in:
parent
d6f92b9136
commit
da796cba8c
@ -196,6 +196,61 @@ func (Deploy) Publish(gp *core.Goploy) *core.Response {
|
||||
return &core.Response{}
|
||||
}
|
||||
|
||||
// GreyPublish the project
|
||||
func (Deploy) GreyPublish(gp *core.Goploy) *core.Response {
|
||||
type ReqData struct {
|
||||
ProjectID int64 `json:"projectId" validate:"gt=0"`
|
||||
Commit string `json:"commit"`
|
||||
ServerIDs []int64 `json:"serverIds"`
|
||||
}
|
||||
var reqData ReqData
|
||||
if err := verify(gp.Body, &reqData); err != nil {
|
||||
return &core.Response{Code: core.Error, Message: err.Error()}
|
||||
}
|
||||
var err error
|
||||
project, err := model.Project{ID: reqData.ProjectID}.GetData()
|
||||
|
||||
if err != nil {
|
||||
return &core.Response{Code: core.Error, Message: err.Error()}
|
||||
}
|
||||
if project.DeployState == model.ProjectDeploying {
|
||||
return &core.Response{Code: core.Error, Message: "project is being build"}
|
||||
}
|
||||
|
||||
bindProjectServers, err := model.ProjectServer{ProjectID: project.ID}.GetBindServerListByProjectID()
|
||||
|
||||
if err != nil {
|
||||
return &core.Response{Code: core.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 &core.Response{Code: core.Error, Message: err.Error()}
|
||||
}
|
||||
go service.Sync{
|
||||
UserInfo: gp.UserInfo,
|
||||
Project: project,
|
||||
ProjectServers: projectServers,
|
||||
CommitID: reqData.Commit,
|
||||
}.Exec()
|
||||
|
||||
return &core.Response{}
|
||||
}
|
||||
|
||||
func (Deploy) Review(gp *core.Goploy) *core.Response {
|
||||
type ReqData struct {
|
||||
ProjectReviewID int64 `json:"projectReviewId" validate:"gt=0"`
|
||||
|
@ -80,6 +80,7 @@ func Init() *router.Router {
|
||||
rt.Add("/deploy/getPreview", http.MethodGet, controller.Deploy{}.GetPreview)
|
||||
rt.Add("/deploy/review", http.MethodPost, controller.Deploy{}.Review).Roles([]string{core.RoleAdmin, core.RoleManager, core.RoleGroupManager})
|
||||
rt.Add("/deploy/publish", http.MethodPost, controller.Deploy{}.Publish, middleware.HasPublishAuth)
|
||||
rt.Add("/deploy/greyPublish", http.MethodPost, controller.Deploy{}.GreyPublish, middleware.HasPublishAuth).Roles([]string{core.RoleAdmin, core.RoleManager, core.RoleGroupManager})
|
||||
rt.Add("/deploy/webhook", http.MethodPost, controller.Deploy{}.Webhook, middleware.FilterEvent)
|
||||
rt.Add("/deploy/callback", http.MethodGet, controller.Deploy{}.Callback)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* @param {string} projectName
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function getList(projectName) {
|
||||
@ -12,7 +13,7 @@ export function getList(projectName) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {int} id
|
||||
* @param {string} lastPublishToken
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function getDetail(lastPublishToken) {
|
||||
@ -26,7 +27,8 @@ export function getDetail(lastPublishToken) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {int} id
|
||||
* @param {object} pagination
|
||||
* @param {object} params
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function getPreview({ page, rows }, params) {
|
||||
@ -66,7 +68,8 @@ export function getTagList(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {int} id
|
||||
* @param {int} projectId
|
||||
* @param {string} commit
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function publish(projectId, commit) {
|
||||
@ -78,7 +81,22 @@ export function publish(projectId, commit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {int} id
|
||||
* @param {int} projectId
|
||||
* @param {string} commit
|
||||
* @param {Array} serverIds
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function greyPublish(projectId, commit, serverIds) {
|
||||
return request({
|
||||
url: '/deploy/greyPublish',
|
||||
method: 'post',
|
||||
data: { projectId, commit, serverIds }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {int} projectReviewId
|
||||
* @param {int} state
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function review(projectReviewId, state) {
|
||||
@ -88,15 +106,3 @@ export function review(projectReviewId, state) {
|
||||
data: { projectReviewId, state }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {int} id
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function rollback(projectId, commit) {
|
||||
return request({
|
||||
url: '/deploy/rollback',
|
||||
method: 'post',
|
||||
data: { projectId, commit }
|
||||
})
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ export default {
|
||||
func: 'Func',
|
||||
param: 'Param',
|
||||
deploy: 'Deploy',
|
||||
grey: 'Grey',
|
||||
initial: 'Initial',
|
||||
search: 'Search',
|
||||
tips: 'Tips',
|
||||
@ -180,6 +181,6 @@ export default {
|
||||
reviewTips: 'This action will approve commit, continue?',
|
||||
reviewStateOption: ['Wait', 'Reviewed', 'Rejected'],
|
||||
removeProjectTaskTips: 'This action will delete the crontab task in {projectName}, continue?',
|
||||
rollbackTips: 'This action will rebuild {commit}, continue?'
|
||||
publishCommitTips: 'This action will rebuild {commit}, continue?'
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ export default {
|
||||
func: '功能',
|
||||
param: '参数',
|
||||
deploy: '构建',
|
||||
grey: '灰度',
|
||||
initial: '初始化',
|
||||
search: '搜索',
|
||||
tips: '提示',
|
||||
@ -191,6 +192,6 @@ export default {
|
||||
reviewTips: '此操作将通过该次提交, 是否继续?',
|
||||
reviewStateOption: ['待审', '已审', '拒审'],
|
||||
removeProjectTaskTips: '此操作删除{projectName}的定时任务, 是否继续?',
|
||||
rollbackTips: '此操作将重新构建{commit}, 是否继续?'
|
||||
publishCommitTips: '此操作将重新构建{commit}, 是否继续?'
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@
|
||||
<!-- <span v-if="item.publishState === 1" style="color:#67C23A;float:right;">{{ $t('success') }}</span>
|
||||
<span v-else style="color:#F56C6C;float:right;">{{ $t('fail') }}</span> -->
|
||||
</el-radio>
|
||||
<el-button type="danger" plain @click="rollback(item)">rebuild</el-button>
|
||||
<el-button type="danger" plain @click="publishByCommit(item)">rebuild</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-radio-group>
|
||||
@ -255,9 +255,10 @@
|
||||
{{ parseTime(scope.row.timestamp) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operation" :label="$t('op')" width="80" align="center" fixed="right">
|
||||
<el-table-column prop="operation" :label="$t('op')" width="160" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" @click="rollback(scope.row)">{{ $t('deploy') }}</el-button>
|
||||
<el-button type="danger" @click="publishByCommit(scope.row)">{{ $t('deploy') }}</el-button>
|
||||
<el-button v-if="!isMember()" type="warning" @click="handleGreyPublish(scope.row)">{{ $t('grey') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -312,9 +313,10 @@
|
||||
{{ parseTime(scope.row.timestamp) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="operation" :label="$t('op')" width="80" align="center" fixed="right">
|
||||
<el-table-column prop="operation" :label="$t('op')" width="160" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" @click="rollback(scope.row)">{{ $t('deploy') }}</el-button>
|
||||
<el-button type="danger" @click="publishByCommit(scope.row)">{{ $t('deploy') }}</el-button>
|
||||
<el-button v-if="!isMember()" type="warning" @click="handleGreyPublish(scope.row)">{{ $t('grey') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -322,6 +324,25 @@
|
||||
<el-button @click="tagDialogVisible = false">{{ $t('cancel') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog :title="$t('deploy')" :visible.sync="greyServerDialogVisible">
|
||||
<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.serverName+ '(' + item.serverDescription + ')' }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="greyServerDialogVisible = false">{{ $t('cancel') }}</el-button>
|
||||
<el-button :disabled="greyServerFormProps.disabled" type="primary" @click="greyPublish">{{ $t('confirm') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog :title="$t('manage')" :visible.sync="taskListDialogVisible">
|
||||
<el-row class="app-bar" type="flex" justify="end">
|
||||
<el-button type="primary" icon="el-icon-plus" @click="handleAddProjectTask(selectedItem)" />
|
||||
@ -473,8 +494,8 @@
|
||||
</template>
|
||||
<script>
|
||||
import tableHeight from '@/mixin/tableHeight'
|
||||
import { getList, getDetail, getPreview, getCommitList, getTagList, publish, review } from '@/api/deploy'
|
||||
import { addTask, editTask, removeTask, getTaskList, getReviewList } from '@/api/project'
|
||||
import { getList, getDetail, getPreview, getCommitList, getTagList, publish, review, greyPublish } from '@/api/deploy'
|
||||
import { addTask, editTask, removeTask, getTaskList, getBindServerList, getReviewList } from '@/api/project'
|
||||
import { getUserOption } from '@/api/namespace'
|
||||
import { parseTime, parseGitURL } from '@/utils'
|
||||
|
||||
@ -489,6 +510,7 @@ export default {
|
||||
publishToken: '',
|
||||
commitDialogVisible: false,
|
||||
tagDialogVisible: false,
|
||||
greyServerDialogVisible: false,
|
||||
taskDialogVisible: false,
|
||||
taskListDialogVisible: false,
|
||||
reviewDialogVisible: false,
|
||||
@ -556,6 +578,20 @@ export default {
|
||||
commitTableData: [],
|
||||
tagTableLoading: false,
|
||||
tagTableData: [],
|
||||
greyServerFormProps: {
|
||||
disabled: false,
|
||||
serverOption: []
|
||||
},
|
||||
greyServerFormData: {
|
||||
projectId: 0,
|
||||
commit: 0,
|
||||
serverIds: []
|
||||
},
|
||||
greyServerFormRules: {
|
||||
serverIds: [
|
||||
{ type: 'array', required: true, message: 'Server required', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
publishTraceList: [],
|
||||
publishLocalTraceList: [],
|
||||
publishRemoteTraceList: {},
|
||||
@ -667,37 +703,6 @@ export default {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
publish(data) {
|
||||
const id = data.id
|
||||
const h = this.$createElement
|
||||
let color = ''
|
||||
if (data.environment === 1) {
|
||||
color = 'color: #F56C6C'
|
||||
} else if (data.environment === 3) {
|
||||
color = 'color: #E6A23C'
|
||||
} else {
|
||||
color = 'color: #909399'
|
||||
}
|
||||
this.$confirm('', this.$i18n.t('tips'), {
|
||||
message: h('p', null, [
|
||||
h('span', null, 'Deploy Project: '),
|
||||
h('b', { style: color }, data.name + ' - ' + this.$i18n.t(`envOption[${data.environment}]`))
|
||||
]),
|
||||
confirmButtonText: this.$i18n.t('confirm'),
|
||||
cancelButtonText: this.$i18n.t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.gitLog = []
|
||||
this.remoteLog = {}
|
||||
publish(id, '').then((response) => {
|
||||
const projectIndex = this.tableData.findIndex(element => element.id === id)
|
||||
this.tableData[projectIndex].deployState = 1
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message.info('Cancel')
|
||||
})
|
||||
},
|
||||
|
||||
getDetail() {
|
||||
getDetail(this.publishToken).then((response) => {
|
||||
const publishTraceList = response.data.publishTraceList || []
|
||||
@ -765,6 +770,16 @@ export default {
|
||||
this.getDetail()
|
||||
},
|
||||
|
||||
handleGreyPublish(data) {
|
||||
getBindServerList(data.projectId).then((response) => {
|
||||
this.greyServerFormProps.serverOption = response.data.list
|
||||
})
|
||||
// 先把projectID写入添加服务器的表单
|
||||
this.greyServerFormData.projectId = data.projectId
|
||||
this.greyServerFormData.commit = data.commit
|
||||
this.greyServerDialogVisible = true
|
||||
},
|
||||
|
||||
getCommitList(data) {
|
||||
const id = data.id
|
||||
this.commitDialogVisible = true
|
||||
@ -953,8 +968,39 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
rollback(data) {
|
||||
this.$confirm(this.$i18n.t('deployPage.rollbackTips', { commit: data.commit }), this.$i18n.t('tips'), {
|
||||
publish(data) {
|
||||
const id = data.id
|
||||
const h = this.$createElement
|
||||
let color = ''
|
||||
if (data.environment === 1) {
|
||||
color = 'color: #F56C6C'
|
||||
} else if (data.environment === 3) {
|
||||
color = 'color: #E6A23C'
|
||||
} else {
|
||||
color = 'color: #909399'
|
||||
}
|
||||
this.$confirm('', this.$i18n.t('tips'), {
|
||||
message: h('p', null, [
|
||||
h('span', null, 'Deploy Project: '),
|
||||
h('b', { style: color }, data.name + ' - ' + this.$i18n.t(`envOption[${data.environment}]`))
|
||||
]),
|
||||
confirmButtonText: this.$i18n.t('confirm'),
|
||||
cancelButtonText: this.$i18n.t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.gitLog = []
|
||||
this.remoteLog = {}
|
||||
publish(id, '').then((response) => {
|
||||
const projectIndex = this.tableData.findIndex(element => element.id === id)
|
||||
this.tableData[projectIndex].deployState = 1
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message.info('Cancel')
|
||||
})
|
||||
},
|
||||
|
||||
publishByCommit(data) {
|
||||
this.$confirm(this.$i18n.t('deployPage.publishCommitTips', { commit: data.commit }), this.$i18n.t('tips'), {
|
||||
confirmButtonText: this.$i18n.t('confirm'),
|
||||
cancelButtonText: this.$i18n.t('cancel'),
|
||||
type: 'warning'
|
||||
@ -963,6 +1009,7 @@ export default {
|
||||
const projectIndex = this.tableData.findIndex(element => element.id === data.projectId)
|
||||
this.tableData[projectIndex].deployState = 1
|
||||
this.commitDialogVisible = false
|
||||
this.tagDialogVisible = false
|
||||
this.dialogVisible = false
|
||||
})
|
||||
}).catch(() => {
|
||||
@ -970,6 +1017,31 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
greyPublish() {
|
||||
this.$refs.greyServerForm.validate((valid) => {
|
||||
if (valid) {
|
||||
const data = this.greyServerFormData
|
||||
this.$confirm(this.$i18n.t('deployPage.publishCommitTips', { commit: data.commit }), this.$i18n.t('tips'), {
|
||||
confirmButtonText: this.$i18n.t('confirm'),
|
||||
cancelButtonText: this.$i18n.t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
greyPublish(data.projectId, data.commit, data.serverIds).then((response) => {
|
||||
const projectIndex = this.tableData.findIndex(element => element.id === data.projectId)
|
||||
this.tableData[projectIndex].deployState = 1
|
||||
this.commitDialogVisible = false
|
||||
this.tagDialogVisible = false
|
||||
this.greyServerDialogVisible = false
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message.info('Cancel')
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
formatDetail(detail) {
|
||||
return detail ? detail.replace(/\n|(\r\n)/g, '<br>') : ''
|
||||
}
|
||||
|
@ -345,8 +345,8 @@
|
||||
</el-dialog>
|
||||
<el-dialog :title="$t('add')" :visible.sync="dialogAddServerVisible">
|
||||
<el-form ref="addServerForm" :rules="addServerFormRules" :model="addServerFormData">
|
||||
<el-form-item :label="$t('server')" label-width="120px" prop="serverIds">
|
||||
<el-select v-model="addServerFormData.serverIds" multiple>
|
||||
<el-form-item :label="$t('server')" label-width="80px" prop="serverIds">
|
||||
<el-select v-model="addServerFormData.serverIds" multiple style="width: 100%">
|
||||
<el-option
|
||||
v-for="(item, index) in serverOption"
|
||||
:key="index"
|
||||
@ -363,8 +363,8 @@
|
||||
</el-dialog>
|
||||
<el-dialog :title="$t('add')" :visible.sync="dialogAddUserVisible">
|
||||
<el-form ref="addUserForm" :rules="addUserFormRules" :model="addUserFormData">
|
||||
<el-form-item :label="$t('member')" label-width="120px" prop="userIds">
|
||||
<el-select v-model="addUserFormData.userIds" multiple>
|
||||
<el-form-item :label="$t('member')" label-width="80px" prop="userIds">
|
||||
<el-select v-model="addUserFormData.userIds" multiple style="width: 100%">
|
||||
<el-option
|
||||
v-for="(item, index) in userOption.filter(item => [$global.Admin, $global.Manager].indexOf(item.role) === -1)"
|
||||
:key="index"
|
||||
|
Loading…
Reference in New Issue
Block a user