feat: 集成TAPD平台

This commit is contained in:
shiziyuan9527 2020-08-13 17:15:19 +08:00
parent 47fad33be1
commit f42a920fcf
5 changed files with 189 additions and 24 deletions

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
})
}
}
}