refactor(devops): 重构流水线相关代码
- 新增 WebSocket 消息解析工具类 WsMessageUtil - 添加流水线实例节点明细查询功能 - 优化流水线重试逻辑,支持指定节点重试 - 新增多个流水线节点处理服务类 - 调整流水线模板获取方式 - 优化流水线状态检查逻辑
This commit is contained in:
@@ -8,6 +8,14 @@ export function startPipeline(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function retryPipeline(data) {
|
||||||
|
return request({
|
||||||
|
url: 'api/devops/pipelineInstance/retry',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function restartPipeline(data) {
|
export function restartPipeline(data) {
|
||||||
return request({
|
return request({
|
||||||
url: 'api/devops/pipelineInstance/restart',
|
url: 'api/devops/pipelineInstance/restart',
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 在modules中定义后,需要到这注册
|
||||||
|
* @type {any}
|
||||||
|
*/
|
||||||
const getters = {
|
const getters = {
|
||||||
deployUploadApi: state => state.api.deployUploadApi,
|
deployUploadApi: state => state.api.deployUploadApi,
|
||||||
databaseUploadApi: state => state.api.databaseUploadApi,
|
databaseUploadApi: state => state.api.databaseUploadApi,
|
||||||
@@ -19,6 +23,7 @@ const getters = {
|
|||||||
druidSqlApi: state => state.api.druidSqlApi,
|
druidSqlApi: state => state.api.druidSqlApi,
|
||||||
swaggerApi: state => state.api.swaggerApi,
|
swaggerApi: state => state.api.swaggerApi,
|
||||||
websocketApi: state => state.api.websocketApi,
|
websocketApi: state => state.api.websocketApi,
|
||||||
sidebarRouters: state => state.permission.sidebarRouters
|
sidebarRouters: state => state.permission.sidebarRouters,
|
||||||
|
statusConst: state => state.pipeline.statusConst
|
||||||
}
|
}
|
||||||
export default getters
|
export default getters
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
const pipeline = {
|
||||||
|
/**
|
||||||
|
* 全局常量
|
||||||
|
*/
|
||||||
|
state: {
|
||||||
|
statusConst: {
|
||||||
|
pending: { code: 'pending', label: '未开始', color: '#C0C4CC', icon: 'el-icon-time' },
|
||||||
|
running: { code: 'running', label: '运行中', color: '#409EFF', icon: 'el-icon-loading' },
|
||||||
|
success: { code: 'success', label: '执行成功', color: '#67C23A', icon: 'el-icon-success' },
|
||||||
|
fail: { code: 'fail', label: '执行失败', color: '#F56C6C', icon: 'el-icon-error' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default pipeline
|
||||||
@@ -30,7 +30,9 @@ service.interceptors.request.use(
|
|||||||
// response 拦截器
|
// response 拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
response => {
|
response => {
|
||||||
return response.data
|
const data = response.data
|
||||||
|
// console.error('data', data)
|
||||||
|
return data
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
// 兼容blob下载出错json提示
|
// 兼容blob下载出错json提示
|
||||||
@@ -57,7 +59,7 @@ service.interceptors.response.use(
|
|||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(code)
|
// console.log(code)
|
||||||
if (code) {
|
if (code) {
|
||||||
if (code === 401) {
|
if (code === 401) {
|
||||||
store.dispatch('LogOut').then(() => {
|
store.dispatch('LogOut').then(() => {
|
||||||
|
|||||||
@@ -1,118 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="box-card"
|
class="box-card"
|
||||||
:style="{
|
:style="cardStyle"
|
||||||
borderTopWidth: '5px',
|
|
||||||
borderTopStyle: 'solid',
|
|
||||||
borderTopColor: statusColorConst[pipelineData.currentNodeStatus ? pipelineData.currentNodeStatus : statusColorConst.pending.code].color
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div style="float: left;">
|
<div style="float: left;">
|
||||||
<i
|
<i :class="statusIconClass" :style="statusIconStyle" />
|
||||||
v-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.pending.code"
|
|
||||||
class="el-icon-time"
|
|
||||||
:style="{
|
|
||||||
fontSize: '22px',
|
|
||||||
color: statusColorConst.pending.color
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.running.code"
|
|
||||||
class="el-icon-loading"
|
|
||||||
:style="{
|
|
||||||
fontSize: '22px',
|
|
||||||
color: statusColorConst.running.color
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.success.code"
|
|
||||||
class="el-icon-success"
|
|
||||||
:style="{
|
|
||||||
fontSize: '22px',
|
|
||||||
color: statusColorConst.success.color
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.fail.code"
|
|
||||||
class="el-icon-error"
|
|
||||||
:style="{
|
|
||||||
fontSize: '22px',
|
|
||||||
color: statusColorConst.fail.color
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<i
|
|
||||||
v-else
|
|
||||||
class="el-icon-time"
|
|
||||||
:style="{
|
|
||||||
fontSize: '22px',
|
|
||||||
color: statusColorConst.pending.color
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="box-name">{{ pipelineData.name }}</div>
|
<div class="box-name">{{ currentTemplateData.name }}</div>
|
||||||
<div style="clear: both" />
|
<div style="clear: both" />
|
||||||
</div>
|
</div>
|
||||||
<div class="box-current-node">
|
<div class="box-current-node">
|
||||||
<a @click="onCurrentNodeClick">
|
<a @click="onCurrentNodeClick">
|
||||||
{{ pipelineData.currentNodeMsg ? pipelineData.currentNodeMsg : statusColorConst.pending.label }}
|
{{ currentNodeDisplayText }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12" style="text-align: left">
|
<el-col :span="12" style="text-align: left">
|
||||||
<!-- 流水线状态为fail,且节点支持重试 -->
|
<!-- 流水线节点状态为fail,且节点支持重试 -->
|
||||||
<div v-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === 'fail' && pipelineData.retry === true">
|
<div v-if="showRetryButton">
|
||||||
<div class="box-buttons">
|
<div class="box-buttons">
|
||||||
{{ '1' }}
|
|
||||||
<el-button
|
<el-button
|
||||||
|
v-prevent-re-click="5000"
|
||||||
type="text"
|
type="text"
|
||||||
size="medium"
|
size="medium"
|
||||||
:style="{
|
:style="getButtonStyle()"
|
||||||
padding: 0,
|
|
||||||
margin: '0 10px 0 10px',
|
|
||||||
color: statusColorConst.running.color
|
|
||||||
}"
|
|
||||||
@click="onNodeRetryClick"
|
@click="onNodeRetryClick"
|
||||||
>
|
>
|
||||||
重试
|
重试
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 流水线状态为success,且有需要满足条件的操作按钮 -->
|
<!-- 流水线节点状态为success,且有操作按钮 -->
|
||||||
<div v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus === statusColorConst.success.code && pipelineData.buttons && pipelineData.buttons.length > 0">
|
<div v-else-if="showOperationButtons">
|
||||||
<div class="box-buttons">
|
<div class="box-buttons">
|
||||||
{{ '2' }}
|
|
||||||
<el-button
|
<el-button
|
||||||
v-for="buttonItem in pipelineData.buttons"
|
v-for="buttonItem in currentTemplateData.buttons"
|
||||||
:key="buttonItem.service"
|
:key="buttonItem.service"
|
||||||
size="medium"
|
size="medium"
|
||||||
type="text"
|
type="text"
|
||||||
:style="{
|
:style="getButtonStyle(buttonItem)"
|
||||||
padding: 0,
|
|
||||||
margin: '0 10px 0 10px',
|
|
||||||
color: ['apply','agree','ok','success'].includes(buttonItem.code) ? statusColorConst.running.color : statusColorConst.fail.color,
|
|
||||||
display: ['success', 'fail'].includes(buttonItem.code) && pipelineData.status === buttonItem.code ? '' : 'none'
|
|
||||||
}"
|
|
||||||
@click="onNodeOperationClick(buttonItem)"
|
@click="onNodeOperationClick(buttonItem)"
|
||||||
>
|
>
|
||||||
{{ buttonItem.title }}
|
{{ buttonItem.title }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 流水线状态非pending,且有操作按钮 -->
|
<!-- 流水线节点状态为running,且有操作按钮 -->
|
||||||
<div v-else-if="pipelineData.currentNodeStatus && pipelineData.currentNodeStatus !== statusColorConst.pending.code && pipelineData.buttons && pipelineData.buttons.length > 0">
|
<div v-else-if="showOperationButtons">
|
||||||
<div class="box-buttons">
|
<div class="box-buttons">
|
||||||
{{ '3' }}
|
|
||||||
<el-button
|
<el-button
|
||||||
v-for="buttonItem in pipelineData.buttons"
|
v-for="buttonItem in currentTemplateData.buttons"
|
||||||
:key="buttonItem.service"
|
:key="buttonItem.service"
|
||||||
size="medium"
|
size="medium"
|
||||||
type="text"
|
type="text"
|
||||||
:style="{
|
:style="getButtonStyle(buttonItem)"
|
||||||
padding: 0,
|
|
||||||
margin: '0 10px 0 10px',
|
|
||||||
color: ['apply','agree','ok','success'].includes(buttonItem.code) ? statusColorConst.running.color : statusColorConst.fail.color
|
|
||||||
}"
|
|
||||||
@click="onNodeOperationClick(buttonItem)"
|
@click="onNodeOperationClick(buttonItem)"
|
||||||
>
|
>
|
||||||
{{ buttonItem.title }}
|
{{ buttonItem.title }}
|
||||||
@@ -131,10 +73,27 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<div style="clear: both" />
|
<div style="clear: both" />
|
||||||
</el-row>
|
</el-row>
|
||||||
<cute-preview-drawer ref="detailDrawer" :title="pipelineData.name">
|
<cute-preview-drawer ref="detailDrawer" :title="currentTemplateData.name">
|
||||||
<div style="padding: 20px">
|
<el-timeline>
|
||||||
这里是明细
|
<el-timeline-item timestamp="2018/4/12" placement="top">
|
||||||
</div>
|
<el-card>
|
||||||
|
<h4>更新 Github 模板</h4>
|
||||||
|
<p>王小虎 提交于 2018/4/12 20:46</p>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
<el-timeline-item timestamp="2018/4/3" placement="top">
|
||||||
|
<el-card>
|
||||||
|
<h4>更新 Github 模板</h4>
|
||||||
|
<p>王小虎 提交于 2018/4/3 20:46</p>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
<el-timeline-item timestamp="2018/4/2" placement="top">
|
||||||
|
<el-card>
|
||||||
|
<h4>更新 Github 模板</h4>
|
||||||
|
<p>王小虎 提交于 2018/4/2 20:46</p>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline>
|
||||||
</cute-preview-drawer>
|
</cute-preview-drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -142,7 +101,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import CutePreviewDrawer from '@/views/components/dev/CutePreviewDrawer'
|
import CutePreviewDrawer from '@/views/components/dev/CutePreviewDrawer'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
import CsMessage from '@/utils/elementui/CsMessage'
|
||||||
|
import { retryPipeline } from '@/api/devops/pipelineInstance'
|
||||||
export default {
|
export default {
|
||||||
name: 'CutePipelineNode',
|
name: 'CutePipelineNode',
|
||||||
components: { CutePreviewDrawer },
|
components: { CutePreviewDrawer },
|
||||||
@@ -153,34 +114,137 @@ export default {
|
|||||||
default: function() {
|
default: function() {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
instanceData: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: function() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
statusColorConst: {
|
currentTemplateData: {},
|
||||||
pending: { code: 'pending', label: '未开始', color: '#C0C4CC' },
|
currentInstanceData: {}
|
||||||
running: { code: 'running', label: '运行中', color: '#409EFF' },
|
}
|
||||||
success: { code: 'success', label: '执行成功', color: '#67C23A' },
|
},
|
||||||
fail: { code: 'fail', label: '执行失败', color: '#F56C6C' }
|
// 动态计算
|
||||||
},
|
computed: {
|
||||||
executeTimeStr: '',
|
...mapGetters([
|
||||||
pipelineData: {}
|
'statusConst'
|
||||||
|
]),
|
||||||
|
cardStyle() {
|
||||||
|
const statusKey = this.currentTemplateData.currentNodeStatus || this.statusConst.pending.code
|
||||||
|
const statusConfig = this.statusConst[statusKey] || this.statusConst.pending
|
||||||
|
return {
|
||||||
|
borderTop: `5px solid ${statusConfig.color}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
statusIconClass() {
|
||||||
|
const status = this.currentTemplateData.currentNodeStatus || this.statusConst.pending.code
|
||||||
|
return this.statusConst[status].icon || 'el-icon-time'
|
||||||
|
},
|
||||||
|
statusIconStyle() {
|
||||||
|
return {
|
||||||
|
fontSize: '22px',
|
||||||
|
color: this.getStatusColor()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentNodeDisplayText() {
|
||||||
|
return this.currentTemplateData.currentNodeMsg || this.statusConst.pending.label
|
||||||
|
},
|
||||||
|
showRetryButton() {
|
||||||
|
return this.currentTemplateData.currentNodeStatus === this.statusConst.fail.code &&
|
||||||
|
this.currentTemplateData.retry === true
|
||||||
|
},
|
||||||
|
showOperationButtons() {
|
||||||
|
const status = this.currentTemplateData.currentNodeStatus
|
||||||
|
const hasButtons = this.currentTemplateData.buttons && this.currentTemplateData.buttons.length > 0
|
||||||
|
return hasButtons && (
|
||||||
|
status === this.statusConst.success.code ||
|
||||||
|
status === this.statusConst.running.code
|
||||||
|
)
|
||||||
|
},
|
||||||
|
executeTimeStr() {
|
||||||
|
return this.renderDateTimeStr(this.currentTemplateData)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
templateData: {
|
templateData: {
|
||||||
handler(newVal, oldVal) {
|
handler(newVal, oldVal) {
|
||||||
this.pipelineData = { ...newVal }
|
this.currentTemplateData = { ...newVal }
|
||||||
this.executeTimeStr = this.renderDateTimeStr(newVal)
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
instanceData: {
|
||||||
|
handler(newVal, oldVal) {
|
||||||
|
this.currentInstanceData = { ...newVal }
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.pipelineData = this.templateData
|
// 初始化时,设置流水线模板
|
||||||
this.executeTimeStr = this.renderDateTimeStr(this.templateData)
|
this.currentTemplateData = this.templateData
|
||||||
|
this.currentInstanceData = this.instanceData
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getStatusColor() {
|
||||||
|
const status = this.currentTemplateData.currentNodeStatus || this.statusConst.pending.code
|
||||||
|
const statusConfig = this.statusConst[status] || this.statusConst.pending
|
||||||
|
return statusConfig.color
|
||||||
|
},
|
||||||
|
getButtonStyle(buttonItem) {
|
||||||
|
if (buttonItem) {
|
||||||
|
const isPositiveAction = ['apply', 'agree', 'ok', 'success'].includes(buttonItem.code)
|
||||||
|
const status = this.currentTemplateData.currentNodeStatus
|
||||||
|
const color = isPositiveAction
|
||||||
|
? this.statusConst.running.color
|
||||||
|
: this.statusConst.fail.color
|
||||||
|
let display = ''
|
||||||
|
if (status === this.statusConst.running.code) {
|
||||||
|
display = this.getRunningNodeButtonVisibleStatus(buttonItem)
|
||||||
|
} else if (status === this.statusConst.success.code) {
|
||||||
|
display = this.getSuccessNodeButtonVisibleStatus(buttonItem)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
padding: 0,
|
||||||
|
margin: '0 10px 0 10px',
|
||||||
|
color,
|
||||||
|
display
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
padding: 0,
|
||||||
|
margin: '0 10px 0 10px',
|
||||||
|
color: this.statusConst.running.color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 运行中节点的按钮显示
|
||||||
|
* @param buttonItem
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getRunningNodeButtonVisibleStatus(buttonItem) {
|
||||||
|
if (buttonItem.type === 'qrCodeDialog') {
|
||||||
|
return 'none'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 成功节点的按钮显示
|
||||||
|
* @param buttonItem
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getSuccessNodeButtonVisibleStatus(buttonItem) {
|
||||||
|
const that = this
|
||||||
|
// 根据按钮编码
|
||||||
|
if (buttonItem.code === that.currentTemplateData.currentNodeStatus) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return 'none'
|
||||||
|
},
|
||||||
renderDateTimeStr(newVal) {
|
renderDateTimeStr(newVal) {
|
||||||
let executeTimeStr = ''
|
let executeTimeStr = ''
|
||||||
switch (newVal.status) {
|
switch (newVal.status) {
|
||||||
@@ -190,7 +254,7 @@ export default {
|
|||||||
case 'running':
|
case 'running':
|
||||||
case 'success':
|
case 'success':
|
||||||
case 'fail':
|
case 'fail':
|
||||||
if (newVal.currentNodeStatus !== this.statusColorConst.pending.code) {
|
if (newVal.currentNodeStatus !== this.statusConst.pending.code) {
|
||||||
if (newVal.startTime && newVal.finishTime) {
|
if (newVal.startTime && newVal.finishTime) {
|
||||||
executeTimeStr = this.formatTimeDifference(newVal.startTime, newVal.finishTime)
|
executeTimeStr = this.formatTimeDifference(newVal.startTime, newVal.finishTime)
|
||||||
return executeTimeStr
|
return executeTimeStr
|
||||||
@@ -240,21 +304,27 @@ export default {
|
|||||||
return `${diffInMilliseconds} 毫秒`
|
return `${diffInMilliseconds} 毫秒`
|
||||||
},
|
},
|
||||||
onCurrentNodeClick() {
|
onCurrentNodeClick() {
|
||||||
const pipelineData = this.pipelineData || { click: false }
|
const currentTemplateData = this.currentTemplateData || { click: false }
|
||||||
if (!pipelineData.click) {
|
if (!currentTemplateData.click) {
|
||||||
console.warn('当前流水线节点不支持查看明细')
|
CsMessage.Warning('当前流水线节点不支持查看明细')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.error('templateData', this.templateData)
|
console.error('templateData', this.templateData)
|
||||||
this.$refs.detailDrawer.show()
|
this.$refs.detailDrawer.show()
|
||||||
},
|
},
|
||||||
onNodeRetryClick() {
|
onNodeRetryClick() {
|
||||||
const pipelineData = this.pipelineData || { retry: false }
|
const currentTemplateData = this.currentTemplateData || { retry: false }
|
||||||
if (!pipelineData.retry) {
|
if (!currentTemplateData.retry) {
|
||||||
console.warn('当前流水线节点不支持重试')
|
CsMessage.Warning('当前流水线节点不支持重试')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.error('pipelineData', this.pipelineData)
|
const data = {
|
||||||
|
...this.currentInstanceData,
|
||||||
|
code: this.currentTemplateData.code
|
||||||
|
}
|
||||||
|
// console.error('data', data)
|
||||||
|
retryPipeline(data)
|
||||||
|
this.$emit('retry', data)
|
||||||
},
|
},
|
||||||
onNodeOperationClick(buttonInfo) {
|
onNodeOperationClick(buttonInfo) {
|
||||||
console.error('buttonInfo', buttonInfo)
|
console.error('buttonInfo', buttonInfo)
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
v-for="(template, index) in dynamicInstance.nodes"
|
v-for="(template, index) in dynamicInstance.nodes"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data.sync="dynamicInstance.nodes[index]"
|
:template-data.sync="dynamicInstance.nodes[index]"
|
||||||
|
:instance-data.sync="dynamicInstance"
|
||||||
|
@retry="onPipelineRetrySuccess"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="box-pipeline-content">
|
<div v-else class="box-pipeline-content">
|
||||||
@@ -24,6 +26,7 @@
|
|||||||
v-for="(template, index) in dynamicTemplateList"
|
v-for="(template, index) in dynamicTemplateList"
|
||||||
:key="template.code"
|
:key="template.code"
|
||||||
:template-data.sync="dynamicTemplateList[index]"
|
:template-data.sync="dynamicTemplateList[index]"
|
||||||
|
:instance-data.sync="dynamicInstance"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -462,7 +465,7 @@ export default {
|
|||||||
dynamicStartButtonLoading: false,
|
dynamicStartButtonLoading: false,
|
||||||
// 当前模板
|
// 当前模板
|
||||||
dynamicTemplate: {
|
dynamicTemplate: {
|
||||||
id: 6
|
id: 21
|
||||||
},
|
},
|
||||||
// 当前流水线节点模板
|
// 当前流水线节点模板
|
||||||
dynamicTemplateList: [],
|
dynamicTemplateList: [],
|
||||||
@@ -553,6 +556,7 @@ export default {
|
|||||||
// 所有节点执行成功
|
// 所有节点执行成功
|
||||||
if (that.dynamicWsClient) {
|
if (that.dynamicWsClient) {
|
||||||
that.dynamicWsClient.close()
|
that.dynamicWsClient.close()
|
||||||
|
sessionStorage.removeItem('pipelineInstanceId')
|
||||||
}
|
}
|
||||||
that.dynamicStartupStatus = that.dynamicStartupStatusMap.start.code
|
that.dynamicStartupStatus = that.dynamicStartupStatusMap.start.code
|
||||||
} else {
|
} else {
|
||||||
@@ -597,7 +601,7 @@ export default {
|
|||||||
* 启动流水线
|
* 启动流水线
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async startPipelineTest(data) {
|
async startPipelineTest() {
|
||||||
const that = this
|
const that = this
|
||||||
const args = {
|
const args = {
|
||||||
id: that.dynamicTemplate.id
|
id: that.dynamicTemplate.id
|
||||||
@@ -625,6 +629,10 @@ export default {
|
|||||||
console.error('error', e)
|
console.error('error', e)
|
||||||
that.dynamicStartButtonLoading = false
|
that.dynamicStartButtonLoading = false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onPipelineRetrySuccess(data) {
|
||||||
|
sessionStorage.setItem('pipelineInstanceId', data.instanceId)
|
||||||
|
this.connectWebSocketServer(data.instanceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package cn.odboy.framework.websocket.model;
|
||||||
|
|
||||||
|
import cn.odboy.base.CsObject;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class WsSidVo extends CsObject {
|
||||||
|
private String username;
|
||||||
|
private String bizCode;
|
||||||
|
private String param;
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package cn.odboy.framework.websocket.util;
|
||||||
|
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import cn.odboy.framework.websocket.model.WsSidVo;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket消息解析工具
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-25
|
||||||
|
*/
|
||||||
|
@UtilityClass
|
||||||
|
public class WsMessageUtil {
|
||||||
|
public static WsSidVo parseSid(String sid) {
|
||||||
|
// sid {username}_{bizCode}_{param}
|
||||||
|
String[] sids = sid.split("_");
|
||||||
|
if (sids.length != 3) {
|
||||||
|
throw new BadRequestException("sid格式异常");
|
||||||
|
}
|
||||||
|
WsSidVo sidVo = new WsSidVo();
|
||||||
|
sidVo.setUsername(sids[0]);
|
||||||
|
sidVo.setBizCode(sids[1]);
|
||||||
|
sidVo.setParam(sids[2]);
|
||||||
|
return sidVo;
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-15
@@ -3,6 +3,7 @@ package cn.odboy.devops.controller;
|
|||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceTb;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineTemplateTb;
|
import cn.odboy.devops.dal.dataobject.PipelineTemplateTb;
|
||||||
import cn.odboy.devops.dal.model.DevOpsQueryLastPipelineDetailArgs;
|
import cn.odboy.devops.dal.model.DevOpsQueryLastPipelineDetailArgs;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineInstanceVo;
|
||||||
import cn.odboy.devops.service.core.PipelineInstanceService;
|
import cn.odboy.devops.service.core.PipelineInstanceService;
|
||||||
import cn.odboy.devops.service.core.PipelineTemplateService;
|
import cn.odboy.devops.service.core.PipelineTemplateService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
@@ -68,21 +69,8 @@ public class DevopsPipelineInstanceController {
|
|||||||
@ApiOperation("流水线节点重试")
|
@ApiOperation("流水线节点重试")
|
||||||
@PostMapping(value = "/retry")
|
@PostMapping(value = "/retry")
|
||||||
@PreAuthorize("@el.check()")
|
@PreAuthorize("@el.check()")
|
||||||
public ResponseEntity<?> retryPipelineNode(@RequestBody PipelineTemplateTb args) {
|
public ResponseEntity<?> retryPipelineNode(@RequestBody PipelineInstanceVo args) {
|
||||||
String appName = "cuteops";
|
return ResponseEntity.ok(pipelineInstanceService.retryPipelineNode(args));
|
||||||
String envCode = "daily";
|
|
||||||
PipelineTemplateTb pipelineTemplateTb = pipelineTemplateService.getPipelineTemplateById(args.getId());
|
|
||||||
PipelineInstanceTb pipelineInstanceTb = new PipelineInstanceTb();
|
|
||||||
pipelineInstanceTb.setTemplateId(pipelineTemplateTb.getId());
|
|
||||||
pipelineInstanceTb.setInstanceName("流水线测试");
|
|
||||||
pipelineInstanceTb.setTemplateType(pipelineTemplateTb.getType());
|
|
||||||
pipelineInstanceTb.setContextName(appName);
|
|
||||||
pipelineInstanceTb.setEnv(envCode);
|
|
||||||
pipelineInstanceTb.setTemplateContent(pipelineTemplateTb.getTemplate());
|
|
||||||
pipelineInstanceTb.setInstanceId(1947604330727079936L);
|
|
||||||
String retryNodeCode = "node_build_java";
|
|
||||||
pipelineInstanceService.restartPipeline(pipelineInstanceTb, retryNodeCode);
|
|
||||||
return ResponseEntity.ok(pipelineInstanceService.restartPipeline(pipelineInstanceTb, retryNodeCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("查询流水线明细")
|
@ApiOperation("查询流水线明细")
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ public abstract class AbstractPipelineNodeJobService {
|
|||||||
return pipelineInstanceNodeService.getPipelineInstanceNodeByArgs(instanceId, code);
|
return pipelineInstanceNodeService.getPipelineInstanceNodeByArgs(instanceId, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLog(PipelineInstanceNodeTb pipelineInstanceNode, String stepName, PipelineStatusEnum stepStatus, String stepMsg, Date finishTime) {
|
public void addPipelineInstanceNodeDetailLog(PipelineInstanceNodeTb pipelineInstanceNode, String stepName, PipelineStatusEnum stepStatus, String stepMsg, Date finishTime) {
|
||||||
if (pipelineInstanceNode != null) {
|
if (pipelineInstanceNode != null) {
|
||||||
pipelineInstanceNodeDetailService.addLog(pipelineInstanceNode.getId(), pipelineInstanceNode.getCode(), stepName, stepStatus, stepMsg, finishTime);
|
pipelineInstanceNodeDetailService.addLog(pipelineInstanceNode.getId(), pipelineInstanceNode.getCode(), stepName, stepStatus, stepMsg, finishTime);
|
||||||
}
|
}
|
||||||
|
|||||||
-10
@@ -45,16 +45,6 @@ public class PipelineJobBean implements InterruptableJob {
|
|||||||
PipelineInstanceTb pipelineInstanceTb = (PipelineInstanceTb) jobDataMap.get(PipelineConst.INSTANCE);
|
PipelineInstanceTb pipelineInstanceTb = (PipelineInstanceTb) jobDataMap.get(PipelineConst.INSTANCE);
|
||||||
pipelineInstanceTb.setStatus(PipelineStatusEnum.PENDING.getCode());
|
pipelineInstanceTb.setStatus(PipelineStatusEnum.PENDING.getCode());
|
||||||
|
|
||||||
// // 模拟终止流水线
|
|
||||||
// ThreadUtil.execAsync(() -> {
|
|
||||||
// ThreadUtil.safeSleep(6000);
|
|
||||||
// try {
|
|
||||||
// pipelineJobManage.interruptJob(pipelineInstanceTb.getInstanceId());
|
|
||||||
// } catch (SchedulerException e) {
|
|
||||||
// log.error("终止流水线异常", e);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (StrUtil.isBlank(retryNodeCode)) {
|
if (StrUtil.isBlank(retryNodeCode)) {
|
||||||
// 创建实例
|
// 创建实例
|
||||||
pipelineInstanceMapper.insert(pipelineInstanceTb);
|
pipelineInstanceMapper.insert(pipelineInstanceTb);
|
||||||
|
|||||||
+1
-1
@@ -11,5 +11,5 @@ import org.quartz.JobDataMap;
|
|||||||
* @date 2025-07-21
|
* @date 2025-07-21
|
||||||
*/
|
*/
|
||||||
public interface PipelineNodeJobExecutor {
|
public interface PipelineNodeJobExecutor {
|
||||||
PipelineNodeJobExecuteResult execute(JobDataMap contextArgs) throws BadRequestException;
|
PipelineNodeJobExecuteResult execute(JobDataMap contextArgs) throws Exception;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -46,17 +46,17 @@ public class PipelineNodeStepLogAspect extends AbstractPipelineNodeJobService {
|
|||||||
}
|
}
|
||||||
PipelineNodeStepLog pipelineNodeStepLog = method.getAnnotation(PipelineNodeStepLog.class);
|
PipelineNodeStepLog pipelineNodeStepLog = method.getAnnotation(PipelineNodeStepLog.class);
|
||||||
try {
|
try {
|
||||||
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.RUNNING, PipelineStatusEnum.RUNNING.getDesc(), null);
|
addPipelineInstanceNodeDetailLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.RUNNING, PipelineStatusEnum.RUNNING.getDesc(), null);
|
||||||
Object result = joinPoint.proceed();
|
Object result = joinPoint.proceed();
|
||||||
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc(), new Date());
|
addPipelineInstanceNodeDetailLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.SUCCESS, PipelineStatusEnum.SUCCESS.getDesc(), new Date());
|
||||||
return result;
|
return result;
|
||||||
} catch (BadRequestException e) {
|
} catch (BadRequestException e) {
|
||||||
log.error("执行失败", e);
|
log.error("执行失败", e);
|
||||||
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.FAIL, e.getMessage(), new Date());
|
addPipelineInstanceNodeDetailLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.FAIL, e.getMessage(), new Date());
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
log.error("执行失败", e);
|
log.error("执行失败", e);
|
||||||
addLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.FAIL, PipelineStatusEnum.FAIL.getDesc(), new Date());
|
addPipelineInstanceNodeDetailLog(currentNodeInfo, pipelineNodeStepLog.value(), PipelineStatusEnum.FAIL, PipelineStatusEnum.FAIL.getDesc(), new Date());
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -1,9 +1,12 @@
|
|||||||
package cn.odboy.devops.framework.pipeline.model;
|
package cn.odboy.devops.framework.pipeline.model;
|
||||||
|
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线节点数据
|
* 流水线节点数据
|
||||||
@@ -12,7 +15,7 @@ import java.util.Date;
|
|||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class PipelineNodeDataVo extends PipelineNodeTemplateVo {
|
public class PipelineInstanceNodeVo extends PipelineNodeTemplateVo {
|
||||||
/**
|
/**
|
||||||
* 节点创建时间
|
* 节点创建时间
|
||||||
*/
|
*/
|
||||||
@@ -41,4 +44,8 @@ public class PipelineNodeDataVo extends PipelineNodeTemplateVo {
|
|||||||
* 流水线实例状态
|
* 流水线实例状态
|
||||||
*/
|
*/
|
||||||
private String status;
|
private String status;
|
||||||
|
/**
|
||||||
|
* 节点步骤明细记录
|
||||||
|
*/
|
||||||
|
private List<PipelineInstanceNodeDetailTb> historys = new ArrayList<>();
|
||||||
}
|
}
|
||||||
+5
-2
@@ -1,6 +1,8 @@
|
|||||||
package cn.odboy.devops.framework.pipeline.model;
|
package cn.odboy.devops.framework.pipeline.model;
|
||||||
|
|
||||||
import cn.odboy.base.CsObject;
|
import cn.odboy.base.CsObject;
|
||||||
|
import com.alibaba.fastjson2.annotation.JSONField;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -14,10 +16,11 @@ import java.util.List;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class PipelineInstanceVo extends CsObject {
|
public class PipelineInstanceVo extends CsObject {
|
||||||
private Long instanceId;
|
private String instanceId;
|
||||||
private String instanceName;
|
private String instanceName;
|
||||||
private String env;
|
private String env;
|
||||||
|
private String code;
|
||||||
private String contextName;
|
private String contextName;
|
||||||
private String contextParams;
|
private String contextParams;
|
||||||
private List<PipelineNodeDataVo> nodes;
|
private List<PipelineInstanceNodeVo> nodes;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -42,7 +42,9 @@ public class PipelineNodeTemplateVo extends CsObject {
|
|||||||
*/
|
*/
|
||||||
protected String detailType = "";
|
protected String detailType = "";
|
||||||
/**
|
/**
|
||||||
* 默认参数
|
* 默认参数<br/>
|
||||||
|
* execute: 执行调用
|
||||||
|
* describe: 明细调用
|
||||||
*/
|
*/
|
||||||
protected Map<String, Object> parameters = new HashMap<>();
|
protected Map<String, Object> parameters = new HashMap<>();
|
||||||
/**
|
/**
|
||||||
|
|||||||
+3
-1
@@ -23,5 +23,7 @@ public interface PipelineInstanceNodeDetailService extends IService<PipelineInst
|
|||||||
|
|
||||||
void removeByNodeIds(List<Long> nodeIds);
|
void removeByNodeIds(List<Long> nodeIds);
|
||||||
|
|
||||||
PipelineInstanceNodeDetailTb getLastPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode, Long nodeId, String nodeCode);
|
PipelineInstanceNodeDetailTb getLastPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode);
|
||||||
|
|
||||||
|
List<PipelineInstanceNodeDetailTb> queryPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNodeTb);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -15,9 +15,9 @@ import cn.odboy.devops.framework.pipeline.model.PipelineInstanceVo;
|
|||||||
public interface PipelineInstanceService {
|
public interface PipelineInstanceService {
|
||||||
StartPipelineResultVo startPipeline(PipelineInstanceTb pipelineInstanceTb);
|
StartPipelineResultVo startPipeline(PipelineInstanceTb pipelineInstanceTb);
|
||||||
|
|
||||||
StartPipelineResultVo restartPipeline(PipelineInstanceTb pipelineInstanceTb, String retryNodeCode);
|
|
||||||
|
|
||||||
PipelineInstanceVo queryLastPipelineDetail(String instanceId);
|
PipelineInstanceVo queryLastPipelineDetail(String instanceId);
|
||||||
|
|
||||||
void queryLastPipelineDetailWs(String sid);
|
void queryLastPipelineDetailWs(String sid);
|
||||||
|
|
||||||
|
StartPipelineResultVo retryPipelineNode(PipelineInstanceVo args);
|
||||||
}
|
}
|
||||||
|
|||||||
-5
@@ -26,9 +26,4 @@ public class PipelineTemplateService {
|
|||||||
}
|
}
|
||||||
return pipelineTemplateTb;
|
return pipelineTemplateTb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPipelineTemplateContentById(Long id) {
|
|
||||||
PipelineTemplateTb pipelineTemplateTb = getPipelineTemplateById(id);
|
|
||||||
return pipelineTemplateTb.getTemplate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-6
@@ -11,6 +11,7 @@ import com.anwen.mongo.service.impl.ServiceImpl;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -40,22 +41,27 @@ public class PipelineInstanceNodeDetailServiceImpl extends ServiceImpl<PipelineI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipelineInstanceNodeDetailTb getPipelineInstanceNodeDetailByArgs(Long nodeId, String nodeCode, String stepName) {
|
public PipelineInstanceNodeDetailTb getPipelineInstanceNodeDetailByArgs(Long nodeId, String nodeCode, String stepName) {
|
||||||
return one(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class).eq(PipelineInstanceNodeDetailTb::getNodeId, nodeId).eq(PipelineInstanceNodeDetailTb::getNodeCode, nodeCode).eq(PipelineInstanceNodeDetailTb::getStepName, stepName));
|
return one(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
||||||
|
.eq(PipelineInstanceNodeDetailTb::getNodeId, nodeId).eq(PipelineInstanceNodeDetailTb::getNodeCode, nodeCode)
|
||||||
|
.eq(PipelineInstanceNodeDetailTb::getStepName, stepName)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeByNodeIds(List<Long> nodeIds) {
|
public void removeByNodeIds(List<Long> nodeIds) {
|
||||||
if (CollUtil.isNotEmpty(nodeIds)) {
|
if (CollUtil.isNotEmpty(nodeIds)) {
|
||||||
remove(new LambdaUpdateChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class).in(PipelineInstanceNodeDetailTb::getNodeId, nodeIds));
|
remove(new LambdaUpdateChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
||||||
|
.in(PipelineInstanceNodeDetailTb::getNodeId, nodeIds)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipelineInstanceNodeDetailTb getLastPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode, Long nodeId, String nodeCode) {
|
public PipelineInstanceNodeDetailTb getLastPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode) {
|
||||||
List<PipelineInstanceNodeDetailTb> pipelineInstanceNodeDetailList = list(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
List<PipelineInstanceNodeDetailTb> pipelineInstanceNodeDetailList = list(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
||||||
.eq(PipelineInstanceNodeDetailTb::getNodeId, nodeId)
|
.eq(PipelineInstanceNodeDetailTb::getNodeId, instanceNode.getId())
|
||||||
.eq(PipelineInstanceNodeDetailTb::getNodeCode, nodeCode)
|
.eq(PipelineInstanceNodeDetailTb::getNodeCode, instanceNode.getCode())
|
||||||
.orderByDesc(PipelineInstanceNodeDetailTb::getId)
|
.orderByDesc(PipelineInstanceNodeDetailTb::getStartTime)
|
||||||
);
|
);
|
||||||
// 明细为空,返回节点状态
|
// 明细为空,返回节点状态
|
||||||
if (pipelineInstanceNodeDetailList.isEmpty()) {
|
if (pipelineInstanceNodeDetailList.isEmpty()) {
|
||||||
@@ -87,4 +93,13 @@ public class PipelineInstanceNodeDetailServiceImpl extends ServiceImpl<PipelineI
|
|||||||
pipelineInstanceNodeDetailTb.setStepMsg(pipelineInstanceNodeDetailTb.getStepName());
|
pipelineInstanceNodeDetailTb.setStepMsg(pipelineInstanceNodeDetailTb.getStepName());
|
||||||
return pipelineInstanceNodeDetailTb;
|
return pipelineInstanceNodeDetailTb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PipelineInstanceNodeDetailTb> queryPipelineInstanceNodeDetailByArgs(PipelineInstanceNodeTb instanceNode) {
|
||||||
|
return list(new LambdaQueryChainWrapper<>(getBaseMapper(), PipelineInstanceNodeDetailTb.class)
|
||||||
|
.eq(PipelineInstanceNodeDetailTb::getNodeId, instanceNode.getId())
|
||||||
|
.eq(PipelineInstanceNodeDetailTb::getNodeCode, instanceNode.getCode())
|
||||||
|
.orderByAsc(PipelineInstanceNodeDetailTb::getStartTime)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-30
@@ -2,6 +2,7 @@ package cn.odboy.devops.service.core.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
import cn.odboy.devops.constant.pipeline.PipelineStatusEnum;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeDetailTb;
|
||||||
@@ -11,15 +12,17 @@ import cn.odboy.devops.dal.model.StartPipelineResultVo;
|
|||||||
import cn.odboy.devops.dal.mysql.PipelineInstanceMapper;
|
import cn.odboy.devops.dal.mysql.PipelineInstanceMapper;
|
||||||
import cn.odboy.devops.dal.redis.PipelineInstanceDAO;
|
import cn.odboy.devops.dal.redis.PipelineInstanceDAO;
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineJobManage;
|
import cn.odboy.devops.framework.pipeline.core.PipelineJobManage;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineInstanceNodeVo;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineInstanceVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineInstanceVo;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeDataVo;
|
|
||||||
import cn.odboy.devops.service.core.PipelineInstanceNodeDetailService;
|
import cn.odboy.devops.service.core.PipelineInstanceNodeDetailService;
|
||||||
import cn.odboy.devops.service.core.PipelineInstanceNodeService;
|
import cn.odboy.devops.service.core.PipelineInstanceNodeService;
|
||||||
import cn.odboy.devops.service.core.PipelineInstanceService;
|
import cn.odboy.devops.service.core.PipelineInstanceService;
|
||||||
import cn.odboy.framework.exception.BadRequestException;
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import cn.odboy.framework.websocket.model.WsSidVo;
|
||||||
import cn.odboy.framework.websocket.context.CsWsClientManager;
|
import cn.odboy.framework.websocket.context.CsWsClientManager;
|
||||||
import cn.odboy.framework.websocket.context.CsWsMessage;
|
import cn.odboy.framework.websocket.context.CsWsMessage;
|
||||||
import cn.odboy.framework.websocket.context.CsWsServer;
|
import cn.odboy.framework.websocket.context.CsWsServer;
|
||||||
|
import cn.odboy.framework.websocket.util.WsMessageUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -51,28 +54,23 @@ public class PipelineInstanceServiceImpl implements PipelineInstanceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StartPipelineResultVo restartPipeline(PipelineInstanceTb pipelineInstanceTb, String retryNodeCode) {
|
public StartPipelineResultVo retryPipelineNode(PipelineInstanceVo args) {
|
||||||
if (pipelineInstanceTb.getInstanceId() == null) {
|
if (args.getInstanceId() == null) {
|
||||||
throw new BadRequestException("流水线实例Id必填");
|
throw new BadRequestException("流水线实例Id必填");
|
||||||
}
|
}
|
||||||
PipelineInstanceTb currentInstance = pipelineInstanceMapper.selectById(pipelineInstanceTb.getInstanceId());
|
PipelineInstanceTb currentInstance = pipelineInstanceMapper.selectById(args.getInstanceId());
|
||||||
if (currentInstance == null) {
|
if (currentInstance == null) {
|
||||||
throw new BadRequestException("无效流水线,请刷新页面后再试");
|
throw new BadRequestException("无效流水线,请刷新页面后再试");
|
||||||
}
|
}
|
||||||
if (pipelineInstanceDAO.lock(currentInstance)) {
|
if (StrUtil.isBlank(args.getCode())) {
|
||||||
throw new BadRequestException("流水线运行中,无法重复执行");
|
throw new BadRequestException("重试节点Code必填");
|
||||||
}
|
}
|
||||||
// pending、running、success、fail
|
if (!PipelineStatusEnum.FAIL.getCode().equals(currentInstance.getCurrentNodeStatus())) {
|
||||||
List<String> canRestartStatus = new ArrayList<>() {{
|
throw new BadRequestException("流水线节点无异常,无法重试");
|
||||||
add(PipelineStatusEnum.SUCCESS.getCode());
|
|
||||||
add(PipelineStatusEnum.FAIL.getCode());
|
|
||||||
}};
|
|
||||||
if (!canRestartStatus.contains(currentInstance.getStatus())) {
|
|
||||||
throw new BadRequestException("流水线运行中,无法重复执行");
|
|
||||||
}
|
}
|
||||||
log.info("解锁流水线, {}", JSON.toJSONString(currentInstance));
|
|
||||||
pipelineInstanceDAO.unLock(currentInstance);
|
pipelineInstanceDAO.unLock(currentInstance);
|
||||||
PipelineInstanceTb record = pipelineJobManage.startJobByNodeCode(currentInstance, retryNodeCode);
|
log.info("解锁流水线, {}", JSON.toJSONString(currentInstance));
|
||||||
|
PipelineInstanceTb record = pipelineJobManage.startJobByNodeCode(currentInstance, args.getCode());
|
||||||
StartPipelineResultVo resultVo = new StartPipelineResultVo();
|
StartPipelineResultVo resultVo = new StartPipelineResultVo();
|
||||||
resultVo.setInstanceId(record.getInstanceId());
|
resultVo.setInstanceId(record.getInstanceId());
|
||||||
resultVo.setTemplateContent(record.getTemplateContent());
|
resultVo.setTemplateContent(record.getTemplateContent());
|
||||||
@@ -83,45 +81,39 @@ public class PipelineInstanceServiceImpl implements PipelineInstanceService {
|
|||||||
public PipelineInstanceVo queryLastPipelineDetail(String instanceIdStr) {
|
public PipelineInstanceVo queryLastPipelineDetail(String instanceIdStr) {
|
||||||
String realInstanceIdStr = instanceIdStr.replace(PipelineConst.INSTANCE_ID, "");
|
String realInstanceIdStr = instanceIdStr.replace(PipelineConst.INSTANCE_ID, "");
|
||||||
Long instanceId = Long.valueOf(realInstanceIdStr);
|
Long instanceId = Long.valueOf(realInstanceIdStr);
|
||||||
List<PipelineNodeDataVo> records = new ArrayList<>();
|
List<PipelineInstanceNodeVo> records = new ArrayList<>();
|
||||||
PipelineInstanceTb pipelineInstanceTb = pipelineInstanceMapper.selectById(instanceId);
|
PipelineInstanceTb pipelineInstanceTb = pipelineInstanceMapper.selectById(instanceId);
|
||||||
if (pipelineInstanceTb == null) {
|
if (pipelineInstanceTb == null) {
|
||||||
throw new BadRequestException("流水线实例不存在");
|
throw new BadRequestException("流水线实例不存在");
|
||||||
}
|
}
|
||||||
|
PipelineInstanceVo pipelineInstanceVo = BeanUtil.copyProperties(pipelineInstanceTb, PipelineInstanceVo.class);
|
||||||
String status = pipelineInstanceTb.getStatus();
|
String status = pipelineInstanceTb.getStatus();
|
||||||
List<PipelineInstanceNodeTb> instanceNodeTbs = pipelineInstanceNodeService.queryPipelineInstanceNodeListByInstanceId(instanceId);
|
List<PipelineInstanceNodeTb> instanceNodeTbs = pipelineInstanceNodeService.queryPipelineInstanceNodeListByInstanceId(instanceId);
|
||||||
for (PipelineInstanceNodeTb instanceNodeTb : instanceNodeTbs) {
|
for (PipelineInstanceNodeTb instanceNodeTb : instanceNodeTbs) {
|
||||||
PipelineNodeDataVo dataVo = BeanUtil.copyProperties(instanceNodeTb, PipelineNodeDataVo.class);
|
PipelineInstanceNodeVo dataVo = BeanUtil.copyProperties(instanceNodeTb, PipelineInstanceNodeVo.class);
|
||||||
dataVo.setStatus(status);
|
dataVo.setStatus(status);
|
||||||
// 取流水线节点最后一步的信息
|
// 取流水线节点最后一步的信息
|
||||||
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetail = pipelineInstanceNodeDetailService.getLastPipelineInstanceNodeDetailByArgs(instanceNodeTb, instanceNodeTb.getId(), instanceNodeTb.getCode());
|
PipelineInstanceNodeDetailTb pipelineInstanceNodeDetail = pipelineInstanceNodeDetailService.getLastPipelineInstanceNodeDetailByArgs(instanceNodeTb);
|
||||||
dataVo.setCurrentNodeMsg(pipelineInstanceNodeDetail.getStepMsg());
|
dataVo.setCurrentNodeMsg(pipelineInstanceNodeDetail.getStepMsg());
|
||||||
dataVo.setCurrentNodeStatus(pipelineInstanceNodeDetail.getStepStatus());
|
// 取执行历史
|
||||||
|
dataVo.setHistorys(pipelineInstanceNodeDetailService.queryPipelineInstanceNodeDetailByArgs(instanceNodeTb));
|
||||||
records.add(dataVo);
|
records.add(dataVo);
|
||||||
}
|
}
|
||||||
PipelineInstanceVo pipelineInstanceVo = BeanUtil.copyProperties(pipelineInstanceTb, PipelineInstanceVo.class);
|
|
||||||
pipelineInstanceVo.setNodes(records);
|
pipelineInstanceVo.setNodes(records);
|
||||||
return pipelineInstanceVo;
|
return pipelineInstanceVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queryLastPipelineDetailWs(String sid) {
|
public void queryLastPipelineDetailWs(String sid) {
|
||||||
// sid {username}_{bizCode}_{contextParams}
|
WsSidVo sidVo = WsMessageUtil.parseSid(sid);
|
||||||
String[] sids = sid.split("_");
|
|
||||||
if (sids.length != 3) {
|
|
||||||
throw new BadRequestException("sid格式异常");
|
|
||||||
}
|
|
||||||
CsWsServer wsServer = CsWsClientManager.getClientBySid(sid);
|
CsWsServer wsServer = CsWsClientManager.getClientBySid(sid);
|
||||||
wsServer.restartTask(() -> {
|
wsServer.restartTask(() -> {
|
||||||
// String username = sids[0];
|
|
||||||
String bizCode = sids[1];
|
|
||||||
String instanceId = sids[2];
|
|
||||||
boolean loop = true;
|
boolean loop = true;
|
||||||
while (loop) {
|
while (loop) {
|
||||||
ThreadUtil.safeSleep(1000);
|
ThreadUtil.safeSleep(1000);
|
||||||
try {
|
try {
|
||||||
PipelineInstanceVo pipelineInstanceVo = queryLastPipelineDetail(instanceId);
|
PipelineInstanceVo pipelineInstanceVo = queryLastPipelineDetail(sidVo.getParam());
|
||||||
CsWsMessage message = new CsWsMessage(bizCode, JSON.toJSONString(pipelineInstanceVo));
|
CsWsMessage message = new CsWsMessage(sidVo.getBizCode(), JSON.toJSONString(pipelineInstanceVo));
|
||||||
wsServer.sendMessage(message, sid);
|
wsServer.sendMessage(message, sid);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("推送流水线最新数据失败", e);
|
log.error("推送流水线最新数据失败", e);
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import java.util.List;
|
|||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_apk_sign_android")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_sign_android_apk")
|
||||||
public class PipelineNodeApkSignAndroidService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeApkSignAndroidService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -16,14 +16,14 @@ import org.springframework.stereotype.Service;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线节点任务:Post调用插件 代码上传扫描
|
* 流水线节点任务:人工审批C++构建结果
|
||||||
*
|
*
|
||||||
* @author odboy
|
* @author odboy
|
||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_http_post_plugin-stc_upload")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_approve_cplus")
|
||||||
public class PipelineNodeHttpPostPluginStcUploadService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeApproveCPlusService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+3
-3
@@ -16,14 +16,14 @@ import org.springframework.stereotype.Service;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线节点任务:上传安卓发布包
|
* 流水线节点任务:人工确认Android测试通过
|
||||||
*
|
*
|
||||||
* @author odboy
|
* @author odboy
|
||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_mpaas_upload_android")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_approve_test_android")
|
||||||
public class PipelineNodeMPassUploadAndroidService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeApproveTestAndroidService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.odboy.devops.service.pipeline;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.pipeline.node.PipelineNodeDemoBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线节点任务:C++构建
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-24
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_build_cplus")
|
||||||
|
public class PipelineNodeBuildCPlusService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeDemoBiz.start(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDemoBiz.finish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.odboy.devops.service.pipeline;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.pipeline.node.PipelineNodeDemoBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线节点任务:IOS构建
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-24
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_build_ios")
|
||||||
|
public class PipelineNodeBuildIOSService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeDemoBiz.start(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDemoBiz.finish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.odboy.devops.service.pipeline;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.pipeline.node.PipelineNodeDemoBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线节点任务:检查Flutter版本
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-24
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_check_flutter_version")
|
||||||
|
public class PipelineNodeCheckFlutterVersionService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeDemoBiz.start(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDemoBiz.finish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -22,7 +22,7 @@ import java.util.List;
|
|||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_deploy_python")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_deploy_node")
|
||||||
public class PipelineNodeDeployNodeService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeDeployNodeService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
|
|||||||
+13
-7
@@ -2,11 +2,13 @@ package cn.odboy.devops.service.pipeline;
|
|||||||
|
|
||||||
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineTemplateTb;
|
||||||
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
import cn.odboy.devops.service.pipeline.node.PipelineNodeDemoBiz;
|
import cn.odboy.devops.service.core.PipelineTemplateService;
|
||||||
|
import cn.odboy.devops.service.pipeline.node.PipelineNodeDeployJavaBiz;
|
||||||
import cn.odboy.framework.exception.BadRequestException;
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -16,20 +18,23 @@ import org.springframework.stereotype.Service;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线节点任务:Post调用插件 代码上传扫描结果
|
* 流水线节点任务:Python部署
|
||||||
*
|
*
|
||||||
* @author odboy
|
* @author odboy
|
||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_http_post_plugin-stc_result")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_deploy_python")
|
||||||
public class PipelineNodeHttpPostPluginStcResultService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeDeployPythonService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDeployJavaBiz pipelineNodeDeployJavaBiz;
|
||||||
|
private final PipelineTemplateService pipelineTemplateService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
// 参数列表
|
// 参数列表
|
||||||
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
long templateId = jobDataMap.getLong(PipelineConst.TEMPLATE_ID);
|
||||||
|
PipelineTemplateTb pipelineTemplate = pipelineTemplateService.getPipelineTemplateById(templateId);
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
@@ -37,8 +42,9 @@ public class PipelineNodeHttpPostPluginStcResultService extends AbstractPipeline
|
|||||||
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
// 步骤执行
|
// 步骤执行
|
||||||
pipelineNodeDemoBiz.start(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
pipelineNodeDeployJavaBiz.deployStart(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
pipelineNodeDemoBiz.finish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
pipelineNodeDeployJavaBiz.deployJavaByWithContextName(pipelineInstanceNode, contextName, env, templateList, lastNodeResult, pipelineTemplate);
|
||||||
|
pipelineNodeDeployJavaBiz.deployFinish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
return PipelineNodeJobExecuteResult.success();
|
return PipelineNodeJobExecuteResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -16,14 +16,14 @@ import org.springframework.stereotype.Service;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水线节点任务:特殊合并到release分支
|
* 流水线节点任务:Post调用插件
|
||||||
*
|
*
|
||||||
* @author odboy
|
* @author odboy
|
||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_release_android")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_http_post_plugin")
|
||||||
public class PipelineNodeReleaseAndroidService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeHttpPostPluginService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+1
-1
@@ -27,7 +27,7 @@ public class PipelineNodeMergeBranchService extends AbstractPipelineNodeJobServi
|
|||||||
private final PipelineNodeMergeBranchBiz pipelineNodeMergeBranchBiz;
|
private final PipelineNodeMergeBranchBiz pipelineNodeMergeBranchBiz;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws Exception {
|
||||||
// 参数列表
|
// 参数列表
|
||||||
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
|||||||
+2
-2
@@ -22,8 +22,8 @@ import java.util.List;
|
|||||||
* @date 2025-07-24
|
* @date 2025-07-24
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_mpaas_start_android")
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_reinforce_android_apk")
|
||||||
public class PipelineNodeMPassStartAndroidService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
public class PipelineNodeReinforceAndroidApkService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package cn.odboy.devops.service.pipeline;
|
||||||
|
|
||||||
|
import cn.odboy.devops.constant.pipeline.PipelineConst;
|
||||||
|
import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
||||||
|
import cn.odboy.devops.framework.pipeline.AbstractPipelineNodeJobService;
|
||||||
|
import cn.odboy.devops.framework.pipeline.core.PipelineNodeJobExecutor;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.devops.service.pipeline.node.PipelineNodeDemoBiz;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流水线节点任务:上传安卓发布包
|
||||||
|
*
|
||||||
|
* @author odboy
|
||||||
|
* @date 2025-07-24
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service(value = PipelineConst.EXECUTOR_PREFIX + "node_upload_android_apk")
|
||||||
|
public class PipelineNodeUploadAndroidApkService extends AbstractPipelineNodeJobService implements PipelineNodeJobExecutor {
|
||||||
|
private final PipelineNodeDemoBiz pipelineNodeDemoBiz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PipelineNodeJobExecuteResult execute(JobDataMap jobDataMap) throws BadRequestException {
|
||||||
|
// 参数列表
|
||||||
|
long instanceId = jobDataMap.getLong(PipelineConst.INSTANCE_ID);
|
||||||
|
PipelineNodeTemplateVo currentNodeTemplate = (PipelineNodeTemplateVo) jobDataMap.get(PipelineConst.CURRENT_NODE_TEMPLATE);
|
||||||
|
PipelineInstanceNodeTb pipelineInstanceNode = getCurrentNodeInfo(instanceId, currentNodeTemplate.getCode());
|
||||||
|
String contextName = jobDataMap.getString(PipelineConst.CONTEXT_NAME);
|
||||||
|
String env = jobDataMap.getString(PipelineConst.ENV);
|
||||||
|
List<PipelineNodeTemplateVo> templateList = JSON.parseArray(jobDataMap.getString(PipelineConst.TEMPLATE), PipelineNodeTemplateVo.class);
|
||||||
|
PipelineNodeJobExecuteResult lastNodeResult = (PipelineNodeJobExecuteResult) jobDataMap.get(PipelineConst.LAST_NODE_RESULT);
|
||||||
|
// 步骤执行
|
||||||
|
pipelineNodeDemoBiz.start(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
pipelineNodeDemoBiz.finish(pipelineInstanceNode, contextName, env, templateList, lastNodeResult);
|
||||||
|
return PipelineNodeJobExecuteResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -16,11 +16,11 @@ public class PipelineNodeDemoBiz {
|
|||||||
|
|
||||||
@PipelineNodeStepLog("开始")
|
@PipelineNodeStepLog("开始")
|
||||||
public void start(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
public void start(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
ThreadUtil.safeSleep(1000);
|
ThreadUtil.safeSleep(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PipelineNodeStepLog("完成")
|
@PipelineNodeStepLog("完成")
|
||||||
public void finish(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
public void finish(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
ThreadUtil.safeSleep(1000);
|
ThreadUtil.safeSleep(2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -5,6 +5,7 @@ import cn.odboy.devops.dal.dataobject.PipelineInstanceNodeTb;
|
|||||||
import cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog;
|
import cn.odboy.devops.framework.pipeline.log.PipelineNodeStepLog;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeJobExecuteResult;
|
||||||
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
import cn.odboy.devops.framework.pipeline.model.PipelineNodeTemplateVo;
|
||||||
|
import cn.odboy.framework.exception.BadRequestException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ public class PipelineNodeMergeBranchBiz {
|
|||||||
@PipelineNodeStepLog("集成区分支合并到release分支")
|
@PipelineNodeStepLog("集成区分支合并到release分支")
|
||||||
public void integrationAreaBranchMergeRelease(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
public void integrationAreaBranchMergeRelease(PipelineInstanceNodeTb pipelineInstanceNode, String contextName, String env, List<PipelineNodeTemplateVo> templateList, PipelineNodeJobExecuteResult lastNodeResult) {
|
||||||
ThreadUtil.safeSleep(2000);
|
ThreadUtil.safeSleep(2000);
|
||||||
|
throw new BadRequestException("合并失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PipelineNodeStepLog("分支合并完成")
|
@PipelineNodeStepLog("分支合并完成")
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
### 注意事项
|
||||||
|
|
||||||
|
long、bigdecimal放回前端时,字段尽量设置为String,否则会出现精度丢失问题
|
||||||
Reference in New Issue
Block a user