feat: 集成TAPD平台
This commit is contained in:
parent
47fad33be1
commit
f42a920fcf
|
@ -2,7 +2,8 @@ package io.metersphere.service;
|
|||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.base.domain.ServiceIntegration;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.TestCaseIssuesMapper;
|
||||
import io.metersphere.commons.constants.IssuesManagePlatform;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.user.SessionUser;
|
||||
|
@ -11,20 +12,35 @@ import io.metersphere.commons.utils.RestTemplateUtils;
|
|||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import io.metersphere.controller.ResultHolder;
|
||||
import io.metersphere.controller.request.IntegrationRequest;
|
||||
import io.metersphere.track.dto.IssuesDTO;
|
||||
import io.metersphere.track.request.testcase.IssuesRequest;
|
||||
import io.metersphere.track.service.TestCaseService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class IssuesService {
|
||||
|
||||
@Resource
|
||||
private IntegrationService integrationService;
|
||||
@Resource
|
||||
private TestCaseIssuesMapper testCaseIssuesMapper;
|
||||
@Resource
|
||||
private ProjectService projectService;
|
||||
@Resource
|
||||
private TestCaseService testCaseService;
|
||||
|
||||
|
||||
public void testAuth() {
|
||||
|
@ -33,14 +49,32 @@ public class IssuesService {
|
|||
System.out.println(call.getData());
|
||||
}
|
||||
|
||||
public void addIssues() {
|
||||
public void addIssues(IssuesRequest issuesRequest) {
|
||||
String url = "https://api.tapd.cn/bugs";
|
||||
String testCaseId = issuesRequest.getTestCaseId();
|
||||
String tapdId = getTapdProjectId(testCaseId);
|
||||
|
||||
if (StringUtils.isBlank(tapdId)) {
|
||||
MSException.throwException("未关联Tapd 项目ID");
|
||||
}
|
||||
|
||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||
paramMap.add("title", "20200812bug2");
|
||||
paramMap.add("workspace_id", "55049933");
|
||||
paramMap.add("description", "20200812 api add bug 2");
|
||||
ResultHolder call = call(url, HttpMethod.POST, paramMap);
|
||||
System.out.println(call.getData());
|
||||
paramMap.add("title", issuesRequest.getTitle());
|
||||
paramMap.add("workspace_id", tapdId);
|
||||
paramMap.add("description", issuesRequest.getContent());
|
||||
|
||||
ResultHolder result = call(url, HttpMethod.POST, paramMap);
|
||||
|
||||
String listJson = JSON.toJSONString(result.getData());
|
||||
JSONObject jsonObject = JSONObject.parseObject(listJson);
|
||||
String issuesId = jsonObject.getObject("Bug", IssuesDTO.class).getId();
|
||||
|
||||
// 用例与第三方缺陷平台中的缺陷关联
|
||||
TestCaseIssues issues = new TestCaseIssues();
|
||||
issues.setId(UUID.randomUUID().toString());
|
||||
issues.setIssuesId(issuesId);
|
||||
issues.setTestCaseId(testCaseId);
|
||||
testCaseIssuesMapper.insert(issues);
|
||||
}
|
||||
|
||||
private ResultHolder call(String url) {
|
||||
|
@ -98,4 +132,46 @@ public class IssuesService {
|
|||
headers.add("Authorization", "Basic " + authKey);
|
||||
return headers;
|
||||
}
|
||||
|
||||
public IssuesDTO getTapdIssues(String projectId, String issuesId) {
|
||||
String url = "https://api.tapd.cn/bugs?workspace_id=" + projectId + "&id=" + issuesId;
|
||||
ResultHolder call = call(url);
|
||||
String listJson = JSON.toJSONString(call.getData());
|
||||
if (StringUtils.equals(Boolean.FALSE.toString(), listJson)) {
|
||||
return new IssuesDTO();
|
||||
}
|
||||
JSONObject jsonObject = JSONObject.parseObject(listJson);
|
||||
return jsonObject.getObject("Bug", IssuesDTO.class);
|
||||
}
|
||||
|
||||
public List<IssuesDTO> getIssues(String caseId) {
|
||||
List<IssuesDTO> list = new ArrayList<>();
|
||||
String tapdId = getTapdProjectId(caseId);
|
||||
|
||||
TestCaseIssuesExample example = new TestCaseIssuesExample();
|
||||
example.createCriteria().andTestCaseIdEqualTo(caseId);
|
||||
|
||||
List<TestCaseIssues> issues = testCaseIssuesMapper.selectByExample(example);
|
||||
List<String> issuesIds = issues.stream().map(issue -> issue.getIssuesId()).collect(Collectors.toList());
|
||||
issuesIds.forEach(issuesId -> {
|
||||
IssuesDTO dto = getTapdIssues(tapdId, issuesId);
|
||||
if (StringUtils.isBlank(dto.getId())) {
|
||||
// 缺陷不存在,解除用例和缺陷的关联
|
||||
TestCaseIssuesExample issuesExample = new TestCaseIssuesExample();
|
||||
issuesExample.createCriteria()
|
||||
.andTestCaseIdEqualTo(caseId)
|
||||
.andIssuesIdEqualTo(issuesId);
|
||||
testCaseIssuesMapper.deleteByExample(issuesExample);
|
||||
} else {
|
||||
list.add(dto);
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
public String getTapdProjectId(String testCaseId) {
|
||||
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
|
||||
Project project = projectService.getProjectById(testCase.getProjectId());
|
||||
return project.getTapdId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package io.metersphere.track.controller;
|
||||
|
||||
import io.metersphere.service.IssuesService;
|
||||
import io.metersphere.track.dto.IssuesDTO;
|
||||
import io.metersphere.track.request.testcase.IssuesRequest;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RequestMapping("issues")
|
||||
@RestController
|
||||
public class TestCaseIssuesController {
|
||||
|
||||
@Resource
|
||||
private IssuesService issuesService;
|
||||
|
||||
@PostMapping("/add")
|
||||
public void addIssues(@RequestBody IssuesRequest issuesRequest) {
|
||||
issuesService.addIssues(issuesRequest);
|
||||
}
|
||||
|
||||
@GetMapping("/get/{id}")
|
||||
public List<IssuesDTO> getIssues(@PathVariable String id) {
|
||||
return issuesService.getIssues(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.track.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class IssuesDTO {
|
||||
private String id;
|
||||
private String title;
|
||||
private String status;
|
||||
private String description;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.track.request.testcase;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class IssuesRequest {
|
||||
private String title;
|
||||
private String content;
|
||||
private String projectId;
|
||||
private String testCaseId;
|
||||
}
|
|
@ -172,11 +172,11 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="testCase.issues">
|
||||
<el-row>
|
||||
<el-col :span="5" :offset="1">
|
||||
<el-switch
|
||||
:disabled="isReadOnly"
|
||||
v-model="testCase.issues.hasIssues"
|
||||
v-model="issuesSwitch"
|
||||
@change="issuesChange"
|
||||
:active-text="$t('test_track.plan_view.submit_issues')">
|
||||
</el-switch>
|
||||
|
@ -188,7 +188,7 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="testCase.issues && testCase.issues.hasIssues">
|
||||
<el-row v-if="issuesSwitch">
|
||||
<el-col :span="20" :offset="1" class="issues-edit">
|
||||
<el-input
|
||||
type="text"
|
||||
|
@ -199,8 +199,19 @@
|
|||
/>
|
||||
<ckeditor :editor="editor" :disabled="isReadOnly" :config="editorConfig"
|
||||
v-model="testCase.issues.content"/>
|
||||
<el-button type="primary" size="small">{{$t('commons.save')}}</el-button>
|
||||
<el-button size="small" @click="cancel">{{$t('commons.cancel')}}</el-button>
|
||||
<el-button type="primary" size="small" @click="saveIssues">{{$t('commons.save')}}</el-button>
|
||||
<el-button size="small" @click="issuesSwitch=false">{{$t('commons.cancel')}}</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="20" :offset="1" class="issues-edit">
|
||||
<el-table border class="adjust-table" :data="issues" style="width: 100%">
|
||||
<el-table-column prop="id" label="缺陷ID"/>
|
||||
<el-table-column prop="title" label="缺陷标题"/>
|
||||
<el-table-column prop="status" label="缺陷状态"/>
|
||||
<el-table-column prop="description" label="缺陷描述" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
@ -240,6 +251,7 @@
|
|||
import PerformanceTestDetail from "./test/PerformanceTestDetail";
|
||||
import PerformanceTestResult from "./test/PerformanceTestResult";
|
||||
import {listenGoBack, removeGoBackListener} from "../../../../../../common/js/utils";
|
||||
import {CURRENT_PROJECT} from "../../../../../../common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "TestPlanTestCaseEdit",
|
||||
|
@ -256,7 +268,9 @@
|
|||
showDialog: false,
|
||||
testCase: {},
|
||||
index: 0,
|
||||
issuesSwitch: false,
|
||||
testCases: [],
|
||||
issues: [],
|
||||
editor: ClassicEditor,
|
||||
editorConfig: {
|
||||
// 'increaseIndent','decreaseIndent'
|
||||
|
@ -365,6 +379,7 @@
|
|||
this.activeTab = 'detail';
|
||||
listenGoBack(this.handleClose);
|
||||
this.initData(testCase);
|
||||
this.getIssues(testCase.caseId);
|
||||
},
|
||||
initTest() {
|
||||
this.$nextTick(() => {
|
||||
|
@ -417,18 +432,18 @@
|
|||
}
|
||||
},
|
||||
issuesChange() {
|
||||
if (this.testCase.issues.hasIssues) {
|
||||
let desc = this.addPLabel('[' + this.$t('test_track.plan_view.operate_step') + ']');
|
||||
let result = this.addPLabel('[' + this.$t('test_track.case.expected_results') + ']');
|
||||
let executeResult = this.addPLabel('[' + this.$t('test_track.plan_view.actual_result') + ']');
|
||||
this.testCase.steps.forEach(step => {
|
||||
let stepPrefix = this.$t('test_track.plan_view.step') + step.num + ':';
|
||||
desc += this.addPLabel(stepPrefix + (step.desc == undefined ? '' : step.desc));
|
||||
result += this.addPLabel(stepPrefix + (step.result == undefined ? '' : step.result));
|
||||
executeResult += this.addPLabel(stepPrefix + (step.executeResult == undefined ? '' : step.executeResult));
|
||||
});
|
||||
this.testCase.issues.content = desc + this.addPLabel('') + result + this.addPLabel('') + executeResult + this.addPLabel('');
|
||||
}
|
||||
// if (this.testCase.issues.hasIssues) {
|
||||
// let desc = this.addPLabel('[' + this.$t('test_track.plan_view.operate_step') + ']');
|
||||
// let result = this.addPLabel('[' + this.$t('test_track.case.expected_results') + ']');
|
||||
// let executeResult = this.addPLabel('[' + this.$t('test_track.plan_view.actual_result') + ']');
|
||||
// this.testCase.steps.forEach(step => {
|
||||
// let stepPrefix = this.$t('test_track.plan_view.step') + step.num + ':';
|
||||
// desc += this.addPLabel(stepPrefix + (step.desc == undefined ? '' : step.desc));
|
||||
// result += this.addPLabel(stepPrefix + (step.result == undefined ? '' : step.result));
|
||||
// executeResult += this.addPLabel(stepPrefix + (step.executeResult == undefined ? '' : step.executeResult));
|
||||
// });
|
||||
// this.testCase.issues.content = desc + this.addPLabel('') + result + this.addPLabel('') + executeResult + this.addPLabel('');
|
||||
// }
|
||||
},
|
||||
addPLabel(str) {
|
||||
return "<p>" + str + "</p>";
|
||||
|
@ -443,6 +458,27 @@
|
|||
}).length > 0;
|
||||
}
|
||||
|
||||
},
|
||||
saveIssues() {
|
||||
if (!this.testCase.issues.title || !this.testCase.issues.content) {
|
||||
this.$warning("标题和描述必填");
|
||||
return;
|
||||
}
|
||||
let param = {};
|
||||
param.title = this.testCase.issues.title;
|
||||
param.content = this.testCase.issues.content;
|
||||
param.testCaseId = this.testCase.caseId;
|
||||
this.result = this.$post("/issues/add", param, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.getIssues(param.testCaseId);
|
||||
})
|
||||
},
|
||||
getIssues(caseId) {
|
||||
this.result = this.$get("/issues/get/"+caseId,response => {
|
||||
let data = response.data;
|
||||
this.issues = data;
|
||||
console.log(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue