fix(接口测试): 第三方平台 禅道 & azure devops 缺陷同步问题

--bug=1010929 --user=zhaoqian
禅道:
[缺陷管理]github#11147metersphere对接禅道企业版v9.0.3提交带有图片的缺陷同步至禅道后图片打不开
AzureDevops:
1、缺陷同步信息丢失
2、在测试计划的功能用例下新建缺陷(用例已关联TFS需求),推回TFS后仍是游离缺陷,没有挂在用户故事下
3、在测试计划的功能用例下变更需求,再次打开需求被置空且azure devops平台的需求与缺陷的关联关系没有变更
4、删除用例时,删除用例与需求的关联关系
5、功能用例关联TFS用户故事时仅第一次会同步,后续如果功能用例名称修改或者再次关联,就不会同步
6、新增缺陷图片上传后,将图片信息添加到tfs描述信息中
7、同步超链接图片未登陆第三方平台时,图片无法预览的问题

Closes #11147
This commit is contained in:
zhaoqian 2022-04-07 18:22:34 +08:00 committed by jianxing
parent 01073c00c1
commit 5022c07117
7 changed files with 86 additions and 19 deletions

View File

@ -416,4 +416,23 @@ public class FileUtils {
}
return multipartFiles;
}
public static Boolean writeToFile(String filePath, byte[] content) {
OutputStream oStream = null;
try {
oStream = new FileOutputStream(filePath);
oStream.write(content);
return Boolean.TRUE;
} catch (Exception exception) {
exception.printStackTrace();
return Boolean.FALSE;
} finally {
try {
oStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View File

@ -334,6 +334,32 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
return result;
}
/**
* 转译字符串中的特殊字符
* @param str
* @return
*/
protected String transferSpecialCharacter(String str) {
String regEx="[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(str);
if(matcher.find()){
CharSequence cs = str;
int j =0;
for(int i=0; i< cs.length(); i++){
String temp = String.valueOf(cs.charAt(i));
Matcher m2 = pattern.matcher(temp);
if(m2.find()){
StringBuilder sb = new StringBuilder(str);
str = sb.insert(j, "\\").toString();
j++;
}
j++; //转义完成后str的长度增1
}
}
return str;
}
public List<File> getImageFiles(String input) {
List<File> files = new ArrayList<>();
String regex = "(\\!\\[.*?\\]\\((.*?)\\))";

View File

@ -150,7 +150,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
String description = bugObj.getSteps();
String steps = description;
try {
steps = zentao2MsDescription(description);
steps = htmlDesc2MsDesc(zentao2MsDescription(description));
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
@ -429,7 +429,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
String src = getMatcherResultForImg("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)", imgPath);
String alt = getMatcherResultForImg("alt\\s*=\\s*\"?(.*?)(\"|>|\\s+)", imgPath);
String hyperLinkPath = packageDescriptionByPathAndName(src, alt);
imgPath = imgPath.replace("{", "\\{").replace("}", "\\}");
imgPath = transferSpecialCharacter(imgPath);
ztDescription = ztDescription.replaceAll(imgPath, hyperLinkPath);
}
}
@ -446,8 +446,15 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
if (StringUtils.isEmpty(name)) {
name = srcContent;
}
if (Arrays.stream(imgArray).anyMatch(imgType -> StringUtils.equals(imgType, srcContent.substring(srcContent.indexOf('.') + 1)))) {
path = zentaoClient.getBaseUrl() + "/file-read-" + srcContent;
if (zentaoClient.getBaseUrl().contains("biz")) {
// 禅道企业版
path = zentaoClient.getBaseUrl() + "/index.php?m=file&f=read&fileID=" + srcContent;
} else {
// 禅道开源版
path = zentaoClient.getBaseUrl() + "/file-read-" + srcContent;
}
} else {
return result;
}

View File

@ -181,7 +181,9 @@ public abstract class ZentaoClient extends BaseClient {
String baseUrl = getBaseUrl();
String[] split = baseUrl.split("/");
String suffix = split[split.length - 1];
if (!StringUtils.equalsAny(suffix, "zentao", "zentaopms", "zentaopro", "zentaobiz")) {
if (StringUtils.equals("biz", suffix)) {
suffix = baseUrl;
} else if (!StringUtils.equalsAny(suffix, "zentao", "zentaopms", "zentaopro", "zentaobiz")) {
suffix = "";
} else {
suffix = "/" + suffix;

View File

@ -41,6 +41,10 @@ public class AzureDevopsWorkItemsBatchResponse {
private String changedBy;
@JSONField(name = "System.CreatedBy")
private String createdBy;
@JSONField(name = "Microsoft.VSTS.TCM.ReproSteps")
private String reproSteps;
@JSONField(name = "System.CreatedDate")
private String createdDate;
}
}
}

View File

@ -215,20 +215,18 @@ public class TestCaseService {
return request;
}
private void addDemandHyperLink(EditTestCaseRequest request, String type) {
if (StringUtils.isNotEmpty(request.getDemandId())) {
IssuesRequest updateRequest = new IssuesRequest();
updateRequest.setId(request.getId());
updateRequest.setResourceId(request.getDemandId());
updateRequest.setProjectId(request.getProjectId());
updateRequest.setTestCaseId(request.getId());
Project project = projectService.getProjectById(request.getProjectId());
updateRequest.setWorkspaceId(project.getWorkspaceId());
List<AbstractIssuePlatform> platformList = getAddPlatforms(updateRequest);
platformList.forEach(platform -> {
platform.updateDemandHyperLink(request, project, type);
});
}
public void addDemandHyperLink(EditTestCaseRequest request, String type) {
IssuesRequest updateRequest = new IssuesRequest();
updateRequest.setId(request.getId());
updateRequest.setResourceId(request.getDemandId());
updateRequest.setProjectId(request.getProjectId());
updateRequest.setTestCaseId(request.getId());
Project project = projectService.getProjectById(request.getProjectId());
updateRequest.setWorkspaceId(project.getWorkspaceId());
List<AbstractIssuePlatform> platformList = getAddPlatforms(updateRequest);
platformList.forEach(platform -> {
platform.updateDemandHyperLink(request, project, type);
});
}
private List<AbstractIssuePlatform> getAddPlatforms(IssuesRequest request) {
@ -352,7 +350,7 @@ public class TestCaseService {
* 判断azure devops用例关联的需求是否发生变更若发生变更则重新建立需求与缺陷的关联关系
* @param testCase
*/
private void updateThirdPartyIssuesLink(EditTestCaseRequest testCase) {
public void updateThirdPartyIssuesLink(EditTestCaseRequest testCase) {
try {
if (Class.forName("io.metersphere.xpack.issue.service.XpackIssueService") != null) {
Class clazz = Class.forName("io.metersphere.xpack.issue.service.XpackIssueService");
@ -596,6 +594,15 @@ public class TestCaseService {
testCase.setId(testCaseId);
testCase.setDeleteUserId(SessionUtils.getUserId());
testCase.setDeleteTime(System.currentTimeMillis());
// 同步删除用例与需求的关联关系
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(testCaseId);
if (testCaseWithBLOBs != null) {
EditTestCaseRequest request = new EditTestCaseRequest();
BeanUtils.copyBean(request, testCaseWithBLOBs);
addDemandHyperLink(request, "delete");
}
return extTestCaseMapper.deleteToGc(testCase);
}

View File

@ -311,6 +311,8 @@ export default {
param.remark = this.testCase.remark;
param.projectId = this.testCase.projectId;
param.nodeId = this.testCase.nodeId;
param.demandId = this.testCase.demandId;
param.name = this.testCase.name;
let option = this.getOption(param);
for (let i = 0; i < this.testCase.steptResults.length; i++) {
let result = {};