refactor(缺陷管理): 优化第三方插件模板字段&&同步逻辑

This commit is contained in:
song-cc-rock 2023-12-28 18:56:39 +08:00 committed by Craftsman
parent 3f6ba6680c
commit a4e739eee8
8 changed files with 110 additions and 36 deletions

View File

@ -9,9 +9,9 @@ import java.util.Map;
public class DemandRelatePageResponse {
/**
* 自定义表头字段
* 自定义表头字段(支持过滤)
*/
private Map<String, String> customHeaderMap;
private List<PlatformCustomFieldItemDTO> customHeaders;
/**
* 需求列表数据
*/

View File

@ -19,5 +19,5 @@ public class PlatformBugDTO extends MsSyncBugDTO {
/**
* 缺陷同步所需处理的平台自定义字段ID(同步第三方平台到MS时需要, 非默认模板时使用)
*/
private List<String> needSyncCustomFields;
private List<PlatformCustomFieldItemDTO> needSyncCustomFields;
}

View File

@ -5,7 +5,7 @@ import lombok.Data;
@Data
public class PluginPager<T> {
private T list;
private T data;
private long total;
private long pageSize;
private long current;
@ -13,8 +13,15 @@ public class PluginPager<T> {
public PluginPager() {
}
public PluginPager(long pageSize, long current) {
this.data = null;
this.total = 0;
this.pageSize = pageSize;
this.current = current;
}
public PluginPager(T list, long total, long pageSize, long current) {
this.list = list;
this.data = list;
this.total = total;
this.pageSize = pageSize;
this.current = current;

View File

@ -394,8 +394,14 @@ public class BugService {
// 非平台默认模板, 需处理MS模板中映射的字段
if (!platformBug.getPlatformDefaultTemplate()) {
List<TemplateCustomField> templateCustomFields = templateFieldMap.get(platformBug.getTemplateId());
List<String> needSyncApiFields = templateCustomFields.stream().map(TemplateCustomField::getApiFieldId).filter(StringUtils::isNotBlank).toList();
platformBug.setNeedSyncCustomFields(needSyncApiFields);
List<PlatformCustomFieldItemDTO> needSyncFields = templateCustomFields.stream().filter(templateCustomField -> StringUtils.isNotBlank(templateCustomField.getApiFieldId())).map(templateCustomField -> {
PlatformCustomFieldItemDTO needSyncField = new PlatformCustomFieldItemDTO();
needSyncField.setId(templateCustomField.getFieldId());
needSyncField.setCustomData(templateCustomField.getApiFieldId());
return needSyncField;
}).toList();
// 需同步的自定义字段
platformBug.setNeedSyncCustomFields(needSyncFields);
}
});
request.setBugs(platformBugs);
@ -467,13 +473,16 @@ public class BugService {
// 来自平台模板
templateDTO.setPlatformDefault(false);
String platformName = projectApplicationService.getPlatformName(projectId);
// TODO: 严重程度
// 状态字段
attachTemplateStatusField(templateDTO, projectId, fromStatusId, platformBugKey);
// 处理人字段
if (!StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) {
// 获取插件中自定义的注入字段(处理人)
ServiceIntegration serviceIntegration = projectApplicationService.getPlatformServiceIntegrationWithSyncOrDemand(projectId, true);
if (serviceIntegration == null) {
return null;
}
// 状态选项获取时, 获取平台校验了服务集成配置, 所以此处不需要再次校验
Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(),
new String(serviceIntegration.getConfiguration()));
AbstractPlatformPlugin platformPlugin = (AbstractPlatformPlugin) pluginLoadService.getMsPluginManager().getPlugin(serviceIntegration.getPluginId()).getPlugin();
@ -489,7 +498,7 @@ public class BugService {
request.setOptionMethod(injectField.getOptionMethod());
request.setProjectConfig(projectApplicationService.getProjectBugThirdPartConfig(projectId));
templateCustomFieldDTO.setPlatformOptionJson(JSON.toJSONString(platform.getFormOptions(request)));
templateDTO.getCustomFields().addLast(templateCustomFieldDTO);
templateDTO.getCustomFields().addFirst(templateCustomFieldDTO);
}
} else {
// Local(处理人)
@ -508,11 +517,10 @@ public class BugService {
handleUserField.setType(CustomFieldType.SELECT.getType());
handleUserField.setPlatformOptionJson(JSON.toJSONString(projectMemberOptions));
handleUserField.setRequired(true);
templateDTO.getCustomFields().addLast(handleUserField);
templateDTO.getCustomFields().addFirst(handleUserField);
}
// TODO: 严重程度
// 状态字段
return attachTemplateStatusField(templateDTO, projectId, fromStatusId, platformBugKey);
return templateDTO;
}
/**
@ -523,14 +531,17 @@ public class BugService {
* @param platformBugKey 平台缺陷key
* @return 模板
*/
private TemplateDTO attachTemplateStatusField(TemplateDTO templateDTO , String projectId, String fromStatusId, String platformBugKey) {
public TemplateDTO attachTemplateStatusField(TemplateDTO templateDTO , String projectId, String fromStatusId, String platformBugKey) {
if (templateDTO == null) {
return null;
}
TemplateCustomFieldDTO statusField = new TemplateCustomFieldDTO();
statusField.setFieldId(BugTemplateCustomField.STATUS.getId());
statusField.setFieldName(BugTemplateCustomField.STATUS.getName());
statusField.setType(CustomFieldType.SELECT.getType());
statusField.setPlatformOptionJson(JSON.toJSONString(bugStatusService.getToStatusItemOption(projectId, fromStatusId, platformBugKey)));
statusField.setRequired(true);
templateDTO.getCustomFields().addLast(statusField);
templateDTO.getCustomFields().addFirst(statusField);
return templateDTO;
}
@ -556,8 +567,8 @@ public class BugService {
// 设置基础字段
if (StringUtils.equalsIgnoreCase(BugPlatform.LOCAL.getName(), platformName)) {
bug.setPlatformBugId(null);
// Local缺陷处理人从自定义字段中获取
bug.setPlatformBugId(null);
// Local缺陷处理人从自定义字段中获取
Optional<BugCustomFieldDTO> handleUserField = request.getCustomFields().stream().filter(field -> StringUtils.equals(field.getId(), BugTemplateCustomField.HANDLE_USER.getId())).findFirst();
if (handleUserField.isPresent()) {
bug.setHandleUser(handleUserField.get().getValue());
@ -566,19 +577,21 @@ public class BugService {
throw new MSException(Translator.get("handle_user_can_not_be_empty"));
}
} else {
bug.setPlatformBugId(platformBug.getPlatformBugKey());
if (StringUtils.isNotBlank(platformBug.getPlatformTitle())) {
bug.setPlatformBugId(platformBug.getPlatformBugKey());
if (StringUtils.isNotBlank(platformBug.getPlatformTitle())) {
bug.setTitle(platformBug.getPlatformTitle());
}
if (StringUtils.isNotBlank(platformBug.getPlatformDescription())) {
}
if (StringUtils.isNotBlank(platformBug.getPlatformDescription())) {
request.setDescription(platformBug.getPlatformDescription());
}
if (StringUtils.isNotBlank(platformBug.getPlatformHandleUser())) {
}
if (StringUtils.isNotBlank(platformBug.getPlatformHandleUser())) {
bug.setHandleUser(platformBug.getPlatformHandleUser());
}
if (StringUtils.isNotBlank(platformBug.getPlatformStatus())) {
}
if (StringUtils.isNotBlank(platformBug.getPlatformStatus())) {
bug.setStatus(platformBug.getPlatformStatus());
}
}
// 第三方平台内置的处理人字段需要从自定义字段中移除
request.getCustomFields().removeIf(field -> StringUtils.startsWith(field.getName(), BugTemplateCustomField.HANDLE_USER.getName()));
}
//保存基础信息
@ -857,7 +870,7 @@ public class BugService {
*/
TemplateDTO pluginDefaultTemplate = getPluginBugDefaultTemplate(request.getProjectId(), false);
// 参数模板为插件默认模板, 处理所有自定义字段, 无需过滤API映射
boolean noApiFilter = StringUtils.equals(pluginDefaultTemplate.getId(), request.getTemplateId());
boolean noApiFilter = pluginDefaultTemplate != null && StringUtils.equals(pluginDefaultTemplate.getId(), request.getTemplateId());
platformRequest.setCustomFieldList(transferCustomToPlatformField(request.getTemplateId(), request.getCustomFields(), noApiFilter));
// TITLE, DESCRIPTION 传到平台插件处理
platformRequest.setTitle(request.getTitle());
@ -971,6 +984,9 @@ public class BugService {
ServiceIntegration serviceIntegration = projectApplicationService.getPlatformServiceIntegrationWithSyncOrDemand(projectId, true);
TemplateDTO template = new TemplateDTO();
Template pluginTemplate = projectTemplateService.getPluginBugTemplate(projectId);
if (pluginTemplate == null) {
return null;
}
BeanUtils.copyBean(template, pluginTemplate);
if (setPluginTemplateField) {
Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(),
@ -1000,7 +1016,7 @@ public class BugService {
* @param projectId 项目ID
*/
public void clearAssociate(String bugId, String projectId) {
// 清空附件关系及附件
// 清空附件关系本地附件
FileAssociationExample example = new FileAssociationExample();
example.createCriteria().andSourceIdEqualTo(bugId).andSourceTypeEqualTo(FileAssociationSourceUtil.SOURCE_TYPE_BUG);
fileAssociationMapper.deleteByExample(example);
@ -1016,7 +1032,7 @@ public class BugService {
}
});
bugLocalAttachmentMapper.deleteByExample(attachmentExample);
// 清空关联用例
// 清空关联用例
BugRelationCaseExample relationCaseExample = new BugRelationCaseExample();
relationCaseExample.createCriteria().andBugIdEqualTo(bugId);
bugRelationCaseMapper.deleteByExample(relationCaseExample);
@ -1024,6 +1040,10 @@ public class BugService {
BugCustomFieldExample customFieldExample = new BugCustomFieldExample();
customFieldExample.createCriteria().andBugIdEqualTo(bugId);
bugCustomFieldMapper.deleteByExample(customFieldExample);
// 清空缺陷内容
BugContentExample contentExample = new BugContentExample();
contentExample.createCriteria().andBugIdEqualTo(bugId);
bugContentMapper.deleteByExample(contentExample);
}
/**

View File

@ -535,14 +535,16 @@ public class BugControllerTests extends BaseTest {
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);
this.requestPost(BUG_TEMPLATE_DETAIL, request, status().is5xxServerError());
// 开启插件集成
record.setEnable(true);
serviceIntegrationMapper.updateByPrimaryKeySelective(record);
this.requestPostWithOk(BUG_TEMPLATE_DETAIL, request);
// 关闭同步
ProjectApplicationExample example = new ProjectApplicationExample();
example.createCriteria().andProjectIdEqualTo("default-project-for-bug").andTypeEqualTo("BUG_SYNC_PLATFORM_KEY");
@ -581,6 +583,11 @@ public class BugControllerTests extends BaseTest {
this.requestMultipartWithOkAndReturn(BUG_ADD, addParam2);
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
// 添加使用Jira默认模板的缺陷
addRequest.setTemplateId("jira");
MultiValueMap<String, Object> addParam3 = getDefaultMultiPartParam(addRequest, null);
this.requestMultipart(BUG_ADD, addParam3).andExpect(status().is5xxServerError());
// 更新Jira缺陷
BugEditRequest updateRequest = buildJiraBugRequest(true);
updateRequest.setUnLinkRefIds(List.of(getAddJiraAssociateFile().getId()));
@ -665,6 +672,27 @@ public class BugControllerTests extends BaseTest {
rollBackApiField();
}
@Test
@Order(99)
void coverZentaoBugTests() throws Exception {
// 上传禅道插件
addZentaoPlugin();
// 同步配置更改为禅道
ProjectApplicationExample example = new ProjectApplicationExample();
example.createCriteria().andProjectIdEqualTo("default-project-for-bug").andTypeEqualTo("BUG_SYNC_PLATFORM_KEY");
ProjectApplication record = new ProjectApplication();
record.setTypeValue("zentao");
projectApplicationMapper.updateByExampleSelective(record, example);
// 添加禅道缺陷
BugEditRequest addRequest = buildRequest(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.requestMultipart(BUG_ADD, addParam).andExpect(status().is5xxServerError());
// 获取禅道模板(删除默认项目模板)
bugService.attachTemplateStatusField(null, null, null, null);
}
/**
* 生成请求过滤参数
* @return filter param
@ -800,7 +828,23 @@ public class BugControllerTests extends BaseTest {
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.setName("测试插件-JIRA");
request.setGlobal(true);
request.setEnable(true);
request.setCreateUser(ADMIN.name());
pluginService.add(request, mockMultipartFile);
}
/**
* 添加Jira插件供测试使用
* @throws Exception 异常
*/
public void addZentaoPlugin() throws Exception {
PluginUpdateRequest request = new PluginUpdateRequest();
File jiraTestFile = new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/metersphere-zentao-test.jar")).getPath());
FileInputStream inputStream = new FileInputStream(jiraTestFile);
MockMultipartFile mockMultipartFile = new MockMultipartFile(jiraTestFile.getName(), jiraTestFile.getName(), "jar", inputStream);
request.setName("测试插件-ZENTAO");
request.setGlobal(true);
request.setEnable(true);
request.setCreateUser(ADMIN.name());

View File

@ -14,7 +14,8 @@ INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_
('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);
('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),
('default-bug-id-jira-sync', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'jira', '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"]');
@ -61,7 +62,9 @@ INSERT INTO project_application (project_id, type, type_value) VALUES
INSERT INTO service_integration(`id`, `plugin_id`, `enable`, `configuration`, `organization_id`) VALUES
('621103810617344', 'jira', true, 0x504B0304140008080800BC517657000000000000000000000000030000007A6970258DC10EC2201044FF65CF06D2C498D89347B5574FBD6D8158222CD85D6268E3BF4BE3F5CDBC990DD0DAC531430FB348E65EEBE06B41AAA9289480CC1E4991130D07C022F3A366D7DA13B2373B32261592469AF1572FCF883E289362CB735BF8A4C5EE073474C3CB8E59A6F85EEFF12AE676EC4E67F8FE00504B0708384DA4307800000087000000504B01021400140008080800BC517657384DA43078000000870000000300000000000000000000000000000000007A6970504B0506000000000100010031000000A90000000000, '100001');
('621103810617344', 'jira', true, 0x504B0304140008080800BC517657000000000000000000000000030000007A6970258DC10EC2201044FF65CF06D2C498D89347B5574FBD6D8158222CD85D6268E3BF4BE3F5CDBC990DD0DAC531430FB348E65EEBE06B41AAA9289480CC1E4991130D07C022F3A366D7DA13B2373B32261592469AF1572FCF883E289362CB735BF8A4C5EE073474C3CB8E59A6F85EEFF12AE676EC4E67F8FE00504B0708384DA4307800000087000000504B01021400140008080800BC517657384DA43078000000870000000300000000000000000000000000000000007A6970504B0506000000000100010031000000A90000000000, '100001'),
('652096294625281', 'zentao', true, 0x504B03041400080808003B939C57000000000000000000000000030000007A6970AB564A4C49294A2D2E56B252CA282929B0D2D7373437D23334D33334D03333D3AF4ACD2B49CCD757D2514A4C4ECE2FCD2B01AA4B4CC9CDCC038A1424161797E717A500859C1373F2F3D21D8C0C0C4D811245A985A5A9C525219505A940B900C7108F784F3F377FA55A00504B07081BBBB5766A0000006E000000504B010214001400080808003B939C571BBBB5766A0000006E0000000300000000000000000000000000000000007A6970504B05060000000001000100310000009B0000000000, '100001');