mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-02 12:09:13 +08:00
feat(缺陷管理): 第三方平台同步功能&&批量日志校验检查
This commit is contained in:
parent
7490ec669a
commit
f9ffd26e67
@ -1,15 +0,0 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class DemandDTO {
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected String platform;
|
||||
protected List<? extends DemandDTO> children;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class MsBugDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String title;
|
||||
|
||||
private String status;
|
||||
|
||||
private Long createTime;
|
||||
|
||||
private Long updateTime;
|
||||
|
||||
private String reporter;
|
||||
|
||||
private String lastmodify;
|
||||
|
||||
private String platform;
|
||||
|
||||
private String projectId;
|
||||
|
||||
private String creator;
|
||||
|
||||
private String resourceId;
|
||||
|
||||
private Integer num;
|
||||
|
||||
private String platformStatus;
|
||||
|
||||
private String platformId;
|
||||
|
||||
private String description;
|
||||
|
||||
private String customFields;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class PlatformBugDTO extends MsBugDTO {
|
||||
private List<PlatformCustomFieldItemDTO> customFieldList;
|
||||
private List<PlatformAttachment> attachments = new ArrayList<>();
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class PlatformStatusDTO {
|
||||
protected String value;
|
||||
protected String label;
|
||||
}
|
@ -1,17 +1,15 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Data
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SelectOption {
|
||||
public SelectOption(String text, String value) {
|
||||
this.text = text;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private String text;
|
||||
private String value;
|
||||
|
@ -1,31 +0,0 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class SyncAllBugRequest extends SyncBugRequest {
|
||||
/**
|
||||
* 项目设置的配置项
|
||||
*/
|
||||
private String projectConfig;
|
||||
/**
|
||||
* 缺陷模板所关联的自定义字段
|
||||
*/
|
||||
private String defaultCustomFields;
|
||||
/**
|
||||
* 需要同步的缺陷列表
|
||||
*/
|
||||
private List<PlatformBugDTO> bugs;
|
||||
|
||||
private boolean pre;
|
||||
|
||||
private Long createTime;
|
||||
|
||||
private Consumer<Map> handleSyncFunc;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.reponse.MsSyncBugDTO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -11,7 +12,7 @@ import java.util.Map;
|
||||
@Setter
|
||||
@Getter
|
||||
public class SyncAllBugResult extends SyncBugResult {
|
||||
private List<MsBugDTO> updateBugs = new ArrayList<>();
|
||||
private List<MsSyncBugDTO> updateBugs = new ArrayList<>();
|
||||
private Map<String, List<PlatformAttachment>> attachmentMap = new HashMap<>();
|
||||
/**
|
||||
* 保存当前查询到的缺陷的平台ID
|
||||
|
@ -1,23 +0,0 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class SyncBugRequest {
|
||||
/**
|
||||
* 项目设置的配置项
|
||||
*/
|
||||
private String projectConfig;
|
||||
/**
|
||||
* 缺陷模板所关联的自定义字段
|
||||
*/
|
||||
private String defaultCustomFields;
|
||||
/**
|
||||
* 需要同步的缺陷列表
|
||||
*/
|
||||
private List<PlatformBugDTO> bugs;
|
||||
}
|
@ -1,18 +1,30 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformBugDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@Data
|
||||
public class SyncBugResult {
|
||||
private List<MsBugDTO> updateBug= new ArrayList<>();
|
||||
private List<MsBugDTO> addBug = new ArrayList<>();
|
||||
private Map<String, List<PlatformAttachment>> attachmentMap = new HashMap<>();
|
||||
/**
|
||||
* 同步新增的缺陷
|
||||
*/
|
||||
private List<PlatformBugDTO> addBug = new ArrayList<>();
|
||||
/**
|
||||
* 同步更新的缺陷
|
||||
*/
|
||||
private List<PlatformBugDTO> updateBug = new ArrayList<>();
|
||||
/**
|
||||
* 同步失败需删除的ID
|
||||
*/
|
||||
private List<String> deleteBugIds = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 需同步的平台附件集合(统一处理) {key: bugId, value: attachmentList}
|
||||
*/
|
||||
private Map<String, List<PlatformAttachment>> attachmentMap = new HashMap<>();
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DemandDTO {
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
protected String id;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
protected String name;
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MsSyncBugDTO {
|
||||
|
||||
/**
|
||||
* 缺陷ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 缺陷业务ID
|
||||
*/
|
||||
private Integer num;
|
||||
|
||||
/**
|
||||
* 缺陷标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 缺陷状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 缺陷处理人
|
||||
*/
|
||||
private String handleUser;
|
||||
|
||||
/**
|
||||
* 缺陷处理人集合
|
||||
*/
|
||||
private String handleUsers;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createUser;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private String updateUser;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Long updateTime;
|
||||
|
||||
/**
|
||||
* 删除人
|
||||
*/
|
||||
private String deleteUser;
|
||||
|
||||
/**
|
||||
* 删除时间
|
||||
*/
|
||||
private Long deleteTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 所属项目
|
||||
*/
|
||||
private String projectId;
|
||||
|
||||
/**
|
||||
* 所属平台
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 第三方平台缺陷ID
|
||||
*/
|
||||
private String platformBugId;
|
||||
|
||||
/**
|
||||
* 模板ID
|
||||
*/
|
||||
private String templateId;
|
||||
|
||||
/**
|
||||
* 缺陷描述
|
||||
*/
|
||||
private String description;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PlatformBugDTO extends MsSyncBugDTO {
|
||||
/**
|
||||
* 自定义字段集合(双向同步需要)
|
||||
*/
|
||||
private List<PlatformCustomFieldItemDTO> customFieldList;
|
||||
|
||||
/**
|
||||
* 是否平台默认模板(默认模板时, 第三方自定义字段默认都需同步)
|
||||
*/
|
||||
private Boolean platformDefaultTemplate;
|
||||
|
||||
/**
|
||||
* 缺陷同步所需处理的平台自定义字段ID(同步第三方平台到MS时需要, 非默认模板时使用)
|
||||
*/
|
||||
private List<String> needSyncCustomFields;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PlatformBugUpdateDTO {
|
||||
|
||||
/**
|
||||
* 平台缺陷唯一标识
|
||||
*/
|
||||
private String platformBugKey;
|
||||
/**
|
||||
* 平台缺陷标题
|
||||
*/
|
||||
private String platformTitle;
|
||||
/**
|
||||
* 平台缺陷处理人
|
||||
*/
|
||||
private String platformHandleUser;
|
||||
/**
|
||||
* 平台缺陷状态
|
||||
*/
|
||||
private String platformStatus;
|
||||
/**
|
||||
* 平台描述
|
||||
*/
|
||||
private String platformDescription;
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class PlatformCustomFieldDTO implements Serializable {
|
||||
public class PlatformCustomFieldDTO implements Serializable{
|
||||
private String id;
|
||||
|
||||
private String name;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -11,4 +11,6 @@ public class PlatformCustomFieldItemDTO extends PlatformCustomFieldDTO {
|
||||
private String customData;
|
||||
private Boolean required;
|
||||
private String defaultValue;
|
||||
private Boolean supportSearch;
|
||||
private String searchMethod;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PlatformStatusDTO {
|
||||
protected String id;
|
||||
protected String name;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.reponse;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
@ -0,0 +1,27 @@
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DemandPageRequest {
|
||||
|
||||
/**
|
||||
* 项目配置信息
|
||||
*/
|
||||
private String projectConfig;
|
||||
|
||||
/**
|
||||
* 需求分页查询关键字
|
||||
*/
|
||||
private String query;
|
||||
|
||||
/**
|
||||
* 开始页码
|
||||
*/
|
||||
private int startPage;
|
||||
|
||||
/**
|
||||
* 每页条数
|
||||
*/
|
||||
private int pageSize;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DemandRelateQueryRequest {
|
||||
|
||||
/**
|
||||
* 项目配置信息
|
||||
*/
|
||||
private String projectConfig;
|
||||
|
||||
/**
|
||||
* 关联的需求ID集合
|
||||
*/
|
||||
private List<String> relateDemandIds;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.reponse.TestCaseDemandDTO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -14,4 +14,8 @@ public class GetOptionRequest {
|
||||
* 对应插件中获取选项的方法名
|
||||
*/
|
||||
private String optionMethod;
|
||||
/**
|
||||
* 输入的查询关键字
|
||||
*/
|
||||
private String query;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformBugDTO;
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformStatusDTO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -10,15 +12,15 @@ import java.util.Set;
|
||||
public class PlatformBugUpdateRequest extends PlatformBugDTO {
|
||||
|
||||
/**
|
||||
* 用户信息的第三方平台的配置项
|
||||
* 服务集成配置的用户及平台信息
|
||||
*/
|
||||
private String userPlatformUserConfig;
|
||||
private String userPlatformConfig;
|
||||
/**
|
||||
* 项目设置的配置项
|
||||
* 项目配置信息
|
||||
*/
|
||||
private String projectConfig;
|
||||
/**
|
||||
* 改缺陷关联的附件集合
|
||||
* 该缺陷关联的附件集合
|
||||
*/
|
||||
private Set<String> msAttachmentNames;
|
||||
/**
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
@ -0,0 +1,24 @@
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Data
|
||||
public class SyncAllBugRequest extends SyncBugRequest {
|
||||
|
||||
/**
|
||||
* 创建时间前后
|
||||
*/
|
||||
private boolean pre;
|
||||
|
||||
/**
|
||||
* 条件: 缺陷创建时间
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 同步后置方法
|
||||
*/
|
||||
private Consumer<SyncPostParamRequest> syncPostProcessFunc;
|
||||
}
|
@ -1,10 +1,14 @@
|
||||
package io.metersphere.plugin.platform.dto;
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SyncAttachmentToPlatformRequest {
|
||||
/**
|
||||
* 平台资源Key(需求或缺陷ID)
|
@ -0,0 +1,19 @@
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformBugDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SyncBugRequest {
|
||||
/**
|
||||
* 项目设置的配置项
|
||||
*/
|
||||
private String projectConfig;
|
||||
|
||||
/**
|
||||
* 需要同步的平台缺陷列表
|
||||
*/
|
||||
private List<PlatformBugDTO> bugs;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package io.metersphere.plugin.platform.dto.request;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.PlatformAttachment;
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformBugDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class SyncPostParamRequest {
|
||||
|
||||
/**
|
||||
* 需要同步的缺陷集合
|
||||
*/
|
||||
List<PlatformBugDTO> needSyncBugs;
|
||||
|
||||
/**
|
||||
* 需要处理的缺陷集合
|
||||
*/
|
||||
Map<String, List<PlatformAttachment>> attachmentMap;
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package io.metersphere.plugin.platform.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum PlatformCustomFieldType {
|
||||
|
||||
/**
|
||||
* 输入框
|
||||
*/
|
||||
INPUT(false, "input"),
|
||||
/**
|
||||
* 文本框
|
||||
*/
|
||||
TEXTAREA(false, "textarea"),
|
||||
/**
|
||||
* 单选下拉框框
|
||||
*/
|
||||
SELECT(true, "select"),
|
||||
/**
|
||||
* 多选下拉框框
|
||||
*/
|
||||
MULTIPLE_SELECT(true, "multipleSelect"),
|
||||
/**
|
||||
* 单选框
|
||||
*/
|
||||
RADIO(true, "radio"),
|
||||
/**
|
||||
* 复选框
|
||||
*/
|
||||
CHECKBOX(true, "checkbox"),
|
||||
/**
|
||||
* 单选成员
|
||||
*/
|
||||
MEMBER(true, "member"),
|
||||
/**
|
||||
* 多选成员
|
||||
*/
|
||||
MULTIPLE_MEMBER(true, "multipleMember"),
|
||||
/**
|
||||
* 日期
|
||||
*/
|
||||
DATE(false, "date"),
|
||||
/**
|
||||
* 日期时间
|
||||
*/
|
||||
DATETIME(false, "datetime"),
|
||||
/**
|
||||
* 整型
|
||||
*/
|
||||
INT(false, "int"),
|
||||
/**
|
||||
* 浮点型
|
||||
*/
|
||||
FLOAT(false, "float"),
|
||||
/**
|
||||
* 多值输入框(标签输入框)
|
||||
*/
|
||||
MULTIPLE_INPUT(false, "multipleInput"),
|
||||
/**
|
||||
* 级联选择
|
||||
*/
|
||||
CASCADE_SELECT(true, "cascadingSelect"),
|
||||
/**
|
||||
* 富文本
|
||||
*/
|
||||
RICH_TEXT(false, "richText");
|
||||
|
||||
private final Boolean hasOption;
|
||||
|
||||
private final String type;
|
||||
|
||||
PlatformCustomFieldType(Boolean hasOption, String type) {
|
||||
this.hasOption = hasOption;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package io.metersphere.plugin.platform.spi;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.PlatformRequest;
|
||||
import io.metersphere.plugin.platform.dto.PluginOptionsRequest;
|
||||
import io.metersphere.plugin.platform.dto.SelectOption;
|
||||
import io.metersphere.plugin.sdk.util.PluginUtils;
|
||||
import io.metersphere.plugin.platform.dto.request.PlatformRequest;
|
||||
import io.metersphere.plugin.platform.dto.request.PluginOptionsRequest;
|
||||
import io.metersphere.plugin.sdk.util.MSPluginException;
|
||||
import io.metersphere.plugin.sdk.util.PluginUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -8,6 +8,7 @@ public abstract class AbstractPlatformPlugin extends AbstractMsPlugin {
|
||||
private static final String DEFAULT_ACCOUNT_SCRIPT_ID = "account";
|
||||
private static final String PROJECT_BUG_SCRIPT_ID = "project_bug";
|
||||
private static final String PROJECT_DEMAND_SCRIPT_ID = "project_demand";
|
||||
private static final String PROJECT_BUG_TEMPLATE_INJECT_FIELD = "inject_field";
|
||||
|
||||
/**
|
||||
* 返回插件的描述信息
|
||||
@ -52,4 +53,8 @@ public abstract class AbstractPlatformPlugin extends AbstractMsPlugin {
|
||||
public String getProjectDemandScriptId() {
|
||||
return PROJECT_DEMAND_SCRIPT_ID;
|
||||
}
|
||||
|
||||
public String getProjectBugTemplateInjectField() {
|
||||
return PROJECT_BUG_TEMPLATE_INJECT_FIELD;
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ package io.metersphere.plugin.platform.spi;
|
||||
|
||||
import io.metersphere.plugin.platform.utils.EnvProxySelector;
|
||||
import io.metersphere.plugin.platform.utils.PluginCodingUtils;
|
||||
import io.metersphere.plugin.sdk.util.PluginUtils;
|
||||
import io.metersphere.plugin.sdk.util.MSPluginException;
|
||||
import io.metersphere.plugin.sdk.util.PluginLogUtils;
|
||||
import io.metersphere.plugin.sdk.util.PluginUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
@ -24,7 +24,7 @@ import javax.net.ssl.SSLContext;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BaseClient {
|
||||
|
||||
@ -86,11 +86,11 @@ public abstract class BaseClient {
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
protected Object getResultForList(Class clazz, ResponseEntity<String> response) {
|
||||
return Arrays.asList(PluginUtils.parseArray(getResult(response), clazz).toArray());
|
||||
protected <T> List<T> getResultForList(Class<T> clazz, ResponseEntity<String> response) {
|
||||
return PluginUtils.parseArray(getResult(response), clazz);
|
||||
}
|
||||
|
||||
protected Object getResultForObject(Class clazz, ResponseEntity<String> response) {
|
||||
protected <T> T getResultForObject(Class<T> clazz, ResponseEntity<String> response) {
|
||||
return PluginUtils.parseObject(getResult(response), clazz);
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
package io.metersphere.plugin.platform.spi;
|
||||
|
||||
import io.metersphere.plugin.platform.dto.PlatformBugUpdateRequest;
|
||||
import io.metersphere.plugin.platform.dto.PlatformCustomFieldItemDTO;
|
||||
import io.metersphere.plugin.platform.dto.PluginOptionsRequest;
|
||||
import io.metersphere.plugin.platform.dto.SelectOption;
|
||||
import io.metersphere.plugin.platform.dto.PlatformStatusDTO;
|
||||
import io.metersphere.plugin.platform.dto.SyncAttachmentToPlatformRequest;
|
||||
import io.metersphere.plugin.platform.dto.SyncBugResult;
|
||||
import io.metersphere.plugin.platform.dto.reponse.DemandDTO;
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformBugUpdateDTO;
|
||||
import io.metersphere.plugin.platform.dto.reponse.PlatformCustomFieldItemDTO;
|
||||
import io.metersphere.plugin.platform.dto.request.*;
|
||||
import io.metersphere.plugin.platform.utils.PluginPager;
|
||||
import org.pf4j.ExtensionPoint;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 平台对接相关业务接口
|
||||
@ -30,42 +33,72 @@ public interface Platform extends ExtensionPoint {
|
||||
void validateProjectConfig(String projectConfig);
|
||||
|
||||
/**
|
||||
* 平台是否支持第三方模板
|
||||
* 平台是否支持第三方默认模板
|
||||
*
|
||||
* @return 是否支持第三方模板
|
||||
* @return True时会在MS平台展示第三方的默认模板
|
||||
*/
|
||||
boolean isThirdPartTemplateSupport();
|
||||
boolean isSupportDefaultTemplate();
|
||||
|
||||
/**
|
||||
* 获取第三方平台缺陷的自定义字段
|
||||
* 需要 PluginMetaInfo 的 isThirdPartTemplateSupport 返回 true
|
||||
* 获取第三方平台模板的自定义字段(isSupportDefaultTemplate为true时才会调用)
|
||||
*
|
||||
* @param projectConfig 项目配置信息
|
||||
* @return 平台自定义字段集合
|
||||
*/
|
||||
List<PlatformCustomFieldItemDTO> getThirdPartCustomField(String projectConfig);
|
||||
List<PlatformCustomFieldItemDTO> getDefaultTemplateCustomField(String projectConfig);
|
||||
|
||||
/**
|
||||
* 获取第三方联级下拉options
|
||||
* @param optionsRequest
|
||||
* @return
|
||||
* @param optionsRequest 插件请求参数
|
||||
* @return 选项集合
|
||||
*/
|
||||
List<SelectOption> getPluginOptions(PluginOptionsRequest optionsRequest);
|
||||
|
||||
/**
|
||||
* 获取第三方平台表单下拉选项
|
||||
* @param optionsRequest 选项请求参数
|
||||
* @return 选项集合
|
||||
*/
|
||||
List<SelectOption> getFormOptions(GetOptionRequest optionsRequest);
|
||||
|
||||
/**
|
||||
* 获取第三方平台缺陷状态选项
|
||||
* @param projectConfig 项目配置信息
|
||||
* @param issueKey 缺陷ID
|
||||
* @return 缺陷平台状态
|
||||
*/
|
||||
List<SelectOption> getStatusTransitions(String projectConfig, String issueKey);
|
||||
|
||||
/**
|
||||
* 获取第三方平台需求
|
||||
* @param request 需求分页查询参数
|
||||
* @return 需求分页数据
|
||||
*/
|
||||
PluginPager<List<DemandDTO>> pageDemand(DemandPageRequest request);
|
||||
|
||||
/**
|
||||
* 获取第三方平台已关联的需求集合
|
||||
* @param request 查询请求参数
|
||||
* @return 需求数据集合
|
||||
*/
|
||||
List<DemandDTO> getDemands(DemandRelateQueryRequest request);
|
||||
|
||||
|
||||
/**
|
||||
* 新增平台缺陷
|
||||
*
|
||||
* @param request 平台缺陷参数
|
||||
* @return 平台缺陷ID
|
||||
* @return 平台缺陷
|
||||
*/
|
||||
String addBug(PlatformBugUpdateRequest request);
|
||||
PlatformBugUpdateDTO addBug(PlatformBugUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 修改平台缺陷
|
||||
*
|
||||
* @param request 平台缺陷参数
|
||||
* @return 平台缺陷
|
||||
*/
|
||||
void updateBug(PlatformBugUpdateRequest request);
|
||||
PlatformBugUpdateDTO updateBug(PlatformBugUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 删除平台缺陷
|
||||
@ -75,28 +108,37 @@ public interface Platform extends ExtensionPoint {
|
||||
void deleteBug(String platformBugId);
|
||||
|
||||
/**
|
||||
* 平台是否支持附件同步
|
||||
* 平台是否支持附件API
|
||||
*
|
||||
* @return 是否支持附件同步
|
||||
*/
|
||||
boolean isAttachmentUploadSupport();
|
||||
boolean isSupportAttachment();
|
||||
|
||||
/**
|
||||
* 同步MS附件至第三方平台(isAttachmentUploadSupport返回true时执行同步附件的逻辑)
|
||||
* 同步MS附件至第三方平台(isSupportAttachment为true时执行同步附件的逻辑)
|
||||
*
|
||||
* @param request 同步附件参数
|
||||
*/
|
||||
void syncAttachmentToPlatform(SyncAttachmentToPlatformRequest request);
|
||||
|
||||
/**
|
||||
* 同步部分缺陷
|
||||
* 同步存量缺陷
|
||||
*
|
||||
* @param request 同步缺陷参数
|
||||
* @return 同步缺陷结果
|
||||
*/
|
||||
void syncPartIssues();
|
||||
SyncBugResult syncBugs(SyncBugRequest request);
|
||||
|
||||
/**
|
||||
* 同步全量缺陷
|
||||
*/
|
||||
void syncAllIssues();
|
||||
void syncAllBugs(SyncAllBugRequest request);
|
||||
|
||||
List<PlatformStatusDTO> getStatusList();
|
||||
/**
|
||||
* 获取附件输入流,并做相应处理
|
||||
* 同步缺陷中,同步附件时会调用
|
||||
* @param fileKey 文件关键字
|
||||
* @param inputStreamHandler 获取响应的输入流后,做对应处理
|
||||
*/
|
||||
void getAttachmentContent(String fileKey, Consumer<InputStream> inputStreamHandler);
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package io.metersphere.plugin.platform.utils;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PluginPager<T> {
|
||||
|
||||
private T list;
|
||||
private long total;
|
||||
private long pageSize;
|
||||
private long current;
|
||||
|
||||
public PluginPager() {
|
||||
}
|
||||
|
||||
public PluginPager(T list, long total, long pageSize, long current) {
|
||||
this.list = list;
|
||||
this.total = total;
|
||||
this.pageSize = pageSize;
|
||||
this.current = current;
|
||||
}
|
||||
}
|
@ -15,6 +15,8 @@ bug.project_id.not_blank=项目ID不能为空
|
||||
bug.project_id.length_range=项目ID长度必须在1-50之间
|
||||
bug.template_id.not_blank=模板ID不能为空
|
||||
bug.template_id.length_range=模板ID长度必须在1-50之间
|
||||
bug.platform_id.not_blank=平台缺陷ID不能为空
|
||||
bug.platform_id.length_range=平台缺陷ID长度必须在1-50之间
|
||||
bug.platform.not_blank=缺陷平台不能为空
|
||||
bug.platform.length_range=缺陷平台长度必须在1-50之间
|
||||
bug.status.not_blank=平台状态不能为空
|
||||
@ -96,6 +98,13 @@ bug_comment_not_exist=缺陷评论不存在
|
||||
bug_relate_case_not_found=未查询到关联的用例
|
||||
bug_relate_case_type_unknown=关联的用例类型未知, 无法查看
|
||||
bug_relate_case_permission_error=无权限查看, 请联系管理员
|
||||
bug_status_can_not_be_empty=缺陷状态不能为空
|
||||
handle_user_can_not_be_empty=缺陷处理人不能为空
|
||||
bug.title=缺项名称
|
||||
bug.handle_user=处理人
|
||||
bug.status=状态
|
||||
bug.tag=标签
|
||||
bug.description=缺陷内容
|
||||
# bug export
|
||||
bug.system_columns.not_empty=系统字段不能为空
|
||||
bug.export.system.columns.name=缺陷名称
|
||||
|
@ -15,6 +15,8 @@ bug.project_id.not_blank=projectId cannot be empty
|
||||
bug.project_id.length_range=projectId length must be between 1-50
|
||||
bug.template_id.not_blank=templateId cannot be empty
|
||||
bug.template_id.length_range=templateId length must be between 1-50
|
||||
bug.platform_id.not_blank=platformId cannot be empty
|
||||
bug.platform_id.length_range=platformId length must be between 1-50
|
||||
bug.platform.not_blank=platform cannot be empty
|
||||
bug.platform.length_range=platform length must be between 1-50
|
||||
bug.status.not_blank=status cannot be empty
|
||||
@ -96,6 +98,13 @@ bug_comment_not_exist=Bug comment does not exist
|
||||
bug_relate_case_not_found=Bug related case not found
|
||||
bug_relate_case_type_unknown=Bug related case type unknown
|
||||
bug_relate_case_permission_error=No permission to show the case
|
||||
bug_status_can_not_be_empty=Status cannot be empty
|
||||
handle_user_can_not_be_empty=Handle user cannot be empty
|
||||
bug.title=Title
|
||||
bug.handle_user=Assignee
|
||||
bug.status=Status
|
||||
bug.tag=Tag
|
||||
bug.description=Description
|
||||
# bug export
|
||||
bug.system_columns.not_empty=System columns cannot be empty
|
||||
bug.export.system.columns.name=Name
|
||||
|
@ -15,6 +15,8 @@ bug.project_id.not_blank=项目ID不能为空
|
||||
bug.project_id.length_range=项目ID长度必须在1-50之间
|
||||
bug.template_id.not_blank=模板ID不能为空
|
||||
bug.template_id.length_range=模板ID长度必须在1-50之间
|
||||
bug.platform_id.not_blank=平台缺陷ID不能为空
|
||||
bug.platform_id.length_range=平台缺陷ID长度必须在1-50之间
|
||||
bug.platform.not_blank=缺陷平台不能为空
|
||||
bug.platform.length_range=缺陷平台长度必须在1-50之间
|
||||
bug.status.not_blank=平台状态不能为空
|
||||
@ -96,6 +98,13 @@ bug_comment_not_exist=缺陷评论不存在
|
||||
bug_relate_case_not_found=未查询到关联的用例
|
||||
bug_relate_case_type_unknown=关联的用例类型未知, 无法查看
|
||||
bug_relate_case_permission_error=无用例查看权限, 请联系管理员
|
||||
bug_status_can_not_be_empty=缺陷状态不能为空
|
||||
handle_user_can_not_be_empty=缺陷处理人不能为空
|
||||
bug.title=缺项名称
|
||||
bug.handle_user=处理人
|
||||
bug.status=状态
|
||||
bug.tag=标签
|
||||
bug.description=缺陷内容
|
||||
# bug export
|
||||
bug.system_columns.not_empty=系统字段不能为空
|
||||
bug.export.system.columns.name=缺陷名称
|
||||
|
@ -15,6 +15,8 @@ bug.project_id.not_blank=项目ID不能為空
|
||||
bug.project_id.length_range=项目ID長度必須在1-50之間
|
||||
bug.template_id.not_blank=模板ID不能為空
|
||||
bug.template_id.length_range=模板ID長度必須在1-50之間
|
||||
bug.platform_id.not_blank=平台缺陷ID不能為空
|
||||
bug.platform_id.length_range=平台缺陷ID長度必須在1-50之間
|
||||
bug.platform.not_blank=缺陷平台不能為空
|
||||
bug.platform.length_range=缺陷平台長度必須在1-50之間
|
||||
bug.status.not_blank=平台状态不能為空
|
||||
@ -96,6 +98,14 @@ bug_comment_not_exist=缺陷評論不存在
|
||||
bug_relate_case_not_found=未查詢到關聯的用例
|
||||
bug_relate_case_type_unknown=關聯的用例類型未知, 無法查看
|
||||
bug_relate_case_permission_error=無權限查看, 請聯繫管理員
|
||||
bug_status_can_not_be_empty=缺陷狀態不能為空
|
||||
handle_user_can_not_be_empty=缺陷處理人不能為空
|
||||
bug.title=缺項名稱
|
||||
bug.handle_user=處理人
|
||||
bug.status=狀態
|
||||
bug.tag=標籤
|
||||
bug.description=缺陷內容
|
||||
|
||||
# bug export
|
||||
bug.system_columns.not_empty=系統字段不能為空
|
||||
bug.export.system.columns.name=缺陷名稱
|
||||
|
@ -459,6 +459,7 @@ set_default_template=设置默认模板
|
||||
project_template_enable=开启项目模板
|
||||
|
||||
# 状态流
|
||||
status=状态
|
||||
status_flow.name=状态流
|
||||
status_item.bug_new=新建
|
||||
status_item.bug_in_process=处理中
|
||||
@ -488,4 +489,3 @@ priority_is_null=用例等级不能为空
|
||||
apikey_has_expired=ApiKey 已过期
|
||||
user_key.id.not_blank=ApiKey ID不能为空
|
||||
expire_time_not_null=过期时间不能为空
|
||||
|
||||
|
@ -469,6 +469,7 @@ node.name.repeat=Name repeat
|
||||
project.cannot.match.parent=Project can not match parent
|
||||
|
||||
# 状态流
|
||||
status=Status
|
||||
status_flow.name=Status Flow
|
||||
status_item.bug_new=NEW
|
||||
status_item.bug_in_process=IN PROCESS
|
||||
|
@ -465,6 +465,7 @@ api_test_environment_not_exist=环境不存在
|
||||
mock_environment_not_delete=Mock环境不允许删除
|
||||
|
||||
# 状态流
|
||||
status=状态
|
||||
status_flow.name=状态流
|
||||
status_item.bug_new=新建
|
||||
status_item.bug_in_process=处理中
|
||||
|
@ -465,6 +465,7 @@ api_test_environment_not_exist=環境不存在
|
||||
mock_environment_not_delete=Mock 環境不允許刪除
|
||||
|
||||
# 状态流
|
||||
status=狀態
|
||||
status_flow.name=狀態流
|
||||
status_item.bug_new=新建
|
||||
status_item.bug_in_process=處理中
|
||||
|
@ -0,0 +1,43 @@
|
||||
package io.metersphere.bug;
|
||||
|
||||
import io.metersphere.bug.service.BugSyncService;
|
||||
import io.metersphere.bug.service.XpackBugService;
|
||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.system.dto.sdk.LicenseDTO;
|
||||
import io.metersphere.system.sechedule.BaseScheduleJob;
|
||||
import io.metersphere.system.service.LicenseService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.quartz.JobExecutionContext;
|
||||
|
||||
/**
|
||||
* 缺陷同步定时任务
|
||||
*/
|
||||
public class BugSyncJob extends BaseScheduleJob {
|
||||
|
||||
private final LicenseService licenseService;
|
||||
|
||||
private final XpackBugService xpackBugService;
|
||||
|
||||
private final BugSyncService bugSyncService;
|
||||
|
||||
public BugSyncJob() {
|
||||
licenseService = CommonBeanFactory.getBean(LicenseService.class);
|
||||
xpackBugService = CommonBeanFactory.getBean(XpackBugService.class);
|
||||
bugSyncService = CommonBeanFactory.getBean(BugSyncService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void businessExecute(JobExecutionContext context) {
|
||||
LicenseDTO licenseDTO = licenseService.validate();
|
||||
if (licenseDTO != null && licenseDTO.getLicense() != null
|
||||
&& StringUtils.equals(licenseDTO.getStatus(), "valid")) {
|
||||
LogUtils.info("sync all bug");
|
||||
xpackBugService.syncPlatformBugsBySchedule();
|
||||
} else {
|
||||
LogUtils.info("sync remain bug");
|
||||
bugSyncService.syncPlatformBugBySchedule();
|
||||
}
|
||||
LogUtils.info("sync bug end");
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package io.metersphere.bug.constants;
|
||||
|
||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import lombok.Data;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.metersphere.bug.controller;
|
||||
|
||||
import io.metersphere.bug.domain.BugComment;
|
||||
import io.metersphere.bug.dto.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||
import io.metersphere.bug.dto.response.BugCommentDTO;
|
||||
import io.metersphere.bug.service.BugCommentService;
|
||||
import io.metersphere.system.utils.SessionUtils;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
@ -3,9 +3,10 @@ package io.metersphere.bug.controller;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.bug.constants.BugExportColumns;
|
||||
import io.metersphere.bug.dto.BugDTO;
|
||||
import io.metersphere.bug.dto.request.*;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.bug.service.BugService;
|
||||
import io.metersphere.bug.service.BugSyncService;
|
||||
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
|
||||
import io.metersphere.project.service.ProjectTemplateService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
@ -39,6 +40,8 @@ public class BugController {
|
||||
@Resource
|
||||
private BugService bugService;
|
||||
@Resource
|
||||
private BugSyncService bugSyncService;
|
||||
@Resource
|
||||
private ProjectTemplateService projectTemplateService;
|
||||
|
||||
@PostMapping("/page")
|
||||
@ -56,7 +59,7 @@ public class BugController {
|
||||
@RequiresPermissions(PermissionConstants.BUG_ADD)
|
||||
public void add(@Validated({Created.class}) @RequestPart(value = "request") BugEditRequest request,
|
||||
@RequestPart(value = "file", required = false) List<MultipartFile> files) {
|
||||
bugService.add(request, files, SessionUtils.getUserId());
|
||||
bugService.addOrUpdate(request, files, SessionUtils.getUserId(), false);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
@ -64,7 +67,7 @@ public class BugController {
|
||||
@RequiresPermissions(PermissionConstants.BUG_UPDATE)
|
||||
public void update(@Validated({Updated.class}) @RequestPart(value = "request") BugEditRequest request,
|
||||
@RequestPart(value = "file", required = false) List<MultipartFile> files) {
|
||||
bugService.update(request, files, SessionUtils.getUserId());
|
||||
bugService.addOrUpdate(request, files, SessionUtils.getUserId(), true);
|
||||
}
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
@ -81,11 +84,11 @@ public class BugController {
|
||||
return projectTemplateService.getOption(projectId, TemplateScene.BUG.name());
|
||||
}
|
||||
|
||||
@GetMapping("/template/{id}")
|
||||
@Operation(summary = "缺陷管理-获取模板内容")
|
||||
@PostMapping("/template/detail")
|
||||
@Operation(summary = "缺陷管理-获取模板详情内容")
|
||||
@RequiresPermissions(PermissionConstants.BUG_READ)
|
||||
public TemplateDTO getTemplateField(@PathVariable String id, @RequestParam(value = "projectId") String projectId) {
|
||||
return bugService.getTemplate(id, projectId);
|
||||
public TemplateDTO getTemplateDetail(@RequestBody BugTemplateRequest request) {
|
||||
return bugService.getTemplate(request.getId(), request.getProjectId(), request.getFromStatusId(), request.getPlatformBugKey());
|
||||
}
|
||||
|
||||
@PostMapping("/batch-delete")
|
||||
@ -116,6 +119,20 @@ public class BugController {
|
||||
bugService.unfollow(id, SessionUtils.getUserId());
|
||||
}
|
||||
|
||||
@GetMapping("/sync/{projectId}")
|
||||
@Operation(summary = "缺陷管理-同步缺陷(开源)")
|
||||
@RequiresPermissions(PermissionConstants.BUG_UPDATE)
|
||||
public void sync(@PathVariable String projectId) {
|
||||
bugSyncService.syncBugs(projectId);
|
||||
}
|
||||
|
||||
@PostMapping("/sync/all")
|
||||
@Operation(summary = "缺陷管理-同步缺陷(全量)")
|
||||
@RequiresPermissions(PermissionConstants.BUG_UPDATE)
|
||||
public void syncAll(@RequestBody BugSyncRequest request) {
|
||||
bugSyncService.syncAllBugs(request);
|
||||
}
|
||||
|
||||
@GetMapping("/export/columns/{projectId}")
|
||||
@Operation(summary = "缺陷管理-获取导出字段配置")
|
||||
@RequiresPermissions(PermissionConstants.BUG_EXPORT)
|
||||
|
@ -2,8 +2,8 @@ package io.metersphere.bug.controller;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.bug.dto.response.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.service.BugRelateCaseService;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.system.utils.PageUtils;
|
||||
|
@ -1,14 +0,0 @@
|
||||
package io.metersphere.bug.dto;
|
||||
|
||||
import io.metersphere.system.domain.User;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugCommentUserInfo extends User {
|
||||
|
||||
@Schema(description = "用户头像")
|
||||
private String createUserAvatar;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
package io.metersphere.bug.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
@ -1,7 +1,9 @@
|
||||
package io.metersphere.bug.dto;
|
||||
|
||||
import io.metersphere.bug.domain.BugContent;
|
||||
import io.metersphere.bug.dto.request.BugExportColumn;
|
||||
import io.metersphere.bug.dto.response.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.sdk.util.DateUtils;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
@ -1,24 +0,0 @@
|
||||
package io.metersphere.bug.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BugHistoryContentDTO extends BugDTO {
|
||||
|
||||
/**
|
||||
* 缺陷自定义字段
|
||||
*/
|
||||
private List<BugCustomFieldDTO> customFields;
|
||||
|
||||
/**
|
||||
* 缺陷内容
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 附件名称集合
|
||||
*/
|
||||
private List<String> attachmentNames;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package io.metersphere.bug.dto;
|
||||
|
||||
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BugStatusOptionDTO extends OptionDTO {
|
||||
|
||||
// 状态流转信息
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package io.metersphere.bug.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BugTemplateInjectField {
|
||||
private String id;
|
||||
private String name;
|
||||
private String type;
|
||||
private String defaultValue;
|
||||
private Boolean required;
|
||||
private Boolean supportSearch;
|
||||
private String optionMethod;
|
||||
}
|
@ -1,22 +1,14 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.metersphere.system.dto.sdk.BaseCondition;
|
||||
import io.metersphere.system.dto.table.TableBatchProcessDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugBatchRequest extends BaseCondition {
|
||||
public class BugBatchRequest extends TableBatchProcessDTO {
|
||||
|
||||
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "是否全选", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private boolean selectAll;
|
||||
|
||||
@Schema(description = "缺陷ID勾选集合")
|
||||
private List<String> includeBugIds;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -9,15 +8,9 @@ import lombok.EqualsAndHashCode;
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class BugBatchUpdateRequest extends BugBatchRequest{
|
||||
|
||||
@Schema(description = "处理人")
|
||||
private String handleUser;
|
||||
|
||||
@Schema(description = "标签")
|
||||
private String tag;
|
||||
|
||||
@Schema(description = "自定义字段")
|
||||
private BugCustomFieldDTO customField;
|
||||
|
||||
@Schema(description = "是否追加", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private boolean append;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
|
||||
import io.metersphere.validation.groups.Created;
|
||||
import io.metersphere.validation.groups.Updated;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@ -9,7 +10,6 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author song-cc-rock
|
||||
@ -23,16 +23,10 @@ public class BugEditRequest {
|
||||
@Size(min = 1, max = 50, message = "{bug.id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String id;
|
||||
|
||||
@Schema(description = "缺陷标题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{bug.title.not_blank}", groups = {Created.class, Updated.class})
|
||||
@Schema(description = "缺陷标题")
|
||||
@Size(min = 1, max = 300, message = "{bug.title.length_range}", groups = {Created.class, Updated.class})
|
||||
private String title;
|
||||
|
||||
@Schema(description = "处理人", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{bug.assign_user.not_blank}", groups = {Created.class, Updated.class})
|
||||
@Size(min = 1, max = 50, message = "{bug.assign_user.length_range}", groups = {Created.class, Updated.class})
|
||||
private String handleUser;
|
||||
|
||||
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{bug.project_id.not_blank}", groups = {Created.class, Updated.class})
|
||||
@Size(min = 1, max = 50, message = "{bug.project_id.length_range}", groups = {Created.class, Updated.class})
|
||||
@ -43,11 +37,6 @@ public class BugEditRequest {
|
||||
@Size(min = 1, max = 50, message = "{bug.template_id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String templateId;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{bug.status.not_blank}", groups = {Created.class, Updated.class})
|
||||
@Size(min = 1, max = 50, message = "{bug.status.length_range}", groups = {Created.class, Updated.class})
|
||||
private String status;
|
||||
|
||||
@Schema(description = "标签")
|
||||
private String tag;
|
||||
|
||||
@ -55,14 +44,14 @@ public class BugEditRequest {
|
||||
private String description;
|
||||
|
||||
@Schema(description = "自定义字段集合")
|
||||
private Map<String, String> customFieldMap;
|
||||
private List<BugCustomFieldDTO> customFields;
|
||||
|
||||
@Schema(description = "删除的本地附件集合")
|
||||
@Schema(description = "删除的本地附件集合, 文件ID")
|
||||
private List<String> deleteLocalFileIds;
|
||||
|
||||
@Schema(description = "取消关联附件关系ID集合")
|
||||
@Schema(description = "取消关联附件关系ID集合, 关联关系ID")
|
||||
private List<String> unLinkRefIds;
|
||||
|
||||
@Schema(description = "关联附件集合")
|
||||
@Schema(description = "关联附件集合, 文件ID")
|
||||
private List<String> linkFileIds;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.metersphere.bug.dto.BugExportColumn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
@ -0,0 +1,17 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BugSyncRequest {
|
||||
|
||||
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "创建时间前或后", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private boolean pre;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long createTime;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.metersphere.bug.dto.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BugTemplateRequest {
|
||||
|
||||
@Schema(description = "模板ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String id;
|
||||
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String projectId;
|
||||
@Schema(description = "缺陷当前状态ID")
|
||||
private String fromStatusId;
|
||||
@Schema(description = "缺陷第三方平台Key")
|
||||
private String platformBugKey;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.metersphere.bug.domain.BugComment;
|
||||
import io.metersphere.system.dto.CommentUserInfo;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.metersphere.system.domain.CustomField;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.metersphere.bug.domain.Bug;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
@ -0,0 +1,34 @@
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class BugFileDTO {
|
||||
|
||||
@Schema(description = "关系ID")
|
||||
private String refId;
|
||||
|
||||
@Schema(description = "文件ID")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "文件名称")
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "文件类型")
|
||||
private String fileType;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String createUser;
|
||||
|
||||
@Schema(description = "是否关联")
|
||||
private Boolean associated;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.metersphere.functional.domain.FunctionalCase;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
@ -1,4 +1,4 @@
|
||||
package io.metersphere.bug.dto;
|
||||
package io.metersphere.bug.dto.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
@ -0,0 +1,27 @@
|
||||
package io.metersphere.bug.enums;
|
||||
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum BugTemplateCustomField {
|
||||
|
||||
/**
|
||||
* 处理人
|
||||
*/
|
||||
HANDLE_USER("handleUser", Translator.get("bug.handle_user")),
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
STATUS("status", Translator.get("bug.status"));
|
||||
|
||||
|
||||
private final String id;
|
||||
|
||||
private final String name;
|
||||
|
||||
BugTemplateCustomField(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package io.metersphere.bug.mapper;
|
||||
|
||||
import io.metersphere.bug.domain.BugCustomField;
|
||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
@ -9,12 +9,20 @@ import java.util.List;
|
||||
public interface ExtBugCustomFieldMapper {
|
||||
|
||||
/**
|
||||
* 获取缺陷自定义字段值
|
||||
* 获取缺陷存在的自定义字段值
|
||||
* @param bugIds 缺陷集合
|
||||
* @param projectId 项目ID
|
||||
* @return 缺陷自定义字段值
|
||||
*/
|
||||
List<BugCustomFieldDTO> getBugCustomFields(@Param("ids") List<String> bugIds, @Param("projectId") String projectId);
|
||||
List<BugCustomFieldDTO> getBugExistCustomFields(@Param("ids") List<String> bugIds, @Param("projectId") String projectId);
|
||||
|
||||
/**
|
||||
* 获取缺陷所有自定义字段映射值
|
||||
* @param bugIds 缺陷集合
|
||||
* @param projectId 项目ID
|
||||
* @return 缺陷自定义字段值
|
||||
*/
|
||||
List<BugCustomFieldDTO> getBugAllCustomFields(@Param("ids") List<String> bugIds, @Param("projectId") String projectId);
|
||||
|
||||
/**
|
||||
* 批量插入缺陷自定义字段值
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.bug.mapper.ExtBugCustomFieldMapper">
|
||||
<select id="getBugCustomFields" resultType="io.metersphere.bug.dto.BugCustomFieldDTO">
|
||||
<select id="getBugExistCustomFields" resultType="io.metersphere.bug.dto.response.BugCustomFieldDTO">
|
||||
select cf.*, bcf.value, bcf.bug_id from bug_custom_field bcf join custom_field cf on bcf.field_id = cf.id
|
||||
where cf.scene = 'BUG' and cf.scope_type = 'PROJECT' and scope_id = #{projectId}
|
||||
and bug_id in
|
||||
@ -10,6 +10,15 @@
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="getBugAllCustomFields" resultType="io.metersphere.bug.dto.response.BugCustomFieldDTO">
|
||||
select cf.name, bcf.value, bcf.bug_id, bcf.field_id as id from bug_custom_field bcf left join custom_field cf on bcf.field_id = cf.id
|
||||
and cf.scene = 'BUG' and cf.scope_type = 'PROJECT' and scope_id = #{projectId}
|
||||
where bug_id in
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<insert id="batchInsert" parameterType="io.metersphere.bug.domain.BugCustomField">
|
||||
insert into bug_custom_field (bug_id, field_id, value) values
|
||||
<foreach collection="list" item="field" separator=",">
|
||||
|
@ -1,9 +1,9 @@
|
||||
package io.metersphere.bug.mapper;
|
||||
|
||||
import io.metersphere.bug.dto.BugDTO;
|
||||
import io.metersphere.bug.dto.BugTagEditDTO;
|
||||
import io.metersphere.bug.dto.request.BugBatchUpdateRequest;
|
||||
import io.metersphere.bug.dto.request.BugPageRequest;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.bug.dto.response.BugTagEditDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
@ -18,7 +18,22 @@ public interface ExtBugMapper {
|
||||
*/
|
||||
List<BugDTO> list(@Param("request") BugPageRequest request);
|
||||
|
||||
/**
|
||||
* 缺陷列表查询
|
||||
*
|
||||
* @param request 请求查询参数
|
||||
* @return 缺陷列表
|
||||
*/
|
||||
List<String> getIdsByPageRequest(@Param("request") BugPageRequest request);
|
||||
|
||||
/**
|
||||
* 根据ID列表查询缺陷
|
||||
*
|
||||
* @param ids 缺陷ID集合
|
||||
* @return 缺陷列表
|
||||
*/
|
||||
List<BugDTO> listByIds(@Param("ids") List<String> ids);
|
||||
|
||||
/**
|
||||
* 获取缺陷业务ID
|
||||
*
|
||||
|
@ -1,13 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.bug.mapper.ExtBugMapper">
|
||||
<select id="list" resultType="io.metersphere.bug.dto.BugDTO">
|
||||
<select id="list" resultType="io.metersphere.bug.dto.response.BugDTO">
|
||||
select b.id, b.num, b.title, b.handle_user, b.create_user, b.create_time, b.update_time, b.delete_time, b.delete_user,
|
||||
b.project_id, b.template_id, b.platform, b.status, bc.description from bug b left join bug_content bc on b.id = bc.bug_id
|
||||
<include refid="queryWhereCondition"/>
|
||||
</select>
|
||||
|
||||
<select id="listByIds" resultType="io.metersphere.bug.dto.BugDTO">
|
||||
<select id="getIdsByPageRequest" resultType="java.lang.String">
|
||||
select b.id from bug b left join bug_content bc on b.id = bc.bug_id
|
||||
<include refid="queryWhereCondition"/>
|
||||
</select>
|
||||
|
||||
<select id="listByIds" resultType="io.metersphere.bug.dto.response.BugDTO">
|
||||
select b.id,
|
||||
b.num,
|
||||
b.title,
|
||||
@ -33,7 +38,7 @@
|
||||
select max(num) from bug where project_id = #{projectId}
|
||||
</select>
|
||||
|
||||
<select id="getBugTagList" resultType="io.metersphere.bug.dto.BugTagEditDTO">
|
||||
<select id="getBugTagList" resultType="io.metersphere.bug.dto.response.BugTagEditDTO">
|
||||
select id as bugId, tag from bug where id in
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
@ -43,10 +48,6 @@
|
||||
<update id="batchUpdate" parameterType="io.metersphere.bug.dto.request.BugBatchUpdateRequest">
|
||||
update bug
|
||||
<set>
|
||||
<if test="request.handleUser != null and request.handleUser != ''">
|
||||
handle_user = #{request.handleUser},
|
||||
handle_users = handle_users + concat(',', #{request.handleUser}),
|
||||
</if>
|
||||
<if test="request.tag != null and request.tag != ''">
|
||||
tag = #{request.tag},
|
||||
</if>
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.metersphere.bug.mapper;
|
||||
|
||||
import io.metersphere.bug.dto.BugRelateCaseCountDTO;
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.bug.dto.response.BugRelateCaseCountDTO;
|
||||
import io.metersphere.bug.dto.response.BugRelateCaseDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.bug.mapper.ExtBugRelateCaseMapper">
|
||||
<select id="countRelationCases" resultType="io.metersphere.bug.dto.BugRelateCaseCountDTO">
|
||||
<select id="countRelationCases" resultType="io.metersphere.bug.dto.response.BugRelateCaseCountDTO">
|
||||
select count(id) as relationCaseCount, bug_id as bugId from bug_relation_case brc
|
||||
where brc.bug_id in
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
@ -10,11 +10,11 @@
|
||||
group by brc.bug_id
|
||||
</select>
|
||||
|
||||
<select id="list" resultType="io.metersphere.bug.dto.BugRelateCaseDTO">
|
||||
<select id="list" resultType="io.metersphere.bug.dto.response.BugRelateCaseDTO">
|
||||
select fc.num, fc.name, fc.project_id, fc.version_id, brc.case_type relateCaseType, brc.id relateId,
|
||||
brc.test_plan_id is not null relatePlanCase, brc.case_id is not null relateCase
|
||||
from bug_relation_case brc join functional_case fc on (brc.case_id = fc.id or brc.test_plan_case_id = fc.id)
|
||||
where brc.bug_id = #{request.bugId}
|
||||
where brc.bug_id = #{request.bugId} and fc.deleted = false
|
||||
<if test="request.keyword != null and request.keyword != ''">
|
||||
and fc.name like concat('%', #{request.keyword}, '%')
|
||||
</if>
|
||||
|
@ -0,0 +1,84 @@
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.domain.BugLocalAttachment;
|
||||
import io.metersphere.bug.domain.BugLocalAttachmentExample;
|
||||
import io.metersphere.bug.dto.response.BugFileDTO;
|
||||
import io.metersphere.bug.mapper.BugLocalAttachmentMapper;
|
||||
import io.metersphere.project.domain.FileAssociation;
|
||||
import io.metersphere.project.domain.FileAssociationExample;
|
||||
import io.metersphere.project.domain.FileMetadata;
|
||||
import io.metersphere.project.domain.FileMetadataExample;
|
||||
import io.metersphere.project.mapper.FileAssociationMapper;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.sdk.util.FileAssociationSourceUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class BugAttachmentService {
|
||||
|
||||
@Resource
|
||||
private FileAssociationMapper fileAssociationMapper;
|
||||
@Resource
|
||||
private FileMetadataMapper fileMetadataMapper;
|
||||
@Resource
|
||||
private BugLocalAttachmentMapper bugLocalAttachmentMapper;
|
||||
|
||||
/**
|
||||
* 查询缺陷的附件集合
|
||||
* @param bugId 缺陷ID
|
||||
* @return 缺陷附件关系集合
|
||||
*/
|
||||
public List<BugFileDTO> getAllBugFiles(String bugId) {
|
||||
List<BugFileDTO> bugFiles = new ArrayList<>();
|
||||
BugLocalAttachmentExample localAttachmentExample = new BugLocalAttachmentExample();
|
||||
localAttachmentExample.createCriteria().andBugIdEqualTo(bugId);
|
||||
List<BugLocalAttachment> bugLocalAttachments = bugLocalAttachmentMapper.selectByExample(localAttachmentExample);
|
||||
if (!CollectionUtils.isEmpty(bugLocalAttachments)) {
|
||||
bugLocalAttachments.forEach(localFile -> {
|
||||
BugFileDTO localFileDTO = BugFileDTO.builder().refId(localFile.getId()).fileId(localFile.getFileId()).fileName(localFile.getFileName()).fileType(getLocalFileType(localFile.getFileName()))
|
||||
.fileSize(localFile.getSize()).createTime(localFile.getCreateTime()).createUser(localFile.getCreateUser()).associated(false).build();
|
||||
bugFiles.add(localFileDTO);
|
||||
});
|
||||
}
|
||||
FileAssociationExample associationExample = new FileAssociationExample();
|
||||
associationExample.createCriteria().andSourceIdEqualTo(bugId).andSourceTypeEqualTo(FileAssociationSourceUtil.SOURCE_TYPE_BUG);
|
||||
List<FileAssociation> fileAssociations = fileAssociationMapper.selectByExample(associationExample);
|
||||
if (!CollectionUtils.isEmpty(fileAssociations)) {
|
||||
List<String> associateFileIds = fileAssociations.stream().map(FileAssociation::getFileId).toList();
|
||||
FileMetadataExample metadataExample = new FileMetadataExample();
|
||||
metadataExample.createCriteria().andIdIn(associateFileIds);
|
||||
List<FileMetadata> fileMetadataList = fileMetadataMapper.selectByExample(metadataExample);
|
||||
Map<String, FileMetadata> fileMetadataMap = fileMetadataList.stream().collect(Collectors.toMap(FileMetadata::getId, v -> v));
|
||||
fileAssociations.forEach(associatedFile -> {
|
||||
FileMetadata associatedFileMetadata = fileMetadataMap.get(associatedFile.getFileId());
|
||||
BugFileDTO associatedFileDTO = BugFileDTO.builder().refId(associatedFile.getId()).fileId(associatedFile.getFileId()).fileName(associatedFileMetadata.getName() + "." + associatedFileMetadata.getType())
|
||||
.fileType(associatedFileMetadata.getType()).fileSize(associatedFileMetadata.getSize()).createTime(associatedFileMetadata.getCreateTime())
|
||||
.createUser(associatedFileMetadata.getCreateUser()).associated(true).build();
|
||||
bugFiles.add(associatedFileDTO);
|
||||
});
|
||||
}
|
||||
return bugFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地文件类型
|
||||
* @param fileName 文件名
|
||||
* @return 文件类型
|
||||
*/
|
||||
private String getLocalFileType(String fileName) {
|
||||
int i = fileName.lastIndexOf(".");
|
||||
if (i > 0) {
|
||||
return fileName.substring(i);
|
||||
} else {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.domain.Bug;
|
||||
import io.metersphere.bug.dto.BugCommentNoticeDTO;
|
||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||
import io.metersphere.bug.dto.response.BugCommentNoticeDTO;
|
||||
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.mapper.BugMapper;
|
||||
import io.metersphere.bug.mapper.ExtBugCustomFieldMapper;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
@ -82,7 +82,7 @@ public class BugCommentNoticeService {
|
||||
* @param bugCommentNoticeDTO 缺陷通知参数
|
||||
*/
|
||||
private void setCustomField(BugCommentNoticeDTO bugCommentNoticeDTO) {
|
||||
List<BugCustomFieldDTO> bugCustomFields = extBugCustomFieldMapper.getBugCustomFields(List.of(bugCommentNoticeDTO.getId()), bugCommentNoticeDTO.getProjectId());
|
||||
List<BugCustomFieldDTO> bugCustomFields = extBugCustomFieldMapper.getBugExistCustomFields(List.of(bugCommentNoticeDTO.getId()), bugCommentNoticeDTO.getProjectId());
|
||||
if (CollectionUtils.isNotEmpty(bugCustomFields)) {
|
||||
List<OptionDTO> fields = bugCustomFields.stream().map(field -> new OptionDTO(field.getName(), field.getValue())).toList();
|
||||
bugCommentNoticeDTO.setFields(fields);
|
||||
|
@ -3,9 +3,9 @@ package io.metersphere.bug.service;
|
||||
import io.metersphere.bug.domain.Bug;
|
||||
import io.metersphere.bug.domain.BugComment;
|
||||
import io.metersphere.bug.domain.BugCommentExample;
|
||||
import io.metersphere.bug.dto.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.BugCommentNoticeDTO;
|
||||
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||
import io.metersphere.bug.dto.response.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.response.BugCommentNoticeDTO;
|
||||
import io.metersphere.bug.mapper.BugCommentMapper;
|
||||
import io.metersphere.bug.mapper.BugMapper;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
|
@ -4,10 +4,10 @@ import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.support.ExcelTypeEnum;
|
||||
import io.metersphere.bug.domain.BugContent;
|
||||
import io.metersphere.bug.domain.BugContentExample;
|
||||
import io.metersphere.bug.dto.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.BugDTO;
|
||||
import io.metersphere.bug.dto.BugExportColumn;
|
||||
import io.metersphere.bug.dto.BugExportExcelModel;
|
||||
import io.metersphere.bug.dto.request.BugExportColumn;
|
||||
import io.metersphere.bug.dto.response.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.bug.mapper.BugContentMapper;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -1,29 +0,0 @@
|
||||
//package io.metersphere.bug.service;
|
||||
//
|
||||
//import io.metersphere.bug.mapper.BugAttachmentMapper;
|
||||
//import io.metersphere.bug.mapper.BugMapper;
|
||||
//import jakarta.annotation.Resource;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//
|
||||
//@Service
|
||||
//public class BugHistoryService {
|
||||
//
|
||||
// @Resource
|
||||
// private BugMapper bugMapper;
|
||||
// @Resource
|
||||
// private BugAttachmentMapper bugAttachmentMapper;
|
||||
//
|
||||
// public void save(String bugId) {
|
||||
// /*
|
||||
// * 变更历史内容: BUG信息(基础字段, 自定义字段, 缺陷内容大字段, 附件)
|
||||
// */
|
||||
// }
|
||||
//
|
||||
// public void compare() {
|
||||
// // 对比变更历史
|
||||
// }
|
||||
//
|
||||
// public void rollback() {
|
||||
// // 回退变更历史
|
||||
// }
|
||||
//}
|
@ -1,8 +1,8 @@
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.domain.BugRelationCase;
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.bug.dto.response.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
||||
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
|
||||
import io.metersphere.project.domain.Project;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,66 +1,55 @@
|
||||
//package io.metersphere.bug.service;
|
||||
//
|
||||
//import io.metersphere.bug.dto.BugStatusOptionDTO;
|
||||
//import io.metersphere.bug.enums.BugPlatform;
|
||||
//import io.metersphere.plugin.platform.spi.Platform;
|
||||
//import io.metersphere.project.service.ProjectApplicationService;
|
||||
//import io.metersphere.project.service.ProjectTemplateService;
|
||||
//import io.metersphere.sdk.exception.MSException;
|
||||
//import io.metersphere.sdk.util.Translator;
|
||||
//import io.metersphere.system.domain.ServiceIntegration;
|
||||
//import io.metersphere.system.service.PlatformPluginService;
|
||||
//import jakarta.annotation.Resource;
|
||||
//import org.apache.commons.lang3.StringUtils;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.transaction.annotation.Transactional;
|
||||
//
|
||||
//import java.util.List;
|
||||
//
|
||||
//@Service
|
||||
//@Transactional(rollbackFor = Exception.class)
|
||||
//public class BugStatusService {
|
||||
//
|
||||
// @Resource
|
||||
// private ProjectApplicationService projectApplicationService;
|
||||
// @Resource
|
||||
// private ProjectTemplateService projectTemplateService;
|
||||
// @Resource
|
||||
// private PlatformPluginService platformPluginService;
|
||||
//
|
||||
// /**
|
||||
// * 获取状态下拉选项
|
||||
// * @param projectId 项目ID
|
||||
// * @return 选项集合
|
||||
// */
|
||||
// public List<BugStatusOptionDTO> getProjectStatusOption(String projectId) {
|
||||
// // TODO: 获取状态下拉选项 {Local平台: 直接取状态流中的选项, 第三方平台: 取第三方插件平台的状态和状态流中的选项}
|
||||
// String platformName = projectApplicationService.getPlatformName(projectId);
|
||||
// if (StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) {
|
||||
// return getProjectStatusItemOption(projectId);
|
||||
// } else {
|
||||
// // 状态流 && 第三方平台状态流
|
||||
// ServiceIntegration serviceIntegration = projectTemplateService.getServiceIntegration(projectId);
|
||||
// if (serviceIntegration == null) {
|
||||
// // 项目未配置第三方平台
|
||||
// throw new MSException(Translator.get("third_party_not_config"));
|
||||
// }
|
||||
// // 获取配置平台, 获取第三方平台状态流
|
||||
// Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(),
|
||||
// new String(serviceIntegration.getConfiguration()));
|
||||
//// List<PlatformStatusDTO> statusList = platform.getStatusList();
|
||||
// // 获取项目状态流
|
||||
//// List<BugStatusOptionDTO> projectStatusItemOption = getProjectStatusItemOption(projectId);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取项目状态流选项
|
||||
// * @param projectId 项目ID
|
||||
// * @return 选项集合
|
||||
// */
|
||||
// public List<BugStatusOptionDTO> getProjectStatusItemOption(String projectId) {
|
||||
// // TODO: 获取项目状态流选项
|
||||
// return null;
|
||||
// }
|
||||
//}
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.enums.BugPlatform;
|
||||
import io.metersphere.plugin.platform.dto.SelectOption;
|
||||
import io.metersphere.plugin.platform.spi.Platform;
|
||||
import io.metersphere.project.service.ProjectApplicationService;
|
||||
import io.metersphere.sdk.constants.TemplateScene;
|
||||
import io.metersphere.system.service.BaseStatusFlowSettingService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class BugStatusService {
|
||||
|
||||
@Resource
|
||||
private ProjectApplicationService projectApplicationService;
|
||||
@Resource
|
||||
private BaseStatusFlowSettingService baseStatusFlowSettingService;
|
||||
|
||||
/**
|
||||
* 获取缺陷下一批状态流转选项
|
||||
* @param projectId 项目ID
|
||||
* @param fromStatusId 当前状态选项值ID
|
||||
* @param platformBugKey 平台缺陷Key
|
||||
* @return 选项集合
|
||||
*/
|
||||
public List<SelectOption> getToStatusItemOption(String projectId, String fromStatusId, String platformBugKey) {
|
||||
String platformName = projectApplicationService.getPlatformName(projectId);
|
||||
if (StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) {
|
||||
// Local状态流
|
||||
return getToStatusItemOptionOnLocal(projectId, fromStatusId);
|
||||
} else {
|
||||
// 第三方平台状态流
|
||||
// 获取配置平台, 获取第三方平台状态流
|
||||
Platform platform = projectApplicationService.getPlatform(projectId, true);
|
||||
String projectConfig = projectApplicationService.getProjectBugThirdPartConfig(projectId);
|
||||
return platform.getStatusTransitions(projectConfig, platformBugKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缺陷下一批状态流转选项
|
||||
* @param projectId 项目ID
|
||||
* @param fromStatusId 当前状态选项值ID
|
||||
* @return 选项集合
|
||||
*/
|
||||
public List<SelectOption> getToStatusItemOptionOnLocal(String projectId, String fromStatusId) {
|
||||
return baseStatusFlowSettingService.getStatusTransitions(projectId, TemplateScene.BUG.name(), fromStatusId);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,241 @@
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.domain.BugLocalAttachment;
|
||||
import io.metersphere.bug.domain.BugLocalAttachmentExample;
|
||||
import io.metersphere.bug.dto.response.BugFileDTO;
|
||||
import io.metersphere.bug.mapper.BugLocalAttachmentMapper;
|
||||
import io.metersphere.plugin.platform.dto.PlatformAttachment;
|
||||
import io.metersphere.plugin.platform.dto.request.SyncAttachmentToPlatformRequest;
|
||||
import io.metersphere.plugin.platform.spi.Platform;
|
||||
import io.metersphere.project.domain.FileAssociationExample;
|
||||
import io.metersphere.project.mapper.FileAssociationMapper;
|
||||
import io.metersphere.project.service.ProjectApplicationService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.file.FileCenter;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class BugSyncExtraService {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private ProjectApplicationService projectApplicationService;
|
||||
@Resource
|
||||
private BugAttachmentService bugAttachmentService;
|
||||
@Resource
|
||||
private BugLocalAttachmentMapper bugLocalAttachmentMapper;
|
||||
@Resource
|
||||
private FileAssociationMapper fileAssociationMapper;
|
||||
|
||||
private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC";
|
||||
private static final String SYNC_THIRD_PARTY_ISSUES_ERROR_KEY = "ISSUE:SYNC:ERROR";
|
||||
|
||||
/**
|
||||
* 设置手动同步缺陷唯一Key
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public void setSyncKey(String projectId) {
|
||||
stringRedisTemplate.opsForValue().set(SYNC_THIRD_PARTY_ISSUES_KEY + ":" + projectId, UUID.randomUUID().toString(), 60 * 10L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取手动同步缺陷唯一Key
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public String getSyncKey(String projectId) {
|
||||
return stringRedisTemplate.opsForValue().get(SYNC_THIRD_PARTY_ISSUES_KEY + ":" + projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除手动同步缺陷唯一Key
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public void deleteSyncKey(String projectId) {
|
||||
stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_KEY + ":" + projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置手动同步缺陷错误信息
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public void setSyncErrorMsg(String projectId, String errorMsg) {
|
||||
stringRedisTemplate.opsForValue().set(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId, errorMsg, 30L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取手动同步缺陷错误信息
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public String getSyncErrorMsg(String projectId) {
|
||||
return stringRedisTemplate.opsForValue().get(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除手动同步缺陷错误信息
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public void deleteSyncErrorMsg(String projectId) {
|
||||
stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步附件到平台
|
||||
* @param platformAttachments 平台附件参数
|
||||
* @param projectId 项目ID
|
||||
* @param tmpFilePath 临时文件路径
|
||||
*/
|
||||
@Async
|
||||
public void syncAttachmentToPlatform(List<SyncAttachmentToPlatformRequest> platformAttachments, String projectId, File tmpFilePath) {
|
||||
// 平台缺陷需同步附件
|
||||
Platform platform = projectApplicationService.getPlatform(projectId, true);
|
||||
platformAttachments.forEach(platform::syncAttachmentToPlatform);
|
||||
tmpFilePath.deleteOnExit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步平台附件到MS
|
||||
* @param platform 平台对象
|
||||
* @param attachmentMap 平台附件缺陷集合
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
@Async
|
||||
public void syncAttachmentToMs(Platform platform, Map<String, List<PlatformAttachment>> attachmentMap, String projectId) {
|
||||
for (String bugId : attachmentMap.keySet()) {
|
||||
List<PlatformAttachment> syncAttachments = attachmentMap.get(bugId);
|
||||
// 获取所有MS附件
|
||||
Set<String> platformAttachmentSet = new HashSet<>();
|
||||
List<BugFileDTO> allBugFiles = bugAttachmentService.getAllBugFiles(bugId);
|
||||
Set<String> attachmentsNameSet = allBugFiles.stream().map(BugFileDTO::getFileName).collect(Collectors.toSet());
|
||||
for (PlatformAttachment syncAttachment : syncAttachments) {
|
||||
String fileName = syncAttachment.getFileName();
|
||||
String fileKey = syncAttachment.getFileKey();
|
||||
platformAttachmentSet.add(fileName);
|
||||
if (!attachmentsNameSet.contains(fileName)) {
|
||||
saveSyncAttachmentToMs(platform, bugId, fileName, fileKey, projectId);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除Jira中不存在的附件
|
||||
deleteSyncAttachmentFromMs(platformAttachmentSet, allBugFiles, bugId, projectId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存同步附件到MS
|
||||
* @param platform 平台对象
|
||||
* @param bugId 缺陷ID
|
||||
* @param fileName 附件名称
|
||||
* @param fileKey 附件唯一Key
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public void saveSyncAttachmentToMs(Platform platform, String bugId, String fileName, String fileKey, String projectId) {
|
||||
try {
|
||||
platform.getAttachmentContent(fileKey, (in) -> {
|
||||
if (in == null) {
|
||||
return;
|
||||
}
|
||||
byte[] bytes;
|
||||
try {
|
||||
// upload platform attachment to minio
|
||||
bytes = in.readAllBytes();
|
||||
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(projectId, bugId, fileName));
|
||||
} catch (Exception e) {
|
||||
throw new MSException(e);
|
||||
}
|
||||
// save bug attachment relation
|
||||
BugLocalAttachment localAttachment = new BugLocalAttachment();
|
||||
localAttachment.setId(IDGenerator.nextStr());
|
||||
localAttachment.setBugId(bugId);
|
||||
localAttachment.setFileId(IDGenerator.nextStr());
|
||||
localAttachment.setFileName(fileName);
|
||||
localAttachment.setSize((long) bytes.length);
|
||||
localAttachment.setCreateTime(System.currentTimeMillis());
|
||||
localAttachment.setCreateUser("admin");
|
||||
bugLocalAttachmentMapper.insert(localAttachment);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除MS中不存在的平台附件
|
||||
* @param platformAttachmentSet 已处理的平台附件集合
|
||||
* @param allMsAttachments 所有MS附件集合
|
||||
* @param bugId 缺陷ID
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
private void deleteSyncAttachmentFromMs(Set<String> platformAttachmentSet, List<BugFileDTO> allMsAttachments, String bugId, String projectId) {
|
||||
try {
|
||||
// 删除MS中不存在的平台附件
|
||||
if (!CollectionUtils.isEmpty(allMsAttachments)) {
|
||||
List<BugFileDTO> deleteMsAttachments = allMsAttachments.stream()
|
||||
.filter(msAttachment -> !platformAttachmentSet.contains(msAttachment.getFileName()))
|
||||
.toList();
|
||||
List<String> unLinkIds = new ArrayList<>();
|
||||
List<String> deleteLocalIds = new ArrayList<>();
|
||||
deleteMsAttachments.forEach(deleteMsFile -> {
|
||||
if (deleteMsFile.getAssociated()) {
|
||||
unLinkIds.add(deleteMsFile.getRefId());
|
||||
} else {
|
||||
deleteLocalIds.add(deleteMsFile.getRefId());
|
||||
}
|
||||
});
|
||||
if (!CollectionUtils.isEmpty(unLinkIds)) {
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andIdIn(unLinkIds);
|
||||
fileAssociationMapper.deleteByExample(example);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(deleteLocalIds)) {
|
||||
Map<String, BugFileDTO> localFileMap = deleteMsAttachments.stream().collect(Collectors.toMap(BugFileDTO::getRefId, f -> f));
|
||||
deleteLocalIds.forEach(deleteLocalId -> {
|
||||
try {
|
||||
BugFileDTO bugFileDTO = localFileMap.get(deleteLocalId);
|
||||
FileCenter.getDefaultRepository().delete(buildBugFileRequest(projectId, bugId, bugFileDTO.getFileName()));
|
||||
} catch (Exception e) {
|
||||
throw new MSException(e);
|
||||
}
|
||||
});
|
||||
BugLocalAttachmentExample example = new BugLocalAttachmentExample();
|
||||
example.createCriteria().andIdIn(deleteLocalIds);
|
||||
bugLocalAttachmentMapper.deleteByExample(example);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建文件库请求参数
|
||||
* @param projectId 项目ID
|
||||
* @param resourceId 资源ID(缺陷ID)
|
||||
* @param fileName 文件名
|
||||
* @return 构建文件库请求对象
|
||||
*/
|
||||
private FileRequest buildBugFileRequest(String projectId, String resourceId, String fileName) {
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
fileRequest.setFolder(DefaultRepositoryDir.getBugDir(projectId, resourceId));
|
||||
fileRequest.setFileName(StringUtils.isEmpty(fileName) ? null : fileName);
|
||||
fileRequest.setStorage(StorageType.MINIO.name());
|
||||
return fileRequest;
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.domain.Bug;
|
||||
import io.metersphere.bug.domain.BugExample;
|
||||
import io.metersphere.bug.dto.request.BugSyncRequest;
|
||||
import io.metersphere.bug.enums.BugPlatform;
|
||||
import io.metersphere.bug.mapper.BugMapper;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.domain.ProjectExample;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
import io.metersphere.project.service.ProjectApplicationService;
|
||||
import io.metersphere.project.service.ProjectTemplateService;
|
||||
import io.metersphere.sdk.constants.TemplateScene;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.system.domain.Template;
|
||||
import io.metersphere.system.domain.TemplateExample;
|
||||
import io.metersphere.system.mapper.TemplateMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author song-cc-rock
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class BugSyncService {
|
||||
|
||||
@Resource
|
||||
private BugMapper bugMapper;
|
||||
@Resource
|
||||
private BugService bugService;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
@Resource
|
||||
private TemplateMapper templateMapper;
|
||||
@Resource
|
||||
private BugSyncExtraService bugSyncExtraService;
|
||||
@Resource
|
||||
private ProjectTemplateService projectTemplateService;
|
||||
@Resource
|
||||
private ProjectApplicationService projectApplicationService;
|
||||
|
||||
/**
|
||||
* XPACK用户 (同步全量缺陷)
|
||||
* @param request 同步全量参数
|
||||
*/
|
||||
public void syncAllBugs(BugSyncRequest request) {
|
||||
try {
|
||||
// 获取当前项目同步缺陷唯一Key
|
||||
String syncValue = bugSyncExtraService.getSyncKey(request.getProjectId());
|
||||
if (StringUtils.isEmpty(syncValue)) {
|
||||
// 不存在, 设置保证唯一性, 并开始同步
|
||||
bugSyncExtraService.setSyncKey(request.getProjectId());
|
||||
Project project = getProjectById(request.getProjectId());
|
||||
bugService.syncPlatformAllBugs(request, project);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
bugSyncExtraService.deleteSyncKey(request.getProjectId());
|
||||
throw new MSException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开源用户 (同步存量缺陷)
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
public void syncBugs(String projectId) {
|
||||
try {
|
||||
String syncValue = bugSyncExtraService.getSyncKey(projectId);
|
||||
if (StringUtils.isEmpty(syncValue)) {
|
||||
bugSyncExtraService.setSyncKey(projectId);
|
||||
Project project = getProjectById(projectId);
|
||||
String platformName = projectApplicationService.getPlatformName(projectId);
|
||||
if (StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) {
|
||||
// 当前项目为本地平台, 不需要同步第三方
|
||||
bugSyncExtraService.deleteSyncKey(projectId);
|
||||
}
|
||||
// 查询存量的平台缺陷
|
||||
BugExample example = new BugExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andPlatformEqualTo(platformName).andDeletedEqualTo(false);
|
||||
List<Bug> bugs = bugMapper.selectByExample(example);
|
||||
if (CollectionUtils.isEmpty(bugs)) {
|
||||
bugSyncExtraService.deleteSyncKey(projectId);
|
||||
} else {
|
||||
Template pluginTemplate = projectTemplateService.getPluginBugTemplate(projectId);
|
||||
List<String> templateIds = bugs.stream().map(Bug::getTemplateId).toList();
|
||||
TemplateExample templateExample = new TemplateExample();
|
||||
templateExample.createCriteria().andScopeIdEqualTo(projectId).andSceneEqualTo(TemplateScene.BUG.name()).andIdIn(templateIds);
|
||||
List<Template> templates = templateMapper.selectByExample(templateExample);
|
||||
Map<String, Template> templateMap = templates.stream().collect(Collectors.toMap(Template::getId, t -> t));
|
||||
// 非插件默认模板且模板不存在, 无需同步
|
||||
bugs.removeIf(bug -> !templateMap.containsKey(bug.getTemplateId()) && !StringUtils.equals(bug.getTemplateId(), pluginTemplate.getId()));
|
||||
bugService.syncPlatformBugs(bugs, project);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
bugSyncExtraService.deleteSyncKey(projectId);
|
||||
throw new MSException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务同步缺陷(存量)
|
||||
*/
|
||||
public void syncPlatformBugBySchedule() {
|
||||
ProjectExample example = new ProjectExample();
|
||||
List<Project> projects = projectMapper.selectByExample(example);
|
||||
List<String> allProjectIds = projects.stream().map(Project::getId).toList();
|
||||
List<String> syncProjectIds = projectApplicationService.filterNoLocalPlatform(allProjectIds);
|
||||
syncProjectIds.forEach(id -> {
|
||||
try {
|
||||
syncBugs(id);
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据项目ID获取项目信息
|
||||
* @param projectId 项目ID
|
||||
* @return 项目信息
|
||||
*/
|
||||
private Project getProjectById(String projectId) {
|
||||
return projectMapper.selectByPrimaryKey(projectId);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package io.metersphere.bug.service;
|
||||
|
||||
import io.metersphere.bug.dto.request.BugSyncRequest;
|
||||
import io.metersphere.project.domain.Project;
|
||||
|
||||
/**
|
||||
* 缺陷Xpack功能接口 (全量同步)
|
||||
*/
|
||||
public interface XpackBugService {
|
||||
|
||||
/**
|
||||
* 同步系统下所有第三方平台项目缺陷(定时任务)
|
||||
*/
|
||||
void syncPlatformBugsBySchedule();
|
||||
|
||||
/**
|
||||
* 同步当前项目第三方平台缺陷(前台调用)
|
||||
* @param project 项目
|
||||
* @param request 同步请求参数
|
||||
*/
|
||||
void syncPlatformBugs(Project project, BugSyncRequest request);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package io.metersphere.bug.utils;
|
||||
|
||||
import io.metersphere.bug.dto.BugDTO;
|
||||
import io.metersphere.bug.dto.request.BugExportColumn;
|
||||
import io.metersphere.bug.dto.BugExportColumn;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.sdk.util.CompressUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.metersphere.bug.controller;
|
||||
|
||||
import io.metersphere.bug.domain.BugComment;
|
||||
import io.metersphere.bug.dto.BugCommentDTO;
|
||||
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||
import io.metersphere.bug.dto.response.BugCommentDTO;
|
||||
import io.metersphere.bug.mapper.BugCommentMapper;
|
||||
import io.metersphere.project.domain.Notification;
|
||||
import io.metersphere.project.domain.NotificationExample;
|
||||
|
@ -1,21 +1,51 @@
|
||||
package io.metersphere.bug.controller;
|
||||
|
||||
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.BugDTO;
|
||||
import io.metersphere.bug.domain.Bug;
|
||||
import io.metersphere.bug.domain.BugExample;
|
||||
import io.metersphere.bug.domain.BugLocalAttachment;
|
||||
import io.metersphere.bug.domain.BugLocalAttachmentExample;
|
||||
import io.metersphere.bug.dto.BugExportColumn;
|
||||
import io.metersphere.bug.dto.request.*;
|
||||
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
|
||||
import io.metersphere.bug.dto.response.BugDTO;
|
||||
import io.metersphere.bug.mapper.BugLocalAttachmentMapper;
|
||||
import io.metersphere.bug.mapper.BugMapper;
|
||||
import io.metersphere.bug.service.BugService;
|
||||
import io.metersphere.bug.service.BugSyncExtraService;
|
||||
import io.metersphere.bug.service.BugSyncService;
|
||||
import io.metersphere.bug.utils.CustomFieldUtils;
|
||||
import io.metersphere.plugin.platform.dto.request.SyncAllBugRequest;
|
||||
import io.metersphere.project.domain.*;
|
||||
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
|
||||
import io.metersphere.project.mapper.FileAssociationMapper;
|
||||
import io.metersphere.project.mapper.FileMetadataMapper;
|
||||
import io.metersphere.project.mapper.ProjectApplicationMapper;
|
||||
import io.metersphere.project.service.FileService;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.constants.PermissionConstants;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.file.FileRequest;
|
||||
import io.metersphere.sdk.util.FileAssociationSourceUtil;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.domain.CustomField;
|
||||
import io.metersphere.system.domain.CustomFieldExample;
|
||||
import io.metersphere.system.domain.ServiceIntegration;
|
||||
import io.metersphere.system.dto.request.PluginUpdateRequest;
|
||||
import io.metersphere.system.dto.sdk.TemplateDTO;
|
||||
import io.metersphere.system.mapper.CustomFieldMapper;
|
||||
import io.metersphere.system.mapper.ServiceIntegrationMapper;
|
||||
import io.metersphere.system.service.PluginService;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
@ -23,9 +53,11 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@ -38,17 +70,56 @@ public class BugControllerTests extends BaseTest {
|
||||
public static final String BUG_UPDATE = "/bug/update";
|
||||
public static final String BUG_DELETE = "/bug/delete";
|
||||
public static final String BUG_TEMPLATE_OPTION = "/bug/template/option";
|
||||
public static final String BUG_TEMPLATE_DETAIL = "/bug/template";
|
||||
public static final String BUG_TEMPLATE_DETAIL = "/bug/template/detail";
|
||||
public static final String BUG_BATCH_DELETE = "/bug/batch-delete";
|
||||
public static final String BUG_BATCH_UPDATE = "/bug/batch-update";
|
||||
public static final String BUG_FOLLOW = "/bug/follow";
|
||||
public static final String BUG_UN_FOLLOW = "/bug/unfollow";
|
||||
public static final String BUG_SYNC = "/bug/sync";
|
||||
public static final String BUG_SYNC_ALL = "/bug/sync/all";
|
||||
public static final String BUG_EXPORT_COLUMNS = "/bug/export/columns/%s";
|
||||
public static final String BUG_EXPORT = "/bug/export";
|
||||
|
||||
@Resource
|
||||
private PluginService pluginService;
|
||||
@Resource
|
||||
private BugMapper bugMapper;
|
||||
@Resource
|
||||
private BugLocalAttachmentMapper bugLocalAttachmentMapper;
|
||||
@Resource
|
||||
private FileMetadataMapper fileMetadataMapper;
|
||||
@Resource
|
||||
private CustomFieldMapper customFieldMapper;
|
||||
@Resource
|
||||
private FileAssociationMapper fileAssociationMapper;
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
@Resource
|
||||
private BugSyncService bugSyncService;
|
||||
@Resource
|
||||
private BugSyncExtraService bugSyncExtraService;
|
||||
@Resource
|
||||
private BugService bugService;
|
||||
@Resource
|
||||
private ServiceIntegrationMapper serviceIntegrationMapper;
|
||||
@Resource
|
||||
private ProjectApplicationMapper projectApplicationMapper;
|
||||
|
||||
@Test
|
||||
@Order(0)
|
||||
@Sql(scripts = {"/dml/init_bug.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||
void prepareData() throws Exception {
|
||||
// 插入准备的文件
|
||||
FileRequest fileRequest = new FileRequest();
|
||||
fileRequest.setFolder(DefaultRepositoryDir.getFileManagementDir("default-project-for-bug"));
|
||||
fileRequest.setFileName("default-bug-file-id-1");
|
||||
fileRequest.setStorage(StorageType.MINIO.name());
|
||||
fileService.upload(getMockFile(), fileRequest);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void testBugPageSuccess() throws Exception {
|
||||
BugPageRequest bugRequest = new BugPageRequest();
|
||||
bugRequest.setCurrent(1);
|
||||
@ -89,7 +160,7 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@Order(2)
|
||||
void testBugPageEmptySuccess() throws Exception {
|
||||
BugPageRequest bugPageRequest = new BugPageRequest();
|
||||
bugPageRequest.setCurrent(1);
|
||||
@ -161,7 +232,7 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
@Order(3)
|
||||
void testBugPageError() throws Exception {
|
||||
// 页码有误
|
||||
BugPageRequest bugPageRequest = new BugPageRequest();
|
||||
@ -176,7 +247,7 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@Order(4)
|
||||
void testAddBugSuccess() throws Exception {
|
||||
BugEditRequest request = buildRequest(false);
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath();
|
||||
@ -186,7 +257,7 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@Order(5)
|
||||
void testAddBugError() throws Exception {
|
||||
BugEditRequest request = buildRequest(false);
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath();
|
||||
@ -195,30 +266,27 @@ public class BugControllerTests extends BaseTest {
|
||||
request.setProjectId(null);
|
||||
MultiValueMap<String, Object> paramMap = getDefaultMultiPartParam(request, file);
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest());
|
||||
// 标题为空
|
||||
request.setProjectId("default-project-for-bug");
|
||||
request.setTitle(null);
|
||||
paramMap = getDefaultMultiPartParam(request, file);
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest());
|
||||
// 处理人为空
|
||||
request.setTitle("default-bug-title");
|
||||
request.setHandleUser(null);
|
||||
List<BugCustomFieldDTO> noHandleUser = request.getCustomFields().stream().filter(field -> !StringUtils.equals(field.getId(), "handleUser")).toList();
|
||||
request.setCustomFields(noHandleUser);
|
||||
paramMap = getDefaultMultiPartParam(request, file);
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest());
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().is5xxServerError());
|
||||
// 模板为空
|
||||
request.setHandleUser("admin");
|
||||
request.setTemplateId(null);
|
||||
paramMap = getDefaultMultiPartParam(request, file);
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest());
|
||||
// 状态为空
|
||||
request.setTemplateId("default-bug-template");
|
||||
request.setStatus(null);
|
||||
List<BugCustomFieldDTO> noStatus = request.getCustomFields().stream().filter(field -> !StringUtils.equals(field.getId(), "status")).toList();
|
||||
request.setCustomFields(noStatus);
|
||||
paramMap = getDefaultMultiPartParam(request, file);
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest());
|
||||
this.requestMultipart(BUG_ADD, paramMap).andExpect(status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
@Order(6)
|
||||
void testUpdateBugSuccess() throws Exception {
|
||||
BugEditRequest request = buildRequest(true);
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath();
|
||||
@ -228,12 +296,14 @@ public class BugControllerTests extends BaseTest {
|
||||
// 第二次更新, no-file
|
||||
MultiValueMap<String, Object> noFileParamMap = new LinkedMultiValueMap<>();
|
||||
request.setLinkFileIds(null);
|
||||
request.setUnLinkRefIds(null);
|
||||
request.setDeleteLocalFileIds(null);
|
||||
noFileParamMap.add("request", JSON.toJSONString(request));
|
||||
this.requestMultipartWithOkAndReturn(BUG_UPDATE, noFileParamMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
@Order(7)
|
||||
void testUpdateBugError() throws Exception {
|
||||
BugEditRequest request = buildRequest(true);
|
||||
request.setId("default-bug-id-not-exist");
|
||||
@ -244,18 +314,22 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
@Order(8)
|
||||
void testUpdateBugWithEmptyField() throws Exception {
|
||||
BugEditRequest request = buildRequest(true);
|
||||
request.setCustomFieldMap(null);
|
||||
List<BugCustomFieldDTO> statusAndHandleUser = request.getCustomFields().stream().filter(field -> StringUtils.equalsAny(field.getId(), "status", "handleUser")).toList();
|
||||
request.setCustomFields(statusAndHandleUser);
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath();
|
||||
File file = new File(filePath);
|
||||
request.setLinkFileIds(null);
|
||||
request.setUnLinkRefIds(null);
|
||||
request.setDeleteLocalFileIds(null);
|
||||
MultiValueMap<String, Object> paramMap = getDefaultMultiPartParam(request, file);
|
||||
this.requestMultipartWithOkAndReturn(BUG_UPDATE, paramMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(8)
|
||||
@Order(9)
|
||||
void testGetBugTemplateOption() throws Exception {
|
||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_OPTION + "?projectId=default-project-for-bug");
|
||||
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
@ -266,82 +340,71 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
@Order(10)
|
||||
void testGetBugTemplateDetailSuccess() throws Exception {
|
||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_DETAIL + "/default-bug-template-id" + "?projectId=default-project-for-bug");
|
||||
BugTemplateRequest request = new BugTemplateRequest();
|
||||
request.setId("default-bug-template-id");
|
||||
request.setProjectId("default-project-for-bug");
|
||||
MvcResult mvcResult = this.requestPostWithOkAndReturn(BUG_TEMPLATE_DETAIL, request);
|
||||
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class);
|
||||
TemplateDTO templateDTO = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TemplateDTO.class);
|
||||
Assertions.assertNotNull(templateDTO);
|
||||
Assertions.assertEquals("default-bug-template-id", templateDTO.getId());
|
||||
// 获取默认模板
|
||||
MvcResult defaultResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_DETAIL + "/default-bug-template-id-not-exist" + "?projectId=default-project-for-bug");
|
||||
String defaultData = defaultResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
ResultHolder defaultResultHolder = JSON.parseObject(defaultData, ResultHolder.class);
|
||||
TemplateDTO defaultTemplate = JSON.parseObject(JSON.toJSONString(defaultResultHolder.getData()), TemplateDTO.class);
|
||||
Assertions.assertNotNull(defaultTemplate);
|
||||
Assertions.assertEquals("default-bug-template-id", defaultTemplate.getId());
|
||||
// 编辑时的模板详情
|
||||
// 覆盖状态流
|
||||
request.setFromStatusId("1");
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
request.setFromStatusId("2");
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
request.setProjectId("no-status-project");
|
||||
request.setId("no-status-template");
|
||||
request.setFromStatusId(null);
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
@Order(11)
|
||||
void testBatchUpdateBugSuccess() throws Exception {
|
||||
BugBatchUpdateRequest request = new BugBatchUpdateRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
// 全选, 编辑所有数据
|
||||
request.setSelectAll(true);
|
||||
request.setSelectIds(List.of("test"));
|
||||
// TAG追加
|
||||
request.setTag(JSON.toJSONString(List.of("TAG", "TEST_TAG")));
|
||||
request.setAppend(true);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
// TAG覆盖
|
||||
request.setExcludeIds(List.of("default-bug-id-tapd1"));
|
||||
request.setTag(JSON.toJSONString(List.of("A", "B")));
|
||||
request.setAppend(false);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
// TAG追加
|
||||
request.setTag(JSON.toJSONString(List.of("C", "D")));
|
||||
request.setAppend(true);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
// 处理人修改
|
||||
request.setTag(null);
|
||||
request.setHandleUser("default-admin");
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
// 自定义字段追加
|
||||
BugCustomFieldDTO field = new BugCustomFieldDTO();
|
||||
field.setId("test_field");
|
||||
field.setValue(JSON.toJSONString(List.of("test1")));
|
||||
request.setCustomField(field);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
// 自定义字段覆盖
|
||||
request.setAppend(false);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
// 勾选部分
|
||||
request.setSelectAll(false);
|
||||
request.setIncludeBugIds(List.of("default-bug-id"));
|
||||
request.setSelectIds(List.of("default-bug-id"));
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11)
|
||||
@Order(12)
|
||||
void testBatchUpdateEmptyBugSuccess() throws Exception {
|
||||
BugBatchUpdateRequest request = new BugBatchUpdateRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
request.setCombine(buildRequestCombine());
|
||||
request.setProjectId("default-project-for-bug-no-data");
|
||||
// 全选, 空数据
|
||||
request.setSelectAll(true);
|
||||
request.setSelectIds(List.of("test"));
|
||||
request.setTag(JSON.toJSONString(List.of("TAG", "TEST_TAG")));
|
||||
request.setAppend(true);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError());
|
||||
// 取消全选, 空数据
|
||||
request.setSelectAll(false);
|
||||
request.setIncludeBugIds(List.of("not-exist-bug-id"));
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError());
|
||||
request.setSelectAll(false);
|
||||
request.setIncludeBugIds(null);
|
||||
request.setSelectIds(null);
|
||||
this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12)
|
||||
@Order(13)
|
||||
void testExportColumns() throws Exception {
|
||||
this.requestGetWithOkAndReturn(String.format(BUG_EXPORT_COLUMNS, "default-project-for-bug"));
|
||||
//校验权限
|
||||
@ -349,7 +412,7 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(13)
|
||||
@Order(14)
|
||||
void testExportBugs() throws Exception {
|
||||
BugExportRequest request = new BugExportRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
@ -379,13 +442,13 @@ public class BugControllerTests extends BaseTest {
|
||||
|
||||
// 勾选部分
|
||||
request.setSelectAll(false);
|
||||
request.setIncludeBugIds(List.of("default-bug-id-single"));
|
||||
request.setSelectIds(List.of("default-bug-id-single"));
|
||||
result = this.requestPostDownloadFile(BUG_EXPORT, null, request);
|
||||
bytes = result.getResponse().getContentAsByteArray();
|
||||
Assertions.assertTrue(bytes.length > 0);
|
||||
|
||||
//不存在的ID
|
||||
request.setIncludeBugIds(List.of(IDGenerator.nextStr()));
|
||||
request.setSelectIds(List.of(IDGenerator.nextStr()));
|
||||
this.requestPost(BUG_EXPORT, request).andExpect(status().is5xxServerError());
|
||||
|
||||
//没有数据
|
||||
@ -402,11 +465,13 @@ public class BugControllerTests extends BaseTest {
|
||||
request.setExportColumns(exportColumns);
|
||||
this.requestPostPermissionTest(PermissionConstants.BUG_EXPORT, BUG_EXPORT, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(90)
|
||||
void testDeleteBugSuccess() throws Exception {
|
||||
// Local
|
||||
this.requestGet(BUG_DELETE + "/default-bug-id", status().isOk());
|
||||
// 非Local缺陷
|
||||
// Tapd
|
||||
this.requestGet(BUG_DELETE + "/default-bug-id-tapd1", status().isOk());
|
||||
}
|
||||
|
||||
@ -418,20 +483,6 @@ public class BugControllerTests extends BaseTest {
|
||||
|
||||
@Test
|
||||
@Order(92)
|
||||
void testBatchDeleteEmptyBugSuccess() throws Exception {
|
||||
BugBatchRequest request = new BugBatchRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
request.setCombine(buildRequestCombine());
|
||||
// 全选, 空数据
|
||||
request.setSelectAll(true);
|
||||
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||
// 勾选部分, 空数据
|
||||
request.setSelectAll(false);
|
||||
this.requestPost(BUG_BATCH_DELETE, request, status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(93)
|
||||
void testFollowBug() throws Exception {
|
||||
// 关注的缺陷存在
|
||||
this.requestGet(BUG_FOLLOW + "/default-bug-id-single", status().isOk());
|
||||
@ -440,7 +491,7 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(94)
|
||||
@Order(93)
|
||||
void testUnFollowBug() throws Exception {
|
||||
// 取消关注的缺陷存在
|
||||
this.requestGet(BUG_UN_FOLLOW + "/default-bug-id-single", status().isOk());
|
||||
@ -449,26 +500,169 @@ public class BugControllerTests extends BaseTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(95)
|
||||
@Order(94)
|
||||
void testBatchDeleteBugSuccess() throws Exception {
|
||||
BugBatchRequest request = new BugBatchRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
// 全选, 删除所有
|
||||
request.setSelectAll(true);
|
||||
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||
// 非Local的缺陷删除
|
||||
request.setProjectId("default-project-for-bug-no-local");
|
||||
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||
// 勾选部分
|
||||
request.setSelectAll(false);
|
||||
request.setIncludeBugIds(List.of("default-bug-id-single"));
|
||||
this.requestPost(BUG_BATCH_DELETE, request, status().isOk());
|
||||
request.setSelectIds(List.of("test"));
|
||||
request.setExcludeIds(List.of("default-bug-id-jira-delete"));
|
||||
this.requestPost(BUG_BATCH_DELETE, request, status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(95)
|
||||
void coverUtilsTests() {
|
||||
CustomFieldUtils.appendToMultipleCustomField(null, "test");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(96)
|
||||
void coverUtilsTest() throws Exception {
|
||||
CustomFieldUtils.appendToMultipleCustomField(null, "test");
|
||||
void coverPlatformTemplateTests() throws Exception{
|
||||
// 覆盖同步缺陷(Local)
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-not-integration");
|
||||
|
||||
// 上传Jira插件
|
||||
addJiraPlugin();
|
||||
|
||||
// 获取Jira默认模板
|
||||
BugTemplateRequest request = new BugTemplateRequest();
|
||||
request.setId("jira");
|
||||
request.setProjectId("default-project-for-bug");
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
// 获取MS默认模板
|
||||
request.setId("default-bug-template-not-exist");
|
||||
request.setProjectId("default-project-for-bug");
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
// 关闭集成
|
||||
ServiceIntegration record = new ServiceIntegration();
|
||||
record.setId("621103810617344");
|
||||
record.setEnable(false);
|
||||
serviceIntegrationMapper.updateByPrimaryKeySelective(record);
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
record.setEnable(true);
|
||||
serviceIntegrationMapper.updateByPrimaryKeySelective(record);
|
||||
// 关闭同步
|
||||
ProjectApplicationExample example = new ProjectApplicationExample();
|
||||
example.createCriteria().andProjectIdEqualTo("default-project-for-bug").andTypeEqualTo("BUG_SYNC_PLATFORM_KEY");
|
||||
projectApplicationMapper.deleteByExample(example);
|
||||
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
|
||||
ProjectApplication projectApplication = new ProjectApplication();
|
||||
projectApplication.setProjectId("default-project-for-bug");
|
||||
projectApplication.setType("BUG_SYNC_PLATFORM_KEY");
|
||||
projectApplication.setTypeValue("jira");
|
||||
projectApplicationMapper.insert(projectApplication);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(96)
|
||||
void coverPlatformBugSyncTests() throws Exception {
|
||||
// 添加一条需要同步删除的缺陷
|
||||
BugEditRequest deleteRequest = buildJiraBugRequest(false);
|
||||
MultiValueMap<String, Object> deleteParam = getDefaultMultiPartParam(deleteRequest, null);
|
||||
this.requestMultipartWithOkAndReturn(BUG_ADD, deleteParam);
|
||||
Bug record = new Bug();
|
||||
record.setId(getAddJiraBug().getId());
|
||||
record.setPlatformBugId("Tapd-XXX");
|
||||
bugMapper.updateByPrimaryKeySelective(record);
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||
|
||||
// 添加Jira缺陷
|
||||
BugEditRequest addRequest = buildJiraBugRequest(false);
|
||||
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath();
|
||||
File file = new File(filePath);
|
||||
MultiValueMap<String, Object> addParam = getDefaultMultiPartParam(addRequest, file);
|
||||
this.requestMultipartWithOkAndReturn(BUG_ADD, addParam);
|
||||
|
||||
// 添加没有附件的Jira缺陷
|
||||
addRequest.setLinkFileIds(null);
|
||||
MultiValueMap<String, Object> addParam2 = getDefaultMultiPartParam(addRequest, null);
|
||||
this.requestMultipartWithOkAndReturn(BUG_ADD, addParam2);
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||
|
||||
// 更新Jira缺陷
|
||||
BugEditRequest updateRequest = buildJiraBugRequest(true);
|
||||
updateRequest.setUnLinkRefIds(List.of(getAddJiraAssociateFile().getId()));
|
||||
updateRequest.setDeleteLocalFileIds(List.of(getAddJiraLocalFile().getFileId()));
|
||||
MultiValueMap<String, Object> updateParma = getDefaultMultiPartParam(updateRequest, null);
|
||||
this.requestMultipartWithOkAndReturn(BUG_UPDATE, updateParma);
|
||||
|
||||
// 删除Jira缺陷
|
||||
this.requestGet(BUG_DELETE + "/" + updateRequest.getId(), status().isOk());
|
||||
|
||||
// 更新没有附件的缺陷
|
||||
BugEditRequest updateRequest2 = buildJiraBugRequest(true);
|
||||
updateRequest2.setLinkFileIds(List.of("default-bug-file-id-1"));
|
||||
MultiValueMap<String, Object> updateParam2 = getDefaultMultiPartParam(updateRequest2, file);
|
||||
this.requestMultipartWithOkAndReturn(BUG_UPDATE, updateParam2);
|
||||
// 同步第一次
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||
// 同步第二次
|
||||
renameLocalFile(updateRequest2.getId()); // 重命名后, 同步时会删除本地文件
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||
// 同步第三次
|
||||
deleteLocalFile(updateRequest2.getId()); // 手动删除关联的文件, 重新同步时会下载平台附件
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||
|
||||
// 删除唯一条平台缺陷
|
||||
BugBatchRequest batchRequest = new BugBatchRequest();
|
||||
batchRequest.setProjectId("default-project-for-bug");
|
||||
batchRequest.setSelectAll(true);
|
||||
batchRequest.setSelectIds(List.of("test"));
|
||||
batchRequest.setExcludeIds(List.of("default-bug-id-tapd1"));
|
||||
this.requestPost(BUG_BATCH_DELETE, batchRequest, status().isOk());
|
||||
// 同步Jira存量缺陷(存量数据为空)
|
||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||
|
||||
// 集成配置为空
|
||||
addRequest.setProjectId("default-project-for-not-integration");
|
||||
MultiValueMap<String, Object> notIntegrationParam = getDefaultMultiPartParam(addRequest, file);
|
||||
this.requestMultipart(BUG_ADD, notIntegrationParam).andExpect(status().is5xxServerError());
|
||||
|
||||
// 同步全量缺陷
|
||||
BugSyncRequest request = new BugSyncRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
request.setPre(true);
|
||||
request.setCreateTime(1702021500000L);
|
||||
this.requestPostWithOk(BUG_SYNC_ALL, request);
|
||||
|
||||
// 执行同步全部
|
||||
Project project = new Project();
|
||||
project.setId("default-project-for-bug");
|
||||
SyncAllBugRequest syncAllBugRequest = new SyncAllBugRequest();
|
||||
syncAllBugRequest.setPre(true);
|
||||
syncAllBugRequest.setCreateTime(1702021500000L);
|
||||
// 同步后置方法处理为空, 覆盖主工程代码即可
|
||||
syncAllBugRequest.setSyncPostProcessFunc((param) -> {});
|
||||
bugService.execSyncAll(project, syncAllBugRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(97)
|
||||
void coverSyncScheduleTests() {
|
||||
// 定时同步存量缺陷
|
||||
bugSyncService.syncPlatformBugBySchedule();
|
||||
// 异常信息
|
||||
bugSyncExtraService.setSyncErrorMsg("default-project-for-bug", "sync error!");
|
||||
String syncErrorMsg = bugSyncExtraService.getSyncErrorMsg("default-project-for-bug");
|
||||
Assertions.assertEquals(syncErrorMsg, "sync error!");
|
||||
bugSyncExtraService.deleteSyncErrorMsg("default-project-for-bug");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(98)
|
||||
void coverBugTests() {
|
||||
BugCustomFieldDTO field = new BugCustomFieldDTO();
|
||||
field.setId("test_field");
|
||||
field.setName("test");
|
||||
field.setValue("test");
|
||||
field.setType("multipleSelect");
|
||||
bugService.transferCustomToPlatformField(null, List.of(field), true);
|
||||
// 添加没有配置自定义映射字段的Jira缺陷
|
||||
removeApiFieldTmp();
|
||||
bugService.transferCustomToPlatformField("default-bug-template-id-not-exist", List.of(field), false);
|
||||
rollBackApiField();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -508,20 +702,199 @@ public class BugControllerTests extends BaseTest {
|
||||
request.setProjectId("default-project-for-bug");
|
||||
request.setTitle("default-bug-title");
|
||||
request.setDescription("default-bug-description");
|
||||
request.setHandleUser("admin");
|
||||
request.setTemplateId("default-bug-template");
|
||||
request.setStatus("prepare");
|
||||
request.setLinkFileIds(List.of("default-bug-file-id-1"));
|
||||
Map<String, String> customFieldMap = new HashMap<>();
|
||||
customFieldMap.put("custom-field", "oasis");
|
||||
customFieldMap.put("test_field", JSON.toJSONString(List.of("test")));
|
||||
if (isUpdate) {
|
||||
request.setId("default-bug-id");
|
||||
request.setUnLinkRefIds(List.of("default-bug-file-id-1"));
|
||||
request.setUnLinkRefIds(List.of("default-file-association-id"));
|
||||
request.setDeleteLocalFileIds(List.of("default-bug-file-id"));
|
||||
request.setLinkFileIds(List.of("default-bug-file-id-2"));
|
||||
}
|
||||
request.setCustomFieldMap(customFieldMap);
|
||||
BugCustomFieldDTO fieldDTO1 = new BugCustomFieldDTO();
|
||||
fieldDTO1.setId("custom-field");
|
||||
fieldDTO1.setName("oasis");
|
||||
BugCustomFieldDTO fieldDTO2 = new BugCustomFieldDTO();
|
||||
fieldDTO2.setId("test_field");
|
||||
fieldDTO2.setName(JSON.toJSONString(List.of("test")));
|
||||
BugCustomFieldDTO handleUserField = new BugCustomFieldDTO();
|
||||
handleUserField.setId("handleUser");
|
||||
handleUserField.setName("处理人");
|
||||
handleUserField.setValue("admin");
|
||||
BugCustomFieldDTO statusField = new BugCustomFieldDTO();
|
||||
statusField.setId("status");
|
||||
statusField.setName("状态");
|
||||
statusField.setValue("1");
|
||||
request.setCustomFields(List.of(fieldDTO1, fieldDTO2, handleUserField, statusField));
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成添加Jira缺陷的请求参数
|
||||
* @param isUpdate 是否更新
|
||||
* @return 缺陷编辑请求参数
|
||||
*/
|
||||
private BugEditRequest buildJiraBugRequest(boolean isUpdate) {
|
||||
BugEditRequest request = new BugEditRequest();
|
||||
request.setProjectId("default-project-for-bug");
|
||||
request.setTitle("这是一个系统Jira模板创建的缺陷");
|
||||
request.setDescription("这是一段缺陷内容!!!!");
|
||||
request.setTemplateId("default-bug-template-id");
|
||||
BugCustomFieldDTO customFieldDTO1 = new BugCustomFieldDTO();
|
||||
customFieldDTO1.setId("custom-field-1");
|
||||
customFieldDTO1.setName("开发团队");
|
||||
customFieldDTO1.setValue("10068");
|
||||
customFieldDTO1.setType("SELECT");
|
||||
BugCustomFieldDTO customFieldDTO2 = new BugCustomFieldDTO();
|
||||
customFieldDTO2.setId("custom-field-2");
|
||||
customFieldDTO2.setName("同名验证");
|
||||
customFieldDTO2.setValue("10062");
|
||||
customFieldDTO2.setType("SELECT");
|
||||
request.setCustomFields(new ArrayList<>(List.of(customFieldDTO1, customFieldDTO2)));
|
||||
if (!isUpdate) {
|
||||
// 新增
|
||||
request.setLinkFileIds(List.of("default-bug-file-id-1"));
|
||||
BugCustomFieldDTO handleUserField = new BugCustomFieldDTO();
|
||||
handleUserField.setId("assignee");
|
||||
handleUserField.setName("处理人");
|
||||
handleUserField.setType("select");
|
||||
handleUserField.setValue("60f68f7952162b0068de6a2d");
|
||||
BugCustomFieldDTO statusField = new BugCustomFieldDTO();
|
||||
statusField.setId("status");
|
||||
statusField.setName("状态");
|
||||
statusField.setType("select");
|
||||
statusField.setValue("10003");
|
||||
request.getCustomFields().addAll(List.of(handleUserField, statusField));
|
||||
}
|
||||
if (isUpdate) {
|
||||
// 更新
|
||||
Bug addJiraBug = getAddJiraBug();
|
||||
request.setId(addJiraBug.getId());
|
||||
request.setLinkFileIds(List.of("default-bug-file-id-3"));
|
||||
|
||||
BugCustomFieldDTO summaryField = new BugCustomFieldDTO();
|
||||
summaryField.setId("summary");
|
||||
summaryField.setName("摘要");
|
||||
summaryField.setType("input");
|
||||
summaryField.setValue("这是一段summary内容!!!!");
|
||||
BugCustomFieldDTO descriptionField = new BugCustomFieldDTO();
|
||||
descriptionField.setId("description");
|
||||
descriptionField.setName("描述");
|
||||
descriptionField.setType("richText");
|
||||
descriptionField.setValue("这是一段描述内容!!!!");
|
||||
BugCustomFieldDTO statusField = new BugCustomFieldDTO();
|
||||
statusField.setId("status");
|
||||
statusField.setName("状态");
|
||||
statusField.setType("select");
|
||||
statusField.setValue("31");
|
||||
request.getCustomFields().addAll(List.of(summaryField, descriptionField, statusField));
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加Jira插件,供测试使用
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public void addJiraPlugin() throws Exception {
|
||||
PluginUpdateRequest request = new PluginUpdateRequest();
|
||||
File jiraTestFile = new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/metersphere-jira-test.jar")).getPath());
|
||||
FileInputStream inputStream = new FileInputStream(jiraTestFile);
|
||||
MockMultipartFile mockMultipartFile = new MockMultipartFile(jiraTestFile.getName(), jiraTestFile.getName(), "jar", inputStream);
|
||||
request.setName("测试插件");
|
||||
request.setGlobal(true);
|
||||
request.setEnable(true);
|
||||
request.setCreateUser(ADMIN.name());
|
||||
pluginService.add(request, mockMultipartFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取添加的Jira缺陷
|
||||
* @return 缺陷
|
||||
*/
|
||||
private Bug getAddJiraBug() {
|
||||
BugExample example = new BugExample();
|
||||
example.createCriteria().andTitleEqualTo("这是一个系统Jira模板创建的缺陷");
|
||||
return bugMapper.selectByExample(example).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取创建Jira缺陷时的本地文件
|
||||
* @return 本地附件
|
||||
*/
|
||||
private BugLocalAttachment getAddJiraLocalFile() {
|
||||
BugLocalAttachmentExample example = new BugLocalAttachmentExample();
|
||||
example.createCriteria().andBugIdEqualTo(getAddJiraBug().getId());
|
||||
return bugLocalAttachmentMapper.selectByExample(example).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取创建Jira缺陷时的关联文件
|
||||
* @return 关联文件
|
||||
*/
|
||||
private FileAssociation getAddJiraAssociateFile() {
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andSourceIdEqualTo(getAddJiraBug().getId()).andSourceTypeEqualTo(FileAssociationSourceUtil.SOURCE_TYPE_BUG);
|
||||
return fileAssociationMapper.selectByExample(example).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取File上传
|
||||
* @return multipartFile
|
||||
*/
|
||||
private MockMultipartFile getMockFile() {
|
||||
return new MockMultipartFile(
|
||||
"test-file.xlsx",
|
||||
"test-file.xlsx",
|
||||
MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
"Hello, World!".getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名本地文件
|
||||
*/
|
||||
private void renameLocalFile(String bugId) {
|
||||
BugLocalAttachmentExample example = new BugLocalAttachmentExample();
|
||||
example.createCriteria().andBugIdEqualTo(bugId);
|
||||
BugLocalAttachment record = new BugLocalAttachment();
|
||||
record.setFileName("test1");
|
||||
bugLocalAttachmentMapper.updateByExampleSelective(record, example);
|
||||
FileMetadata associatedFile = new FileMetadata();
|
||||
associatedFile.setId("default-bug-file-id-1");
|
||||
associatedFile.setName("test1");
|
||||
fileMetadataMapper.updateByPrimaryKeySelective(associatedFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时移除API字段
|
||||
*/
|
||||
private void removeApiFieldTmp() {
|
||||
CustomFieldExample example = new CustomFieldExample();
|
||||
example.createCriteria().andIdIn(List.of("custom-field-1", "custom-field-2"));
|
||||
CustomField record = new CustomField();
|
||||
record.setScopeId("default-project-for-bug-tmp");
|
||||
customFieldMapper.updateByExampleSelective(record, example);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复API字段
|
||||
*/
|
||||
private void rollBackApiField() {
|
||||
CustomFieldExample example = new CustomFieldExample();
|
||||
example.createCriteria().andIdIn(List.of("custom-field-1", "custom-field-2"));
|
||||
CustomField record = new CustomField();
|
||||
record.setScopeId("default-project-for-bug");
|
||||
customFieldMapper.updateByExampleSelective(record, example);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除本地文件
|
||||
*/
|
||||
private void deleteLocalFile(String bugId) {
|
||||
BugLocalAttachmentExample localExample = new BugLocalAttachmentExample();
|
||||
localExample.createCriteria().andBugIdEqualTo(bugId);
|
||||
bugLocalAttachmentMapper.deleteByExample(localExample);
|
||||
FileAssociationExample example = new FileAssociationExample();
|
||||
example.createCriteria().andSourceIdEqualTo(bugId).andSourceTypeEqualTo(FileAssociationSourceUtil.SOURCE_TYPE_BUG);
|
||||
fileAssociationMapper.deleteByExample(example);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.metersphere.bug.controller;
|
||||
|
||||
import io.metersphere.bug.dto.BugRelateCaseDTO;
|
||||
import io.metersphere.bug.dto.request.BugRelatedCasePageRequest;
|
||||
import io.metersphere.bug.dto.response.BugRelateCaseDTO;
|
||||
import io.metersphere.sdk.constants.UserRoleType;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
|
@ -2,24 +2,34 @@ INSERT INTO project (id, num, organization_id, name, description, create_user, u
|
||||
('default-project-for-bug-tmp', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
||||
|
||||
INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUE
|
||||
('default-project-for-bug', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
||||
('default-project-for-bug', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000),
|
||||
('no-status-project', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
||||
|
||||
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUES
|
||||
(UUID(), 'admin', 'project_admin', 'default-project-for-bug', '100001', UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
|
||||
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, deleted) VALUES
|
||||
('default-bug-id', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
||||
('default-bug-id-tapd1', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0),
|
||||
('default-bug-id-tapd2', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-no-local', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0),
|
||||
('default-bug-id-single', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-single', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0);
|
||||
('default-bug-id', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0),
|
||||
('default-bug-id-tapd1', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'default-bug-template-id', 'Tapd', 'open', '["default-tag"]', null, 0),
|
||||
('default-bug-id-tapd2', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-no-local', 'default-bug-template-id', 'Tapd', 'open', '["default-tag"]', null, 0),
|
||||
('default-bug-id-single', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-single', 'default-bug-template-id', 'Tapd', 'open', '["default-tag"]', null, 0),
|
||||
('default-bug-id-jira', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-single', 'default-bug-template-id', 'Jira', 'open', '["default-tag"]', 'TES-TEST', 0);
|
||||
|
||||
INSERT INTO bug_custom_field (bug_id, field_id, value) VALUE ('default-bug-id', 'test_field', '["default", "default-1"]');
|
||||
|
||||
INSERT INTO custom_field (id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, scope_id) VALUE
|
||||
('test_field', '测试字段', 'BUG', 'MULTIPLE_SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug'),
|
||||
('custom-field', '测试字段', 'BUG', 'SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug');
|
||||
('custom-field-1', '测试字段1', 'BUG', 'SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug'),
|
||||
('custom-field-2', '测试字段2', 'BUG', 'SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug');
|
||||
|
||||
INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, scene) VALUES
|
||||
('bug-template-id', 'bug-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG'),
|
||||
('default-bug-template-id', 'bug-default-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG');
|
||||
('default-bug-template-id', 'bug-default-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG'),
|
||||
('no-status-template', 'no-status-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'no-status-project', 0, 'BUG');
|
||||
INSERT INTO template_custom_field(`id`, `field_id`, `template_id`, `required`, `system_field`, `pos`, `api_field_id`, `default_value`) VALUES
|
||||
('100581234408685570', 'custom-field-1', 'default-bug-template-id', false, false, 0, 'customfield_10097', NULL),
|
||||
('100581234408685571', 'custom-field-2', 'default-bug-template-id', false, false, 0, 'customfield_10098', NULL);
|
||||
|
||||
INSERT INTO bug_relation_case (id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time) VALUE
|
||||
(UUID_SHORT(), UUID_SHORT(), 'default-bug-id', 'functional', null, null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
||||
@ -31,4 +41,27 @@ INSERT INTO file_metadata (id, name, type, size, create_time, update_time, proje
|
||||
('default-bug-file-id-2', 'test-file', 'xlsx', 100, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'MINIO', 'admin', 'admin',
|
||||
'["default-tag"]', 'test-file', null, 'test-file', 1, 'default-bug-id', 1);
|
||||
|
||||
INSERT INTO project_application (project_id, type, type_value) VALUES ('default-project-for-bug', 'BUG_DEFAULT_TEMPLATE', 'default-bug-template-id');
|
||||
INSERT INTO bug_local_attachment (id, bug_id, file_id, file_name, size, create_user, create_time) VALUES
|
||||
('default-local-attachment-id', 'default-bug-id', 'default-bug-file-id', 'test-file-1', 100, 'admin', UNIX_TIMESTAMP() * 1000);
|
||||
|
||||
INSERT INTO file_association (id, source_type, source_id, file_id, file_ref_id, file_version, create_user, create_time, update_user, update_time) VALUES
|
||||
('default-file-association-id', 'BUG', 'default-bug-id', 'default-bug-file-id-1', 'default-bug-file-id-1', '1', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000);
|
||||
|
||||
INSERT INTO project_application (project_id, type, type_value) VALUES
|
||||
('default-project-for-bug', 'BUG_DEFAULT_TEMPLATE', 'default-bug-template-id'),
|
||||
('default-project-for-bug', 'BUG_SYNC_BUG_PLATFORM_CONFIG', '{"jiraKey":"TES","jiraBugTypeId":"10009"}'),
|
||||
('default-project-for-bug', 'BUG_SYNC_CRON_EXPRESSION', '0 0 0/1 * * ?'),
|
||||
('default-project-for-bug', 'BUG_SYNC_MECHANISM', 'increment'),
|
||||
('default-project-for-bug', 'BUG_SYNC_PLATFORM_KEY', 'jira'),
|
||||
('default-project-for-not-integration', 'BUG_SYNC_PLATFORM_KEY', 'jira'),
|
||||
('default-project-for-bug', 'BUG_SYNC_SYNC_ENABLE', 'true'),
|
||||
('default-project-for-bug', 'CASE_ENABLE', 'false'),
|
||||
('default-project-for-bug', 'CASE_RELATED_DEMAND_PLATFORM_CONFIG', '{"jiraKey":"TES","jiraDemandTypeId":"10007"}'),
|
||||
('default-project-for-bug', 'CASE_RELATED_PLATFORM_KEY', 'jira');
|
||||
|
||||
|
||||
INSERT INTO service_integration(`id`, `plugin_id`, `enable`, `configuration`, `organization_id`) VALUES
|
||||
('621103810617344', 'jira', true, 0x504B0304140008080800BC517657000000000000000000000000030000007A6970258DC10EC2201044FF65CF06D2C498D89347B5574FBD6D8158222CD85D6268E3BF4BE3F5CDBC990DD0DAC531430FB348E65EEBE06B41AAA9289480CC1E4991130D07C022F3A366D7DA13B2373B32261592469AF1572FCF883E289362CB735BF8A4C5EE073474C3CB8E59A6F85EEFF12AE676EC4E67F8FE00504B0708384DA4307800000087000000504B01021400140008080800BC517657384DA43078000000870000000300000000000000000000000000000000007A6970504B0506000000000100010031000000A90000000000, '100001');
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
@ -4,15 +4,13 @@ import io.metersphere.plugin.platform.spi.AbstractPlatformPlugin;
|
||||
import io.metersphere.plugin.platform.spi.Platform;
|
||||
import io.metersphere.plugin.sdk.spi.MsPlugin;
|
||||
import io.metersphere.project.domain.FakeErrorExample;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.domain.ProjectApplication;
|
||||
import io.metersphere.project.domain.ProjectApplicationExample;
|
||||
import io.metersphere.project.dto.ModuleDTO;
|
||||
import io.metersphere.project.job.BugSyncJob;
|
||||
import io.metersphere.project.job.CleanUpReportJob;
|
||||
import io.metersphere.project.mapper.ExtProjectMapper;
|
||||
import io.metersphere.project.mapper.ExtProjectUserRoleMapper;
|
||||
import io.metersphere.project.mapper.FakeErrorMapper;
|
||||
import io.metersphere.project.mapper.ProjectApplicationMapper;
|
||||
import io.metersphere.project.mapper.*;
|
||||
import io.metersphere.project.request.ProjectApplicationRequest;
|
||||
import io.metersphere.project.utils.ModuleSortUtils;
|
||||
import io.metersphere.sdk.constants.OperationLogConstants;
|
||||
@ -20,6 +18,7 @@ import io.metersphere.sdk.constants.ProjectApplicationType;
|
||||
import io.metersphere.sdk.constants.ScheduleType;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.domain.*;
|
||||
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
@ -77,6 +76,8 @@ public class ProjectApplicationService {
|
||||
|
||||
@Resource
|
||||
private ServiceIntegrationService serviceIntegrationService;
|
||||
@Resource
|
||||
private ProjectMapper projectMapper;
|
||||
|
||||
/**
|
||||
* 更新配置信息
|
||||
@ -550,7 +551,7 @@ public class ProjectApplicationService {
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andTypeLike(ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.PLATFORM_BUG_CONFIG.BUG_PLATFORM_CONFIG.name());
|
||||
List<ProjectApplication> list = projectApplicationMapper.selectByExample(example);
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
return list.get(0).getTypeValue();
|
||||
return list.get(0).getTypeValue().replaceAll("\\\\", "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -567,7 +568,7 @@ public class ProjectApplicationService {
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andTypeLike(ProjectApplicationType.CASE_RELATED_CONFIG.CASE_RELATED.name() + "_" + ProjectApplicationType.PLATFORM_DEMAND_CONFIG.DEMAND_PLATFORM_CONFIG.name());
|
||||
List<ProjectApplication> list = projectApplicationMapper.selectByExample(example);
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
return list.get(0).getTypeValue();
|
||||
return list.get(0).getTypeValue().replaceAll("\\\\", "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -590,11 +591,120 @@ public class ProjectApplicationService {
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andTypeEqualTo(ProjectApplicationType.BUG.BUG_SYNC.name() + "_PLATFORM_KEY");
|
||||
List<ProjectApplication> list = projectApplicationMapper.selectByExample(example);
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
PluginWrapper pluginWrapper = pluginLoadService.getPluginWrapper(list.get(0).getTypeValue());
|
||||
MsPlugin plugin = (MsPlugin) pluginWrapper.getPlugin();
|
||||
return plugin.getName();
|
||||
return getPluginName(list.get(0).getTypeValue());
|
||||
} else {
|
||||
return "local";
|
||||
return "Local";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤掉非Local平台的项目
|
||||
* @param projectIds 项目ID集合
|
||||
* @return 非Local平台的项目
|
||||
*/
|
||||
public List<String> filterNoLocalPlatform(List<String> projectIds) {
|
||||
ProjectApplicationExample example = new ProjectApplicationExample();
|
||||
example.createCriteria().andProjectIdIn(projectIds).andTypeEqualTo(ProjectApplicationType.BUG.BUG_SYNC.name() + "_PLATFORM_KEY");
|
||||
List<ProjectApplication> allProjectPlatformKeys = projectApplicationMapper.selectByExample(example);
|
||||
if (CollectionUtils.isNotEmpty(allProjectPlatformKeys)) {
|
||||
for (ProjectApplication projectApplication : allProjectPlatformKeys) {
|
||||
String pluginName = getPluginName(projectApplication.getTypeValue());
|
||||
if (StringUtils.equals("Local", pluginName)) {
|
||||
// 本地平台
|
||||
projectIds.remove(projectApplication.getProjectId());
|
||||
}
|
||||
}
|
||||
return projectIds;
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目同步机制
|
||||
*
|
||||
* @param projectId 项目ID
|
||||
* @return 项目所属平台
|
||||
*/
|
||||
public boolean isPlatformSyncMethodByIncrement(String projectId) {
|
||||
ProjectApplicationExample example = new ProjectApplicationExample();
|
||||
example.createCriteria().andProjectIdEqualTo(projectId).andTypeEqualTo(ProjectApplicationType.BUG.BUG_SYNC.name() + "_MECHANISM");
|
||||
List<ProjectApplication> list = projectApplicationMapper.selectByExample(example);
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
return StringUtils.equals(list.get(0).getTypeValue(), "increment");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询插件具体的服务集成信息(缺陷PLATFORM_KEY, 需求PLATFORM_KEY)
|
||||
* @param projectId 项目ID
|
||||
* @param isSync 是否缺陷同步配置
|
||||
* @return 插件服务集成信息
|
||||
*/
|
||||
public ServiceIntegration getPlatformServiceIntegrationWithSyncOrDemand(String projectId, boolean isSync) {
|
||||
// 是否开启项目配置第三方平台
|
||||
ProjectApplication platformEnableConfig;
|
||||
ProjectApplication platformKeyConfig;
|
||||
if (isSync) {
|
||||
platformEnableConfig = getByType(projectId, ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name());
|
||||
platformKeyConfig = getByType(projectId, ProjectApplicationType.BUG.BUG_SYNC.name() + "_PLATFORM_KEY");
|
||||
} else {
|
||||
platformEnableConfig = getByType(projectId, ProjectApplicationType.CASE_RELATED_CONFIG.CASE_ENABLE.name());
|
||||
platformKeyConfig = getByType(projectId, ProjectApplicationType.CASE_RELATED_CONFIG.CASE_RELATED.name() + "_PLATFORM_KEY");
|
||||
}
|
||||
|
||||
boolean isEnable = platformEnableConfig != null && Boolean.parseBoolean(platformEnableConfig.getTypeValue()) && platformKeyConfig != null;
|
||||
if (!isEnable) {
|
||||
return null;
|
||||
}
|
||||
Project project = projectMapper.selectByPrimaryKey(projectId);
|
||||
// 查询组织下有权限的插件
|
||||
Set<String> orgPluginIds = platformPluginService.getOrgEnabledPlatformPlugins(project.getOrganizationId())
|
||||
.stream()
|
||||
.map(Plugin::getId)
|
||||
.collect(Collectors.toSet());
|
||||
// 查询服务集成中启用并且支持第三方模板的插件
|
||||
return serviceIntegrationService.getServiceIntegrationByOrgId(project.getOrganizationId())
|
||||
.stream()
|
||||
.filter(serviceIntegration -> {
|
||||
return serviceIntegration.getEnable() // 服务集成开启
|
||||
&& orgPluginIds.contains(serviceIntegration.getPluginId())
|
||||
&& StringUtils.equals(serviceIntegration.getPluginId(), platformKeyConfig.getTypeValue()); // 该服务集成对应的插件有权限
|
||||
})
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目同步配置或需求配置的所属平台
|
||||
* @param projectId 项目ID
|
||||
* @param isSync 是否同步
|
||||
* @return 平台
|
||||
*/
|
||||
public Platform getPlatform(String projectId, boolean isSync) {
|
||||
// 第三方平台状态流
|
||||
ServiceIntegration serviceIntegration = getPlatformServiceIntegrationWithSyncOrDemand(projectId, isSync);
|
||||
if (serviceIntegration == null) {
|
||||
// 项目未配置第三方平台
|
||||
throw new MSException(Translator.get("third_party_not_config"));
|
||||
}
|
||||
return platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(),
|
||||
new String(serviceIntegration.getConfiguration()));
|
||||
}
|
||||
|
||||
private String getPluginName(String platformKey) {
|
||||
PluginWrapper pluginWrapper = pluginLoadService.getPluginWrapper(platformKey);
|
||||
if (pluginWrapper == null) {
|
||||
// 插件未找到
|
||||
return "Local";
|
||||
}
|
||||
MsPlugin plugin = (MsPlugin) pluginWrapper.getPlugin();
|
||||
if (plugin == null) {
|
||||
// 插件未找到
|
||||
return "Local";
|
||||
}
|
||||
return plugin.getName();
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
package io.metersphere.project.service;
|
||||
|
||||
import io.metersphere.sdk.constants.TemplateScopeType;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.system.domain.StatusItem;
|
||||
import io.metersphere.system.dto.StatusItemDTO;
|
||||
import io.metersphere.system.dto.sdk.request.StatusDefinitionUpdateRequest;
|
||||
import io.metersphere.system.dto.sdk.request.StatusFlowUpdateRequest;
|
||||
import io.metersphere.system.dto.sdk.request.StatusItemAddRequest;
|
||||
import io.metersphere.system.dto.sdk.request.StatusItemUpdateRequest;
|
||||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.system.domain.StatusItem;
|
||||
import io.metersphere.system.dto.StatusItemDTO;
|
||||
import io.metersphere.system.service.BaseStatusFlowSettingService;
|
||||
import io.metersphere.system.service.OrganizationService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -104,6 +103,7 @@ public class ProjectStatusFlowSettingService extends BaseStatusFlowSettingServic
|
||||
* 更新状态流配置
|
||||
* @param request
|
||||
*/
|
||||
@Override
|
||||
public void updateStatusFlow(StatusFlowUpdateRequest request) {
|
||||
StatusItem fromStatusItem = baseStatusItemService.getWithCheck(request.getFromId());
|
||||
StatusItem toStatusItem = baseStatusItemService.getWithCheck(request.getToId());
|
||||
|
@ -16,8 +16,8 @@ import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.domain.*;
|
||||
import io.metersphere.system.dto.ProjectDTO;
|
||||
import io.metersphere.system.dto.sdk.TemplateDTO;
|
||||
import io.metersphere.system.mapper.CustomFieldOptionMapper;
|
||||
import io.metersphere.system.dto.sdk.request.TemplateUpdateRequest;
|
||||
import io.metersphere.system.mapper.CustomFieldOptionMapper;
|
||||
import io.metersphere.system.service.BaseTemplateService;
|
||||
import io.metersphere.system.service.PlatformPluginService;
|
||||
import io.metersphere.system.service.PluginLoadService;
|
||||
@ -227,13 +227,13 @@ public class ProjectTemplateService extends BaseTemplateService {
|
||||
* @return
|
||||
*/
|
||||
public Template getPluginBugTemplate(String projectId) {
|
||||
ServiceIntegration serviceIntegration = getServiceIntegration(projectId);
|
||||
ServiceIntegration serviceIntegration = projectApplicationService.getPlatformServiceIntegrationWithSyncOrDemand(projectId, true);
|
||||
if (serviceIntegration == null) {
|
||||
return null;
|
||||
}
|
||||
Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(),
|
||||
serviceIntegration.getOrganizationId(), new String(serviceIntegration.getConfiguration()));
|
||||
if (platform != null && platform.isThirdPartTemplateSupport()) {
|
||||
if (platform != null && platform.isSupportDefaultTemplate()) {
|
||||
return getPluginBugTemplate(projectId, serviceIntegration.getPluginId()); // 该插件支持第三方平台模板
|
||||
}
|
||||
return null;
|
||||
@ -254,37 +254,6 @@ public class ProjectTemplateService extends BaseTemplateService {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果项目下配置了第三方平台信息
|
||||
* 获取对应的服务集成信息
|
||||
*
|
||||
* @param projectId
|
||||
* @return
|
||||
*/
|
||||
public ServiceIntegration getServiceIntegration(String projectId) {
|
||||
// 判断项目是否开启集成缺陷
|
||||
ProjectApplication syncEnableConfig = projectApplicationService.getByType(projectId, ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name());
|
||||
boolean isSyncEnable = syncEnableConfig != null && Boolean.parseBoolean(syncEnableConfig.getTypeValue());
|
||||
if (!isSyncEnable) {
|
||||
return null;
|
||||
}
|
||||
ProjectDTO project = projectService.getProjectById(projectId);
|
||||
// 查询组织下有权限的插件
|
||||
Set<String> orgPluginIds = platformPluginService.getOrgEnabledPlatformPlugins(project.getOrganizationId())
|
||||
.stream()
|
||||
.map(Plugin::getId)
|
||||
.collect(Collectors.toSet());
|
||||
// 查询服务集成中启用并且支持第三方模板的插件
|
||||
return serviceIntegrationService.getServiceIntegrationByOrgId(project.getOrganizationId())
|
||||
.stream()
|
||||
.filter(serviceIntegration -> {
|
||||
return serviceIntegration.getEnable() // 服务集成开启
|
||||
&& orgPluginIds.contains(serviceIntegration.getPluginId()); // 该服务集成对应的插件有权限
|
||||
})
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板以及字段
|
||||
* @param id
|
||||
|
@ -7,11 +7,14 @@ import io.metersphere.project.request.ProjectApplicationRequest;
|
||||
import io.metersphere.project.service.ProjectApplicationService;
|
||||
import io.metersphere.sdk.constants.ProjectApplicationType;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.base.BasePluginTestService;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.domain.Plugin;
|
||||
import io.metersphere.system.dto.request.PluginUpdateRequest;
|
||||
import io.metersphere.system.domain.ServiceIntegration;
|
||||
import io.metersphere.system.dto.request.ServiceIntegrationUpdateRequest;
|
||||
import io.metersphere.system.mapper.ServiceIntegrationMapper;
|
||||
import io.metersphere.system.service.PluginService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Getter;
|
||||
@ -22,17 +25,16 @@ import org.mockserver.model.Header;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlConfig;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
|
||||
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
|
||||
import static org.mockserver.model.HttpRequest.request;
|
||||
import static org.mockserver.model.HttpResponse.response;
|
||||
@ -46,7 +48,11 @@ public class ProjectApplicationControllerTests extends BaseTest {
|
||||
private static Plugin plugin;
|
||||
@Resource
|
||||
private PluginService pluginService;
|
||||
@Resource
|
||||
private BasePluginTestService basePluginTestService;
|
||||
|
||||
@Resource
|
||||
private ServiceIntegrationMapper serviceIntegrationMapper;
|
||||
@Resource
|
||||
private ProjectApplicationService projectApplicationService;
|
||||
|
||||
@ -374,7 +380,7 @@ public class ProjectApplicationControllerTests extends BaseTest {
|
||||
@Test
|
||||
@Order(26)
|
||||
public void testGetPlatformInfo() throws Exception {
|
||||
plugin = addPlugin();
|
||||
plugin = basePluginTestService.addJiraPlugin();
|
||||
MvcResult mvcResult = this.requestGetWithOkAndReturn(GET_PLATFORM_INFO_URL + "/" + plugin.getId());
|
||||
// 获取返回值
|
||||
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
@ -467,23 +473,6 @@ public class ProjectApplicationControllerTests extends BaseTest {
|
||||
* ==========缺陷管理 end==========
|
||||
*/
|
||||
|
||||
|
||||
public Plugin addPlugin() throws Exception {
|
||||
PluginUpdateRequest request = new PluginUpdateRequest();
|
||||
File jarFile = new File(
|
||||
this.getClass().getClassLoader().getResource("file/metersphere-jira-plugin-3.x.jar")
|
||||
.getPath()
|
||||
);
|
||||
FileInputStream inputStream = new FileInputStream(jarFile);
|
||||
MockMultipartFile mockMultipartFile = new MockMultipartFile(jarFile.getName(), jarFile.getName(), "jar", inputStream);
|
||||
request.setName("测试插件1");
|
||||
request.setGlobal(true);
|
||||
request.setEnable(true);
|
||||
request.setCreateUser(ADMIN.name());
|
||||
return pluginService.add(request, mockMultipartFile);
|
||||
}
|
||||
|
||||
|
||||
private ProjectApplicationRequest getRequest(String type) {
|
||||
ProjectApplicationRequest request = new ProjectApplicationRequest();
|
||||
request.setProjectId(PROJECT_ID);
|
||||
@ -704,4 +693,56 @@ public class ProjectApplicationControllerTests extends BaseTest {
|
||||
projectApplicationService.getPlatformName(PROJECT_ID);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Order(99)
|
||||
void coverPlatformTest() {
|
||||
// 没有配置平台的项目
|
||||
try {
|
||||
projectApplicationService.getPlatform("default-project-for-application-not-exist", true);
|
||||
} catch (Exception e) {
|
||||
Assertions.assertEquals(e.getMessage(), Translator.get("third_party_not_config"));
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取需求配置
|
||||
projectApplicationService.getPlatform("default-project-for-application", false);
|
||||
} catch (Exception e) {
|
||||
Assertions.assertEquals(e.getMessage(), Translator.get("third_party_not_config"));
|
||||
}
|
||||
|
||||
ServiceIntegration record = new ServiceIntegration();
|
||||
try {
|
||||
// 关闭集成
|
||||
record.setId("621103810617345");
|
||||
record.setEnable(false);
|
||||
serviceIntegrationMapper.updateByPrimaryKeySelective(record);
|
||||
projectApplicationService.getPlatform("default-project-for-application", true);
|
||||
} catch (Exception e) {
|
||||
Assertions.assertEquals(e.getMessage(), Translator.get("third_party_not_config"));
|
||||
}
|
||||
|
||||
try {
|
||||
// 集成Tapd
|
||||
record.setEnable(true);
|
||||
record.setPluginId("Tapd");
|
||||
serviceIntegrationMapper.updateByPrimaryKeySelective(record);
|
||||
projectApplicationService.getPlatform("default-project-for-application", true);
|
||||
} catch (Exception e) {
|
||||
Assertions.assertEquals(e.getMessage(), Translator.get("third_party_not_config"));
|
||||
}
|
||||
|
||||
// 获取缺陷同步配置平台
|
||||
projectApplicationService.getPlatform("default-project-for-application", true);
|
||||
// 获取同步机制
|
||||
Assertions.assertTrue(projectApplicationService.isPlatformSyncMethodByIncrement("default-project-for-application"));
|
||||
Assertions.assertFalse(projectApplicationService.isPlatformSyncMethodByIncrement("default-project-for-application-not-exist"));
|
||||
|
||||
// 过滤Local平台项目
|
||||
projectApplicationService.filterNoLocalPlatform(new ArrayList<>(List.of("default-project-for-application")));
|
||||
projectApplicationService.filterNoLocalPlatform(new ArrayList<>(List.of("default-project-for-application-not-exist")));
|
||||
// 移除插件测试
|
||||
basePluginTestService.deleteJiraPlugin();
|
||||
projectApplicationService.filterNoLocalPlatform(new ArrayList<>(List.of("default-project-for-application")));
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import io.metersphere.sdk.constants.SessionConstants;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.base.BaseTest;
|
||||
import io.metersphere.system.controller.handler.ResultHolder;
|
||||
import io.metersphere.system.log.constants.OperationLogType;
|
||||
import io.metersphere.system.utils.Pager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.*;
|
||||
@ -133,8 +132,6 @@ public class ProjectMemberControllerTests extends BaseTest {
|
||||
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-del"));
|
||||
request.setRoleIds(List.of("project_admin", "project_admin_x", "project_member"));
|
||||
this.requestPost(ADD_MEMBER, request, status().isOk());
|
||||
// 日志
|
||||
checkLog("default-project-member-user-1", OperationLogType.ADD);
|
||||
// 权限校验
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_USER_ADD, ADD_MEMBER, request);
|
||||
@ -172,8 +169,6 @@ public class ProjectMemberControllerTests extends BaseTest {
|
||||
// 存在的用户组
|
||||
request.setRoleIds(List.of("project_admin", "project_member"));
|
||||
this.requestPost(UPDATE_MEMBER, request, status().isOk());
|
||||
// 日志
|
||||
checkLog("default-project-member-user-1", OperationLogType.UPDATE);
|
||||
// 权限校验
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_USER_UPDATE, UPDATE_MEMBER, request);
|
||||
@ -193,8 +188,6 @@ public class ProjectMemberControllerTests extends BaseTest {
|
||||
@Order(11)
|
||||
public void testRemoveMemberSuccess() throws Exception {
|
||||
this.requestGet(REMOVE_MEMBER + "/default-project-member-test/default-project-member-user-1", status().isOk());
|
||||
// 日志
|
||||
checkLog("default-project-member-user-1", OperationLogType.DELETE);
|
||||
// 权限校验
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_USER_DELETE, REMOVE_MEMBER + "/" + DEFAULT_PROJECT_ID + "/default-project-member-user-1");
|
||||
}
|
||||
@ -213,8 +206,6 @@ public class ProjectMemberControllerTests extends BaseTest {
|
||||
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-2"));
|
||||
request.setRoleIds(List.of("project_admin", "project_member"));
|
||||
this.requestPost(ADD_ROLE, request, status().isOk());
|
||||
// 日志
|
||||
checkLog("default-project-member-user-2", OperationLogType.UPDATE);
|
||||
// 权限校验
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_USER_UPDATE, ADD_ROLE, request);
|
||||
@ -237,8 +228,6 @@ public class ProjectMemberControllerTests extends BaseTest {
|
||||
request.setProjectId("default-project-member-test");
|
||||
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-2"));
|
||||
this.requestPost(BATCH_REMOVE_MEMBER, request, status().isOk());
|
||||
// 日志
|
||||
checkLog("default-project-member-user-1", OperationLogType.DELETE);
|
||||
// 权限校验
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_USER_DELETE, BATCH_REMOVE_MEMBER, request);
|
||||
|
@ -1,5 +1,5 @@
|
||||
-- 模拟数据
|
||||
INSERT INTO `service_integration`(`id`, `plugin_id`, `enable`, `configuration`, `organization_id`) VALUES ('1', 'jira', b'1', '1111', '100002');
|
||||
INSERT INTO `service_integration`(`id`, `plugin_id`, `enable`, `configuration`, `organization_id`) VALUES ('1', 'jira', b'1', 0x504B0304140008080800BC517657000000000000000000000000030000007A6970258DC10EC2201044FF65CF06D2C498D89347B5574FBD6D8158222CD85D6268E3BF4BE3F5CDBC990DD0DAC531430FB348E65EEBE06B41AAA9289480CC1E4991130D07C022F3A366D7DA13B2373B32261592469AF1572FCF883E289362CB735BF8A4C5EE073474C3CB8E59A6F85EEFF12AE676EC4E67F8FE00504B0708384DA4307800000087000000504B01021400140008080800BC517657384DA43078000000870000000300000000000000000000000000000000007A6970504B0506000000000100010031000000A90000000000, '100002');
|
||||
|
||||
|
||||
-- 模拟用户
|
||||
@ -10,5 +10,22 @@ replace INTO user(id, name, email, password, create_time, update_time, language,
|
||||
|
||||
replace INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUES (UUID_SHORT(), 'wx-test', 'project_admin', '100001100001', '100001', 1684747668375, 'admin');
|
||||
|
||||
INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUE
|
||||
('default-project-for-application', null, '100002', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
||||
|
||||
-- 集成信息
|
||||
INSERT INTO project_application (project_id, type, type_value) VALUES
|
||||
('default-project-for-application', 'BUG_DEFAULT_TEMPLATE', 'default-bug-template-id'),
|
||||
('default-project-for-application', 'BUG_SYNC_BUG_PLATFORM_CONFIG', '{"jiraKey":"TES","jiraBugTypeId":"10009"}'),
|
||||
('default-project-for-application', 'BUG_SYNC_CRON_EXPRESSION', '0 0 0/1 * * ?'),
|
||||
('default-project-for-application', 'BUG_SYNC_MECHANISM', 'increment'),
|
||||
('default-project-for-application', 'BUG_SYNC_PLATFORM_KEY', 'jira'),
|
||||
('default-project-for-application', 'BUG_SYNC_SYNC_ENABLE', 'true'),
|
||||
('default-project-for-application', 'CASE_ENABLE', 'false'),
|
||||
('default-project-for-application', 'CASE_RELATED_DEMAND_PLATFORM_CONFIG', '{"jiraKey":"TES","jiraDemandTypeId":"10007"}'),
|
||||
('default-project-for-application', 'CASE_RELATED_PLATFORM_KEY', 'jira');
|
||||
|
||||
|
||||
INSERT INTO service_integration(`id`, `plugin_id`, `enable`, `configuration`, `organization_id`) VALUES
|
||||
('621103810617345', 'jira', true, 0x504B0304140008080800BC517657000000000000000000000000030000007A6970258DC10EC2201044FF65CF06D2C498D89347B5574FBD6D8158222CD85D6268E3BF4BE3F5CDBC990DD0DAC531430FB348E65EEBE06B41AAA9289480CC1E4991130D07C022F3A366D7DA13B2373B32261592469AF1572FCF883E289362CB735BF8A4C5EE073474C3CB8E59A6F85EEFF12AE676EC4E67F8FE00504B0708384DA4307800000087000000504B01021400140008080800BC517657384DA43078000000870000000300000000000000000000000000000000007A6970504B0506000000000100010031000000A90000000000, '100002');
|
||||
|
||||
|
@ -8,3 +8,6 @@ VALUES ('test_template_id_2', 'functional_default', '', b'0', 1696992836000, 169
|
||||
INSERT INTO template_custom_field(id, field_id, template_id, required, pos, api_field_id, default_value) VALUES ('100555929702891957', '100555929702891955', 'test_template_id_2', b'1', 0, NULL, NULL);
|
||||
|
||||
INSERT INTO custom_field(id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, ref_id, enable_option_key, scope_id) VALUES ('100555929702891955', '测试自定义字段', 'FUNCTIONAL', 'SELECT', '', b'0', 'ORGANIZATION', 1698810592000, 1698810592000, 'admin', NULL, b'0', '100001');
|
||||
|
||||
INSERT INTO project_application (project_id, type, type_value) VALUES
|
||||
('100001100001', 'BUG_SYNC_PLATFORM_KEY', 'jira');
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user