feat: 集成Jira

This commit is contained in:
shiziyuan9527 2020-08-17 22:01:15 +08:00
parent 60ed8a0535
commit 240ac7ab26
3 changed files with 225 additions and 18 deletions

View File

@ -10,24 +10,26 @@ import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.EncryptUtils;
import io.metersphere.commons.utils.LogUtil;
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.request.testcase.IssuesRequest;
import io.metersphere.track.service.TestCaseService;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
@Service
@ -48,10 +50,42 @@ public class IssuesService {
private ExtIssuesMapper extIssuesMapper;
public void testAuth() {
String url = "https://api.tapd.cn/quickstart/testauth";
ResultHolder call = call(url);
System.out.println(call.getData());
public void testAuth(String platform) {
if (StringUtils.equals(platform, IssuesManagePlatform.Tapd.toString())) {
try {
String tapdConfig = platformConfig(IssuesManagePlatform.Tapd.toString());
JSONObject object = JSON.parseObject(tapdConfig);
String account = object.getString("account");
String password = object.getString("password");
HttpHeaders headers = auth(account, password);
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange("https://api.tapd.cn/quickstart/testauth", HttpMethod.GET, requestEntity, String.class);
} catch (Exception e) {
System.out.println(e);
LogUtil.error(e.getMessage(), e);
MSException.throwException("验证失败!");
}
} else {
try {
String config = platformConfig(IssuesManagePlatform.Jira.toString());
JSONObject object = JSON.parseObject(config);
String account = object.getString("account");
String password = object.getString("password");
String url = object.getString("url");
HttpHeaders headers = auth(account, password);
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange(url + "rest/api/2/issue/createmeta", HttpMethod.GET, requestEntity, String.class);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException("验证失败!");
}
}
}
private ResultHolder call(String url) {
@ -61,7 +95,7 @@ public class IssuesService {
private ResultHolder call(String url, HttpMethod httpMethod, Object params) {
String responseJson;
String config = tapdConfig();
String config = platformConfig(IssuesManagePlatform.Tapd.toString());
JSONObject object = JSON.parseObject(config);
if (object == null) {
@ -71,7 +105,7 @@ public class IssuesService {
String account = object.getString("account");
String password = object.getString("password");
HttpHeaders header = tapdAuth(account, password);
HttpHeaders header = auth(account, password);
if (httpMethod.equals(HttpMethod.GET)) {
responseJson = RestTemplateUtils.get(url, header);
@ -88,7 +122,7 @@ public class IssuesService {
}
private String tapdConfig() {
private String platformConfig(String platform) {
SessionUser user = SessionUtils.getUser();
String orgId = user.getLastOrganizationId();
@ -97,13 +131,13 @@ public class IssuesService {
MSException.throwException("organization id is null");
}
request.setOrgId(orgId);
request.setPlatform(IssuesManagePlatform.Tapd.toString());
request.setPlatform(platform);
ServiceIntegration integration = integrationService.get(request);
return integration.getConfiguration();
}
private HttpHeaders tapdAuth(String apiUser, String password) {
private HttpHeaders auth(String apiUser, String password) {
String authKey = EncryptUtils.base64Encoding(apiUser + ":" + password);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + authKey);
@ -118,10 +152,10 @@ public class IssuesService {
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
String tapdId = getTapdProjectId(issuesRequest.getTestCaseId());
String jiraId = "";
String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId());
if (tapd || jira) {
if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraId)) {
if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey)) {
MSException.throwException("集成了缺陷管理平台,但未进行项目关联!");
}
}
@ -134,7 +168,9 @@ public class IssuesService {
}
if (jira) {
// addJiraIssues(issuesRequest);
if (StringUtils.isNotBlank(jiraKey)) {
addJiraIssues(issuesRequest);
}
}
if (!tapd && !jira) {
@ -177,6 +213,72 @@ public class IssuesService {
issuesMapper.insert(issues);
}
public void addJiraIssues(IssuesRequest issuesRequest) {
String config = platformConfig(IssuesManagePlatform.Jira.toString());
JSONObject object = JSON.parseObject(config);
if (object == null) {
MSException.throwException("jira config is null");
}
String account = object.getString("account");
String password = object.getString("password");
String url = object.getString("url");
String auth = EncryptUtils.base64Encoding(account + ":" + password);
String testCaseId = issuesRequest.getTestCaseId();
String jiraKey = getJiraProjectKey(testCaseId);
if (StringUtils.isBlank(jiraKey)) {
MSException.throwException("未关联Jira 项目Key");
}
String json = "{\n" +
" \"fields\":{\n" +
" \"project\":{\n" +
" \"key\":\"" + jiraKey + "\"\n" +
" },\n" +
" \"summary\":\"" + issuesRequest.getTitle() + "\",\n" +
" \"description\":\"" + issuesRequest.getContent() + "\",\n" +
" \"issuetype\":{\n" +
" \"id\":\"10009\",\n" +
" \"name\":\"Defect\"\n" +
" }\n" +
" }\n" +
"}";
String result = addJiraIssue(url, auth, json);
JSONObject jsonObject = JSON.parseObject(result);
String id = jsonObject.getString("id");
// 用例与第三方缺陷平台中的缺陷关联
TestCaseIssues testCaseIssues = new TestCaseIssues();
testCaseIssues.setId(UUID.randomUUID().toString());
testCaseIssues.setIssuesId(id);
testCaseIssues.setTestCaseId(testCaseId);
testCaseIssuesMapper.insert(testCaseIssues);
// 插入缺陷表
Issues issues = new Issues();
issues.setId(id);
issues.setPlatform(IssuesManagePlatform.Jira.toString());
issuesMapper.insert(issues);
}
private String addJiraIssue(String url, String auth, String json) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Authorization", "Basic " + auth);
requestHeaders.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
//HttpEntity
HttpEntity<String> requestEntity = new HttpEntity<>(json, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
//post
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/rest/api/2/issue", HttpMethod.POST, requestEntity, String.class);
return responseEntity.getBody();
}
public void addLocalIssues(IssuesRequest request) {
SessionUser user = SessionUtils.getUser();
String id = UUID.randomUUID().toString();
@ -209,6 +311,39 @@ public class IssuesService {
return jsonObject.getObject("Bug", Issues.class);
}
public Issues getJiraIssues(HttpHeaders headers, String url, String issuesId) {
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
//post
ResponseEntity<String> responseEntity = null;
Issues issues = new Issues();
try {
responseEntity = restTemplate.exchange(url + "/rest/api/2/issue/" + issuesId, HttpMethod.GET, requestEntity, String.class);
String body = responseEntity.getBody();
JSONObject obj = JSONObject.parseObject(body);
JSONObject fields = (JSONObject) obj.get("fields");
JSONObject statusObj = (JSONObject) fields.get("status");
JSONObject statusCategory = (JSONObject) statusObj.get("statusCategory");
String id = obj.getString("id");
String title = fields.getString("summary");
String description = fields.getString("description");
String status = statusCategory.getString("key");
issues.setId(id);
issues.setTitle(title);
issues.setDescription(description);
issues.setStatus(status);
issues.setPlatform(IssuesManagePlatform.Jira.toString());
} catch (Exception e) {
return new Issues();
}
return issues;
}
public List<Issues> getIssues(String caseId) {
List<Issues> list = new ArrayList<>();
SessionUser user = SessionUtils.getUser();
@ -227,7 +362,10 @@ public class IssuesService {
}
if (jira) {
// getJiraIssues(caseId);
String jiraKey = getJiraProjectKey(caseId);
if (StringUtils.isNotBlank(jiraKey)) {
list.addAll(getJiraIssues(caseId));
}
}
list.addAll(getLocalIssues(caseId));
@ -253,6 +391,7 @@ public class IssuesService {
.andTestCaseIdEqualTo(caseId)
.andIssuesIdEqualTo(issuesId);
testCaseIssuesMapper.deleteByExample(issuesExample);
issuesMapper.deleteByPrimaryKey(issuesId);
} else {
dto.setPlatform(IssuesManagePlatform.Tapd.toString());
// 缺陷状态为 关闭则不显示
@ -264,6 +403,47 @@ public class IssuesService {
return list;
}
public List<Issues> getJiraIssues(String caseId) {
List<Issues> list = new ArrayList<>();
String config = platformConfig(IssuesManagePlatform.Jira.toString());
JSONObject object = JSON.parseObject(config);
if (object == null) {
MSException.throwException("tapd config is null");
}
String account = object.getString("account");
String password = object.getString("password");
String url = object.getString("url");
HttpHeaders headers = auth(account, password);
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andTestCaseIdEqualTo(caseId);
List<Issues> issues = extIssuesMapper.getIssues(caseId, IssuesManagePlatform.Jira.toString());
List<String> issuesIds = issues.stream().map(issue -> issue.getId()).collect(Collectors.toList());
issuesIds.forEach(issuesId -> {
Issues dto = getJiraIssues(headers, url, issuesId);
if (StringUtils.isBlank(dto.getId())) {
// 缺陷不存在解除用例和缺陷的关联
TestCaseIssuesExample issuesExample = new TestCaseIssuesExample();
issuesExample.createCriteria()
.andTestCaseIdEqualTo(caseId)
.andIssuesIdEqualTo(issuesId);
testCaseIssuesMapper.deleteByExample(issuesExample);
issuesMapper.deleteByPrimaryKey(issuesId);
} else {
// 缺陷状态为 完成则不显示
if (!StringUtils.equals("done", dto.getStatus())) {
list.add(dto);
}
}
});
return list;
}
public List<Issues> getLocalIssues(String caseId) {
return extIssuesMapper.getIssues(caseId, IssuesManagePlatform.Local.toString());
}
@ -274,6 +454,12 @@ public class IssuesService {
return project.getTapdId();
}
public String getJiraProjectKey(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getJiraKey();
}
/**
* 是否关联平台
*/

View File

@ -24,4 +24,10 @@ public class TestCaseIssuesController {
public List<Issues> getIssues(@PathVariable String id) {
return issuesService.getIssues(id);
}
@GetMapping("/auth/{platform}")
public void testAuth(@PathVariable String platform) {
issuesService.testAuth(platform);
}
}

View File

@ -19,10 +19,15 @@
<el-input v-model="form.password" auto-complete="new-password"
:placeholder="$t('organization.input_api_password')" show-password/>
</el-form-item>
<el-form-item label="JIRA 地址" prop="url" v-if="platform === 'Jira'">
<el-input v-model="form.url" placeholder="请输入Jira地址"/>
</el-form-item>
</el-form>
</div>
<div style="margin-left: 100px">
<el-button type="primary" size="small" :disabled="!show" @click="testConnection">{{$t('ldap.test_connect')}}
</el-button>
<el-button v-if="showEdit" size="small" @click="edit">{{$t('commons.edit')}}</el-button>
<el-button type="primary" v-if="showSave" size="small" @click="save('form')">{{$t('commons.save')}}</el-button>
<el-button v-if="showCancel" size="small" @click="cancelEdit">取消编辑</el-button>
@ -72,7 +77,8 @@
],
rules: {
account: {required: true, message: this.$t('organization.input_api_account'), trigger: ['change', 'blur']},
password: {required: true, message: this.$t('organization.input_api_password'), trigger: ['change', 'blur']}
password: {required: true, message: this.$t('organization.input_api_password'), trigger: ['change', 'blur']},
url: {required: true, message: '请输入url', trigger: ['change', 'blur']}
},
}
},
@ -91,6 +97,7 @@
let config = JSON.parse(data.configuration);
this.$set(this.form, 'account', config.account);
this.$set(this.form, 'password', config.password);
this.$set(this.form, 'url', config.url);
} else {
this.clear();
}
@ -138,7 +145,8 @@
let param = {};
let auth = {
account: this.form.account,
password: this.form.password
password: this.form.password,
url: this.form.url
};
param.organizationId = getCurrentUser().lastOrganizationId;
param.platform = this.platform;
@ -172,6 +180,7 @@
let config = JSON.parse(data.configuration);
this.$set(this.form, 'account', config.account);
this.$set(this.form, 'password', config.password);
this.$set(this.form, 'url', config.url);
} else {
this.clear();
}
@ -180,9 +189,15 @@
clear() {
this.$set(this.form, 'account', '');
this.$set(this.form, 'password', '');
this.$set(this.form, 'url', '');
this.$nextTick(() => {
this.$refs.form.clearValidate();
});
},
testConnection() {
this.$get("issues/auth/" + this.platform, () => {
this.$success("验证通过!");
});
}
}
}