fix(测试跟踪): Jira同步全量缺陷失败
This commit is contained in:
parent
a3ced967c4
commit
9449bf8243
|
@ -29,7 +29,7 @@
|
||||||
<platform-account-config
|
<platform-account-config
|
||||||
:config="config"
|
:config="config"
|
||||||
:account-config="currentPlatformInfo"
|
:account-config="currentPlatformInfo"
|
||||||
v-if="config.key === 'Jira'"
|
v-if="showPlatformConfig(config.key)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<tapd-user-info @auth="handleAuth" v-if="hasTapd" :data="currentPlatformInfo"/>
|
<tapd-user-info @auth="handleAuth" v-if="hasTapd" :data="currentPlatformInfo"/>
|
||||||
|
@ -64,6 +64,7 @@ import {useUserStore} from "@/store";
|
||||||
import {handleAuth as _handleAuth, getUserInfo, getWsAndPj, updateInfo} from "../../api/user";
|
import {handleAuth as _handleAuth, getUserInfo, getWsAndPj, updateInfo} from "../../api/user";
|
||||||
import PlatformAccountConfig from "./PlatformAccountConfig";
|
import PlatformAccountConfig from "./PlatformAccountConfig";
|
||||||
import {getPlatformAccountInfo} from "../../api/platform-plugin";
|
import {getPlatformAccountInfo} from "../../api/platform-plugin";
|
||||||
|
import {ISSUE_PLATFORM_OPTION} from "../../utils/table-constants";
|
||||||
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
@ -125,6 +126,9 @@ export default {
|
||||||
currentUser: () => {
|
currentUser: () => {
|
||||||
return getCurrentUser();
|
return getCurrentUser();
|
||||||
},
|
},
|
||||||
|
showPlatformConfig(platform) {
|
||||||
|
return ISSUE_PLATFORM_OPTION.map(item => item.value).indexOf(platform) < 0;
|
||||||
|
},
|
||||||
handleAuth(type) {
|
handleAuth(type) {
|
||||||
let param = {...this.currentPlatformInfo};
|
let param = {...this.currentPlatformInfo};
|
||||||
if (type === 'Zentao') {
|
if (type === 'Zentao') {
|
||||||
|
@ -246,7 +250,8 @@ export default {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-form-item-class {
|
.el-form-item-class {
|
||||||
margin-left:110px;
|
margin-left: 110px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package io.metersphere.xpack.track.controller;
|
|
||||||
|
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
|
||||||
import io.metersphere.xpack.track.dto.IssueSyncRequest;
|
|
||||||
import io.metersphere.xpack.track.service.XpackIssueService;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping(value = "/xpack/issue")
|
|
||||||
public class XpackIssueController {
|
|
||||||
|
|
||||||
@PostMapping("/sync")
|
|
||||||
public boolean getPlatformIssue(@RequestBody IssueSyncRequest request) {
|
|
||||||
XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class);
|
|
||||||
return xpackIssueService.syncThirdPartyIssues(request);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.metersphere.request.attachment;
|
package io.metersphere.xpack.track.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
|
@ -2,6 +2,10 @@ package io.metersphere.xpack.track.dto;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author songcc
|
* @author songcc
|
||||||
*/
|
*/
|
||||||
|
@ -22,4 +26,8 @@ public class IssueSyncRequest {
|
||||||
* TRUE: 创建时间之前
|
* TRUE: 创建时间之前
|
||||||
*/
|
*/
|
||||||
private boolean pre;
|
private boolean pre;
|
||||||
|
|
||||||
|
private String defaultCustomFields;
|
||||||
|
|
||||||
|
private Map<String, List<io.metersphere.xpack.track.dto.PlatformAttachment>> attachmentMap = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package io.metersphere.xpack.track.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class PlatformAttachment {
|
||||||
|
private String fileName;
|
||||||
|
private String fileKey;
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package io.metersphere.xpack.track.service;
|
package io.metersphere.xpack.track.service;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.Project;
|
||||||
import io.metersphere.xpack.track.dto.IssueSyncRequest;
|
import io.metersphere.xpack.track.dto.IssueSyncRequest;
|
||||||
|
|
||||||
public interface XpackIssueService {
|
public interface XpackIssueService {
|
||||||
|
|
||||||
boolean syncThirdPartyIssues(IssueSyncRequest request);
|
boolean syncThirdPartyIssues(Project project, IssueSyncRequest request);
|
||||||
|
|
||||||
void syncThirdPartyIssues();
|
void syncThirdPartyIssues();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.metersphere.controller;
|
||||||
import io.metersphere.base.domain.FileAttachmentMetadata;
|
import io.metersphere.base.domain.FileAttachmentMetadata;
|
||||||
import io.metersphere.metadata.service.FileMetadataService;
|
import io.metersphere.metadata.service.FileMetadataService;
|
||||||
import io.metersphere.request.attachment.AttachmentDumpRequest;
|
import io.metersphere.request.attachment.AttachmentDumpRequest;
|
||||||
import io.metersphere.request.attachment.AttachmentRequest;
|
import io.metersphere.xpack.track.dto.AttachmentRequest;
|
||||||
import io.metersphere.service.AttachmentService;
|
import io.metersphere.service.AttachmentService;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|
|
@ -25,10 +25,7 @@ import io.metersphere.service.BaseCheckPermissionService;
|
||||||
import io.metersphere.service.IssuesService;
|
import io.metersphere.service.IssuesService;
|
||||||
import io.metersphere.service.PlatformPluginService;
|
import io.metersphere.service.PlatformPluginService;
|
||||||
import io.metersphere.service.issue.domain.zentao.ZentaoBuild;
|
import io.metersphere.service.issue.domain.zentao.ZentaoBuild;
|
||||||
import io.metersphere.xpack.track.dto.IssueTemplateDao;
|
import io.metersphere.xpack.track.dto.*;
|
||||||
import io.metersphere.xpack.track.dto.IssuesDao;
|
|
||||||
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
|
|
||||||
import io.metersphere.xpack.track.dto.PlatformUser;
|
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -164,10 +161,15 @@ public class IssuesController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/sync/{projectId}")
|
@GetMapping("/sync/{projectId}")
|
||||||
public boolean getPlatformIssue(@PathVariable String projectId) {
|
public boolean syncThirdPartyIssues(@PathVariable String projectId) {
|
||||||
return issuesService.syncThirdPartyIssues(projectId);
|
return issuesService.syncThirdPartyIssues(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/sync/all")
|
||||||
|
public boolean syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) {
|
||||||
|
return issuesService.syncThirdPartyAllIssues(request);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/sync/check/{projectId}")
|
@GetMapping("/sync/check/{projectId}")
|
||||||
public boolean checkSync(@PathVariable String projectId) {
|
public boolean checkSync(@PathVariable String projectId) {
|
||||||
return issuesService.checkSync(projectId);
|
return issuesService.checkSync(projectId);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import io.metersphere.i18n.Translator;
|
||||||
import io.metersphere.metadata.service.FileMetadataService;
|
import io.metersphere.metadata.service.FileMetadataService;
|
||||||
import io.metersphere.metadata.utils.MetadataUtils;
|
import io.metersphere.metadata.utils.MetadataUtils;
|
||||||
import io.metersphere.platform.domain.SyncIssuesAttachmentRequest;
|
import io.metersphere.platform.domain.SyncIssuesAttachmentRequest;
|
||||||
import io.metersphere.request.attachment.AttachmentRequest;
|
import io.metersphere.xpack.track.dto.AttachmentRequest;
|
||||||
import io.metersphere.service.issue.platform.IssueFactory;
|
import io.metersphere.service.issue.platform.IssueFactory;
|
||||||
import io.metersphere.xmind.utils.FileUtil;
|
import io.metersphere.xmind.utils.FileUtil;
|
||||||
import io.metersphere.xpack.track.dto.AttachmentSyncType;
|
import io.metersphere.xpack.track.dto.AttachmentSyncType;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.base.domain.CustomFieldIssues;
|
||||||
import io.metersphere.base.domain.CustomFieldIssuesExample;
|
import io.metersphere.base.domain.CustomFieldIssuesExample;
|
||||||
import io.metersphere.base.mapper.CustomFieldIssuesMapper;
|
import io.metersphere.base.mapper.CustomFieldIssuesMapper;
|
||||||
import io.metersphere.base.mapper.ext.BaseCustomFieldResourceMapper;
|
import io.metersphere.base.mapper.ext.BaseCustomFieldResourceMapper;
|
||||||
|
import io.metersphere.commons.utils.SubListUtil;
|
||||||
import io.metersphere.constants.SystemCustomField;
|
import io.metersphere.constants.SystemCustomField;
|
||||||
import io.metersphere.dto.CustomFieldDao;
|
import io.metersphere.dto.CustomFieldDao;
|
||||||
import io.metersphere.dto.CustomFieldResourceDTO;
|
import io.metersphere.dto.CustomFieldResourceDTO;
|
||||||
|
@ -102,9 +103,19 @@ public class CustomFieldIssuesService extends CustomFieldResourceService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addList.forEach(l -> batchMapper.insert(TABLE_NAME, l));
|
|
||||||
updateList.forEach(l -> batchMapper.updateByPrimaryKeySelective(TABLE_NAME, l));
|
int batchSize = 500;
|
||||||
sqlSession.flushStatements();
|
|
||||||
|
SubListUtil.dealForSubList(addList, batchSize, (subList) -> {
|
||||||
|
subList.forEach(l -> batchMapper.insert(TABLE_NAME, (CustomFieldResourceDTO) l));
|
||||||
|
sqlSession.commit();
|
||||||
|
});
|
||||||
|
|
||||||
|
SubListUtil.dealForSubList(updateList, batchSize, (subList) -> {
|
||||||
|
subList.forEach(l -> batchMapper.updateByPrimaryKeySelective(TABLE_NAME, (CustomFieldResourceDTO) l));
|
||||||
|
sqlSession.commit();
|
||||||
|
});
|
||||||
|
|
||||||
if (sqlSession != null && sqlSessionFactory != null) {
|
if (sqlSession != null && sqlSessionFactory != null) {
|
||||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,9 @@ import io.metersphere.plan.service.TestPlanTestCaseService;
|
||||||
import io.metersphere.plan.utils.TestPlanStatusCalculator;
|
import io.metersphere.plan.utils.TestPlanStatusCalculator;
|
||||||
import io.metersphere.platform.api.Platform;
|
import io.metersphere.platform.api.Platform;
|
||||||
import io.metersphere.platform.domain.*;
|
import io.metersphere.platform.domain.*;
|
||||||
|
import io.metersphere.platform.domain.PlatformAttachment;
|
||||||
import io.metersphere.request.IntegrationRequest;
|
import io.metersphere.request.IntegrationRequest;
|
||||||
import io.metersphere.request.attachment.AttachmentRequest;
|
import io.metersphere.xpack.track.dto.AttachmentRequest;
|
||||||
import io.metersphere.request.issues.IssueExportRequest;
|
import io.metersphere.request.issues.IssueExportRequest;
|
||||||
import io.metersphere.request.issues.IssueImportRequest;
|
import io.metersphere.request.issues.IssueImportRequest;
|
||||||
import io.metersphere.request.issues.PlatformIssueTypeRequest;
|
import io.metersphere.request.issues.PlatformIssueTypeRequest;
|
||||||
|
@ -58,6 +59,7 @@ import io.metersphere.xpack.track.dto.*;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
||||||
import io.metersphere.xpack.track.issue.IssuesPlatform;
|
import io.metersphere.xpack.track.issue.IssuesPlatform;
|
||||||
|
import io.metersphere.xpack.track.service.XpackIssueService;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
@ -1005,7 +1007,7 @@ public class IssuesService {
|
||||||
request.setIssues(platformIssues);
|
request.setIssues(platformIssues);
|
||||||
request.setDefaultCustomFields(defaultCustomFields);
|
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(), project.getWorkspaceId());
|
||||||
|
|
||||||
// 获取需要变更的缺陷
|
// 获取需要变更的缺陷
|
||||||
SyncIssuesResult syncIssuesResult = platform.syncIssues(request);
|
SyncIssuesResult syncIssuesResult = platform.syncIssues(request);
|
||||||
|
@ -1047,61 +1049,125 @@ public class IssuesService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncPluginIssueAttachment(Platform platform, SyncIssuesResult syncIssuesResult, AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
|
private void syncPluginIssueAttachment(Platform platform, SyncIssuesResult syncIssuesResult,
|
||||||
|
AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
|
||||||
Map<String, List<PlatformAttachment>> attachmentMap = syncIssuesResult.getAttachmentMap();
|
Map<String, List<PlatformAttachment>> attachmentMap = syncIssuesResult.getAttachmentMap();
|
||||||
if (MapUtils.isNotEmpty(attachmentMap)) {
|
if (MapUtils.isNotEmpty(attachmentMap)) {
|
||||||
for (String issueId : attachmentMap.keySet()) {
|
for (String issueId : attachmentMap.keySet()) {
|
||||||
// 查询我们平台的附件
|
// 查询我们平台的附件
|
||||||
Set<String> jiraAttachmentSet = new HashSet<>();
|
Set<String> jiraAttachmentSet = new HashSet<>();
|
||||||
AttachmentRequest attachmentRequest = new AttachmentRequest();
|
List<FileAttachmentMetadata> allMsAttachments = getIssueFileAttachmentMetadata(issueId);
|
||||||
attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
|
|
||||||
attachmentRequest.setBelongId(issueId);
|
|
||||||
List<FileAttachmentMetadata> allMsAttachments = attachmentService.listMetadata(attachmentRequest);
|
|
||||||
Set<String> attachmentsNameSet = allMsAttachments.stream()
|
Set<String> attachmentsNameSet = allMsAttachments.stream()
|
||||||
.map(FileAttachmentMetadata::getName)
|
.map(FileAttachmentMetadata::getName)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
List<PlatformAttachment> syncAttachments = attachmentMap.get(issueId);
|
List<PlatformAttachment> syncAttachments = attachmentMap.get(issueId);
|
||||||
for (PlatformAttachment syncAttachment : syncAttachments) {
|
for (PlatformAttachment syncAttachment : syncAttachments) {
|
||||||
if (!attachmentsNameSet.contains(syncAttachment.getFileName())) {
|
String fileName = syncAttachment.getFileName();
|
||||||
jiraAttachmentSet.add(syncAttachment.getFileName());
|
String fileKey = syncAttachment.getFileKey();
|
||||||
try {
|
if (!attachmentsNameSet.contains(fileName)) {
|
||||||
byte[] content = platform.getAttachmentContent(syncAttachment.getFileKey());
|
jiraAttachmentSet.add(fileName);
|
||||||
if (content == null) {
|
saveAttachmentModuleRelation(platform, issueId, fileName, fileKey, batchAttachmentModuleRelationMapper);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
FileAttachmentMetadata fileAttachmentMetadata = attachmentService
|
|
||||||
.saveAttachmentByBytes(content, AttachmentType.ISSUE.type(), issueId, syncAttachment.getFileName());
|
|
||||||
AttachmentModuleRelation attachmentModuleRelation = new AttachmentModuleRelation();
|
|
||||||
attachmentModuleRelation.setAttachmentId(fileAttachmentMetadata.getId());
|
|
||||||
attachmentModuleRelation.setRelationId(issueId);
|
|
||||||
attachmentModuleRelation.setRelationType(AttachmentType.ISSUE.type());
|
|
||||||
batchAttachmentModuleRelationMapper.insert(attachmentModuleRelation);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除Jira中不存在的附件
|
// 删除Jira中不存在的附件
|
||||||
if (CollectionUtils.isNotEmpty(allMsAttachments)) {
|
deleteSyncAttachment(batchAttachmentModuleRelationMapper, jiraAttachmentSet, allMsAttachments);
|
||||||
List<FileAttachmentMetadata> deleteMsAttachments = allMsAttachments.stream()
|
|
||||||
.filter(msAttachment -> !jiraAttachmentSet.contains(msAttachment.getName()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
deleteMsAttachments.forEach(fileAttachmentMetadata -> {
|
|
||||||
List<String> ids = List.of(fileAttachmentMetadata.getId());
|
|
||||||
AttachmentModuleRelationExample example = new AttachmentModuleRelationExample();
|
|
||||||
example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type());
|
|
||||||
// 删除MS附件及关联数据
|
|
||||||
attachmentService.deleteAttachmentByIds(ids);
|
|
||||||
attachmentService.deleteFileAttachmentByIds(ids);
|
|
||||||
batchAttachmentModuleRelationMapper.deleteByExample(example);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void syncAllPluginIssueAttachment(Project project, IssueSyncRequest syncIssuesResult) {
|
||||||
|
// todo 所有平台改造完之后删除
|
||||||
|
if (!StringUtils.equals(project.getPlatform(), IssuesManagePlatform.Jira.name())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
|
try {
|
||||||
|
AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper = sqlSession.getMapper(AttachmentModuleRelationMapper.class);
|
||||||
|
Platform platform = platformPluginService.getPlatform(project.getPlatform(), project.getWorkspaceId());
|
||||||
|
Map<String, List<io.metersphere.xpack.track.dto.PlatformAttachment>> attachmentMap = syncIssuesResult.getAttachmentMap();
|
||||||
|
if (MapUtils.isNotEmpty(attachmentMap)) {
|
||||||
|
for (String issueId : attachmentMap.keySet()) {
|
||||||
|
// 查询我们平台的附件
|
||||||
|
Set<String> jiraAttachmentSet = new HashSet<>();
|
||||||
|
List<FileAttachmentMetadata> allMsAttachments = getIssueFileAttachmentMetadata(issueId);
|
||||||
|
Set<String> attachmentsNameSet = allMsAttachments.stream()
|
||||||
|
.map(FileAttachmentMetadata::getName)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
List<io.metersphere.xpack.track.dto.PlatformAttachment> syncAttachments = attachmentMap.get(issueId);
|
||||||
|
for (io.metersphere.xpack.track.dto.PlatformAttachment syncAttachment : syncAttachments) {
|
||||||
|
String fileName = syncAttachment.getFileName();
|
||||||
|
String fileKey = syncAttachment.getFileKey();
|
||||||
|
if (!attachmentsNameSet.contains(fileName)) {
|
||||||
|
jiraAttachmentSet.add(fileName);
|
||||||
|
saveAttachmentModuleRelation(platform, issueId, fileName, fileKey, batchAttachmentModuleRelationMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除Jira中不存在的附件
|
||||||
|
deleteSyncAttachment(batchAttachmentModuleRelationMapper, jiraAttachmentSet, allMsAttachments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
} finally {
|
||||||
|
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteSyncAttachment(AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper,
|
||||||
|
Set<String> jiraAttachmentSet,
|
||||||
|
List<FileAttachmentMetadata> allMsAttachments) {
|
||||||
|
// 删除Jira中不存在的附件
|
||||||
|
if (CollectionUtils.isNotEmpty(allMsAttachments)) {
|
||||||
|
List<FileAttachmentMetadata> deleteMsAttachments = allMsAttachments.stream()
|
||||||
|
.filter(msAttachment -> !jiraAttachmentSet.contains(msAttachment.getName()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
deleteMsAttachments.forEach(fileAttachmentMetadata -> {
|
||||||
|
List<String> ids = List.of(fileAttachmentMetadata.getId());
|
||||||
|
AttachmentModuleRelationExample example = new AttachmentModuleRelationExample();
|
||||||
|
example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type());
|
||||||
|
// 删除MS附件及关联数据
|
||||||
|
attachmentService.deleteAttachmentByIds(ids);
|
||||||
|
attachmentService.deleteFileAttachmentByIds(ids);
|
||||||
|
batchAttachmentModuleRelationMapper.deleteByExample(example);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAttachmentModuleRelation(Platform platform, String issueId,
|
||||||
|
String fileName, String fileKey,
|
||||||
|
AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
|
||||||
|
try {
|
||||||
|
byte[] content = platform.getAttachmentContent(fileKey);
|
||||||
|
if (content == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileAttachmentMetadata fileAttachmentMetadata = attachmentService
|
||||||
|
.saveAttachmentByBytes(content, AttachmentType.ISSUE.type(), issueId, fileName);
|
||||||
|
AttachmentModuleRelation attachmentModuleRelation = new AttachmentModuleRelation();
|
||||||
|
attachmentModuleRelation.setAttachmentId(fileAttachmentMetadata.getId());
|
||||||
|
attachmentModuleRelation.setRelationId(issueId);
|
||||||
|
attachmentModuleRelation.setRelationType(AttachmentType.ISSUE.type());
|
||||||
|
batchAttachmentModuleRelationMapper.insert(attachmentModuleRelation);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FileAttachmentMetadata> getIssueFileAttachmentMetadata(String issueId) {
|
||||||
|
AttachmentRequest attachmentRequest = new AttachmentRequest();
|
||||||
|
attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
|
||||||
|
attachmentRequest.setBelongId(issueId);
|
||||||
|
List<FileAttachmentMetadata> allMsAttachments = attachmentService.listMetadata(attachmentRequest);
|
||||||
|
return allMsAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取默认的自定义字段的取值,同步之后更新成第三方平台的值
|
* 获取默认的自定义字段的取值,同步之后更新成第三方平台的值
|
||||||
|
@ -1407,9 +1473,6 @@ public class IssuesService {
|
||||||
if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Tapd.name())) {
|
if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Tapd.name())) {
|
||||||
TapdPlatform tapd = new TapdPlatform(issuesRequest);
|
TapdPlatform tapd = new TapdPlatform(issuesRequest);
|
||||||
this.doCheckThirdProjectExist(tapd, project.getTapdId());
|
this.doCheckThirdProjectExist(tapd, project.getTapdId());
|
||||||
} else if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Jira.name())) {
|
|
||||||
JiraPlatform jira = new JiraPlatform(issuesRequest);
|
|
||||||
this.doCheckThirdProjectExist(jira, project.getJiraKey());
|
|
||||||
} else if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Zentao.name())) {
|
} else if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Zentao.name())) {
|
||||||
ZentaoPlatform zentao = new ZentaoPlatform(issuesRequest);
|
ZentaoPlatform zentao = new ZentaoPlatform(issuesRequest);
|
||||||
this.doCheckThirdProjectExist(zentao, project.getZentaoId());
|
this.doCheckThirdProjectExist(zentao, project.getZentaoId());
|
||||||
|
@ -1755,4 +1818,37 @@ public class IssuesService {
|
||||||
return BooleanUtils.isTrue(project.getThirdPartTemplate())
|
return BooleanUtils.isTrue(project.getThirdPartTemplate())
|
||||||
&& platformPluginService.isThirdPartTemplateSupport(project.getPlatform());
|
&& platformPluginService.isThirdPartTemplateSupport(project.getPlatform());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean syncThirdPartyAllIssues(IssueSyncRequest syncRequest) {
|
||||||
|
syncRequest.setProjectId(syncRequest.getProjectId());
|
||||||
|
XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class);
|
||||||
|
if (StringUtils.isNotBlank(syncRequest.getProjectId())) {
|
||||||
|
// 获取当前项目执行同步缺陷Key
|
||||||
|
String syncValue = getSyncKey(syncRequest.getProjectId());
|
||||||
|
// 存在即正在同步中
|
||||||
|
if (StringUtils.isNotEmpty(syncValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 不存在则设置Key, 设置过期时间, 执行完成后delete掉
|
||||||
|
setSyncKey(syncRequest.getProjectId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Project project = baseProjectService.getProjectById(syncRequest.getProjectId());
|
||||||
|
|
||||||
|
if (!isThirdPartTemplate(project)) {
|
||||||
|
syncRequest.setDefaultCustomFields(getDefaultCustomFields(syncRequest.getProjectId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
xpackIssueService.syncThirdPartyIssues(project, syncRequest);
|
||||||
|
|
||||||
|
syncAllPluginIssueAttachment(project, syncRequest);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
|
MSException.throwException(e);
|
||||||
|
} finally {
|
||||||
|
deleteSyncKey(syncRequest.getProjectId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ import io.metersphere.plan.service.TestPlanTestCaseService;
|
||||||
import io.metersphere.request.OrderRequest;
|
import io.metersphere.request.OrderRequest;
|
||||||
import io.metersphere.request.ProjectVersionRequest;
|
import io.metersphere.request.ProjectVersionRequest;
|
||||||
import io.metersphere.request.ResetOrderRequest;
|
import io.metersphere.request.ResetOrderRequest;
|
||||||
import io.metersphere.request.attachment.AttachmentRequest;
|
import io.metersphere.xpack.track.dto.AttachmentRequest;
|
||||||
import io.metersphere.request.member.QueryMemberRequest;
|
import io.metersphere.request.member.QueryMemberRequest;
|
||||||
import io.metersphere.request.testcase.*;
|
import io.metersphere.request.testcase.*;
|
||||||
import io.metersphere.service.issue.platform.IssueFactory;
|
import io.metersphere.service.issue.platform.IssueFactory;
|
||||||
|
|
|
@ -1,290 +0,0 @@
|
||||||
package io.metersphere.service.issue.client;
|
|
||||||
|
|
||||||
import io.metersphere.commons.exception.MSException;
|
|
||||||
import io.metersphere.commons.utils.JSON;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
|
||||||
import io.metersphere.i18n.Translator;
|
|
||||||
import io.metersphere.service.issue.domain.jira.*;
|
|
||||||
import io.metersphere.xpack.track.dto.JiraIssue;
|
|
||||||
import io.metersphere.xpack.track.dto.JiraIssueListResponse;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.core.io.FileSystemResource;
|
|
||||||
import org.springframework.http.*;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.web.client.HttpClientErrorException;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class JiraAbstractClient extends BaseClient {
|
|
||||||
|
|
||||||
protected String ENDPOINT;
|
|
||||||
|
|
||||||
protected String PREFIX;
|
|
||||||
|
|
||||||
protected String USER_NAME;
|
|
||||||
|
|
||||||
protected String PASSWD;
|
|
||||||
|
|
||||||
public JiraIssue getIssues(String issuesId) {
|
|
||||||
LogUtil.info("getIssues: " + issuesId);
|
|
||||||
ResponseEntity<String> responseEntity;
|
|
||||||
responseEntity = restTemplate.exchange(getBaseUrl() + "/issue/" + issuesId, HttpMethod.GET, getAuthHttpEntity(), String.class);
|
|
||||||
return (JiraIssue) getResultForObject(JiraIssue.class, responseEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, JiraCreateMetadataResponse.Field> getCreateMetadata(String projectKey, String issueType) {
|
|
||||||
String url = getBaseUrl() + "/issue/createmeta?projectKeys={1}&issuetypeIds={2}&expand=projects.issuetypes.fields";
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
Map<String, JiraCreateMetadataResponse.Field> fields = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, projectKey, issueType);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
fields = ((JiraCreateMetadataResponse) getResultForObject(JiraCreateMetadataResponse.class, response))
|
|
||||||
.getProjects().get(0).getIssuetypes().get(0).getFields();
|
|
||||||
} catch (Exception e) {
|
|
||||||
MSException.throwException(Translator.get("issue_jira_info_error"));
|
|
||||||
}
|
|
||||||
fields.remove("project");
|
|
||||||
fields.remove("issuetype");
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<JiraIssueType> getIssueType(String projectKey) {
|
|
||||||
JiraIssueProject project = getProject(projectKey);
|
|
||||||
String url = getUrl("/issuetype/project?projectId={0}");
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, project.getId());
|
|
||||||
} catch (HttpClientErrorException e) {
|
|
||||||
if (e.getRawStatusCode() == 404) { // Sass 的jira才有这个接口,报错则调用其他接口
|
|
||||||
return this.getProject(projectKey).getIssueTypes();
|
|
||||||
}
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
return (List<JiraIssueType>) getResultForList(JiraIssueType.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JiraIssueProject getProject(String projectKey) {
|
|
||||||
String url = getUrl("/project/" + projectKey);
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
return (JiraIssueProject) getResultForObject(JiraIssueProject.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<JiraUser> getAssignableUser(String projectKey) {
|
|
||||||
String url = getBaseUrl() + "/user/assignable/search?project={1}&maxResults=" + 1000 + "&startAt=" + 0;
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, projectKey);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
return (List<JiraUser>) getResultForList(JiraUser.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List getDemands(String projectKey, String issueType, int startAt, int maxResults) {
|
|
||||||
String jql = getBaseUrl() + "/search?jql=project=" + projectKey + "+AND+issuetype=" + issueType
|
|
||||||
+ "&maxResults=" + maxResults + "&startAt=" + startAt + "&fields=summary,issuetype";
|
|
||||||
ResponseEntity<String> responseEntity = restTemplate.exchange(jql,
|
|
||||||
HttpMethod.GET, getAuthHttpEntity(), String.class);
|
|
||||||
Map jsonObject = JSON.parseMap(responseEntity.getBody());
|
|
||||||
return (List) jsonObject.get("issues");
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<JiraField> getFields() {
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(getBaseUrl() + "/field", HttpMethod.GET, getAuthHttpEntity(), String.class);
|
|
||||||
return (List<JiraField>) getResultForList(JiraField.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JiraAddIssueResponse addIssue(String body) {
|
|
||||||
LogUtil.info("addIssue: " + body);
|
|
||||||
HttpHeaders headers = getAuthHeader();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(getBaseUrl() + "/issue", HttpMethod.POST, requestEntity, String.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
return (JiraAddIssueResponse) getResultForObject(JiraAddIssueResponse.class, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<JiraTransitionsResponse.Transitions> getTransitions(String issueKey) {
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(getBaseUrl() + "/issue/{1}/transitions", HttpMethod.GET, getAuthHttpEntity(), String.class, issueKey);
|
|
||||||
return ((JiraTransitionsResponse) getResultForObject(JiraTransitionsResponse.class, response)).getTransitions();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateIssue(String id, String body) {
|
|
||||||
LogUtil.info("addIssue: " + body);
|
|
||||||
HttpHeaders headers = getAuthHeader();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(getBaseUrl() + "/issue/" + id, HttpMethod.PUT, requestEntity, String.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteIssue(String id) {
|
|
||||||
LogUtil.info("deleteIssue: " + id);
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(getBaseUrl() + "/issue/" + id, HttpMethod.DELETE, getAuthHttpEntity(), String.class);
|
|
||||||
} catch (HttpClientErrorException e) {
|
|
||||||
if (e.getRawStatusCode() != 404) {// 404说明jira没有,可以直接删
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteAttachment(String id) {
|
|
||||||
LogUtil.info("deleteAttachment: " + id);
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(getBaseUrl() + "/attachment/" + id, HttpMethod.DELETE, getAuthHttpEntity(), String.class);
|
|
||||||
} catch (HttpClientErrorException e) {
|
|
||||||
if (e.getRawStatusCode() != 404) {// 404说明jira没有,可以直接删
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void uploadAttachment(String issueKey, File file) {
|
|
||||||
HttpHeaders authHeader = getAuthHeader();
|
|
||||||
authHeader.add("X-Atlassian-Token", "no-check");
|
|
||||||
authHeader.setContentType(MediaType.parseMediaType("multipart/form-data; charset=UTF-8"));
|
|
||||||
|
|
||||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
|
||||||
FileSystemResource fileResource = new FileSystemResource(file);
|
|
||||||
paramMap.add("file", fileResource);
|
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, authHeader);
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(getBaseUrl() + "/issue/" + issueKey + "/attachments", HttpMethod.POST, requestEntity, String.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
System.out.println(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void auth() {
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
response = restTemplate.exchange(getBaseUrl() + "/myself", HttpMethod.GET, getAuthHttpEntity(), String.class);
|
|
||||||
if (StringUtils.isBlank(response.getBody()) || (StringUtils.isNotBlank(response.getBody()) && !response.getBody().startsWith("{\"self\""))) {
|
|
||||||
MSException.throwException(Translator.get("jira_auth_url_error"));
|
|
||||||
}
|
|
||||||
} catch (HttpClientErrorException e) {
|
|
||||||
if (e.getRawStatusCode() == 401) {
|
|
||||||
MSException.throwException(Translator.get("jira_auth_error"));
|
|
||||||
} else {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HttpEntity<MultiValueMap> getAuthHttpEntity() {
|
|
||||||
return new HttpEntity<>(getAuthHeader());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HttpHeaders getAuthHeader() {
|
|
||||||
return getBasicHttpHeaders(USER_NAME, PASSWD);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HttpHeaders getAuthJsonHeader() {
|
|
||||||
HttpHeaders headers = getAuthHeader();
|
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getBaseUrl() {
|
|
||||||
return ENDPOINT + PREFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getUrl(String path) {
|
|
||||||
return getBaseUrl() + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConfig(JiraConfig config) {
|
|
||||||
if (config == null) {
|
|
||||||
MSException.throwException("config is null");
|
|
||||||
}
|
|
||||||
String url = config.getUrl();
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(url) && url.endsWith("/")) {
|
|
||||||
url = url.substring(0, url.length() - 1);
|
|
||||||
}
|
|
||||||
ENDPOINT = url;
|
|
||||||
USER_NAME = config.getAccount();
|
|
||||||
PASSWD = config.getPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JiraIssueListResponse getProjectIssues(Integer startAt, Integer maxResults, String projectKey, String issueType) {
|
|
||||||
return getProjectIssues(startAt, maxResults, projectKey, issueType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JiraIssueListResponse getProjectIssues(Integer startAt, Integer maxResults, String projectKey, String issueType, String fields) {
|
|
||||||
ResponseEntity<String> responseEntity;
|
|
||||||
String url = getBaseUrl() + "/search?startAt={1}&maxResults={2}&jql=project={3}+AND+issuetype={4}";
|
|
||||||
if (StringUtils.isNotBlank(fields)) {
|
|
||||||
url = url + "&fields=" + fields;
|
|
||||||
}
|
|
||||||
responseEntity = restTemplate.exchange(url,
|
|
||||||
HttpMethod.GET, getAuthHttpEntity(), String.class, startAt, maxResults, projectKey, issueType);
|
|
||||||
return (JiraIssueListResponse)getResultForObject(JiraIssueListResponse.class, responseEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getAttachmentContent(String url) {
|
|
||||||
ResponseEntity<byte[]> responseEntity;
|
|
||||||
responseEntity = restTemplate.exchange(url,
|
|
||||||
HttpMethod.GET, getAuthHttpEntity(), byte[].class);
|
|
||||||
return responseEntity.getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
public JiraIssueListResponse getProjectIssuesAttachment(Integer startAt, Integer maxResults, String projectKey, String issueType) {
|
|
||||||
return getProjectIssues(startAt, maxResults, projectKey, issueType, "attachment");
|
|
||||||
|
|
||||||
}
|
|
||||||
public void setTransitions(String jiraKey, JiraTransitionsResponse.Transitions transitions) {
|
|
||||||
LogUtil.info("setTransitions: " + transitions);
|
|
||||||
Map jsonObject = new LinkedHashMap();
|
|
||||||
jsonObject.put("transition", transitions);
|
|
||||||
HttpEntity<String> requestEntity = new HttpEntity<>(JSON.toJSONString(jsonObject), getAuthJsonHeader());
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(getBaseUrl() + "/issue/{1}/transitions", HttpMethod.POST, requestEntity, String.class, jiraKey);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity proxyForGet(String url, Class responseEntityClazz) {
|
|
||||||
LogUtil.info("jira proxyForGet: " + url);
|
|
||||||
return restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), responseEntityClazz);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package io.metersphere.service.issue.client;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class JiraClientV2 extends JiraAbstractClient {
|
|
||||||
{
|
|
||||||
PREFIX = "/rest/api/2";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package io.metersphere.service.issue.client;
|
|
||||||
|
|
||||||
public class JiraClientV3 extends JiraAbstractClient {
|
|
||||||
{
|
|
||||||
PREFIX = "/rest/api/3";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class JiraAddIssueResponse {
|
|
||||||
private String id;
|
|
||||||
private String key;
|
|
||||||
private String self;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class JiraConfig {
|
|
||||||
private String account;
|
|
||||||
private String password;
|
|
||||||
private String url;
|
|
||||||
private String issuetype;
|
|
||||||
private String storytype;
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public class JiraCreateMetadataResponse {
|
|
||||||
private List<Projects> projects;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public static class Projects {
|
|
||||||
private List<Issuetypes> issuetypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public static class Issuetypes {
|
|
||||||
private Map<String, Field> fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public static class Field {
|
|
||||||
private boolean required;
|
|
||||||
private Schema schema;
|
|
||||||
private String name;
|
|
||||||
private String key;
|
|
||||||
private String autoCompleteUrl;
|
|
||||||
private boolean hasDefaultValue;
|
|
||||||
private Object defaultValue;
|
|
||||||
private List<AllowedValues> allowedValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public static class Schema {
|
|
||||||
private String type;
|
|
||||||
private String items;
|
|
||||||
private String custom;
|
|
||||||
private int customId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public static class AllowedValues {
|
|
||||||
private String self;
|
|
||||||
private String id;
|
|
||||||
private String description;
|
|
||||||
private String name;
|
|
||||||
private String value;
|
|
||||||
private boolean subtask;
|
|
||||||
private int avatarId;
|
|
||||||
private int hierarchyLevel;
|
|
||||||
private List<AllowedValues> children;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class JiraField {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String key;
|
|
||||||
private String name;
|
|
||||||
private boolean custom;
|
|
||||||
// private boolean orderable;
|
|
||||||
// private boolean navigable;
|
|
||||||
// private boolean searchable;
|
|
||||||
// private List<String> clauseNames;
|
|
||||||
// private Schema schema;
|
|
||||||
//
|
|
||||||
// @Getter
|
|
||||||
// @Setter
|
|
||||||
// public class Schema {
|
|
||||||
// private String type;
|
|
||||||
// private String system;
|
|
||||||
// }
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class JiraIssueDescriptionV3 {
|
|
||||||
private String type;
|
|
||||||
private int version;
|
|
||||||
private List<Content> content;
|
|
||||||
|
|
||||||
public JiraIssueDescriptionV3(String text) {
|
|
||||||
List<Content> list = new ArrayList<>();
|
|
||||||
Content content = new Content(text);
|
|
||||||
list.add(content);
|
|
||||||
this.type = "doc";
|
|
||||||
this.version = 1;
|
|
||||||
this.content = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class Content {
|
|
||||||
private String type;
|
|
||||||
private List<ContentInfo> content;
|
|
||||||
|
|
||||||
public Content(String text) {
|
|
||||||
List<ContentInfo> list = new ArrayList<>();
|
|
||||||
ContentInfo content = new ContentInfo(text);
|
|
||||||
list.add(content);
|
|
||||||
this.type = "paragraph";
|
|
||||||
this.content = list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class ContentInfo {
|
|
||||||
private String text;
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
public ContentInfo(String text) {
|
|
||||||
this.text = text;
|
|
||||||
this.type = "text";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class JiraIssueProject {
|
|
||||||
private String id;
|
|
||||||
private String name;
|
|
||||||
private String key;
|
|
||||||
private List<JiraIssueType> issueTypes;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class JiraIssueType {
|
|
||||||
private String id;
|
|
||||||
private String name;
|
|
||||||
private String untranslatedName;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class JiraTransitionsResponse {
|
|
||||||
|
|
||||||
private String expand;
|
|
||||||
private List<Transitions> transitions;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class Transitions {
|
|
||||||
private String id;
|
|
||||||
private String name;
|
|
||||||
private To to;
|
|
||||||
private Boolean hasScreen;
|
|
||||||
private Boolean isGlobal;
|
|
||||||
private Boolean isInitial;
|
|
||||||
private Boolean isAvailable;
|
|
||||||
private Boolean isConditional;
|
|
||||||
private Boolean isLooped;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class To {
|
|
||||||
private String self;
|
|
||||||
private String description;
|
|
||||||
private String iconUrl;
|
|
||||||
private String name;
|
|
||||||
private String id;
|
|
||||||
private StatusCategory statusCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class StatusCategory {
|
|
||||||
private String self;
|
|
||||||
private int id;
|
|
||||||
private String key;
|
|
||||||
private String colorName;
|
|
||||||
private String name;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.jira;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
public class JiraUser {
|
|
||||||
private String accountId;
|
|
||||||
private String key;
|
|
||||||
private String name;
|
|
||||||
private String displayName;
|
|
||||||
private String emailAddress;
|
|
||||||
private Boolean active;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,7 +11,7 @@ import io.metersphere.commons.utils.LogUtil;
|
||||||
import io.metersphere.xpack.track.dto.AttachmentSyncType;
|
import io.metersphere.xpack.track.dto.AttachmentSyncType;
|
||||||
import io.metersphere.constants.AttachmentType;
|
import io.metersphere.constants.AttachmentType;
|
||||||
import io.metersphere.dto.*;
|
import io.metersphere.dto.*;
|
||||||
import io.metersphere.request.attachment.AttachmentRequest;
|
import io.metersphere.xpack.track.dto.AttachmentRequest;
|
||||||
import io.metersphere.xpack.track.dto.DemandDTO;
|
import io.metersphere.xpack.track.dto.DemandDTO;
|
||||||
import io.metersphere.xpack.track.dto.IssuesDao;
|
import io.metersphere.xpack.track.dto.IssuesDao;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
||||||
|
@ -27,8 +27,6 @@ import io.metersphere.service.issue.domain.zentao.ZentaoConfig;
|
||||||
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
|
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.http.entity.mime.MultipartEntity;
|
|
||||||
import org.apache.http.entity.mime.content.FileBody;
|
|
||||||
import org.apache.logging.log4j.util.Strings;
|
import org.apache.logging.log4j.util.Strings;
|
||||||
import org.springframework.core.io.FileSystemResource;
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
|
|
|
@ -148,14 +148,14 @@ export function getRelateIssues(page) {
|
||||||
|
|
||||||
export function syncAllIssues(param) {
|
export function syncAllIssues(param) {
|
||||||
// 浏览器默认策略,请求同一个url,可能导致 stalled 时间过长,加个uuid防止请求阻塞
|
// 浏览器默认策略,请求同一个url,可能导致 stalled 时间过长,加个uuid防止请求阻塞
|
||||||
let url = 'xpack/issue/sync' + "?stamp=" + getUUID();
|
return post(BASE_URL + 'sync/all?stamp=' + getUUID(), param);
|
||||||
return post(url, param);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function syncIssues() {
|
export function syncIssues() {
|
||||||
// 浏览器默认策略,请求同一个url,可能导致 stalled 时间过长,加个uuid防止请求阻塞
|
// 浏览器默认策略,请求同一个url,可能导致 stalled 时间过长,加个uuid防止请求阻塞
|
||||||
let url = 'issues/sync/' + getCurrentProjectID() + "?stamp=" + getUUID();
|
let projectId = getCurrentProjectID();
|
||||||
return get(url);
|
let uuid = getUUID();
|
||||||
|
return get(BASE_URL + `sync/${projectId}?stamp=${uuid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 轮询同步状态
|
// 轮询同步状态
|
||||||
|
|
Loading…
Reference in New Issue