feat(测试跟踪): 同步tapd,jira全量缺陷

This commit is contained in:
chenjianxing 2021-11-18 20:00:09 +08:00 committed by jianxing
parent 491afb54ca
commit 93dbd244a5
13 changed files with 102 additions and 32 deletions

View File

@ -23,4 +23,6 @@ public interface ExtIssuesMapper {
List<PlanReportIssueDTO> selectForPlanReport(String planId);
List<IssuesDao>getCountByStatus(@Param("request") IssuesRequest issuesRequest);
List<String> selectIdNotInUuIds(@Param("projectId") String projectId, @Param("platform") String platform, @Param("platformIds") List<String> platformIds);
}

View File

@ -63,6 +63,13 @@
<select id="selectForPlanReport" resultType="io.metersphere.track.dto.PlanReportIssueDTO">
select id,status,platform_status,platform from issues where resource_id = #{planId} and ( platform_status != 'delete' or platform_status is null);
</select>
<select id="selectIdNotInUuIds" resultType="java.lang.String">
select id from issues
where project_id = #{projectId} and platform = #{platform} and platform_id not in
<foreach collection="platformIds" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</select>
<sql id="queryWhereCondition">
<where>

View File

@ -224,4 +224,9 @@ public class ServiceUtils {
Long lastOrder = getLastOrderFunc.apply(groupId, null);
return (lastOrder == null ? 0 : lastOrder) + 5000;
}
public static SqlSession getBatchSqlSession() {
SqlSessionFactory sqlSessionFactory = CommonBeanFactory.getBean(SqlSessionFactory.class);
return sqlSessionFactory.openSession(ExecutorType.BATCH);
}
}

View File

@ -206,7 +206,7 @@ public class IssueTemplateService extends TemplateBaseService {
public IssueTemplateDao getTemplate(String projectId) {
Project project = projectService.getProjectById(projectId);
String issueTemplateId = project.getIssueTemplateId();
IssueTemplate issueTemplate = null;
IssueTemplate issueTemplate;
IssueTemplateDao issueTemplateDao = new IssueTemplateDao();
if (StringUtils.isNotBlank(issueTemplateId)) {
issueTemplate = issueTemplateMapper.selectByPrimaryKey(issueTemplateId);

View File

@ -7,6 +7,7 @@ import io.metersphere.base.mapper.IssuesMapper;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.TestCaseIssuesMapper;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.commons.constants.IssuesStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.IntegrationRequest;
@ -15,6 +16,7 @@ import io.metersphere.dto.UserDTO;
import io.metersphere.service.*;
import io.metersphere.track.request.testcase.IssuesRequest;
import io.metersphere.track.request.testcase.IssuesUpdateRequest;
import io.metersphere.track.service.IssuesService;
import io.metersphere.track.service.TestCaseIssueService;
import io.metersphere.track.service.TestCaseService;
import org.apache.commons.lang3.StringUtils;
@ -34,10 +36,7 @@ import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -382,4 +381,41 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
return JSONObject.toJSONString(customFields);
}
@Override
public void syncAllIssues(Project project, String defaultCustomFields) {}
protected List<IssuesWithBLOBs> getIssuesByPlatformIds(List<String> platformIds) {
IssuesService issuesService = CommonBeanFactory.getBean(IssuesService.class);
return issuesService.getIssuesByPlatformIds(platformIds, projectId);
}
protected Map<String, IssuesWithBLOBs> getUuIdMap(List<IssuesWithBLOBs> issues) {
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(issues)) {
return issues.stream().collect(Collectors.toMap(Issues::getPlatformId, i -> i));
}
return new HashMap<>();
}
protected void deleteSyncIssue(List<String> ids) {
if (CollectionUtils.isEmpty(ids)) return;
IssuesExample example = new IssuesExample();
IssuesWithBLOBs issue = new IssuesWithBLOBs();
issue.setPlatformStatus(IssuesStatus.DELETE.toString());
example.createCriteria().andIdIn(ids);
issuesMapper.updateByExampleSelective(issue, example);
}
protected List<String> updateSyncDeleteIds(List<String> uuIds, List<String> syncDeleteIds, String platform) {
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(uuIds)) {
// 每次获取不在当前查询的缺陷里的 id
List<String> notInIds = extIssuesMapper.selectIdNotInUuIds(projectId, platform, uuIds);
if (syncDeleteIds == null) {
syncDeleteIds = notInIds;
} else {
// 求交集即不在所有查询里的缺陷即要删除的缺陷
syncDeleteIds.retainAll(notInIds);
}
}
return syncDeleteIds;
}
}

View File

@ -64,4 +64,10 @@ public interface IssuesPlatform {
* @param tapdIssues
*/
void syncIssues(Project project, List<IssuesDao> tapdIssues);
/**
* 同步缺陷全量的缺陷
* @param project
*/
void syncAllIssues(Project project, String defaultCustomFields);
}

View File

