feat 节点分发可以指定文件中心发布

This commit is contained in:
bwcx_jzy 2023-12-27 15:45:26 +08:00
parent b9b14de1d6
commit 7f838e9460
No known key found for this signature in database
GPG Key ID: E187D6E9DDDE8C53
5 changed files with 235 additions and 30 deletions

View File

@ -5,6 +5,7 @@
### 🐣 新增功能
1. 【server】新增 节点分发可以指定构建历史产物发布
2. 【server】新增 节点分发可以指定文件中心发布
### 🐞 解决BUG、优化功能

View File

@ -40,6 +40,8 @@ import org.dromara.jpom.common.BaseServerController;
import org.dromara.jpom.common.ServerConst;
import org.dromara.jpom.common.validator.ValidatorItem;
import org.dromara.jpom.common.validator.ValidatorRule;
import org.dromara.jpom.func.files.model.FileStorageModel;
import org.dromara.jpom.func.files.service.FileStorageService;
import org.dromara.jpom.model.AfterOpt;
import org.dromara.jpom.model.BaseEnum;
import org.dromara.jpom.model.BaseNodeModel;
@ -98,6 +100,7 @@ public class OutGivingProjectController extends BaseServerController {
private final ProjectInfoCacheService projectInfoCacheService;
private final BuildInfoService buildInfoService;
private final DbBuildHistoryLogService dbBuildHistoryLogService;
private final FileStorageService fileStorageService;
public OutGivingProjectController(OutGivingServer outGivingServer,
OutGivingWhitelistService outGivingWhitelistService,
@ -105,7 +108,8 @@ public class OutGivingProjectController extends BaseServerController {
DbOutGivingLogService dbOutGivingLogService,
ProjectInfoCacheService projectInfoCacheService,
BuildInfoService buildInfoService,
DbBuildHistoryLogService dbBuildHistoryLogService) {
DbBuildHistoryLogService dbBuildHistoryLogService,
FileStorageService fileStorageService) {
this.outGivingServer = outGivingServer;
this.outGivingWhitelistService = outGivingWhitelistService;
this.serverConfig = serverConfig;
@ -113,6 +117,7 @@ public class OutGivingProjectController extends BaseServerController {
this.projectInfoCacheService = projectInfoCacheService;
this.buildInfoService = buildInfoService;
this.dbBuildHistoryLogService = dbBuildHistoryLogService;
this.fileStorageService = fileStorageService;
}
@RequestMapping(value = "getItemData.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ -332,7 +337,6 @@ public class OutGivingProjectController extends BaseServerController {
@PostMapping(value = "use-build", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public IJsonMessage<String> useBuild(String id, String afterOpt, String clearOld, String buildId, String buildNumberId,
String autoUnzip,
String secondaryDirectory,
String stripComponents,
String selectProject,
@ -355,7 +359,6 @@ public class OutGivingProjectController extends BaseServerController {
EnvironmentMapBuilder environmentMapBuilder = buildHistoryLog.toEnvironmentMapBuilder();
boolean tarGz = environmentMapBuilder.getBool(BuildUtil.USE_TAR_GZ, false);
int stripComponentsValue = Convert.toInt(stripComponents, 0);
boolean unzip = BooleanUtil.toBoolean(autoUnzip);
//
outGivingModel.setClearOld(Convert.toBool(clearOld, false));
outGivingModel.setAfterOpt(afterOpt1.getCode());
@ -370,7 +373,7 @@ public class OutGivingProjectController extends BaseServerController {
.id(outGivingModel.getId())
.file(zipFile)
.userModel(getUser())
.unzip(unzip)
.unzip(unZip)
// 由构建配置决定是否删除
.doneDeleteFile(false)
.mode(outGivingModel.getMode())
@ -381,6 +384,56 @@ public class OutGivingProjectController extends BaseServerController {
return JsonMessage.success("开始分发!");
}
/**
* 远程文件中心分发文件
*
* @param id 分发id
* @param afterOpt 之后的操作
* @return json
*/
@PostMapping(value = "use-file-storage", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public IJsonMessage<String> useFileStorage(String id, String afterOpt, String clearOld, String fileId, String autoUnzip,
String secondaryDirectory,
String stripComponents,
String selectProject,
HttpServletRequest request) {
OutGivingModel outGivingModel = this.check(id, (status, outGivingModel1) -> Assert.state(status != OutGivingModel.Status.ING, "当前还在分发中,请等待分发结束"));
AfterOpt afterOpt1 = BaseEnum.getEnum(AfterOpt.class, Convert.toInt(afterOpt, 0));
Assert.notNull(afterOpt1, "请选择分发后的操作");
FileStorageModel storageModel = fileStorageService.getByKey(fileId, request);
Assert.notNull(storageModel, "对应的文件不存在");
//
outGivingModel.setClearOld(Convert.toBool(clearOld, false));
outGivingModel.setAfterOpt(afterOpt1.getCode());
outGivingModel.setSecondaryDirectory(secondaryDirectory);
outGivingModel.setMode("file-storage");
outGivingModel.setModeData(fileId);
outGivingServer.updateById(outGivingModel);
File storageSavePath = serverConfig.fileStorageSavePath();
File file = FileUtil.file(storageSavePath, storageModel.getPath());
Assert.state(FileUtil.isFile(file), "当前文件丢失不能执行发布任务");
//
boolean unzip = BooleanUtil.toBoolean(autoUnzip);
//
this.checkZip(file, unzip);
int stripComponentsValue = Convert.toInt(stripComponents, 0);
// 开启
OutGivingRun.OutGivingRunBuilder outGivingRunBuilder = OutGivingRun.builder()
.id(outGivingModel.getId())
.file(file)
.userModel(getUser())
.unzip(unzip)
.mode(outGivingModel.getMode())
.modeData(outGivingModel.getModeData())
// 可以不再设置-会查询最新的
// .projectSecondaryDirectory(secondaryDirectory)
.stripComponents(stripComponentsValue);
outGivingRunBuilder.build().startRun(selectProject);
return JsonMessage.success("开始分发!");
}
@PostMapping(value = "cancel", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public IJsonMessage<String> cancel(@ValidatorItem String id) {

View File

@ -144,6 +144,14 @@ export function useBuild(params) {
});
}
export function useuseFileStorage(params) {
return axios({
url: "/outgiving/use-file-storage",
method: "post",
data: params,
});
}
/**
* 释放分发
* @param {*} id 分发 ID

View File

@ -22,9 +22,10 @@
<a-radio :value="'upload'">上传文件</a-radio>
<a-radio :value="'download'">远程下载</a-radio>
<a-radio :value="'use-build'">构建产物</a-radio>
<a-radio :value="'file-storage'">文件中心</a-radio>
</a-radio-group>
</a-form-model-item>
<!-- 手动上传 -->
<a-form-model-item label="选择分发文件" prop="clearOld" v-if="temp.type === 'upload'">
<a-progress v-if="percentage" :percent="percentage">
<template #format="percent">
@ -39,18 +40,20 @@
<a-button v-else type="primary" icon="upload">选择文件上传</a-button>
</a-upload>
</a-form-model-item>
<!-- 远程下载 -->
<a-form-model-item label="远程下载URL" prop="url" v-else-if="temp.type === 'download'">
<a-input v-model="temp.url" placeholder="远程下载地址" />
</a-form-model-item>
<!-- 在线构建 -->
<template v-else-if="temp.type == 'use-build'">
<a-form-model-item label="选择构建">
<a-space>
{{ buildInfo.name }}
{{ chooseBuildInfo.name }}
<a-button
type="primary"
@click="
() => {
chooseBuildVisible = 1;
chooseVisible = 1;
}
"
>
@ -60,13 +63,13 @@
</a-form-model-item>
<a-form-model-item label="选择产物">
<a-space>
<a-tag v-if="buildInfo.buildNumberId">#{{ buildInfo.buildNumberId }}</a-tag>
<a-tag v-if="chooseBuildInfo.buildNumberId">#{{ chooseBuildInfo.buildNumberId }}</a-tag>
<a-button
type="primary"
:disabled="!buildInfo.id"
:disabled="!chooseBuildInfo.id"
@click="
() => {
chooseBuildVisible = 2;
chooseVisible = 2;
}
"
>
@ -75,6 +78,24 @@
</a-space>
</a-form-model-item>
</template>
<!-- 文件中心 -->
<template v-else-if="temp.type === 'file-storage'">
<a-form-model-item label="选择文件">
<a-space>
{{ chooseFileInfo.name }}
<a-button
type="primary"
@click="
() => {
chooseVisible = 3;
}
"
>
选择文件
</a-button>
</a-space>
</a-form-model-item></template
>
<a-form-model-item prop="clearOld">
<template slot="label">
清空发布
@ -85,7 +106,7 @@
</template>
<a-switch v-model="temp.clearOld" checked-children="" un-checked-children="" />
</a-form-model-item>
<a-form-model-item prop="unzip">
<a-form-model-item prop="unzip" v-if="temp.type !== 'use-build'">
<template slot="label">
是否解压
<a-tooltip>
@ -121,32 +142,32 @@
destroyOnClose
:title="`选择构建`"
placement="right"
:visible="chooseBuildVisible === 1"
:visible="chooseVisible === 1"
width="80vw"
:zIndex="1009"
@close="
() => {
this.chooseBuildVisible = 0;
this.chooseVisible = 0;
}
"
>
<build-list
v-if="chooseBuildVisible === 1"
v-if="chooseVisible === 1"
:choose="'radio'"
layout="table"
mode="choose"
@confirm="
(data) => {
this.buildInfo = {
this.chooseBuildInfo = {
id: data[0].id,
name: data[0].name,
};
this.chooseBuildVisible = 0;
this.chooseVisible = 0;
}
"
@cancel="
() => {
this.chooseBuildVisible = 0;
this.chooseVisible = 0;
}
"
></build-list>
@ -156,43 +177,78 @@
destroyOnClose
:title="`选择构建产物`"
placement="right"
:visible="chooseBuildVisible === 2"
:visible="chooseVisible === 2"
width="80vw"
:zIndex="1009"
@close="
() => {
this.chooseBuildVisible = 0;
this.chooseVisible = 0;
}
"
>
<!-- 选择构建产物 -->
<build-history
v-if="chooseBuildVisible === 2"
v-if="chooseVisible === 2"
:choose="'radio'"
mode="choose"
@confirm="
(data) => {
this.buildInfo = { ...this.buildInfo, buildNumberId: data[0] };
this.chooseBuildVisible = 0;
this.chooseBuildInfo = { ...this.chooseBuildInfo, buildNumberId: data[0] };
this.chooseVisible = 0;
}
"
@cancel="
() => {
this.chooseBuildVisible = 0;
this.chooseVisible = 0;
}
"
></build-history>
</a-drawer>
<!-- 选择文件 -->
<a-drawer
destroyOnClose
:title="`选择文件`"
placement="right"
:visible="chooseVisible === 3"
width="80vw"
:zIndex="1009"
@close="
() => {
this.chooseVisible = 0;
}
"
>
<!-- 选择文件 -->
<file-storage
v-if="chooseVisible === 3"
:choose="'radio'"
mode="choose"
@confirm="
(data) => {
this.chooseFileInfo = { id: data[0].id, name: data[0].name };
this.chooseVisible = 0;
}
"
@cancel="
() => {
this.chooseVisible = 0;
}
"
></file-storage>
</a-drawer>
</div>
</template>
<script>
import { uploadPieces } from "@/utils/upload-pieces";
import { remoteDownload, uploadDispatchFile, uploadDispatchFileMerge, afterOptList, getDispatchProject, useBuild } from "@/api/dispatch";
import { remoteDownload, uploadDispatchFile, uploadDispatchFileMerge, afterOptList, getDispatchProject, useBuild, useuseFileStorage } from "@/api/dispatch";
import { renderSize, formatDuration } from "@/utils/const";
import BuildList from "@/pages/build/list-info";
import BuildHistory from "@/pages/build/history";
import FileStorage from "@/pages/file-manager/fileStorage/list";
import { getBuildGet } from "@/api/build-info";
import { hasFile } from "@/api/file-manager/file-storage";
export default {
components: { BuildList, BuildHistory },
components: { BuildList, BuildHistory, FileStorage },
props: {
data: Object,
},
@ -209,8 +265,9 @@ export default {
url: [{ required: true, message: "请输入远程地址", trigger: "blur" }],
},
temp: { type: "upload" },
chooseBuildVisible: 0,
buildInfo: {},
chooseVisible: 0,
chooseBuildInfo: {},
chooseFileInfo: {},
};
},
created() {
@ -226,18 +283,29 @@ export default {
}
});
if (this.data.mode === "use-build") {
//
const buildData = (this.data.modeData || "").split(":");
if (buildData.length === 2) {
getBuildGet({
id: buildData[0],
}).then((res) => {
if (res.code === 200 && res.data) {
this.buildInfo = { id: res.data.id, name: res.data.name, buildNumberId: buildData[1] };
this.chooseBuildInfo = { id: res.data.id, name: res.data.name, buildNumberId: buildData[1] };
}
});
}
} else if (this.data.mode === "download") {
//
this.temp = { ...this.temp, url: this.data.modeData };
} else if (this.data.mode === "file-storage") {
//
if (this.data.modeData) {
hasFile({ fileSumMd5: this.data.modeData }).then((res) => {
if (res.code === 200 && res.data) {
this.chooseFileInfo = { id: res.data.id, name: res.data.name };
}
});
}
}
// console.log(this.temp);
},
@ -357,13 +425,32 @@ export default {
});
return true;
} else if (this.temp.type == "use-build") {
if (!this.buildInfo || !this.buildInfo.id || !this.buildInfo.buildNumberId) {
//
if (!this.chooseBuildInfo || !this.chooseBuildInfo.id || !this.chooseBuildInfo.buildNumberId) {
this.$notification.error({
message: "请填写构建和产物",
});
return false;
}
useBuild({ ...this.temp, buildId: this.buildInfo.id, buildNumberId: this.buildInfo.buildNumberId }).then((res) => {
useBuild({ ...this.temp, buildId: this.chooseBuildInfo.id, buildNumberId: this.chooseBuildInfo.buildNumberId }).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,
});
this.$emit("cancel");
}
});
return true;
} else if (this.temp.type == "file-storage") {
//
if (!this.chooseFileInfo || !this.chooseFileInfo.id) {
this.$notification.error({
message: "请填写文件中心文件",
});
return false;
}
useuseFileStorage({ ...this.temp, fileId: this.chooseFileInfo.id }).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,

View File

@ -291,6 +291,35 @@
<releaseFile ref="releaseFile" v-if="releaseFileVisible" @commit="handleCommitTask"></releaseFile>
</a-modal>
</div>
<!-- 选择确认区域 -->
<div style="padding-top: 50px" v-if="this.choose">
<div
:style="{
position: 'absolute',
right: 0,
bottom: 0,
width: '100%',
borderTop: '1px solid #e9e9e9',
padding: '10px 16px',
background: '#fff',
textAlign: 'right',
zIndex: 1,
}"
>
<a-space>
<a-button
@click="
() => {
this.$emit('cancel');
}
"
>
取消
</a-button>
<a-button type="primary" @click="handerConfirm"> 确定 </a-button>
</a-space>
</div>
</div>
</div>
</template>
@ -306,6 +335,13 @@ export default {
components: {
releaseFile,
},
props: {
choose: {
// "radio"
type: String,
default: "",
},
},
data() {
return {
loading: false,
@ -381,6 +417,7 @@ export default {
this.tableSelections = selectedRowKeys;
},
selectedRowKeys: this.tableSelections,
type: this.choose || "checkbox",
};
},
},
@ -664,6 +701,25 @@ export default {
releaseFileOk() {
this.$refs.releaseFile?.tryCommit();
},
//
handerConfirm() {
if (!this.tableSelections.length) {
this.$notification.warning({
message: "请选择要使用的文件",
});
return;
}
const selectData = this.list.filter((item) => {
return this.tableSelections.indexOf(item.id) > -1;
});
if (!selectData.length) {
this.$notification.warning({
message: "请选择要使用的文件",
});
return;
}
this.$emit("confirm", selectData);
},
},
};
</script>