This commit is contained in:
chenjianxing 2020-11-16 22:06:57 +08:00
commit 62f32e5d38
23 changed files with 502 additions and 105 deletions

View File

@ -20,7 +20,6 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟
![产品定位](https://metersphere.oss-cn-hangzhou.aliyuncs.com/img/ct-devops.png) ![产品定位](https://metersphere.oss-cn-hangzhou.aliyuncs.com/img/ct-devops.png)
> 如需进一步了解 MeterSphere 开源项目,推荐阅读 [MeterSphere 的初心和使命](https://mp.weixin.qq.com/s/DpCt3BNgBTlV3sJ5qtPmZw) > 如需进一步了解 MeterSphere 开源项目,推荐阅读 [MeterSphere 的初心和使命](https://mp.weixin.qq.com/s/DpCt3BNgBTlV3sJ5qtPmZw)
## 在线体验 ## 在线体验
@ -38,8 +37,8 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟
仅需两步快速安装 MeterSphere 仅需两步快速安装 MeterSphere
1. 准备一台不小于 8 G内存的 64位 Linux 主机; 1. 准备一台不小于 8 G内存的 64位 Linux 主机;
2. 以 root 用户执行如下命令一键安装 MeterSphere。 2. 以 root 用户执行如下命令一键安装 MeterSphere。
```sh ```sh
curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/quick_start.sh | sh
@ -63,7 +62,7 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
MeterSphere 版本号命名规则为v大版本.功能版本.Bug修复版本。比如 MeterSphere 版本号命名规则为v大版本.功能版本.Bug修复版本。比如
``` ```text
v1.0.1 是 v1.0.0 之后的Bug修复版本 v1.0.1 是 v1.0.0 之后的Bug修复版本
v1.1.0 是 v1.0.0 之后的功能版本。 v1.1.0 是 v1.0.0 之后的功能版本。
``` ```

View File

@ -21,5 +21,7 @@ public class Project implements Serializable {
private String jiraKey; private String jiraKey;
private String zentaoId;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -643,6 +643,76 @@ public class ProjectExample {
addCriterion("jira_key not between", value1, value2, "jiraKey"); addCriterion("jira_key not between", value1, value2, "jiraKey");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andZentaoIdIsNull() {
addCriterion("zentao_id is null");
return (Criteria) this;
}
public Criteria andZentaoIdIsNotNull() {
addCriterion("zentao_id is not null");
return (Criteria) this;
}
public Criteria andZentaoIdEqualTo(String value) {
addCriterion("zentao_id =", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdNotEqualTo(String value) {
addCriterion("zentao_id <>", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdGreaterThan(String value) {
addCriterion("zentao_id >", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdGreaterThanOrEqualTo(String value) {
addCriterion("zentao_id >=", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdLessThan(String value) {
addCriterion("zentao_id <", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdLessThanOrEqualTo(String value) {
addCriterion("zentao_id <=", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdLike(String value) {
addCriterion("zentao_id like", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdNotLike(String value) {
addCriterion("zentao_id not like", value, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdIn(List<String> values) {
addCriterion("zentao_id in", values, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdNotIn(List<String> values) {
addCriterion("zentao_id not in", values, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdBetween(String value1, String value2) {
addCriterion("zentao_id between", value1, value2, "zentaoId");
return (Criteria) this;
}
public Criteria andZentaoIdNotBetween(String value1, String value2) {
addCriterion("zentao_id not between", value1, value2, "zentaoId");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -10,6 +10,7 @@
<result column="update_time" jdbcType="BIGINT" property="updateTime" /> <result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="tapd_id" jdbcType="VARCHAR" property="tapdId" /> <result column="tapd_id" jdbcType="VARCHAR" property="tapdId" />
<result column="jira_key" jdbcType="VARCHAR" property="jiraKey" /> <result column="jira_key" jdbcType="VARCHAR" property="jiraKey" />
<result column="zentao_id" jdbcType="VARCHAR" property="zentaoId" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@ -70,7 +71,8 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key id, workspace_id, `name`, description, create_time, update_time, tapd_id, jira_key,
zentao_id
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultMap="BaseResultMap">
select select
@ -105,10 +107,12 @@
<insert id="insert" parameterType="io.metersphere.base.domain.Project"> <insert id="insert" parameterType="io.metersphere.base.domain.Project">
insert into project (id, workspace_id, `name`, insert into project (id, workspace_id, `name`,
description, create_time, update_time, description, create_time, update_time,
tapd_id, jira_key) tapd_id, jira_key, zentao_id
)
values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{workspaceId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}) #{tapdId,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR}, #{zentaoId,jdbcType=VARCHAR}
)
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.Project"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.Project">
insert into project insert into project
@ -137,6 +141,9 @@
<if test="jiraKey != null"> <if test="jiraKey != null">
jira_key, jira_key,
</if> </if>
<if test="zentaoId != null">
zentao_id,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null"> <if test="id != null">
@ -163,6 +170,9 @@
<if test="jiraKey != null"> <if test="jiraKey != null">
#{jiraKey,jdbcType=VARCHAR}, #{jiraKey,jdbcType=VARCHAR},
</if> </if>
<if test="zentaoId != null">
#{zentaoId,jdbcType=VARCHAR},
</if>
</trim> </trim>
</insert> </insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long"> <select id="countByExample" parameterType="io.metersphere.base.domain.ProjectExample" resultType="java.lang.Long">
@ -198,6 +208,9 @@
<if test="record.jiraKey != null"> <if test="record.jiraKey != null">
jira_key = #{record.jiraKey,jdbcType=VARCHAR}, jira_key = #{record.jiraKey,jdbcType=VARCHAR},
</if> </if>
<if test="record.zentaoId != null">
zentao_id = #{record.zentaoId,jdbcType=VARCHAR},
</if>
</set> </set>
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
@ -212,7 +225,8 @@
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
tapd_id = #{record.tapdId,jdbcType=VARCHAR}, tapd_id = #{record.tapdId,jdbcType=VARCHAR},
jira_key = #{record.jiraKey,jdbcType=VARCHAR} jira_key = #{record.jiraKey,jdbcType=VARCHAR},
zentao_id = #{record.zentaoId,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -241,6 +255,9 @@
<if test="jiraKey != null"> <if test="jiraKey != null">
jira_key = #{jiraKey,jdbcType=VARCHAR}, jira_key = #{jiraKey,jdbcType=VARCHAR},
</if> </if>
<if test="zentaoId != null">
zentao_id = #{zentaoId,jdbcType=VARCHAR},
</if>
</set> </set>
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
@ -252,7 +269,8 @@
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
tapd_id = #{tapdId,jdbcType=VARCHAR}, tapd_id = #{tapdId,jdbcType=VARCHAR},
jira_key = #{jiraKey,jdbcType=VARCHAR} jira_key = #{jiraKey,jdbcType=VARCHAR},
zentao_id = #{zentaoId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -4,7 +4,7 @@
<select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO"> <select id="getProjectWithWorkspace" resultType="io.metersphere.dto.ProjectDTO">
select p.id, p.workspace_id, p.name, p.description, p.update_time, select p.id, p.workspace_id, p.name, p.description, p.update_time,
p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key p.create_time, w.id as workspaceId, w.name as workspaceName, p.tapd_id, p.jira_key, p.zentao_id
from project p from project p
join workspace w on p.workspace_id = w.id join workspace w on p.workspace_id = w.id
<where> <where>

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants; package io.metersphere.commons.constants;
public enum IssuesManagePlatform { public enum IssuesManagePlatform {
Tapd, Jira, Local Tapd, Jira, Local, Zentao
} }

View File

@ -16,5 +16,5 @@ public class ProjectDTO {
private Long updateTime; private Long updateTime;
private String tapdId; private String tapdId;
private String jiraKey; private String jiraKey;
private String zentaoId;
} }

View File

@ -10,11 +10,13 @@ import java.util.List;
public class IssueFactory { public class IssueFactory {
public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) { public static AbstractIssuePlatform createPlatform(String platform, IssuesRequest addIssueRequest) {
if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) { if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) {
return new TapdIssue(addIssueRequest); return new TapdPlatform(addIssueRequest);
} else if (StringUtils.equals(IssuesManagePlatform.Jira.toString(), platform)) { } else if (StringUtils.equals(IssuesManagePlatform.Jira.toString(), platform)) {
return new JiraIssue(addIssueRequest); return new JiraPlatform(addIssueRequest);
} else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) {
return new ZentaoPlatform(addIssueRequest);
} else if (StringUtils.equals("LOCAL", platform)) { } else if (StringUtils.equals("LOCAL", platform)) {
return new LocalIssue(addIssueRequest); return new LocalPlatform(addIssueRequest);
} }
return null; return null;
} }

View File

@ -28,10 +28,10 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class JiraIssue extends AbstractIssuePlatform { public class JiraPlatform extends AbstractIssuePlatform {
public JiraIssue(IssuesRequest issuesRequest) { public JiraPlatform(IssuesRequest issuesRequest) {
super(issuesRequest); super(issuesRequest);
} }

View File

@ -10,9 +10,9 @@ import io.metersphere.track.request.testcase.IssuesRequest;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public class LocalIssue extends AbstractIssuePlatform { public class LocalPlatform extends AbstractIssuePlatform {
public LocalIssue(IssuesRequest issuesRequest) { public LocalPlatform(IssuesRequest issuesRequest) {
super(issuesRequest); super(issuesRequest);
} }

View File

@ -24,10 +24,10 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class TapdIssue extends AbstractIssuePlatform { public class TapdPlatform extends AbstractIssuePlatform {
public TapdIssue(IssuesRequest issueRequest) { public TapdPlatform(IssuesRequest issueRequest) {
super(issueRequest); super(issueRequest);
} }

View File

@ -0,0 +1,221 @@
package io.metersphere.track.issue;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.*;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.track.request.testcase.IssuesRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.stream.Collectors;
public class ZentaoPlatform extends AbstractIssuePlatform {
/**
* zentao account
*/
private final String account;
/**
* zentao password
*/
private final String password;
/**
* zentao url eg:http://x.x.x.x/zentao
*/
private final String url;
public ZentaoPlatform(IssuesRequest issuesRequest) {
super(issuesRequest);
String config = getPlatformConfig(IssuesManagePlatform.Zentao.toString());
JSONObject object = JSON.parseObject(config);
this.account = object.getString("account");
this.password = object.getString("password");
this.url = object.getString("url");
}
@Override
String getProjectId() {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getZentaoId();
}
@Override
public List<Issues> getIssue() {
List<Issues> list = new ArrayList<>();
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andTestCaseIdEqualTo(testCaseId);
List<Issues> issues = extIssuesMapper.getIssues(testCaseId, IssuesManagePlatform.Zentao.toString());
List<String> issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList());
issuesIds.forEach(issuesId -> {
Issues dto = getZentaoIssues(issuesId);
if (StringUtils.isBlank(dto.getId())) {
// 缺陷不存在解除用例和缺陷的关联
TestCaseIssuesExample issuesExample = new TestCaseIssuesExample();
issuesExample.createCriteria()
.andTestCaseIdEqualTo(testCaseId)
.andIssuesIdEqualTo(issuesId);
testCaseIssuesMapper.deleteByExample(issuesExample);
issuesMapper.deleteByPrimaryKey(issuesId);
} else {
dto.setPlatform(IssuesManagePlatform.Zentao.toString());
// 缺陷状态为 关闭则不显示
if (!StringUtils.equals("closed", dto.getStatus())) {
list.add(dto);
}
}
});
return list;
}
private Issues getZentaoIssues(String bugId) {
String session = login();
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(new HttpHeaders());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getModel-bug-getById-bugID={bugId}?zentaosid=" + session,
HttpMethod.POST, requestEntity, String.class, bugId);
String body = responseEntity.getBody();
JSONObject obj = JSONObject.parseObject(body);
if (obj != null) {
JSONObject bug = obj.getJSONObject("data");
String id = bug.getString("id");
String title = bug.getString("title");
String description = bug.getString("steps");
Long createTime = bug.getLong("openedDate");
String status = bug.getString("status");
String reporter = bug.getString("openedBy");
int deleted = bug.getInteger("deleted");
if (deleted == 1) {
return new Issues();
}
Issues issues = new Issues();
issues.setId(id);
issues.setTitle(title);
issues.setDescription(description);
issues.setCreateTime(createTime);
issues.setStatus(status);
issues.setReporter(reporter);
return issues;
}
return new Issues();
}
@Override
public void addIssue(IssuesRequest issuesRequest) {
String session = login();
String projectId = getProjectId();
if (StringUtils.isBlank(projectId)) {
MSException.throwException("add zentao bug fail, project zentao id is null");
}
if (StringUtils.isBlank(session)) {
MSException.throwException("session is null");
}
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("product", projectId);
paramMap.add("title", issuesRequest.getTitle());
paramMap.add("openedBuild", "123");
paramMap.add("steps", issuesRequest.getContent());
paramMap.add("assignedTo", "admin");
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getModel-bug-create.json?zentaosid=" + session, HttpMethod.POST, requestEntity, String.class);
String body = responseEntity.getBody();
JSONObject obj = JSONObject.parseObject(body);
if (obj != null) {
JSONObject data = obj.getJSONObject("data");
String id = data.getString("id");
if (StringUtils.isNotBlank(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.Zentao.toString());
issuesMapper.insert(issues);
}
}
}
@Override
public void deleteIssue(String id) {
}
@Override
public void testAuth() {
try {
login();
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException("验证失败!");
}
}
private String login() {
String session = getSession();
String loginUrl = url + "user-login.json?zentaosid=" + session;
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
paramMap.add("account", account);
paramMap.add("password", password);
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(loginUrl, HttpMethod.POST, requestEntity, String.class);
String body = responseEntity.getBody();
JSONObject obj = JSONObject.parseObject(body);
JSONObject user = obj.getJSONObject("user");
if (user == null) {
LogUtil.error("login fail");
LogUtil.error(obj);
// 登录失败获取的session无效置空session
MSException.throwException("zentao login fail");
}
String username = user.getString("account");
if (!StringUtils.equals(username, account)) {
LogUtil.error("login failinconsistent users");
MSException.throwException("zentao login fail");
}
return session;
}
private String getSession() {
RestTemplate restTemplate = new RestTemplate();
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<>(new HttpHeaders());
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "api-getsessionid.json", HttpMethod.GET, requestEntity, String.class);
String body = responseEntity.getBody();
JSONObject obj = JSONObject.parseObject(body);
JSONObject data = obj.getJSONObject("data");
String session = data.getString("sessionID");
return session;
}
@Override
public List<PlatformUser> getPlatformUser() {
return null;
}
}

View File

@ -0,0 +1,26 @@
package io.metersphere.track.issue;
import io.metersphere.commons.utils.EncryptUtils;
public class ZentaoUtils {
/**
* @param code Zentao 应用代号
* @param key Zentao 密钥
* @return token
*/
public static String getToken(String code, String key, String time) {
return (String) EncryptUtils.md5Encrypt(code + key + time);
}
/**
* @param url Zentao url
* @param code Zentao 应用代号
* @param key Zentao 密钥
* @return url
*/
public static String getUrl(String url, String code, String key) {
String time = String.valueOf(System.currentTimeMillis());;
return url + "api.php?" + "code=" + code + "&time=" + time + "&token=" + getToken(code, key, time);
}
}

View File

@ -63,9 +63,11 @@ public class IssuesService {
boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString());
String tapdId = getTapdProjectId(issuesRequest.getTestCaseId()); String tapdId = getTapdProjectId(issuesRequest.getTestCaseId());
String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId()); String jiraKey = getJiraProjectKey(issuesRequest.getTestCaseId());
String zentaoId = getZentaoProjectId(issuesRequest.getTestCaseId());
List<String> platforms = new ArrayList<>(); List<String> platforms = new ArrayList<>();
@ -82,7 +84,13 @@ public class IssuesService {
} }
} }
if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey)) { if (zentao) {
if (StringUtils.isNotBlank(zentaoId)) {
platforms.add(IssuesManagePlatform.Zentao.name());
}
}
if (StringUtils.isBlank(tapdId) && StringUtils.isBlank(jiraKey) && StringUtils.isBlank(zentaoId)) {
platforms.add("LOCAL"); platforms.add("LOCAL");
} }
@ -122,6 +130,7 @@ public class IssuesService {
boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString()); boolean tapd = isIntegratedPlatform(orgId, IssuesManagePlatform.Tapd.toString());
boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString()); boolean jira = isIntegratedPlatform(orgId, IssuesManagePlatform.Jira.toString());
boolean zentao = isIntegratedPlatform(orgId, IssuesManagePlatform.Zentao.toString());
List<String> platforms = new ArrayList<>(); List<String> platforms = new ArrayList<>();
if (tapd) { if (tapd) {
@ -140,6 +149,13 @@ public class IssuesService {
} }
} }
if (zentao) {
String zentaoId = getZentaoProjectId(caseId);
if (StringUtils.isNotBlank(zentaoId)) {
platforms.add(IssuesManagePlatform.Zentao.name());
}
}
platforms.add("LOCAL"); platforms.add("LOCAL");
IssuesRequest issueRequest = new IssuesRequest(); IssuesRequest issueRequest = new IssuesRequest();
issueRequest.setTestCaseId(caseId); issueRequest.setTestCaseId(caseId);
@ -152,18 +168,24 @@ public class IssuesService {
return list; return list;
} }
public String getTapdProjectId(String testCaseId) { private String getTapdProjectId(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId()); Project project = projectService.getProjectById(testCase.getProjectId());
return project.getTapdId(); return project.getTapdId();
} }
public String getJiraProjectKey(String testCaseId) { private String getJiraProjectKey(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId); TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId()); Project project = projectService.getProjectById(testCase.getProjectId());
return project.getJiraKey(); return project.getJiraKey();
} }
private String getZentaoProjectId(String testCaseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(testCaseId);
Project project = projectService.getProjectById(testCase.getProjectId());
return project.getZentaoId();
}
/** /**
* 是否关联平台 * 是否关联平台
*/ */

View File

@ -0,0 +1 @@
alter table project add zentao_id varchar(50) null;

View File

@ -57,9 +57,9 @@ export default {
if (header.default !== undefined) { if (header.default !== undefined) {
this.licenseHeader = "LicenseMessage"; this.licenseHeader = "LicenseMessage";
} }
//
if (display.default !== undefined) { if (display.default !== undefined) {
display.default.valid(this); display.default.showHome(this);
} }
} else { } else {
window.location.href = "/login" window.location.href = "/login"

View File

@ -63,6 +63,9 @@
<el-form-item :label="$t('project.jira_key')" v-if="jira"> <el-form-item :label="$t('project.jira_key')" v-if="jira">
<el-input v-model="form.jiraKey" autocomplete="off"></el-input> <el-input v-model="form.jiraKey" autocomplete="off"></el-input>
</el-form-item> </el-form-item>
<el-form-item :label="$t('project.zentao_id')" v-if="zentao">
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
</el-form-item>
</el-form> </el-form>
<template v-slot:footer> <template v-slot:footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -116,6 +119,7 @@ export default {
items: [], items: [],
tapd: false, tapd: false,
jira: false, jira: false,
zentao: false,
form: {}, form: {},
currentPage: 1, currentPage: 1,
pageSize: 5, pageSize: 5,
@ -194,6 +198,9 @@ export default {
if (platforms.indexOf("Jira") !== -1) { if (platforms.indexOf("Jira") !== -1) {
this.jira = true; this.jira = true;
} }
if (platforms.indexOf("Zentao") !== -1) {
this.zentao = true;
}
}); });
} }
}, },

View File

@ -10,6 +10,9 @@
<el-input v-model="form.password" auto-complete="new-password" <el-input v-model="form.password" auto-complete="new-password"
:placeholder="$t('organization.integration.input_app_key')" show-password/> :placeholder="$t('organization.integration.input_app_key')" show-password/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('organization.integration.zentao_url')" prop="url">
<el-input v-model="form.url" :placeholder="$t('organization.integration.input_zentao_url')"/>
</el-form-item>
</el-form> </el-form>
</div> </div>
@ -63,7 +66,12 @@ export default {
required: true, required: true,
message: this.$t('organization.integration.input_app_key'), message: this.$t('organization.integration.input_app_key'),
trigger: ['change', 'blur'] trigger: ['change', 'blur']
} },
url: {
required: true,
message: this.$t('organization.integration.input_zentao_url'),
trigger: ['change', 'blur']
},
}, },
} }
}, },
@ -71,12 +79,16 @@ export default {
save() { save() {
this.$refs['form'].validate(valid => { this.$refs['form'].validate(valid => {
if (valid) { if (valid) {
let formatUrl = this.form.url.trim();
if (!formatUrl.endsWith('/')) {
formatUrl = formatUrl + '/';
}
const {lastOrganizationId} = getCurrentUser(); const {lastOrganizationId} = getCurrentUser();
let param = {}; let param = {};
let auth = { let auth = {
account: this.form.account, account: this.form.account,
password: this.form.password, password: this.form.password,
url: formatUrl,
}; };
param.organizationId = lastOrganizationId; param.organizationId = lastOrganizationId;
param.platform = ZEN_TAO; param.platform = ZEN_TAO;
@ -106,6 +118,7 @@ export default {
let config = JSON.parse(data.configuration); let config = JSON.parse(data.configuration);
this.$set(this.form, 'account', config.account); this.$set(this.form, 'account', config.account);
this.$set(this.form, 'password', config.password); this.$set(this.form, 'password', config.password);
this.$set(this.form, 'url', config.url);
} else { } else {
this.clear(); this.clear();
} }
@ -114,11 +127,14 @@ export default {
clear() { clear() {
this.$set(this.form, 'account', ''); this.$set(this.form, 'account', '');
this.$set(this.form, 'password', ''); this.$set(this.form, 'password', '');
this.$set(this.form, 'url', '');
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.form.clearValidate(); this.$refs.form.clearValidate();
}); });
}, },
testConnection() { testConnection() {
this.$refs['form'].validate(valid => {
if (valid) {
if (this.form.account && this.form.password) { if (this.form.account && this.form.password) {
this.$parent.result = this.$get("issues/auth/" + ZEN_TAO, () => { this.$parent.result = this.$get("issues/auth/" + ZEN_TAO, () => {
this.$success(this.$t('organization.integration.verified')); this.$success(this.$t('organization.integration.verified'));
@ -127,6 +143,10 @@ export default {
this.$warning(this.$t('organization.integration.not_integrated')); this.$warning(this.$t('organization.integration.not_integrated'));
return false; return false;
} }
} else {
return false;
}
})
}, },
cancelIntegration() { cancelIntegration() {
if (this.form.account && this.form.password) { if (this.form.account && this.form.password) {

View File

@ -262,6 +262,8 @@ export default {
input_app_key: 'Please enter the key', input_app_key: 'Please enter the key',
input_jira_url: 'Please enter Jira address, for example: https://metersphere.atlassian.net/', input_jira_url: 'Please enter Jira address, for example: https://metersphere.atlassian.net/',
input_jira_issuetype: 'Please enter the question type', input_jira_issuetype: 'Please enter the question type',
zentao_url: 'Zentao url',
input_zentao_url: 'Please enter Zentao address, for example: http://xx.xx.xx.xx/zentao/',
use_tip: 'Usage guidelines:', use_tip: 'Usage guidelines:',
use_tip_tapd: 'Basic Auth account information is queried in "Company Management-Security and Integration-Open Platform"', use_tip_tapd: 'Basic Auth account information is queried in "Company Management-Security and Integration-Open Platform"',
use_tip_jira: 'Jira software server authentication information is account password, Jira software cloud authentication information is account + token (account settings-security-create API token)', use_tip_jira: 'Jira software server authentication information is account password, Jira software cloud authentication information is account + token (account settings-security-create API token)',
@ -292,6 +294,7 @@ export default {
special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')', special_characters_are_not_supported: 'Incorrect format (special characters are not supported and cannot end with \'-\')',
tapd_id: 'TAPD Project ID', tapd_id: 'TAPD Project ID',
jira_key: 'JIRA Project key', jira_key: 'JIRA Project key',
zentao_id: 'Zentao Project ID',
}, },
member: { member: {
create: 'Create', create: 'Create',

View File

@ -262,6 +262,8 @@ export default {
input_app_key: '请输入密钥', input_app_key: '请输入密钥',
input_jira_url: '请输入Jira地址https://metersphere.atlassian.net/', input_jira_url: '请输入Jira地址https://metersphere.atlassian.net/',
input_jira_issuetype: '请输入问题类型', input_jira_issuetype: '请输入问题类型',
zentao_url: 'Zentao 地址',
input_zentao_url: '请输入Zentao地址http://xx.xx.xx.xx/zentao/',
use_tip: '使用指引:', use_tip: '使用指引:',
use_tip_tapd: 'Tapd Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询', use_tip_tapd: 'Tapd Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询',
use_tip_jira: 'Jira software server 认证信息为 账号密码Jira software cloud 认证信息为 账号+令牌(账户设置-安全-创建API令牌)', use_tip_jira: 'Jira software server 认证信息为 账号密码Jira software cloud 认证信息为 账号+令牌(账户设置-安全-创建API令牌)',
@ -291,6 +293,7 @@ export default {
special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)', special_characters_are_not_supported: '格式错误(不支持特殊字符,且不能以\'-\'开头结尾)',
tapd_id: 'TAPD项目ID', tapd_id: 'TAPD项目ID',
jira_key: 'JIRA项目key', jira_key: 'JIRA项目key',
zentao_id: 'Zentao项目ID',
}, },
member: { member: {
create: '添加成员', create: '添加成员',

View File

@ -264,6 +264,8 @@ export default {
input_app_key: '請輸入密鑰', input_app_key: '請輸入密鑰',
input_jira_url: '請輸入Jira地址https://metersphere.atlassian.net/', input_jira_url: '請輸入Jira地址https://metersphere.atlassian.net/',
input_jira_issuetype: '請輸入問題類型', input_jira_issuetype: '請輸入問題類型',
zentao_url: 'Zentao 地址',
input_zentao_url: '請輸入Zentao地址http://xx.xx.xx.xx/zentao/',
use_tip: '使用指引:', use_tip: '使用指引:',
use_tip_tapd: 'Tapd Basic Auth 賬號信息在"公司管理-安全與集成-開放平臺"中查詢', use_tip_tapd: 'Tapd Basic Auth 賬號信息在"公司管理-安全與集成-開放平臺"中查詢',
use_tip_jira: 'Jira software server 認證信息為 賬號密碼Jira software cloud 認證信息為 賬號+令牌(賬戶設置-安全-創建API令牌)', use_tip_jira: 'Jira software server 認證信息為 賬號密碼Jira software cloud 認證信息為 賬號+令牌(賬戶設置-安全-創建API令牌)',
@ -293,6 +295,7 @@ export default {
special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)', special_characters_are_not_supported: '格式錯誤(不支持特殊字符,且不能以\'-\'開頭結尾)',
tapd_id: 'TAPD項目ID', tapd_id: 'TAPD項目ID',
jira_key: 'JIRA項目key', jira_key: 'JIRA項目key',
zentao_id: 'Zentao項目ID',
}, },
member: { member: {
create: '添加成員', create: '添加成員',

View File

@ -95,7 +95,7 @@ export default {
this.result = this.$get("/isLogin").then(response => { this.result = this.$get("/isLogin").then(response => {
if (display.default !== undefined) { if (display.default !== undefined) {
display.default.valid(this); display.default.showLogin(this);
} }
if (!response.data.success) { if (!response.data.success) {