@ -83,10 +83,9 @@ public class JiraPlatform extends AbstractIssuePlatform {
public void parseIssue(IssuesWithBLOBs item, JiraIssue jiraIssue, String customFieldsStr) {
String lastmodify = "";
String status = "";
JSONObject fields = jiraIssue.getFields();
status = getStatus(fields);
String status = getStatus(fields);
JSONObject assignee = (JSONObject) fields.get("assignee");
String description = fields.getString("description");
@ -331,6 +330,7 @@ public class JiraPlatform extends AbstractIssuePlatform {
@Override
public void syncIssues(Project project, List<IssuesDao> issues) {
setConfig();
issues.forEach(item -> {
setConfig();
try {

View File

@ -44,8 +44,7 @@ public class TapdPlatform extends AbstractIssuePlatform {
protected String key = IssuesManagePlatform.Tapd.toString();
private TapdClient tapdClient = new TapdClient();
protected TapdClient tapdClient = new TapdClient();
public TapdPlatform(IssuesRequest issueRequest) {
super(issueRequest);
@ -224,16 +223,13 @@ public class TapdPlatform extends AbstractIssuePlatform {
pageNum++;
datas.forEach(issue -> {
JSONObject bug = issue.getJSONObject("Bug");
String id = idMap.get(bug.getString("id"));
IssuesDao issuesDao = new IssuesDao();
BeanUtils.copyBean(issuesDao, bug);
issuesDao.setId(id);
issuesDao.setPlatformStatus(statusMap.get(bug.getString("status")));
issuesDao.setDescription(htmlDesc2MsDesc(issuesDao.getDescription()));
IssuesWithBLOBs issuesWithBLOBs = issuesMapper.selectByPrimaryKey(id);
issuesDao.setCustomFields(syncIssueCustomField(issuesWithBLOBs.getCustomFields(), bug));
issuesMapper.updateByPrimaryKeySelective(issuesDao);
ids.remove(bug.getString("id"));
String platformId = bug.getString("id");
String id = idMap.get(platformId);
IssuesWithBLOBs updateIssue = getUpdateIssue(issuesMapper.selectByPrimaryKey(id), bug, statusMap);
updateIssue.setId(id);
updateIssue.setCustomFields(syncIssueCustomField(updateIssue.getCustomFields(), bug));
issuesMapper.updateByPrimaryKeySelective(updateIssue);
ids.remove(platformId);
});
}
// 查不到的设置为删除
@ -247,6 +243,17 @@ public class TapdPlatform extends AbstractIssuePlatform {
});
}
protected IssuesWithBLOBs getUpdateIssue(IssuesWithBLOBs issue, JSONObject bug, Map<String, String> statusMap) {
if (issue == null) issue = new IssuesWithBLOBs();
TapdBug bugObj = JSONObject.parseObject(bug.toJSONString(), TapdBug.class);
BeanUtils.copyBean(issue, bugObj);
issue.setPlatformStatus(statusMap.get(bugObj.getStatus()));
issue.setDescription(htmlDesc2MsDesc(issue.getDescription()));
issue.setCustomFields(syncIssueCustomField(issue.getCustomFields(), bug));
issue.setPlatform(key);
return issue;
}
@Override
public String getProjectId(String projectId) {
if (StringUtils.isNotBlank(projectId)) {

View File

@ -44,10 +44,10 @@ public class TapdClient extends BaseClient {
public TapdGetIssueResponse getIssueForPageByIds(String projectId, int pageNum, int limit, List<String> ids) {
String url = getBaseUrl() + "/bugs?workspace_id={1}&page={2}&limit={3}&fields={4}";
StringBuilder idStr = new StringBuilder();
ids.forEach(item -> {
idStr.append(item + ",");
});
if (!CollectionUtils.isEmpty(ids)) {
ids.forEach(item -> {
idStr.append(item + ",");
});
url += "&id={5}";
}
String fields = "id,title,description,priority,severity,reporter,status";

View File

@ -13,10 +13,4 @@ public class TapdGetIssueResponse {
private int status;
private List<JSONObject> data;
private String info;
// @Getter
// @Setter
// public static class Data {
// private TapdBug bug;
// }
}

View File

@ -191,7 +191,7 @@ public class IssuesService {
public String getIssueTemplate(String projectId) {
Project project = projectService.getProjectById(projectId);
IssueTemplate issueTemplate = null;
IssueTemplate issueTemplate;
String id = project.getIssueTemplateId();
if (StringUtils.isBlank(id)) {
issueTemplate = issueTemplateService.getDefaultTemplate(project.getWorkspaceId());
@ -596,4 +596,13 @@ public class IssuesService {
result = follows.stream().map(IssueFollow::getFollowId).distinct().collect(Collectors.toList());
return result;
}
public List<IssuesWithBLOBs> getIssuesByPlatformIds(List<String> platformIds, String projectId) {
if (CollectionUtils.isEmpty(platformIds)) return new ArrayList<>();
IssuesExample example = new IssuesExample();
example.createCriteria()
.andPlatformIdIn(platformIds)
.andProjectIdEqualTo(projectId);
return issuesMapper.selectByExampleWithBLOBs(example);
}
}

@ -1 +1 @@
Subproject commit 1eebba8448784bcda225edf6c8b0000a52ca1bd5
Subproject commit 9a24f644b842d930da6019383fc70e11b8973af2

View File

@ -1,6 +1,6 @@
import {post, get} from "@/common/js/ajax";
import {getPageDate} from "@/common/js/tableUtils";
import {getCurrentProjectID} from "@/common/js/utils";
import {getCurrentProjectID, hasLicense} from "@/common/js/utils";
import {baseGet} from "@/network/base-network";
export function buildIssues(page) {
@ -74,7 +74,11 @@ export function getRelateIssues(page) {
}
export function syncIssues(success) {
return get('issues/sync/' + getCurrentProjectID(), (response) => {
let uri = 'issues/sync/';
if (hasLicense()) {
uri = 'xpack/issue/sync/';
}
return get(uri + getCurrentProjectID(), (response) => {
if (success) {
success(response);
}