Skip to content

Commit

Permalink
Merge pull request #11360 from vhwweng/issue_11304
Browse files Browse the repository at this point in the history
feat:导出流水线功能优化 #11304
  • Loading branch information
bkci-bot authored Jan 3, 2025
2 parents ccacc11 + f42ac84 commit 5285dff
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 46 deletions.
3 changes: 2 additions & 1 deletion src/frontend/common-lib/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ const createDocs = (lang, version) => {
TEMPLATE_GUIDE_DOC: `${commonPrefix}/Services/Store/ci-templates/start-new-template.md`, // 模板指引文档
TURBO_GUIDE_DOC: `${commonPrefix}/Services/Turbo/linux-tubo-speed/use_in_linux.md`, // turbo指引文档
BKAPP_NAV_OPEN_SOURCE_URL: 'https://github.com/TencentBlueKing/bk-ci', // 开源社区
FEED_BACK_URL: `${DOCS_URL_PREFIX}/s-mart/community/question` // 问题反馈
FEED_BACK_URL: `${DOCS_URL_PREFIX}/s-mart/community/question`, // 问题反馈
PAC_GUIDE_DOC: `${commonPrefix}/Services/Pipeline-as-Code/01-quick-start/01-quict-start.md` // PAC快速上手文档
}
const pipelineDocs = {
ALIAS_BUILD_NO_DOC: `${commonPrefix}/Services/Pipeline/pipeline-edit-guide/alias-buildno.md`, // 构建号别名文档
Expand Down
26 changes: 23 additions & 3 deletions src/frontend/devops-pipeline/src/components/ExportDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</p>
<bk-button
class="export-button"
@click="downLoadFromApi(exportItem.exportUrl, exportItem.name)"
@click="downLoadFromApi(exportItem)"
:loading="isDownLoading"
>
{{ $t('newlist.exportPipelineJson') }}
Expand All @@ -41,6 +41,7 @@
import { PROCESS_API_URL_PREFIX } from '@/store/constants'
import Logo from '@/components/Logo'
import { mapActions, mapState } from 'vuex'
import { CODE_MODE, UI_MODE } from '@/utils/pipelineConst'
export default {
components: {
Expand All @@ -58,6 +59,8 @@
computed: {
...mapState('atom', [
'pipeline',
'pipelineSetting',
'pipelineInfo'
]),
Expand All @@ -76,11 +79,27 @@
exportList () {
return [
{
type: UI_MODE,
title: 'Pipeline Json',
icon: 'export-pipeline',
name: `${this.pipelineName}.json`,
tips: this.$t('newlist.exportJsonTip'),
exportUrl: `${API_URL_PREFIX}/${PROCESS_API_URL_PREFIX}/user/pipelines/${this.pipelineId}/projects/${this.projectId}/export`
},
{
type: CODE_MODE,
title: 'Pipeline YAML',
icon: 'export-pipeline',
name: `${this.pipelineName}.yml`,
tips: this.$t('newlist.exportPipelineYamlTip'),
exportUrl: `${API_URL_PREFIX}/${PROCESS_API_URL_PREFIX}/user/transfer/projects/${this.projectId}?pipelineId=${this.pipelineId}&actionType=FULL_MODEL2YAML`,
tipsLink: this.BKCI_DOCS?.PAC_GUIDE_DOC,
params: {
modelAndSetting: {
model: this.pipeline,
setting: this.pipelineSetting
}
}
}
]
}
Expand All @@ -93,9 +112,10 @@
this.$emit('update:isShow', false)
},
downLoadFromApi (url, name) {
downLoadFromApi (exportItem) {
const { exportUrl: url, name, params, type } = exportItem
this.isDownLoading = true
this.download({ url, name }).catch((e) => {
this.download({ url, name, params, type }).catch((e) => {
this.handleError(
e,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{{ $t('importPipelineLabel') }}
<bk-upload
v-if="isShow"
accept="application/json"
accept=".json, .yaml, .yml, application/json, application/x-yaml"
:with-credentials="true"
:custom-request="handleSelect"
>
Expand All @@ -23,6 +23,8 @@
<script>
import { hashID } from '@/utils/util'
import { mapActions, mapState } from 'vuex'
import { CODE_MODE, UI_MODE } from '@/utils/pipelineConst'
export default {
name: 'import-pipeline-popup',
props: {
Expand Down Expand Up @@ -62,51 +64,97 @@
'setPipelineSetting',
'setPipelineWithoutTrigger'
]),
...mapActions({
updatePipelineMode: 'updatePipelineMode'
}),
handleSelect ({ fileObj, onProgress, onSuccess, onDone }) {
const reader = new FileReader()
reader.readAsText(fileObj.origin)
reader.addEventListener('loadend', e => {
reader.addEventListener('loadend', async e => {
try {
const jsonResult = JSON.parse(reader.result)
const isValid = this.checkJosnValid(jsonResult)
const code = isValid ? 0 : 1
const message = isValid ? null : this.$t('invalidPipelineJson')
if (fileObj.type === 'application/json' || fileObj.name.endsWith('.json')) {
const jsonResult = JSON.parse(reader.result)
const isValid = this.checkJsonValid(jsonResult)
const code = isValid ? 0 : 1
const message = isValid ? null : this.$t('invalidPipelineJsonOrYaml')
onSuccess({
code,
message,
result: jsonResult
}, fileObj)
onSuccess({
code,
message,
result: jsonResult
}, fileObj)
if (isValid) {
this.handleSuccess(jsonResult)
if (isValid) {
this.handleSuccess(jsonResult, UI_MODE)
}
} else if (fileObj.type === 'application/x-yaml' || fileObj.name.endsWith('.yaml') || fileObj.name.endsWith('.yml')) {
const yaml = e.target.result
const isValid = !!yaml
const code = isValid ? 0 : 1
const message = isValid ? null : this.$t('invalidPipelineJsonOrYaml')
onSuccess({
code,
message,
result: yaml
}, fileObj)
if (isValid) {
this.handleSuccess(yaml, CODE_MODE)
}
}
} catch (e) {
console.log(e)
onSuccess({
code: 1,
message: this.$t('invalidPipelineJson'),
message: this.$t('invalidPipelineJsonOrYaml'),
result: ''
}, fileObj)
} finally {
onDone(fileObj)
}
})
reader.addEventListener('progress', onProgress)
},
async handleSuccess (result) {
const newPipelineName = this.pipelineName || `${result.model.name}_${hashID().slice(0, 8)}`
const res = await this.updatePipeline(result, newPipelineName)
this.setEditFrom(true)
if (res) {
if (typeof this.handleImportSuccess === 'function') {
this.handleImportSuccess()
return
async handleSuccess (result, type = UI_MODE) {
if (type === UI_MODE) {
const newPipelineName = this.pipelineName || `${result.model.name}_${hashID().slice(0, 8)}`
const res = await this.updatePipeline(result, newPipelineName)
this.setEditFrom(true)
if (res) {
if (typeof this.handleImportSuccess === 'function') {
this.handleImportSuccess()
return
}
this.$nextTick(() => {
this.$router.push({
name: 'pipelineImportEdit',
params: {
tab: 'pipeline'
}
})
})
}
} else if (type === CODE_MODE) {
this.updatePipelineMode(CODE_MODE)
this.setEditFrom(true)
this.$store.dispatch('atom/setPipelineYaml', result)
try {
await this.transferPipeline({
projectId: this.$route.params.projectId,
actionType: 'FULL_YAML2MODEL',
oldYaml: result
})
} catch (error) {
this.$showTips({
message: error.message,
theme: 'error'
})
}
this.setPipelineEditing(true)
this.$nextTick(() => {
this.$router.push({
Expand Down Expand Up @@ -166,9 +214,9 @@
this.setPipelineEditing(true)
return true
},
checkJosnValid (json) {
checkJsonValid (json) {
try {
return json.model.stages && json.setting.pipelineName
return (json.model.stages && json.setting.pipelineName) || json.stages
} catch (e) {
return false
}
Expand Down
49 changes: 37 additions & 12 deletions src/frontend/devops-pipeline/src/store/modules/atom/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
STORE_API_URL_PREFIX,
UPDATE_PIPELINE_MODE
} from '@/store/constants'
import { UI_MODE } from '@/utils/pipelineConst'
import { UI_MODE, CODE_MODE } from '@/utils/pipelineConst'
import request from '@/utils/request'
import { hashID, randomString } from '@/utils/util'
import { areDeeplyEqual } from '../../../utils/util'
Expand Down Expand Up @@ -264,7 +264,7 @@ export default {
}
}
},
async transfer ({ getters }, { projectId, pipelineId, actionType, ...params }) {
async transfer ({ getters, state }, { projectId, pipelineId, actionType, ...params }) {
const apis = [
request.post(`${PROCESS_API_URL_PREFIX}/user/transfer/projects/${projectId}`, params, {
params: {
Expand All @@ -273,7 +273,7 @@ export default {
}
})
]
if (actionType === 'FULL_YAML2MODEL') {
if (actionType === 'FULL_YAML2MODEL' && !state.editfromImport) {
apis.push(
request.get(`/${PROCESS_API_URL_PREFIX}/user/pipeline/projects/${projectId}/pipelines/${pipelineId}/atom/prop/list`, {
params: params.version ? { version: params.version } : {}
Expand Down Expand Up @@ -864,22 +864,47 @@ export default {
return request.post(`${PROCESS_API_URL_PREFIX}/user/builds/projects/${projectId}/pipelines/${pipelineId}/builds/${buildId}/taskIds/${taskId}/execution/pause?isContinue=${isContinue}&stageId=${stageId}&containerId=${containerId}`, element)
},

download (_, { url, name }) {
return fetch(url, { credentials: 'include' }).then((res) => {
if (res.status >= 200 && res.status < 300) {
return res.blob()
} else {
return res.json().then((result) => Promise.reject(result))
}
}).then((blob) => {
download (_, { url, name, params, type }) {
const fn = (blob) => {
const a = document.createElement('a')
const url = window.URL || window.webkitURL || window.moxURL
a.href = url.createObjectURL(blob)
if (name) a.download = name
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
})
}

if (type === CODE_MODE) {
return fetch(url, {
credentials: 'include',
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then((res) => {
if (res.status >= 200 && res.status < 300) {
return res.json()
} else {
return res.json().then((result) => Promise.reject(result))
}
}).then((data) => {
const result = data.data.newYaml
const blob = new Blob([result])
fn(blob)
})
} else if (type === UI_MODE) {
return fetch(url, { credentials: 'include' }).then((res) => {
if (res.status >= 200 && res.status < 300) {
return res.blob()
} else {
return res.json().then((result) => Promise.reject(result))
}
}).then((blob) => {
fn(blob)
})
}
},
reviewExcuteAtom: async ({ commit }, { projectId, pipelineId, buildId, elementId, action }) => {
return request.post(`/${PROCESS_API_URL_PREFIX}/user/quality/builds/${projectId}/${pipelineId}/${buildId}/${elementId}/qualityGateReview/${action}`).then(response => {
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/locale/pipeline/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@
"pipelinesDetail": "Details",
"newPipelineFromTemplateLabel": "New From Template",
"newPipelineFromJSONLabel": "Import From Json",
"importPipelineLabel": "Please upload a pipeline JSON file",
"invalidPipelineJson": "Invalid Pipeline JSON",
"importPipelineLabel": "Please upload a pipeline JSON/YAML file",
"invalidPipelineJsonOrYaml": "Invalid Pipeline JSON/YAML",
"exportPipelineSuccess": "Export Pipeline Success",
"sizeLimit": "Maximum file size is 100MB. When re-uploading, if the path remains unchanged, there is no need to save the pipeline.",
"fileUploadSuccess": "Upload Successful",
Expand Down Expand Up @@ -466,6 +466,7 @@
},
"newlist": {
"exportJsonTip": "Through the import function, you can quickly create a pipeline, and you can also implement cross-project and cross-blue shield platform pipeline import.",
"exportPipelineYamlTip": "Export the YAML file to the code repository to enable PAC mode, allowing maintenance of the pipeline through the code repository or UI. ",
"chooseExport": "Choose the export file format",
"defaultViews": "My views",
"copyPipeline": "Copy pipeline",
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/locale/pipeline/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@
"pipelinesDetail": "执行详情",
"newPipelineFromTemplateLabel": "从模板新建",
"newPipelineFromJSONLabel": "导入流水线",
"importPipelineLabel": "请上传一个流水线JSON文件",
"invalidPipelineJson": "非法的流水线JSON文件",
"importPipelineLabel": "请上传一个流水线JSON/YAML文件",
"invalidPipelineJsonOrYaml": "非法的流水线JSON/YAML文件",
"exportPipelineSuccess": "导出流水线成功",
"sizeLimit": "最大上传{0}MB,重新上传时若路径未变更,无需保存流水线",
"fileUploadSuccess": "上传成功",
Expand Down Expand Up @@ -465,6 +465,7 @@
},
"newlist": {
"exportJsonTip": "通过导入功能,可以快速创建流水线,也可以实现跨项目、跨蓝盾平台的流水线导入。",
"exportPipelineYamlTip": "导出 YAML 文件提交到代码库,可以开启 PAC 模式,通过代码库或者UI维护流水线。",
"chooseExport": "选择导出的文件格式",
"defaultViews": "我的常用视图",
"copyPipeline": "复制流水线",
Expand Down

0 comments on commit 5285dff

Please sign in to comment.