fix(测试跟踪): 非xpack同步jira缺陷报错

This commit is contained in:
chenjianxing 2022-11-21 22:15:58 +08:00 committed by jianxing
parent 133f474d39
commit 6142f28f76
5 changed files with 92 additions and 66 deletions

View File

@ -153,9 +153,9 @@ public class IssuesController {
return issuesService.getZentaoBuilds(request); return issuesService.getZentaoBuilds(request);
} }
@PostMapping("/sync") @GetMapping("/sync/{projectId}")
public boolean getPlatformIssue(@RequestBody IssueSyncRequest request) { public boolean getPlatformIssue(@PathVariable String projectId) {
return issuesService.syncThirdPartyIssues(request); return issuesService.syncThirdPartyIssues(projectId);
} }
@GetMapping("/sync/check/{projectId}") @GetMapping("/sync/check/{projectId}")

View File

@ -886,9 +886,7 @@ public class IssuesService {
List<String> projectIds = trackProjectService.getThirdPartProjectIds(); List<String> projectIds = trackProjectService.getThirdPartProjectIds();
projectIds.forEach(id -> { projectIds.forEach(id -> {
try { try {
IssueSyncRequest request = new IssueSyncRequest(); syncThirdPartyIssues(id);
request.setProjectId(id);
syncThirdPartyIssues(request);
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
} }
@ -931,38 +929,35 @@ public class IssuesService {
stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_KEY + ":" + projectId); stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_KEY + ":" + projectId);
} }
public boolean syncThirdPartyIssues(IssueSyncRequest syncRequest) { public boolean syncThirdPartyIssues(String projectId) {
if (StringUtils.isNotBlank(syncRequest.getProjectId())) { if (StringUtils.isNotBlank(projectId)) {
String syncValue = getSyncKey(syncRequest.getProjectId()); String syncValue = getSyncKey(projectId);
if (StringUtils.isNotEmpty(syncValue)) { if (StringUtils.isNotEmpty(syncValue)) {
return false; return false;
} }
setSyncKey(syncRequest.getProjectId()); setSyncKey(projectId);
Project project = baseProjectService.getProjectById(syncRequest.getProjectId()); Project project = baseProjectService.getProjectById(projectId);
List<IssuesDao> issues = extIssuesMapper.getIssueForSync(syncRequest.getProjectId(), project.getPlatform()); List<IssuesDao> issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform());
if (syncRequest.getCreateTime() != null) {
issues = filterSyncIssuesByCreated(issues, syncRequest);
}
if (CollectionUtils.isEmpty(issues)) { if (CollectionUtils.isEmpty(issues)) {
return true; return true;
} }
IssuesRequest issuesRequest = new IssuesRequest(); IssuesRequest issuesRequest = new IssuesRequest();
issuesRequest.setProjectId(syncRequest.getProjectId()); issuesRequest.setProjectId(projectId);
issuesRequest.setWorkspaceId(project.getWorkspaceId()); issuesRequest.setWorkspaceId(project.getWorkspaceId());
try { try {
if (!trackProjectService.isThirdPartTemplate(project)) { if (!trackProjectService.isThirdPartTemplate(project)) {
String defaultCustomFields = getDefaultCustomFields(syncRequest.getProjectId()); String defaultCustomFields = getDefaultCustomFields(projectId);
issuesRequest.setDefaultCustomFields(defaultCustomFields); issuesRequest.setDefaultCustomFields(defaultCustomFields);
} }
if (PlatformPluginService.isPluginPlatform(project.getPlatform())) { if (PlatformPluginService.isPluginPlatform(project.getPlatform())) {
// 分批处理 // 分批处理
SubListUtil.dealForSubList(issues, 500, (subIssue) -> SubListUtil.dealForSubList(issues, 500, (subIssue) ->
syncPluginThirdPartyIssues(subIssue, project)); syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields()));
} else { } else {
IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest); IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest);
syncThirdPartyIssues(platform::syncIssues, project, issues); syncThirdPartyIssues(platform::syncIssues, project, issues);
@ -970,13 +965,13 @@ public class IssuesService {
} catch (Exception e) { } catch (Exception e) {
throw e; throw e;
} finally { } finally {
deleteSyncKey(syncRequest.getProjectId()); deleteSyncKey(projectId);
} }
} }
return true; return true;
} }
public void syncPluginThirdPartyIssues(List<IssuesDao> issues, Project project) { public void syncPluginThirdPartyIssues(List<IssuesDao> issues, Project project, String defaultCustomFields) {
List<PlatformIssuesDTO> platformIssues = JSON.parseArray(JSON.toJSONString(issues), PlatformIssuesDTO.class); List<PlatformIssuesDTO> platformIssues = JSON.parseArray(JSON.toJSONString(issues), PlatformIssuesDTO.class);
platformIssues.stream().forEach(item -> { platformIssues.stream().forEach(item -> {
// 给缺陷添加自定义字段 // 给缺陷添加自定义字段
@ -991,6 +986,7 @@ public class IssuesService {
}); });
SyncIssuesRequest request = new SyncIssuesRequest(); SyncIssuesRequest request = new SyncIssuesRequest();
request.setIssues(platformIssues); request.setIssues(platformIssues);
request.setDefaultCustomFields(defaultCustomFields);
request.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project)); request.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project));
Platform platform = platformPluginService.getPlatform(project.getPlatform()); Platform platform = platformPluginService.getPlatform(project.getPlatform());
@ -999,17 +995,12 @@ public class IssuesService {
List<IssuesWithBLOBs> updateIssues = syncIssuesResult.getUpdateIssues(); List<IssuesWithBLOBs> updateIssues = syncIssuesResult.getUpdateIssues();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
IssuesMapper issueBatchMapper = sqlSession.getMapper(IssuesMapper.class); IssuesMapper issueBatchMapper = sqlSession.getMapper(IssuesMapper.class);
AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper = sqlSession.getMapper(AttachmentModuleRelationMapper.class); AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper = sqlSession.getMapper(AttachmentModuleRelationMapper.class);
// 批量更新 // 批量更新
updateIssues.stream() updateIssues.forEach(issueBatchMapper::updateByPrimaryKeySelective);
.map(item -> {
IssuesWithBLOBs issuesWithBLOBs = new IssuesWithBLOBs();
BeanUtils.copyBean(issuesWithBLOBs, item);
return issuesWithBLOBs;
})
.forEach(issueBatchMapper::updateByPrimaryKeySelective);
// 批量删除 // 批量删除
syncIssuesResult.getDeleteIssuesIds() syncIssuesResult.getDeleteIssuesIds()
@ -1031,6 +1022,12 @@ public class IssuesService {
// 修改自定义字段 // 修改自定义字段
customFieldIssuesService.batchEditFields(customFieldMap); customFieldIssuesService.batchEditFields(customFieldMap);
sqlSession.commit();
} catch (Exception e) {
sqlSession.close();
MSException.throwException(e);
}
} }
private void syncPluginIssueAttachment(Platform platform, SyncIssuesResult syncIssuesResult, AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) { private void syncPluginIssueAttachment(Platform platform, SyncIssuesResult syncIssuesResult, AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
@ -1049,8 +1046,8 @@ public class IssuesService {
List<PlatformAttachment> syncAttachments = attachmentMap.get(issueId); List<PlatformAttachment> syncAttachments = attachmentMap.get(issueId);
for (PlatformAttachment syncAttachment : syncAttachments) { for (PlatformAttachment syncAttachment : syncAttachments) {
jiraAttachmentSet.add(syncAttachment.getFileName());
if (!attachmentsNameSet.contains(syncAttachment.getFileName())) { if (!attachmentsNameSet.contains(syncAttachment.getFileName())) {
jiraAttachmentSet.add(syncAttachment.getFileName());
try { try {
byte[] content = platform.getAttachmentContent(syncAttachment.getFileKey()); byte[] content = platform.getAttachmentContent(syncAttachment.getFileKey());
if (content == null) { if (content == null) {

View File

@ -3,7 +3,6 @@ package io.metersphere.service.wapper;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.service.PlatformPluginService; import io.metersphere.service.PlatformPluginService;
import io.metersphere.xpack.track.dto.request.IssuesRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -35,10 +34,7 @@ public class IssueProxyResourceService {
MSException.throwException(Translator.get("invalid_parameter")); MSException.throwException(Translator.get("invalid_parameter"));
} }
if (StringUtils.isNotBlank(platform)) { if (StringUtils.isNotBlank(platform)) {
IssuesRequest issuesRequest = new IssuesRequest(); return platformPluginService.getPlatform(platform, workspaceId)
issuesRequest.setProjectId(projectId);
issuesRequest.setWorkspaceId(workspaceId);
return platformPluginService.getPlatform(platform)
.proxyForGet(url, byte[].class); .proxyForGet(url, byte[].class);
} }

View File

@ -146,16 +146,18 @@ export function getRelateIssues(page) {
}); });
} }
export function syncIssues(param) { export function syncAllIssues(param) {
let url = 'issues/sync';
if (hasLicense()) {
url = 'xpack/issue/sync';
}
// 浏览器默认策略请求同一个url可能导致 stalled 时间过长加个uuid防止请求阻塞 // 浏览器默认策略请求同一个url可能导致 stalled 时间过长加个uuid防止请求阻塞
url = url + "?stamp=" + getUUID(); let url = 'xpack/issue/sync' + "?stamp=" + getUUID();
return post(url, param); return post(url, param);
} }
export function syncIssues() {
// 浏览器默认策略请求同一个url可能导致 stalled 时间过长加个uuid防止请求阻塞
let url = 'issues/sync/' + getCurrentProjectID() + "?stamp=" + getUUID();
return get(url);
}
// 轮询同步状态 // 轮询同步状态
export function checkSyncIssues(loading, isNotFirst) { export function checkSyncIssues(loading, isNotFirst) {
let url = 'issues/sync/check/' + getCurrentProjectID() + "?stamp=" + getUUID(); let url = 'issues/sync/check/' + getCurrentProjectID() + "?stamp=" + getUUID();

View File

@ -7,7 +7,21 @@
:create-tip="$t('test_track.issue.create_issue')" :create-tip="$t('test_track.issue.create_issue')"
:tip="$t('commons.search_by_name_or_id')"> :tip="$t('commons.search_by_name_or_id')">
<template v-slot:button> <template v-slot:button>
<ms-table-button icon="el-icon-refresh" :content="$t('test_track.issue.sync_bugs')" v-if="isThirdPart && hasPermission('PROJECT_TRACK_ISSUE:READ+CREATE')" @click="syncIssues"/>
<span v-if="isThirdPart && hasPermission('PROJECT_TRACK_ISSUE:READ+CREATE')">
<ms-table-button
v-if="hasLicense"
icon="el-icon-refresh"
:content="$t('test_track.issue.sync_bugs')"
@click="syncAllIssues"/>
<ms-table-button
v-if="!hasLicense"
icon="el-icon-refresh"
:content="$t('test_track.issue.sync_bugs')"
@click="syncIssues"/>
</span>
<ms-table-button icon="el-icon-upload2" :content="$t('commons.import')" v-if="hasPermission('PROJECT_TRACK_ISSUE:READ+CREATE')" @click="handleImport"/> <ms-table-button icon="el-icon-upload2" :content="$t('commons.import')" v-if="hasPermission('PROJECT_TRACK_ISSUE:READ+CREATE')" @click="handleImport"/>
<ms-table-button icon="el-icon-download" :content="$t('commons.export')" v-if="hasPermission('PROJECT_TRACK_ISSUE:READ')" @click="handleExport"/> <ms-table-button icon="el-icon-download" :content="$t('commons.export')" v-if="hasPermission('PROJECT_TRACK_ISSUE:READ')" @click="handleExport"/>
</template> </template>
@ -195,7 +209,7 @@ import {
getIssues, getIssues,
syncIssues, syncIssues,
deleteIssue, deleteIssue,
getIssuesById, batchDeleteIssue, getPlatformOption getIssuesById, batchDeleteIssue, getPlatformOption, syncAllIssues
} from "@/api/issue"; } from "@/api/issue";
import { import {
getCustomFieldValue, getCustomFieldValue,
@ -214,6 +228,7 @@ import {
getAdvSearchCustomField getAdvSearchCustomField
} from "metersphere-frontend/src/components/search/custom-component"; } from "metersphere-frontend/src/components/search/custom-component";
import MsMarkDownText from "metersphere-frontend/src/components/MsMarkDownText"; import MsMarkDownText from "metersphere-frontend/src/components/MsMarkDownText";
import {hasLicense} from "metersphere-frontend/src/utils/permission";
export default { export default {
name: "IssueList", name: "IssueList",
@ -269,7 +284,8 @@ export default {
creatorFilters: [], creatorFilters: [],
loading: false, loading: false,
dataSelectRange: "", dataSelectRange: "",
platformOptions: [] platformOptions: [],
hasLicense: false
}; };
}, },
watch: { watch: {
@ -303,6 +319,8 @@ export default {
.then((r) => { .then((r) => {
this.platformOptions = r.data; this.platformOptions = r.data;
}); });
this.hasLicense = hasLicense();
}, },
computed: { computed: {
platformFilters() { platformFilters() {
@ -467,7 +485,7 @@ export default {
} }
return false; return false;
}, },
syncIssues() { syncAllIssues() {
this.$refs.issueSyncSelect.open(); this.$refs.issueSyncSelect.open();
}, },
handleImport() { handleImport() {
@ -500,7 +518,20 @@ export default {
"createTime": data.createTime.getTime(), "createTime": data.createTime.getTime(),
"pre": data.preValue "pre": data.preValue
} }
syncIssues(param) syncAllIssues(param)
.then((response) => {
if (response.data === false) {
checkSyncIssues(this.loading);
} else {
this.$success(this.$t('test_track.issue.sync_complete'));
this.loading = false;
this.getIssues();
}
});
},
syncIssues() {
this.loading = true;
syncIssues()
.then((response) => { .then((response) => {
if (response.data === false) { if (response.data === false) {
checkSyncIssues(this.loading); checkSyncIssues(this.loading);