fix: 解决冲突
This commit is contained in:
parent
73d6dcd9ca
commit
4e3b2166d0
|
@ -21,5 +21,7 @@ public class CustomFieldTemplate implements Serializable {
|
|||
|
||||
private String customData;
|
||||
|
||||
private Boolean isThirdPart;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -643,6 +643,66 @@ public class CustomFieldTemplateExample {
|
|||
addCriterion("custom_data not between", value1, value2, "customData");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartIsNull() {
|
||||
addCriterion("is_third_part is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartIsNotNull() {
|
||||
addCriterion("is_third_part is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartEqualTo(Boolean value) {
|
||||
addCriterion("is_third_part =", value, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartNotEqualTo(Boolean value) {
|
||||
addCriterion("is_third_part <>", value, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartGreaterThan(Boolean value) {
|
||||
addCriterion("is_third_part >", value, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartGreaterThanOrEqualTo(Boolean value) {
|
||||
addCriterion("is_third_part >=", value, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartLessThan(Boolean value) {
|
||||
addCriterion("is_third_part <", value, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartLessThanOrEqualTo(Boolean value) {
|
||||
addCriterion("is_third_part <=", value, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartIn(List<Boolean> values) {
|
||||
addCriterion("is_third_part in", values, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartNotIn(List<Boolean> values) {
|
||||
addCriterion("is_third_part not in", values, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartBetween(Boolean value1, Boolean value2) {
|
||||
addCriterion("is_third_part between", value1, value2, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andIsThirdPartNotBetween(Boolean value1, Boolean value2) {
|
||||
addCriterion("is_third_part not between", value1, value2, "isThirdPart");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Criteria extends GeneratedCriteria {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<result column="order" jdbcType="INTEGER" property="order" />
|
||||
<result column="default_value" jdbcType="VARCHAR" property="defaultValue" />
|
||||
<result column="custom_data" jdbcType="VARCHAR" property="customData" />
|
||||
<result column="is_third_part" jdbcType="BIT" property="isThirdPart" />
|
||||
</resultMap>
|
||||
<sql id="Example_Where_Clause">
|
||||
<where>
|
||||
|
@ -70,7 +71,8 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, field_id, template_id, scene, required, `order`, default_value, custom_data
|
||||
id, field_id, template_id, scene, required, `order`, default_value, custom_data,
|
||||
is_third_part
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.CustomFieldTemplateExample" resultMap="BaseResultMap">
|
||||
select
|
||||
|
@ -105,10 +107,12 @@
|
|||
<insert id="insert" parameterType="io.metersphere.base.domain.CustomFieldTemplate">
|
||||
insert into custom_field_template (id, field_id, template_id,
|
||||
scene, required, `order`,
|
||||
default_value, custom_data)
|
||||
default_value, custom_data, is_third_part
|
||||
)
|
||||
values (#{id,jdbcType=VARCHAR}, #{fieldId,jdbcType=VARCHAR}, #{templateId,jdbcType=VARCHAR},
|
||||
#{scene,jdbcType=VARCHAR}, #{required,jdbcType=BIT}, #{order,jdbcType=INTEGER},
|
||||
#{defaultValue,jdbcType=VARCHAR}, #{customData,jdbcType=VARCHAR})
|
||||
#{defaultValue,jdbcType=VARCHAR}, #{customData,jdbcType=VARCHAR}, #{isThirdPart,jdbcType=BIT}
|
||||
)
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.CustomFieldTemplate">
|
||||
insert into custom_field_template
|
||||
|
@ -137,6 +141,9 @@
|
|||
<if test="customData != null">
|
||||
custom_data,
|
||||
</if>
|
||||
<if test="isThirdPart != null">
|
||||
is_third_part,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null">
|
||||
|
@ -163,6 +170,9 @@
|
|||
<if test="customData != null">
|
||||
#{customData,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="isThirdPart != null">
|
||||
#{isThirdPart,jdbcType=BIT},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.base.domain.CustomFieldTemplateExample" resultType="java.lang.Long">
|
||||
|
@ -198,6 +208,9 @@
|
|||
<if test="record.customData != null">
|
||||
custom_data = #{record.customData,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.isThirdPart != null">
|
||||
is_third_part = #{record.isThirdPart,jdbcType=BIT},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
|
@ -212,7 +225,8 @@
|
|||
required = #{record.required,jdbcType=BIT},
|
||||
`order` = #{record.order,jdbcType=INTEGER},
|
||||
default_value = #{record.defaultValue,jdbcType=VARCHAR},
|
||||
custom_data = #{record.customData,jdbcType=VARCHAR}
|
||||
custom_data = #{record.customData,jdbcType=VARCHAR},
|
||||
is_third_part = #{record.isThirdPart,jdbcType=BIT}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -241,6 +255,9 @@
|
|||
<if test="customData != null">
|
||||
custom_data = #{customData,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="isThirdPart != null">
|
||||
is_third_part = #{isThirdPart,jdbcType=BIT},
|
||||
</if>
|
||||
</set>
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
|
@ -252,7 +269,8 @@
|
|||
required = #{required,jdbcType=BIT},
|
||||
`order` = #{order,jdbcType=INTEGER},
|
||||
default_value = #{defaultValue,jdbcType=VARCHAR},
|
||||
custom_data = #{customData,jdbcType=VARCHAR}
|
||||
custom_data = #{customData,jdbcType=VARCHAR},
|
||||
is_third_part = #{isThirdPart,jdbcType=BIT}
|
||||
where id = #{id,jdbcType=VARCHAR}
|
||||
</update>
|
||||
</mapper>
|
|
@ -10,7 +10,7 @@
|
|||
<select id="list" resultType="io.metersphere.dto.CustomFieldTemplateDao">
|
||||
select
|
||||
field_id, template_id, required, default_value, custom_data,
|
||||
cft.id as id,
|
||||
cft.id as id, is_third_part,
|
||||
cf.name as name, cf.type as type, cf.remark as remark, cf.`system` as system, cf.options as options
|
||||
from custom_field_template cft
|
||||
inner join custom_field cf
|
||||
|
|
|
@ -12,4 +12,6 @@ public class CustomFieldDao extends CustomField {
|
|||
private String defaultValue;
|
||||
|
||||
private String customData;
|
||||
|
||||
private Boolean isThirdPart;
|
||||
}
|
||||
|
|
|
@ -8,4 +8,5 @@ public class CustomFieldItemDTO {
|
|||
private String name;
|
||||
private String value;
|
||||
private String customData;
|
||||
private Boolean isThirdPart;
|
||||
}
|
||||
|
|
|
@ -16,4 +16,6 @@ public class CustomFieldTemplateDao extends CustomFieldTemplate {
|
|||
private String options;
|
||||
|
||||
private Boolean system;
|
||||
|
||||
private Boolean isThirdPart;
|
||||
}
|
||||
|
|
|
@ -168,6 +168,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
|
|||
issues.setPlatform(issuesRequest.getPlatform());
|
||||
issues.setProjectId(issuesRequest.getProjectId());
|
||||
issues.setCustomFields(issuesRequest.getCustomFields());
|
||||
issues.setCreator(issuesRequest.getCreator());
|
||||
issues.setCreateTime(System.currentTimeMillis());
|
||||
issues.setUpdateTime(System.currentTimeMillis());
|
||||
issuesMapper.insert(issues);
|
||||
|
|
|
@ -9,8 +9,10 @@ import io.metersphere.commons.constants.IssuesStatus;
|
|||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.EncryptUtils;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.dto.CustomFieldItemDTO;
|
||||
import io.metersphere.track.dto.DemandDTO;
|
||||
import io.metersphere.track.issue.domain.PlatformUser;
|
||||
import io.metersphere.track.issue.client.JiraClient;
|
||||
import io.metersphere.track.issue.domain.*;
|
||||
import io.metersphere.track.request.testcase.IssuesRequest;
|
||||
import io.metersphere.track.request.testcase.IssuesUpdateRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -40,6 +42,15 @@ public class JiraPlatform extends AbstractIssuePlatform {
|
|||
super(issuesRequest);
|
||||
}
|
||||
|
||||
public JiraConfig getConfig() {
|
||||
String config = getPlatformConfig(IssuesManagePlatform.Jira.toString());
|
||||
if (StringUtils.isNotBlank(config)) {
|
||||
return JSONObject.parseObject(config, JiraConfig.class);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IssuesDao> getIssue(IssuesRequest issuesRequest) {
|
||||
List<IssuesDao> list = new ArrayList<>();
|
||||
|
@ -51,15 +62,11 @@ public class JiraPlatform extends AbstractIssuePlatform {
|
|||
} else {
|
||||
issues = extIssuesMapper.getIssuesByCaseId(issuesRequest);
|
||||
}
|
||||
|
||||
String config = getPlatformConfig(IssuesManagePlatform.Jira.toString());
|
||||
JSONObject object = JSON.parseObject(config);
|
||||
HttpHeaders headers = getAuthHeader(object);
|
||||
String url = object.getString("url");
|
||||
|
||||
JiraConfig config = getConfig();
|
||||
JiraClient.setConfig(config);
|
||||
List<String> issuesIds = issues.stream().map(Issues::getId).collect(Collectors.toList());
|
||||
issuesIds.forEach(issuesId -> {
|
||||
IssuesDao dto = getJiraIssues(headers, url, issuesId);
|
||||
IssuesDao dto = parseIssue(JiraClient.getIssues(issuesId));
|
||||
if (StringUtils.isBlank(dto.getId())) {
|
||||
// 缺陷不存在,解除用例和缺陷的关联
|
||||
TestCaseIssuesExample issuesExample = new TestCaseIssuesExample();
|
||||
|
@ -78,6 +85,38 @@ public class JiraPlatform extends AbstractIssuePlatform {
|
|||
return list;
|
||||
}
|
||||
|
||||
public IssuesDao parseIssue(JiraIssue jiraIssue) {
|
||||
String lastmodify = "";
|
||||
String status = "";
|
||||
JSONObject fields = jiraIssue.getFields();
|
||||
JSONObject statusObj = (JSONObject) fields.get("status");
|
||||
JSONObject assignee = (JSONObject) fields.get("assignee");
|
||||
if (statusObj != null) {
|
||||
JSONObject statusCategory = (JSONObject) statusObj.get("statusCategory");
|
||||
status = statusCategory.getString("key");
|
||||
}
|
||||
|
||||
String description = fields.getString("description");
|
||||
|
||||
Parser parser = Parser.builder().build();
|
||||
Node document = parser.parse(description);
|
||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
||||
description = renderer.render(document);
|
||||
|
||||
if (assignee != null) {
|
||||
lastmodify = assignee.getString("displayName");
|
||||
}
|
||||
IssuesDao issues = new IssuesDao();
|
||||
issues.setId(jiraIssue.getKey());
|
||||
issues.setTitle(fields.getString("summary"));
|
||||
issues.setCreateTime(fields.getLong("created"));
|
||||
issues.setLastmodify(lastmodify);
|
||||
issues.setDescription(description);
|
||||
issues.setStatus(status);
|
||||
issues.setPlatform(IssuesManagePlatform.Jira.toString());
|
||||
return issues;
|
||||
}
|
||||
|
||||
public HttpHeaders getAuthHeader(JSONObject object) {
|
||||
if (object == null) {
|
||||
MSException.throwException("tapd config is null");
|
||||
|
@ -164,26 +203,18 @@ public class JiraPlatform extends AbstractIssuePlatform {
|
|||
|
||||
@Override
|
||||
public void addIssue(IssuesUpdateRequest issuesRequest) {
|
||||
String config = getPlatformConfig(IssuesManagePlatform.Jira.toString());
|
||||
issuesRequest.setPlatform(IssuesManagePlatform.Jira.toString());
|
||||
JSONObject object = JSON.parseObject(config);
|
||||
|
||||
if (object == null) {
|
||||
JiraConfig config = getConfig();
|
||||
if (config == null) {
|
||||
MSException.throwException("jira config is null");
|
||||
}
|
||||
|
||||
String account = object.getString("account");
|
||||
String password = object.getString("password");
|
||||
String url = object.getString("url");
|
||||
String issuetype = object.getString("issuetype");
|
||||
if (StringUtils.isBlank(issuetype)) {
|
||||
if (StringUtils.isBlank(config.getIssuetype())) {
|
||||
MSException.throwException("Jira 问题类型为空");
|
||||
}
|
||||
String auth = EncryptUtils.base64Encoding(account + ":" + password);
|
||||
|
||||
String jiraKey = getProjectId(issuesRequest.getProjectId());
|
||||
|
||||
|
||||
if (StringUtils.isBlank(jiraKey)) {
|
||||
MSException.throwException("未关联Jira 项目Key");
|
||||
}
|
||||
|
@ -198,30 +229,47 @@ public class JiraPlatform extends AbstractIssuePlatform {
|
|||
String desc = Jsoup.clean(s, "", Whitelist.none(), new Document.OutputSettings().prettyPrint(false));
|
||||
desc = desc.replace(" ", "");
|
||||
|
||||
String json = "{\n" +
|
||||
" \"fields\":{\n" +
|
||||
" \"project\":{\n" +
|
||||
" \"key\":\"" + jiraKey + "\"\n" +
|
||||
" },\n" +
|
||||
" \"summary\":\"" + issuesRequest.getTitle() + "\",\n" +
|
||||
" \"description\": " + JSON.toJSONString(desc) + ",\n" +
|
||||
" \"issuetype\":{\n" +
|
||||
" \"name\":\"" + issuetype + "\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
JSONObject addJiraIssueParam = new JSONObject();
|
||||
JSONObject fields = new JSONObject();
|
||||
JSONObject project = new JSONObject();
|
||||
|
||||
String result = addJiraIssue(url, auth, json);
|
||||
|
||||
JSONObject jsonObject = JSON.parseObject(result);
|
||||
String id = jsonObject.getString("key");
|
||||
fields.put("project", project);
|
||||
project.put("key", jiraKey);
|
||||
|
||||
issuesRequest.setId(id);
|
||||
JSONObject issuetype = new JSONObject();
|
||||
issuetype.put("name", config.getIssuetype());
|
||||
|
||||
fields.put("summary", issuesRequest.getTitle());
|
||||
fields.put("description", new JiraIssueDescription(desc));
|
||||
fields.put("issuetype", issuetype);
|
||||
addJiraIssueParam.put("fields", fields);
|
||||
|
||||
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
|
||||
JiraClient.setConfig(config);
|
||||
// List<JiraField> jiraFields = JiraClient.getFields();
|
||||
// Map<String, Boolean> isCustomMap = jiraFields.stream().
|
||||
// collect(Collectors.toMap(JiraField::getId, JiraField::isCustom));
|
||||
|
||||
customFields.forEach(item -> {
|
||||
if (StringUtils.isNotBlank(item.getCustomData()) && item.getIsThirdPart() != null && item.getIsThirdPart()) {
|
||||
// if (isCustomMap.get(item.getCustomData())) {
|
||||
// fields.put(item.getCustomData(), item.getValue());
|
||||
// } else {
|
||||
JSONObject param = new JSONObject();
|
||||
param.put("id", item.getValue());
|
||||
fields.put(item.getCustomData(), param);
|
||||
// }
|
||||
}
|
||||
});
|
||||
JiraAddIssueResponse result = JiraClient.addIssue(JSONObject.toJSONString(addJiraIssueParam));
|
||||
|
||||
issuesRequest.setId(result.getKey());
|
||||
// 用例与第三方缺陷平台中的缺陷关联
|
||||
handleTestCaseIssues(issuesRequest);
|
||||
|
||||
// 插入缺陷表
|
||||
insertIssuesWithoutContext(id, issuesRequest);
|
||||
insertIssuesWithoutContext(result.getKey(), issuesRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package io.metersphere.track.issue.client;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.EncryptUtils;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustStrategy;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class BaseClient {
|
||||
|
||||
protected static RestTemplate restTemplate;
|
||||
|
||||
static {
|
||||
try {
|
||||
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
|
||||
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
|
||||
.loadTrustMaterial(null, acceptingTrustStrategy)
|
||||
.build();
|
||||
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
|
||||
CloseableHttpClient httpClient = HttpClients.custom()
|
||||
.setSSLSocketFactory(csf)
|
||||
.build();
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
requestFactory.setHttpClient(httpClient);
|
||||
|
||||
restTemplate = new RestTemplate(requestFactory);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static HttpHeaders getBasicHttpHeaders(String userName, String passWd) {
|
||||
String authKey = EncryptUtils.base64Encoding(userName + ":" + passWd);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Authorization", "Basic " + authKey);
|
||||
return headers;
|
||||
}
|
||||
|
||||
protected static String getResult(ResponseEntity<String> response) {
|
||||
int statusCodeValue = response.getStatusCodeValue();
|
||||
LogUtil.info("responseCode: " + statusCodeValue);
|
||||
if(statusCodeValue >= 400){
|
||||
MSException.throwException(response.getBody());
|
||||
}
|
||||
LogUtil.info("result: " + response.getBody());
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
protected static Object getResultForList(Class clazz, ResponseEntity<String> response) {
|
||||
return Arrays.asList(JSONArray.parseArray(getResult(response), clazz).toArray());
|
||||
}
|
||||
|
||||
protected static Object getResultForObject(Class clazz,ResponseEntity<String> response) {
|
||||
return JSONObject.parseObject(getResult(response), clazz);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package io.metersphere.track.issue.client;
|
||||
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.track.issue.domain.JiraAddIssueResponse;
|
||||
import io.metersphere.track.issue.domain.JiraConfig;
|
||||
import io.metersphere.track.issue.domain.JiraField;
|
||||
import io.metersphere.track.issue.domain.JiraIssue;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JiraClient extends BaseClient {
|
||||
|
||||
private static String ENDPOINT;
|
||||
|
||||
private static String PREFIX = "/rest/api/3";
|
||||
|
||||
private static String USER_NAME;
|
||||
|
||||
private static String PASSWD;
|
||||
|
||||
public static List<JiraField> getFields() {
|
||||
String url = getBaseUrl() + "/field";
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class);
|
||||
return (List<JiraField>) getResultForList(JiraField.class, response);
|
||||
}
|
||||
|
||||
public static JiraIssue getIssues(String issuesId) {
|
||||
HttpEntity<MultiValueMap> requestEntity = getAuthHttpEntity();
|
||||
ResponseEntity<String> responseEntity;
|
||||
responseEntity = restTemplate.exchange(ENDPOINT + "/rest/api/2/issue/" + issuesId, HttpMethod.GET, requestEntity, String.class);
|
||||
return (JiraIssue) getResultForObject(JiraIssue.class, responseEntity);
|
||||
}
|
||||
|
||||
public static JiraAddIssueResponse addIssue(String body) {
|
||||
HttpHeaders headers = getAuthHeader();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
|
||||
ResponseEntity<String> entity = restTemplate.exchange(getBaseUrl() + "/issue", HttpMethod.POST, requestEntity, String.class);
|
||||
return (JiraAddIssueResponse) getResultForObject(JiraAddIssueResponse.class, entity);
|
||||
}
|
||||
|
||||
public static void setConfig(JiraConfig config) {
|
||||
if (config == null) {
|
||||
MSException.throwException("config is null");
|
||||
}
|
||||
String url = config.getUrl();
|
||||
|
||||
if (StringUtils.isNotBlank(url) && url.endsWith("/")) {
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
ENDPOINT = url;
|
||||
USER_NAME = config.getAccount();
|
||||
PASSWD = config.getPassword();
|
||||
}
|
||||
|
||||
private static HttpEntity<MultiValueMap> getAuthHttpEntity() {
|
||||
return new HttpEntity<>(getAuthHeader());
|
||||
}
|
||||
|
||||
private static HttpHeaders getAuthHeader() {
|
||||
return getBasicHttpHeaders(USER_NAME, PASSWD);
|
||||
}
|
||||
|
||||
private static String getBaseUrl() {
|
||||
return ENDPOINT + PREFIX;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package io.metersphere.track.issue.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class JiraAddIssueResponse {
|
||||
private String id;
|
||||
private String key;
|
||||
private String self;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.track.issue.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class JiraConfig {
|
||||
private String account;
|
||||
private String password;
|
||||
private String url;
|
||||
private String issuetype;
|
||||
private String storytype;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package io.metersphere.track.issue.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class JiraField {
|
||||
|
||||
private String id;
|
||||
private String key;
|
||||
private String name;
|
||||
private boolean custom;
|
||||
// private boolean orderable;
|
||||
// private boolean navigable;
|
||||
// private boolean searchable;
|
||||
// private List<String> clauseNames;
|
||||
// private Schema schema;
|
||||
//
|
||||
// @Getter
|
||||
// @Setter
|
||||
// public class Schema {
|
||||
// private String type;
|
||||
// private String system;
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.track.issue.domain;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class JiraIssue {
|
||||
private String expand;
|
||||
private String id;
|
||||
private String self;
|
||||
private String key;
|
||||
private JSONObject fields;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package io.metersphere.track.issue.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class JiraIssueDescription {
|
||||
private String type;
|
||||
private int version;
|
||||
private List<Content> content;
|
||||
|
||||
public JiraIssueDescription(String text) {
|
||||
List<Content> list = new ArrayList<>();
|
||||
Content content = new Content(text);
|
||||
list.add(content);
|
||||
this.type = "doc";
|
||||
this.version = 1;
|
||||
this.content = list;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class Content {
|
||||
private String type;
|
||||
private List<ContentInfo> content;
|
||||
|
||||
public Content(String text) {
|
||||
List<ContentInfo> list = new ArrayList<>();
|
||||
ContentInfo content = new ContentInfo(text);
|
||||
list.add(content);
|
||||
this.type = "paragraph";
|
||||
this.content = list;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class ContentInfo {
|
||||
private String text;
|
||||
private String type;
|
||||
|
||||
public ContentInfo(String text) {
|
||||
this.text = text;
|
||||
this.type = "text";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -78,6 +78,7 @@
|
|||
<table tableName="test_plan"/>
|
||||
<table tableName="test_case_test"/>-->
|
||||
<table tableName="api_test_environment"></table>
|
||||
<table tableName="custom_field_template"></table>
|
||||
<!-- <table tableName="custom_field"></table>-->
|
||||
<!-- <table tableName="test_case"></table>-->
|
||||
<!-- <table tableName="test_case"></table>-->
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
<div>
|
||||
<slot name="header">
|
||||
<el-link class="add-text" :underline="false" :disabled="disable" @click="add">
|
||||
<i class="el-icon-plus">添加选项</i>
|
||||
<i class="el-icon-plus">{{$t('custom_field.add_option')}}</i>
|
||||
</el-link>
|
||||
</slot>
|
||||
<ms-instructions-icon size="13" v-if="isKv" :content="$t('选项值用于对接Jira等平台提交缺陷时,对应字段的属性值')"/>
|
||||
</div>
|
||||
|
||||
<draggable :list="data" handle=".handle" class="list-group">
|
||||
|
@ -16,17 +17,33 @@
|
|||
|
||||
<el-input size="mini" type="text"
|
||||
class="text-item"
|
||||
v-if="editIndex === idx"
|
||||
@blur="handleEdit(element)"
|
||||
v-model="element.value"/>
|
||||
<span class="text-item" v-else>
|
||||
:placeholder="$t('custom_field.field_text')"
|
||||
v-if="editIndex === idx && isKv"
|
||||
@blur="handleTextEdit(element)"
|
||||
v-model="element.text"/>
|
||||
<span class="text-item" v-else-if="isKv">
|
||||
<span v-if="element.system">
|
||||
{{$t(element.text)}}
|
||||
({{$t(element.text)}})
|
||||
</span>
|
||||
<span v-else>
|
||||
{{element.text}}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<el-input size="mini" type="value"
|
||||
class="text-item"
|
||||
:placeholder="$t('custom_field.field_value')"
|
||||
v-if="editIndex === idx"
|
||||
@blur="handleValueEdit(element)"
|
||||
v-model="element.value"/>
|
||||
<span class="text-item" v-else>
|
||||
<span v-if="element.system">
|
||||
{{$t(element.value)}}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ (element.value && isKv ? '(' : '') + element.value + (element.value && isKv ? ')' : '')}}
|
||||
</span>
|
||||
</span>
|
||||
<i class="operator-icon" v-for="(item, index) in operators"
|
||||
:key="index"
|
||||
:class="item.icon"
|
||||
|
@ -41,9 +58,11 @@
|
|||
|
||||
<script>
|
||||
import draggable from "vuedraggable";
|
||||
import MsInstructionsIcon from "@/business/components/common/components/MsInstructionsIcon";
|
||||
export default {
|
||||
name: "MsSingleHandleDrag",
|
||||
components: {
|
||||
MsInstructionsIcon,
|
||||
draggable
|
||||
},
|
||||
data() {
|
||||
|
@ -53,6 +72,7 @@ export default {
|
|||
},
|
||||
props: {
|
||||
disable: Boolean,
|
||||
isKv: Boolean,
|
||||
data: {
|
||||
type: Array,
|
||||
default() {
|
||||
|
@ -99,9 +119,17 @@ export default {
|
|||
this.data.push(item);
|
||||
this.editIndex = this.data.length - 1;
|
||||
},
|
||||
handleEdit(element) {
|
||||
handleTextEdit(element) {
|
||||
if (!this.isKv) {
|
||||
element.text = element.value;
|
||||
this.editIndex = -1;
|
||||
}
|
||||
},
|
||||
handleValueEdit(element) {
|
||||
this.editIndex = -1;
|
||||
element.text = element.value;
|
||||
if (!this.isKv) {
|
||||
element.text = element.value;
|
||||
}
|
||||
},
|
||||
isSystem(element) {
|
||||
if (element.system) {
|
||||
|
@ -145,4 +173,8 @@ export default {
|
|||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.instructions-icon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -44,8 +44,9 @@
|
|||
:label="$t('custom_field.field_option')"
|
||||
prop="options" :label-width="labelWidth">
|
||||
<ms-single-handle-drag
|
||||
:disable="form.name === '用例等级'"
|
||||
:data="form.options"/>
|
||||
:is-kv="form.scene === 'ISSUE'"
|
||||
:disable="form.name === '用例等级'"
|
||||
:data="form.options"/>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
|
|
@ -57,6 +57,16 @@
|
|||
</template>
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
v-if="platform !== 'metersphere'"
|
||||
:label="platform + $t('custom_field.field')"
|
||||
width="100"
|
||||
prop="thirdPart">
|
||||
<template v-slot="scope">
|
||||
<el-checkbox v-model="scope.row.isThirdPart"/>
|
||||
</template>
|
||||
</ms-table-column>
|
||||
|
||||
<ms-table-column
|
||||
:label="$t('commons.remark')"
|
||||
prop="remark">
|
||||
|
@ -97,6 +107,7 @@ export default {
|
|||
},
|
||||
},
|
||||
scene: String,
|
||||
platform: String,
|
||||
templateContainIds: Set
|
||||
},
|
||||
watch: {
|
||||
|
@ -128,6 +139,7 @@ export default {
|
|||
}
|
||||
item.fieldId = item.id;
|
||||
item.id = null;
|
||||
item.isThirdPart = false;
|
||||
item.options = JSON.parse(item.options);
|
||||
if (item.type === 'checkbox') {
|
||||
item.defaultValue = [];
|
||||
|
|
|
@ -167,16 +167,7 @@ export default {
|
|||
this.visible = true;
|
||||
},
|
||||
save() {
|
||||
if (this.condition.selectAll) {
|
||||
if (this.scene) {
|
||||
// this.result = this.$post('custom/field/list/ids' + this.currentPage + '/' + this.pageSize,
|
||||
// this.condition, (response) => {
|
||||
// this.$emit('save', response.data);
|
||||
// });
|
||||
}
|
||||
} else {
|
||||
this.$emit('save', this.$refs.table.selectIds);
|
||||
}
|
||||
this.$emit('save', this.$refs.table.selectIds);
|
||||
this.visible = false;
|
||||
},
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
<custom-field-form-list
|
||||
:table-data="relateFields"
|
||||
:scene="scene"
|
||||
:platform="form.platform"
|
||||
:template-contain-ids="templateContainIds"
|
||||
:custom-field-ids="form.customFieldIds"
|
||||
ref="customFieldFormList"
|
||||
|
|
|
@ -140,7 +140,7 @@ export default {
|
|||
for (let i = 0; i < this.tableData.length; i++) {
|
||||
if (this.tableData[i]) {
|
||||
if (this.tableData[i].platform !== 'Local') {
|
||||
this.$post("issues/get/platform/issue", this.tableData[i]).then(response => {
|
||||
this.result = this.$post("issues/get/platform/issue", this.tableData[i]).then(response => {
|
||||
let issues = response.data.data;
|
||||
if (issues) {
|
||||
this.$set(this.tableData[i], "title", issues.title ? issues.title : "--");
|
||||
|
|
|
@ -102,11 +102,13 @@ textarea {
|
|||
/* 表格拖拽表头调整宽度 --> */
|
||||
|
||||
/* <-- 表格 input 编辑效果 */
|
||||
.table-edit-input .el-textarea__inner {
|
||||
.table-edit-input .el-textarea__inner,
|
||||
.table-edit-input .el-input__inner {
|
||||
border-style: hidden;
|
||||
}
|
||||
|
||||
.table-edit-input.is-disabled .el-textarea__inner {
|
||||
.table-edit-input.is-disabled .el-textarea__inner,
|
||||
.table-edit-input.is-disabled .el-input__inner {
|
||||
background-color: white;
|
||||
color: #606266;
|
||||
}
|
||||
|
@ -116,7 +118,8 @@ textarea {
|
|||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.table-edit-input .el-textarea__inner:focus {
|
||||
.table-edit-input .el-textarea__inner:focus,
|
||||
.table-edit-input .el-input__inner:focus {
|
||||
border: 1px solid #409EFF;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ export function buildCustomFields(data, param, template) {
|
|||
hasField = true;
|
||||
customFields[index].name = item.name;
|
||||
customFields[index].value = item.defaultValue;
|
||||
customFields[index].isThirdPart = item.isThirdPart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +102,8 @@ export function buildCustomFields(data, param, template) {
|
|||
id: item.id,
|
||||
name: item.name,
|
||||
value: item.defaultValue,
|
||||
customData: item.customData
|
||||
customData: item.customData,
|
||||
isThirdPart: item.isThirdPart
|
||||
};
|
||||
customFields.push(customField);
|
||||
}
|
||||
|
|
|
@ -279,6 +279,7 @@ export default {
|
|||
}
|
||||
},
|
||||
custom_field: {
|
||||
add_option: 'Add Option',
|
||||
case_status: 'Case Status',
|
||||
case_maintainer: 'Maintainer',
|
||||
case_priority: 'Case Priority',
|
||||
|
@ -292,9 +293,12 @@ export default {
|
|||
scene: 'Use Scene',
|
||||
attribute_type: 'Attribute Type',
|
||||
field_name: 'Field Name',
|
||||
field: 'Field',
|
||||
field_remark: 'Field Remark',
|
||||
field_type: 'Field Type',
|
||||
field_option: 'Options',
|
||||
field_text: 'Field Text',
|
||||
field_value: 'Field Value',
|
||||
add_field: 'Add Field',
|
||||
api_field_name: 'API Field Name',
|
||||
template_setting: 'Template Setting',
|
||||
|
@ -386,7 +390,7 @@ export default {
|
|||
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_zentao: 'The account password is a Zentao account with corresponding permissions, and the account needs to have super model calling interface permissions',
|
||||
use_tip_two: 'After saving the Basic Auth account information, you need to manually associate the ID/key in the MeterSphere project',
|
||||
use_tip_two: 'After saving the Basic Auth account information, you need to manually associate the ID/key and issue template in the MeterSphere project',
|
||||
link_the_project_now: 'Link the project now',
|
||||
cancel_edit: 'Cancel edit',
|
||||
cancel_integration: 'Cancel integration',
|
||||
|
|
|
@ -280,6 +280,7 @@ export default {
|
|||
}
|
||||
},
|
||||
custom_field: {
|
||||
add_option: '添加选项',
|
||||
case_status: '用例状态',
|
||||
case_maintainer: '责任人',
|
||||
case_priority: '用例等级',
|
||||
|
@ -293,9 +294,12 @@ export default {
|
|||
scene: '使用场景',
|
||||
attribute_type: '属性类型',
|
||||
field_name: '字段名',
|
||||
field: '字段',
|
||||
field_remark: '字段备注',
|
||||
field_type: '字段类型',
|
||||
field_option: '选项值',
|
||||
field_text: '选项内容',
|
||||
field_value: '选项值',
|
||||
add_field: '添加字段',
|
||||
api_field_name: 'API字段名',
|
||||
template_setting: '模板设置',
|
||||
|
@ -384,7 +388,7 @@ export default {
|
|||
use_tip_tapd: 'Tapd Basic Auth 账号信息在"公司管理-安全与集成-开放平台"中查询',
|
||||
use_tip_jira: 'Jira software server 认证信息为 账号密码,Jira software cloud 认证信息为 账号+令牌(账户设置-安全-创建API令牌)',
|
||||
use_tip_zentao: '账号密码为具有相应权限的Zentao账号,账号需要具有 超级model调用接口权限',
|
||||
use_tip_two: '保存 Basic Auth 账号信息后,需要在 MeterSphere 项目中手动关联 ID/key',
|
||||
use_tip_two: '保存 Basic Auth 账号信息后,需要在 MeterSphere 项目中手动关联 ID/key 和缺陷模板',
|
||||
link_the_project_now: '马上关联项目',
|
||||
cancel_edit: '取消编辑',
|
||||
cancel_integration: '取消集成',
|
||||
|
|
|
@ -280,6 +280,7 @@ export default {
|
|||
}
|
||||
},
|
||||
custom_field: {
|
||||
add_option: '添加選項',
|
||||
case_status: '用例狀態',
|
||||
case_maintainer: '責任人',
|
||||
case_priority: '用例等級',
|
||||
|
@ -293,9 +294,12 @@ export default {
|
|||
scene: '使用場景',
|
||||
attribute_type: '屬性類型',
|
||||
field_name: '字段名',
|
||||
field: '字段名',
|
||||
field_remark: '字段備註',
|
||||
field_type: '字段類型',
|
||||
field_option: '選項值',
|
||||
field_text: '選項內容',
|
||||
field_value: '選項值',
|
||||
add_field: '添加字段',
|
||||
api_field_name: 'API字段名',
|
||||
template_setting: '模板設置',
|
||||
|
@ -384,7 +388,7 @@ export default {
|
|||
use_tip_tapd: 'Tapd Basic Auth 賬號信息在"公司管理-安全與集成-開放平臺"中查詢',
|
||||
use_tip_jira: 'Jira software server 認證信息為 賬號密碼,Jira software cloud 認證信息為 賬號+令牌(賬戶設置-安全-創建API令牌)',
|
||||
use_tip_zentao: '賬號密碼為具有相應權限的Zentao賬號,賬號需要具有 超級model調用接口權限',
|
||||
use_tip_two: '保存 Basic Auth 賬號信息後,需要在 MeterSphere 項目中手動關聯 ID/key',
|
||||
use_tip_two: '保存 Basic Auth 賬號信息後,需要在 MeterSphere 項目中手動關聯 ID/key 和缺陷模板',
|
||||
link_the_project_now: '馬上關聯項目',
|
||||
cancel_edit: '取消編輯',
|
||||
cancel_integration: '取消集成',
|
||||
|
|
Loading…
Reference in New Issue