mirror of
https://gitee.com/goploy/goploy.git
synced 2024-11-30 03:07:59 +08:00
A show publish info
This commit is contained in:
parent
2ecf1a7516
commit
79cba51e21
@ -34,6 +34,8 @@ type PublishTraces []PublishTrace
|
||||
|
||||
// publish trace state
|
||||
const (
|
||||
QUEUE = 0
|
||||
|
||||
BeforePull = 1
|
||||
|
||||
Pull = 2
|
||||
@ -182,10 +184,14 @@ func (pt PublishTrace) GetPreview(
|
||||
pagination Pagination,
|
||||
) (PublishTraces, Pagination, error) {
|
||||
builder := sq.
|
||||
Select("id, token, project_id, project_name, state, publisher_id, publisher_name, type, ext, insert_time, update_time").
|
||||
Column("!EXISTS (SELECT id FROM " + publishTraceTable + " AS pt where pt.state = 0 AND pt.token = publish_trace.token) as publish_state").
|
||||
From(publishTraceTable).
|
||||
Where(sq.Eq{"type": Pull})
|
||||
Select(
|
||||
"token",
|
||||
"MIN(publisher_name) publisher_name",
|
||||
"MIN(state) publish_state",
|
||||
"GROUP_CONCAT(IF(type = 2 and ext != '', JSON_EXTRACT(ext, '$.commit') , '') SEPARATOR '') as ext",
|
||||
"MIN(update_time) update_time",
|
||||
).
|
||||
From(publishTraceTable)
|
||||
if pt.ProjectID != 0 {
|
||||
builder = builder.Where(sq.Eq{"project_id": pt.ProjectID})
|
||||
}
|
||||
@ -211,6 +217,7 @@ func (pt PublishTrace) GetPreview(
|
||||
builder = builder.Having(sq.Eq{"publish_state": pt.PublishState})
|
||||
}
|
||||
rows, err := builder.RunWith(DB).
|
||||
GroupBy("token").
|
||||
OrderBy("update_time DESC").
|
||||
Limit(pagination.Rows).
|
||||
Offset((pagination.Page - 1) * pagination.Rows).
|
||||
@ -223,18 +230,11 @@ func (pt PublishTrace) GetPreview(
|
||||
var publishTrace PublishTrace
|
||||
|
||||
if err := rows.Scan(
|
||||
&publishTrace.ID,
|
||||
&publishTrace.Token,
|
||||
&publishTrace.ProjectID,
|
||||
&publishTrace.ProjectName,
|
||||
&publishTrace.State,
|
||||
&publishTrace.PublisherID,
|
||||
&publishTrace.PublisherName,
|
||||
&publishTrace.Type,
|
||||
&publishTrace.PublishState,
|
||||
&publishTrace.Ext,
|
||||
&publishTrace.InsertTime,
|
||||
&publishTrace.UpdateTime,
|
||||
&publishTrace.PublishState); err != nil {
|
||||
&publishTrace.UpdateTime); err != nil {
|
||||
return nil, pagination, err
|
||||
}
|
||||
publishTraces = append(publishTraces, publishTrace)
|
||||
|
@ -5,7 +5,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/zhenorzz/goploy/core"
|
||||
"github.com/zhenorzz/goploy/model"
|
||||
@ -52,7 +51,7 @@ func (rt rsyncTransmitter) Args() []string {
|
||||
|
||||
func (rt rsyncTransmitter) String() string {
|
||||
logRsyncCmd := regexp.MustCompile(`sshpass -p .*\s`).
|
||||
ReplaceAllString("rsync "+strings.Join(rt.Args(), " "), "sshpass -p ***** ")
|
||||
ReplaceAllString(exec.Command("rsync", rt.Args()...).String(), "sshpass -p ***** ")
|
||||
return logRsyncCmd
|
||||
}
|
||||
|
||||
@ -60,11 +59,9 @@ func (rt rsyncTransmitter) Exec() (string, error) {
|
||||
// example
|
||||
// rsync -rtv -e "ssh -o StrictHostKeyChecking=no -p 22 -i C:\Users\Administrator\.ssh\id_rsa" --rsync-path="mkdir -p /data/www/test && rsync" ./main.go root@127.0.0.1:/tmp/test/
|
||||
cmd := exec.Command("rsync", rt.Args()...)
|
||||
var outbuf, errbuf bytes.Buffer
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
if err := cmd.Run(); err != nil {
|
||||
return outbuf.String(), errors.New("err: " + err.Error() + ", detail: " + errbuf.String())
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return "", errors.New("err: " + err.Error() + "\noutput: " + string(output))
|
||||
} else {
|
||||
return string(output), nil
|
||||
}
|
||||
return outbuf.String(), nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package task
|
||||
import (
|
||||
"container/list"
|
||||
"github.com/zhenorzz/goploy/config"
|
||||
"github.com/zhenorzz/goploy/model"
|
||||
"github.com/zhenorzz/goploy/service"
|
||||
"github.com/zhenorzz/goploy/ws"
|
||||
"sync"
|
||||
@ -49,8 +50,25 @@ func startDeployTask() {
|
||||
|
||||
func AddDeployTask(gsync service.Gsync) {
|
||||
ws.GetHub().Data <- &ws.Data{
|
||||
Type: ws.TypeProject,
|
||||
Message: ws.ProjectMessage{ProjectID: gsync.Project.ID, ProjectName: gsync.Project.Name, State: ws.TaskWaiting, Message: "Task waiting"},
|
||||
Type: ws.TypeProject,
|
||||
Message: ws.ProjectMessage{
|
||||
ProjectID: gsync.Project.ID,
|
||||
ProjectName: gsync.Project.Name,
|
||||
State: ws.TaskWaiting,
|
||||
Message: "Task waiting",
|
||||
Ext: struct {
|
||||
LastPublishToken string `json:"lastPublishToken"`
|
||||
}{gsync.Project.LastPublishToken},
|
||||
},
|
||||
}
|
||||
model.PublishTrace{
|
||||
Token: gsync.Project.LastPublishToken,
|
||||
ProjectID: gsync.Project.ID,
|
||||
ProjectName: gsync.Project.Name,
|
||||
PublisherID: gsync.UserInfo.ID,
|
||||
PublisherName: gsync.UserInfo.Name,
|
||||
Type: model.QUEUE,
|
||||
State: model.Success,
|
||||
}.AddRow()
|
||||
deployList.PushBack(gsync)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import { logout } from '@/utils/auth'
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API, // url = base url + request url
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 5000, // request timeout
|
||||
timeout: 60000, // request timeout
|
||||
})
|
||||
|
||||
// request interceptor
|
||||
|
@ -18,7 +18,8 @@ export interface ProjectData {
|
||||
afterPullScript: string
|
||||
afterDeployScriptMode: string
|
||||
afterDeployScript: string
|
||||
rsyncOption: string
|
||||
transferType: string
|
||||
transferOption: string
|
||||
autoDeploy: number
|
||||
publisherId: number
|
||||
publisherName: string
|
||||
@ -158,7 +159,8 @@ export class ProjectAdd extends Request {
|
||||
afterPullScript: string
|
||||
afterDeployScriptMode: string
|
||||
afterDeployScript: string
|
||||
rsyncOption: string
|
||||
transferType: string
|
||||
transferOption: string
|
||||
serverIds: number[]
|
||||
userIds: number[]
|
||||
notifyType: number
|
||||
@ -188,7 +190,8 @@ export class ProjectEdit extends Request {
|
||||
afterPullScript: string
|
||||
afterDeployScriptMode: string
|
||||
afterDeployScript: string
|
||||
rsyncOption: string
|
||||
transferType: string
|
||||
transferOption: string
|
||||
notifyType: number
|
||||
notifyTarget: string
|
||||
}
|
||||
|
2
web/src/icons/svg/check.svg
Normal file
2
web/src/icons/svg/check.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1652436746546" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8557" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
|
||||
</style></defs><path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474c-6.1-7.7-15.3-12.2-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1 0.4-12.8-6.3-12.8z" p-id="8558"></path></svg>
|
After Width: | Height: | Size: 913 B |
2
web/src/icons/svg/close.svg
Normal file
2
web/src/icons/svg/close.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1652436937346" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8696" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
|
||||
</style></defs><path d="M563.8 512l262.5-312.9c4.4-5.2 0.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9c-4.4 5.2-0.7 13.1 6.1 13.1h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z" p-id="8697"></path></svg>
|
After Width: | Height: | Size: 1.0 KiB |
@ -299,8 +299,11 @@
|
||||
"projectPage": {
|
||||
"testConnection": "Test",
|
||||
"lishBranch": "List branch",
|
||||
"transferType": "Transfer type",
|
||||
"transferOption": "Transfer option",
|
||||
"scriptMode": "Script mode",
|
||||
"rsyncDoc": "https://linux.die.net/man/1/rsync",
|
||||
"sftpDoc": "https://docs.goploy.icu/#/en/dependency/sftp",
|
||||
"deployNotice": "Deploy notice",
|
||||
"publishReview": "Review",
|
||||
"reviewFooterTips": "Only members deploy projects will trigger review\n1. Go to the Deploy page for review\n2. Push to URL:http(s)://domain?custom-param=1&callback=***\n3. Access the callback value\nRepeated access callback will only be published once",
|
||||
|
@ -295,8 +295,11 @@
|
||||
"projectPage": {
|
||||
"testConnection": "测试连接",
|
||||
"lishBranch": "列出分支",
|
||||
"transferType": "传输方式",
|
||||
"transferOption": "传输选项",
|
||||
"scriptMode": "脚本类型",
|
||||
"rsyncDoc": "https://docs.goploy.icu/#/dependency/rsync",
|
||||
"sftpDoc": "https://docs.goploy.icu/#/dependency/sftp",
|
||||
"deployNotice": "构建通知",
|
||||
"publishReview": "发布审核",
|
||||
"reviewFooterTips": "只有成员构建项目才会触发审核\n审核方式:\n1. 前往构建发布页面进行审核\n2. 推送到URL:http(s)://domain?custom-param=1&callback=***\n3. http get callback的值即可完成审核\n重复访问callback只会发布一次,并且发布过不会再次发布",
|
||||
|
@ -3,7 +3,8 @@
|
||||
v-model="dialogVisible"
|
||||
:title="$t('detail')"
|
||||
:fullscreen="$store.state.app.device === 'mobile'"
|
||||
@close="filterInpurtVisible = false"
|
||||
width="75%"
|
||||
@close="onClose"
|
||||
>
|
||||
<el-row type="flex">
|
||||
<div v-loading="filterloading" class="publish-preview">
|
||||
@ -152,14 +153,27 @@
|
||||
<el-radio class="publish-commit" :label="item.token" border>
|
||||
<span class="publish-name">{{ item.publisherName }}</span>
|
||||
<span class="publish-commitID">
|
||||
commitID: {{ item.commit }}
|
||||
<span v-if="projectRow.repoType === 'svn'">
|
||||
revision: {{ item['commit'] }}
|
||||
</span>
|
||||
<span v-else-if="projectRow.repoType === 'sftp'">
|
||||
uuid: {{ item['token'].substring(0, 6) }}
|
||||
</span>
|
||||
<span v-else-if="projectRow.repoType === 'ftp'">
|
||||
uuid: {{ item['token'].substring(0, 6) }}
|
||||
</span>
|
||||
<span v-else>commitID: {{ item['commit'] }}</span>
|
||||
</span>
|
||||
<span
|
||||
<SvgIcon
|
||||
v-if="item.publishState === 1"
|
||||
class="icon-success"
|
||||
style="float: right"
|
||||
/>
|
||||
<span v-else class="icon-fail" style="float: right" />
|
||||
style="color: #67c23a; font-size: 15px; float: right"
|
||||
icon-class="check"
|
||||
></SvgIcon>
|
||||
<SvgIcon
|
||||
v-else
|
||||
style="color: #f56c6c; font-size: 15px; float: right"
|
||||
icon-class="close"
|
||||
></SvgIcon>
|
||||
</el-radio>
|
||||
<el-button type="danger" plain @click="rebuild(item)">
|
||||
rollback
|
||||
@ -240,11 +254,8 @@
|
||||
<div>Script:</div>
|
||||
<pre style="white-space: pre-line">{{ item.script }}</pre>
|
||||
</el-row>
|
||||
<el-row
|
||||
v-loading="traceDetail[item.id] === ''"
|
||||
style="margin: 5px 0"
|
||||
>
|
||||
<span style="padding: 5px 0">[goploy ~]#</span>
|
||||
<div v-loading="traceDetail[item.id] === ''" style="margin: 5px 0">
|
||||
<span>[goploy ~]#</span>
|
||||
<el-button
|
||||
v-if="item.state === 1 && !(item.id in traceDetail)"
|
||||
type="text"
|
||||
@ -255,7 +266,7 @@
|
||||
<span v-else style="white-space: pre-line; padding: 5px 0">
|
||||
{{ traceDetail[item.id] }}
|
||||
</span>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tabs v-model="activeRomoteTracePane" style="width: 100%">
|
||||
@ -295,7 +306,9 @@
|
||||
</template>
|
||||
<template v-else-if="trace.type === 5">
|
||||
<el-row style="margin: 5px 0" class="project-title">
|
||||
<span style="margin-right: 5px">Rsync</span>
|
||||
<span style="margin-right: 5px">
|
||||
{{ projectRow.transferType.toUpperCase() }}
|
||||
</span>
|
||||
<span v-if="trace.state === 1" class="icon-success"></span>
|
||||
<span v-else class="icon-fail"></span>
|
||||
</el-row>
|
||||
@ -353,7 +366,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Search, Refresh, Close } from '@element-plus/icons-vue'
|
||||
import { Search, Refresh, Check, Close, Loading } from '@element-plus/icons-vue'
|
||||
import RepoURL from '@/components/RepoURL/index.vue'
|
||||
import {
|
||||
DeployPreviewList,
|
||||
@ -506,11 +519,8 @@ const getPreviewList = (projectId: number) => {
|
||||
.then((response) => {
|
||||
gitTraceList.value = response.data.list.map((item) => {
|
||||
let element = <PublishTraceData & PublishTraceExt>item
|
||||
if (element.ext !== '') {
|
||||
Object.assign(element, JSON.parse(element.ext))
|
||||
element.commit = element['commit']
|
||||
? element['commit'].substring(0, 6)
|
||||
: ''
|
||||
if (element.ext) {
|
||||
element.commit = element.ext.replaceAll('"', '').substring(0, 6)
|
||||
}
|
||||
return element
|
||||
})
|
||||
@ -540,8 +550,9 @@ const handlePageChange = (page: number) => {
|
||||
|
||||
const traceLoading = ref(false)
|
||||
const activeRomoteTracePane = ref('')
|
||||
const getPublishTrace = (publishToken: string) => {
|
||||
traceLoading.value = true
|
||||
let timeout: ReturnType<typeof setInterval>
|
||||
function getPublishTrace(publishToken: string) {
|
||||
traceLoading.value = true && !timeout
|
||||
new DeployTrace({ lastPublishToken: publishToken })
|
||||
.request()
|
||||
.then((response) => {
|
||||
@ -567,12 +578,28 @@ const getPublishTrace = (publishToken: string) => {
|
||||
publishRemoteTraceList.value[trace.serverName].push(trace)
|
||||
}
|
||||
activeRomoteTracePane.value = Object.keys(publishRemoteTraceList.value)[0]
|
||||
if (props.projectRow.lastPublishToken === publishToken) {
|
||||
if (props.projectRow.deployState === 1 && !timeout) {
|
||||
timeout = setInterval(() => {
|
||||
getPublishTrace(publishToken)
|
||||
}, 1000)
|
||||
} else if (props.projectRow.deployState !== 1) {
|
||||
clearInterval(timeout)
|
||||
}
|
||||
} else {
|
||||
clearInterval(timeout)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
traceLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
filterInpurtVisible.value = false
|
||||
clearInterval(timeout)
|
||||
}
|
||||
|
||||
const handleTraceChange: InstanceType<typeof ElRadioGroup>['onChange'] = (
|
||||
lastPublishToken
|
||||
) => {
|
||||
|
@ -178,7 +178,7 @@
|
||||
<template v-else-if="trace.type === 5">
|
||||
<el-row style="margin: 5px 0">
|
||||
<div class="project-title">
|
||||
<span style="margin-right: 5px">Rsync</span>
|
||||
<span style="margin-right: 5px">Sync</span>
|
||||
<span v-if="trace.state === 1" class="icon-success"></span>
|
||||
<span v-else class="icon-fail"></span>
|
||||
</div>
|
||||
|
@ -256,19 +256,39 @@
|
||||
</el-button>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item prop="rsyncOption">
|
||||
<template #label>
|
||||
<el-link
|
||||
type="primary"
|
||||
:href="$t('projectPage.rsyncDoc')"
|
||||
target="_blank"
|
||||
>
|
||||
Rsync<br />
|
||||
[OPTION...]
|
||||
</el-link>
|
||||
</template>
|
||||
<el-form-item
|
||||
:label="$t('projectPage.transferType')"
|
||||
prop="transferType"
|
||||
>
|
||||
<el-radio-group v-model="formData.transferType">
|
||||
<el-radio :label="'rsync'">
|
||||
rsync
|
||||
<el-link
|
||||
:underline="false"
|
||||
:href="$t('projectPage.rsyncDoc')"
|
||||
target="_blank"
|
||||
:icon="QuestionFilled"
|
||||
style="color: #666"
|
||||
/>
|
||||
</el-radio>
|
||||
<el-radio :label="'sftp'">
|
||||
sftp
|
||||
<el-link
|
||||
:underline="false"
|
||||
:href="$t('projectPage.sftpDoc')"
|
||||
target="_blank"
|
||||
:icon="QuestionFilled"
|
||||
style="color: #666"
|
||||
/>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('projectPage.transferOption')"
|
||||
prop="transferOption"
|
||||
>
|
||||
<el-input
|
||||
v-model="formData.rsyncOption"
|
||||
v-model="formData.transferOption"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
autocomplete="off"
|
||||
@ -809,7 +829,8 @@ const tempFormData = {
|
||||
afterDeployScript: '',
|
||||
environment: 1,
|
||||
branch: '',
|
||||
rsyncOption: '-rtv --exclude .git',
|
||||
transferType: 'rsync',
|
||||
transferOption: '-rtv --exclude .git',
|
||||
serverIds: [] as number[],
|
||||
userIds: [] as number[],
|
||||
review: 0,
|
||||
|
Loading…
Reference in New Issue
Block a user