refactor(项目设置): 优化缺陷同步定时任务配置逻辑
This commit is contained in:
parent
e15e0611f7
commit
97ece4ad80
|
@ -94,4 +94,10 @@ public class MsSyncBugDTO {
|
||||||
* 缺陷描述
|
* 缺陷描述
|
||||||
*/
|
*/
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缺陷位置
|
||||||
|
*/
|
||||||
|
private Long pos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ public class SyncAllBugRequest extends SyncBugRequest {
|
||||||
/**
|
/**
|
||||||
* 创建时间前后
|
* 创建时间前后
|
||||||
*/
|
*/
|
||||||
private boolean pre;
|
private Boolean pre;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 条件: 缺陷创建时间
|
* 条件: 缺陷创建时间
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class BugSyncRequest implements Serializable {
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
|
||||||
@Schema(description = "创建时间前或后", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间前或后", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private boolean pre;
|
private Boolean pre;
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private Long createTime;
|
private Long createTime;
|
||||||
|
|
|
@ -2,13 +2,18 @@ package io.metersphere.bug.job;
|
||||||
|
|
||||||
import io.metersphere.bug.service.BugSyncService;
|
import io.metersphere.bug.service.BugSyncService;
|
||||||
import io.metersphere.bug.service.XpackBugService;
|
import io.metersphere.bug.service.XpackBugService;
|
||||||
|
import io.metersphere.project.service.ProjectApplicationService;
|
||||||
import io.metersphere.sdk.util.CommonBeanFactory;
|
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||||
import io.metersphere.sdk.util.LogUtils;
|
import io.metersphere.sdk.util.LogUtils;
|
||||||
|
import io.metersphere.system.domain.ServiceIntegration;
|
||||||
import io.metersphere.system.dto.sdk.LicenseDTO;
|
import io.metersphere.system.dto.sdk.LicenseDTO;
|
||||||
import io.metersphere.system.schedule.BaseScheduleJob;
|
import io.metersphere.system.schedule.BaseScheduleJob;
|
||||||
import io.metersphere.system.service.LicenseService;
|
import io.metersphere.system.service.LicenseService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
import org.quartz.JobExecutionContext;
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobKey;
|
||||||
|
import org.quartz.TriggerKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缺陷同步定时任务
|
* 缺陷同步定时任务
|
||||||
|
@ -18,30 +23,55 @@ public class BugSyncJob extends BaseScheduleJob {
|
||||||
private final LicenseService licenseService;
|
private final LicenseService licenseService;
|
||||||
private final BugSyncService bugSyncService;
|
private final BugSyncService bugSyncService;
|
||||||
private final XpackBugService xpackBugService;
|
private final XpackBugService xpackBugService;
|
||||||
|
private final ProjectApplicationService projectApplicationService;
|
||||||
|
|
||||||
public BugSyncJob() {
|
public BugSyncJob() {
|
||||||
licenseService = CommonBeanFactory.getBean(LicenseService.class);
|
licenseService = CommonBeanFactory.getBean(LicenseService.class);
|
||||||
xpackBugService = CommonBeanFactory.getBean(XpackBugService.class);
|
xpackBugService = CommonBeanFactory.getBean(XpackBugService.class);
|
||||||
bugSyncService = CommonBeanFactory.getBean(BugSyncService.class);
|
bugSyncService = CommonBeanFactory.getBean(BugSyncService.class);
|
||||||
|
projectApplicationService = CommonBeanFactory.getBean(ProjectApplicationService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JobKey getJobKey(String resourceId) {
|
||||||
|
return new JobKey(resourceId, BugSyncJob.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TriggerKey getTriggerKey(String resourceId) {
|
||||||
|
return new TriggerKey(resourceId, BugSyncJob.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void businessExecute(JobExecutionContext context) {
|
protected void businessExecute(JobExecutionContext context) {
|
||||||
|
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
|
||||||
|
String resourceId = jobDataMap.getString("resourceId");
|
||||||
|
String userId = jobDataMap.getString("userId");
|
||||||
|
if (!checkBeforeSync(resourceId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
LogUtils.info("bug sync job start......");
|
LogUtils.info("bug sync job start......");
|
||||||
if (licenseService == null) {
|
if (licenseService == null) {
|
||||||
LogUtils.info("license is null, sync remain bug");
|
LogUtils.info("license is null, sync remain bug");
|
||||||
bugSyncService.syncPlatformBugBySchedule();
|
bugSyncService.syncPlatformBugBySchedule(resourceId, userId);
|
||||||
} else {
|
} else {
|
||||||
LicenseDTO licenseDTO = licenseService.validate();
|
LicenseDTO licenseDTO = licenseService.validate();
|
||||||
if (licenseDTO != null && licenseDTO.getLicense() != null
|
if (licenseDTO != null && licenseDTO.getLicense() != null
|
||||||
&& StringUtils.equals(licenseDTO.getStatus(), "valid")) {
|
&& StringUtils.equals(licenseDTO.getStatus(), "valid")) {
|
||||||
LogUtils.info("license is valid, sync all bug");
|
LogUtils.info("license is valid, sync all bug");
|
||||||
xpackBugService.syncPlatformBugsBySchedule();
|
xpackBugService.syncPlatformBugsBySchedule(resourceId, userId);
|
||||||
} else {
|
} else {
|
||||||
LogUtils.info("license is invalid, sync remain bug");
|
LogUtils.info("license is invalid, sync remain bug");
|
||||||
bugSyncService.syncPlatformBugBySchedule();
|
bugSyncService.syncPlatformBugBySchedule(resourceId, userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogUtils.info("bug sync job end......");
|
LogUtils.info("bug sync job end......");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步前检验, 同步配置的平台是否开启插件集成
|
||||||
|
* @return 是否放行
|
||||||
|
*/
|
||||||
|
private boolean checkBeforeSync(String projectId) {
|
||||||
|
ServiceIntegration serviceIntegration = projectApplicationService.getPlatformServiceIntegrationWithSyncOrDemand(projectId, true);
|
||||||
|
return serviceIntegration != null && serviceIntegration.getEnable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package io.metersphere.bug.service;
|
||||||
|
|
||||||
|
import io.metersphere.bug.job.BugSyncJob;
|
||||||
|
import io.metersphere.project.domain.ProjectApplication;
|
||||||
|
import io.metersphere.sdk.constants.ProjectApplicationType;
|
||||||
|
import io.metersphere.sdk.constants.ScheduleResourceType;
|
||||||
|
import io.metersphere.sdk.constants.ScheduleType;
|
||||||
|
import io.metersphere.system.domain.Schedule;
|
||||||
|
import io.metersphere.system.schedule.ScheduleService;
|
||||||
|
import io.metersphere.system.service.BaseBugScheduleService;
|
||||||
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class BugScheduleServiceImpl implements BaseBugScheduleService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ScheduleService scheduleService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBugSyncScheduleConfig(List<ProjectApplication> bugSyncConfigs, String projectId, String currentUser) {
|
||||||
|
List<ProjectApplication> syncCron = bugSyncConfigs.stream().filter(config -> config.getType().equals(ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.BUG_SYNC_CONFIG.CRON_EXPRESSION.name())).toList();
|
||||||
|
List<ProjectApplication> syncEnable = bugSyncConfigs.stream().filter(config -> config.getType().equals(ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name())).toList();
|
||||||
|
if (CollectionUtils.isNotEmpty(syncCron)) {
|
||||||
|
Boolean enable = Boolean.valueOf(syncEnable.get(0).getTypeValue());
|
||||||
|
String typeValue = syncCron.get(0).getTypeValue();
|
||||||
|
Schedule schedule = scheduleService.getScheduleByResource(projectId, BugSyncJob.class.getName());
|
||||||
|
Optional<Schedule> optional = Optional.ofNullable(schedule);
|
||||||
|
optional.ifPresentOrElse(s -> {
|
||||||
|
s.setEnable(enable);
|
||||||
|
s.setValue(typeValue);
|
||||||
|
scheduleService.editSchedule(s);
|
||||||
|
scheduleService.addOrUpdateCronJob(s, BugSyncJob.getJobKey(projectId), BugSyncJob.getTriggerKey(projectId), BugSyncJob.class);
|
||||||
|
}, () -> {
|
||||||
|
Schedule request = new Schedule();
|
||||||
|
request.setName("Bug Sync Job");
|
||||||
|
request.setResourceId(projectId);
|
||||||
|
request.setKey(IDGenerator.nextStr());
|
||||||
|
request.setProjectId(projectId);
|
||||||
|
request.setEnable(enable);
|
||||||
|
request.setCreateUser(currentUser);
|
||||||
|
request.setType(ScheduleType.CRON.name());
|
||||||
|
request.setValue(typeValue);
|
||||||
|
request.setJob(BugSyncJob.class.getName());
|
||||||
|
request.setResourceType(ScheduleResourceType.BUG_SYNC.name());
|
||||||
|
scheduleService.addSchedule(request);
|
||||||
|
scheduleService.addOrUpdateCronJob(request, BugSyncJob.getJobKey(projectId), BugSyncJob.getTriggerKey(projectId), BugSyncJob.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enableOrNotBugSyncSchedule(String projectId, String currentUser, Boolean enable) {
|
||||||
|
Schedule schedule = scheduleService.getScheduleByResource(projectId, BugSyncJob.class.getName());
|
||||||
|
if (schedule != null) {
|
||||||
|
schedule.setEnable(enable);
|
||||||
|
scheduleService.editSchedule(schedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,13 +7,11 @@ import io.metersphere.bug.dto.request.BugSyncRequest;
|
||||||
import io.metersphere.bug.enums.BugPlatform;
|
import io.metersphere.bug.enums.BugPlatform;
|
||||||
import io.metersphere.bug.mapper.BugMapper;
|
import io.metersphere.bug.mapper.BugMapper;
|
||||||
import io.metersphere.project.domain.Project;
|
import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.domain.ProjectExample;
|
|
||||||
import io.metersphere.project.mapper.ProjectMapper;
|
import io.metersphere.project.mapper.ProjectMapper;
|
||||||
import io.metersphere.project.service.ProjectApplicationService;
|
import io.metersphere.project.service.ProjectApplicationService;
|
||||||
import io.metersphere.project.service.ProjectTemplateService;
|
import io.metersphere.project.service.ProjectTemplateService;
|
||||||
import io.metersphere.sdk.constants.TemplateScene;
|
import io.metersphere.sdk.constants.TemplateScene;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.LogUtils;
|
|
||||||
import io.metersphere.system.domain.Template;
|
import io.metersphere.system.domain.Template;
|
||||||
import io.metersphere.system.domain.TemplateExample;
|
import io.metersphere.system.domain.TemplateExample;
|
||||||
import io.metersphere.system.mapper.TemplateMapper;
|
import io.metersphere.system.mapper.TemplateMapper;
|
||||||
|
@ -134,18 +132,8 @@ public class BugSyncService {
|
||||||
/**
|
/**
|
||||||
* 定时任务同步缺陷(存量)
|
* 定时任务同步缺陷(存量)
|
||||||
*/
|
*/
|
||||||
public void syncPlatformBugBySchedule() {
|
public void syncPlatformBugBySchedule(String projectId, String scheduleUser) {
|
||||||
ProjectExample example = new ProjectExample();
|
syncBugs(projectId, scheduleUser);
|
||||||
List<Project> projects = projectMapper.selectByExample(example);
|
|
||||||
List<String> allProjectIds = projects.stream().map(Project::getId).collect(Collectors.toList());
|
|
||||||
List<String> syncProjectIds = projectApplicationService.filterNeedSyncProject(allProjectIds);
|
|
||||||
syncProjectIds.forEach(id -> {
|
|
||||||
try {
|
|
||||||
syncBugs(id, "admin");
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtils.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,8 +14,10 @@ public interface XpackBugService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步系统下所有第三方平台项目缺陷(定时任务)
|
* 同步系统下所有第三方平台项目缺陷(定时任务)
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @param scheduleUser 定时任务执行用户
|
||||||
*/
|
*/
|
||||||
void syncPlatformBugsBySchedule();
|
void syncPlatformBugsBySchedule(String projectId, String scheduleUser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步当前项目第三方平台缺陷(前台调用, 全量同步)
|
* 同步当前项目第三方平台缺陷(前台调用, 全量同步)
|
||||||
|
|
|
@ -554,8 +554,7 @@ public class BugControllerTests extends BaseTest {
|
||||||
this.requestGetWithOk(BUG_HEADER_STATUS_OPTION + "/default-project-for-bug");
|
this.requestGetWithOk(BUG_HEADER_STATUS_OPTION + "/default-project-for-bug");
|
||||||
this.requestGetWithOk(BUG_HEADER_HANDLER_OPTION + "/default-project-for-bug");
|
this.requestGetWithOk(BUG_HEADER_HANDLER_OPTION + "/default-project-for-bug");
|
||||||
|
|
||||||
// 同步删除缺陷(default-bug-id-jira-sync)
|
// 同步并删除的两条缺陷
|
||||||
// 一条模板不存在的缺陷(手动删除default-bug-id-jira-sync-1, 影响后续测试)
|
|
||||||
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
|
||||||
bugMapper.deleteByPrimaryKey("default-bug-id-jira-sync-1");
|
bugMapper.deleteByPrimaryKey("default-bug-id-jira-sync-1");
|
||||||
|
|
||||||
|
@ -618,6 +617,12 @@ public class BugControllerTests extends BaseTest {
|
||||||
deleteLocalFile(updateRequest2.getId()); // 手动删除关联的文件, 重新同步时会下载平台附件
|
deleteLocalFile(updateRequest2.getId()); // 手动删除关联的文件, 重新同步时会下载平台附件
|
||||||
bugService.syncPlatformBugs(remainBugs, defaultProject, "admin");
|
bugService.syncPlatformBugs(remainBugs, defaultProject, "admin");
|
||||||
|
|
||||||
|
// 全选删除所有Jira缺陷
|
||||||
|
BugBatchRequest request = new BugBatchRequest();
|
||||||
|
request.setProjectId("default-project-for-bug");
|
||||||
|
request.setSelectAll(true);
|
||||||
|
this.requestPost(BUG_BATCH_DELETE, request);
|
||||||
|
|
||||||
// 集成配置为空
|
// 集成配置为空
|
||||||
addRequest.setProjectId("default-project-for-not-integration");
|
addRequest.setProjectId("default-project-for-not-integration");
|
||||||
MultiValueMap<String, Object> notIntegrationParam = getDefaultMultiPartParam(addRequest, file);
|
MultiValueMap<String, Object> notIntegrationParam = getDefaultMultiPartParam(addRequest, file);
|
||||||
|
@ -638,7 +643,7 @@ public class BugControllerTests extends BaseTest {
|
||||||
@Order(97)
|
@Order(97)
|
||||||
void coverSyncScheduleTests() {
|
void coverSyncScheduleTests() {
|
||||||
// 定时同步存量缺陷
|
// 定时同步存量缺陷
|
||||||
bugSyncService.syncPlatformBugBySchedule();
|
bugSyncService.syncPlatformBugBySchedule("default-project-for-bug", "admin");
|
||||||
// 异常信息
|
// 异常信息
|
||||||
bugSyncExtraService.setSyncErrorMsg("default-project-for-bug", "sync error!");
|
bugSyncExtraService.setSyncErrorMsg("default-project-for-bug", "sync error!");
|
||||||
String syncErrorMsg = bugSyncExtraService.getSyncErrorMsg("default-project-for-bug");
|
String syncErrorMsg = bugSyncExtraService.getSyncErrorMsg("default-project-for-bug");
|
||||||
|
@ -823,7 +828,7 @@ public class BugControllerTests extends BaseTest {
|
||||||
summaryField.setId("summary");
|
summaryField.setId("summary");
|
||||||
summaryField.setName("摘要");
|
summaryField.setName("摘要");
|
||||||
summaryField.setType("input");
|
summaryField.setType("input");
|
||||||
summaryField.setValue("这是一段summary内容!!!!");
|
summaryField.setValue("这是一段summary内容1!!!!");
|
||||||
BugCustomFieldDTO descriptionField = new BugCustomFieldDTO();
|
BugCustomFieldDTO descriptionField = new BugCustomFieldDTO();
|
||||||
descriptionField.setId("description");
|
descriptionField.setId("description");
|
||||||
descriptionField.setName("描述");
|
descriptionField.setName("描述");
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package io.metersphere.bug.job;
|
|
||||||
|
|
||||||
import io.metersphere.system.dto.sdk.LicenseDTO;
|
|
||||||
import io.metersphere.system.dto.sdk.LicenseInfoDTO;
|
|
||||||
import io.metersphere.system.service.LicenseService;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.junit.jupiter.api.MethodOrderer;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.TestMethodOrder;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
|
||||||
|
|
||||||
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
||||||
@AutoConfigureMockMvc
|
|
||||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
|
||||||
public class BugSyncJobTests {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private LicenseService licenseService;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void test() {
|
|
||||||
// set licenseService field to null by reflection
|
|
||||||
BugSyncJob noLicenseMockObj = new BugSyncJob();
|
|
||||||
ReflectionTestUtils.setField(noLicenseMockObj, "licenseService", null);
|
|
||||||
noLicenseMockObj.businessExecute(null);
|
|
||||||
// set mocLicenseService field
|
|
||||||
BugSyncJob syncJob = new BugSyncJob();
|
|
||||||
// mock license validate return null
|
|
||||||
Mockito.when(licenseService.validate()).thenReturn(null);
|
|
||||||
syncJob.businessExecute(null);
|
|
||||||
// mock license validate return empty info
|
|
||||||
Mockito.when(licenseService.validate()).thenReturn(new LicenseDTO());
|
|
||||||
syncJob.businessExecute(null);
|
|
||||||
// mock license validate return invalid && license info
|
|
||||||
LicenseDTO invalid = new LicenseDTO();
|
|
||||||
invalid.setStatus("invalid");
|
|
||||||
invalid.setLicense(new LicenseInfoDTO());
|
|
||||||
Mockito.when(licenseService.validate()).thenReturn(invalid);
|
|
||||||
syncJob.businessExecute(null);
|
|
||||||
// mock license validate return valid && license info
|
|
||||||
LicenseDTO valid = new LicenseDTO();
|
|
||||||
valid.setStatus("valid");
|
|
||||||
valid.setLicense(new LicenseInfoDTO());
|
|
||||||
Mockito.when(licenseService.validate()).thenReturn(valid);
|
|
||||||
syncJob.businessExecute(null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ import java.util.List;
|
||||||
public class XpackBugMockServiceImpl implements XpackBugService {
|
public class XpackBugMockServiceImpl implements XpackBugService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncPlatformBugsBySchedule() {
|
public void syncPlatformBugsBySchedule(String projectId, String scheduleUser) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -286,7 +286,7 @@ public class ProjectApplicationController {
|
||||||
@Operation(summary = "缺陷管理-同步缺陷配置")
|
@Operation(summary = "缺陷管理-同步缺陷配置")
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_APPLICATION_BUG_UPDATE)
|
@RequiresPermissions(PermissionConstants.PROJECT_APPLICATION_BUG_UPDATE)
|
||||||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateBugSyncLog(#projectId, #configs)", msClass = ProjectApplicationService.class)
|
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateBugSyncLog(#projectId, #configs)", msClass = ProjectApplicationService.class)
|
||||||
public void syncBugConfig(@PathVariable("projectId") String projectId, @RequestBody Map<String, String> configs) {
|
public void syncBugConfig(@PathVariable("projectId") String projectId, @RequestBody Map<String, Object> configs) {
|
||||||
projectApplicationService.syncBugConfig(projectId, configs, SessionUtils.getUserId());
|
projectApplicationService.syncBugConfig(projectId, configs, SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,4 +19,7 @@ public class ProjectTemplateDTO extends Template implements Serializable {
|
||||||
|
|
||||||
@Schema(description = "是否是默认模板")
|
@Schema(description = "是否是默认模板")
|
||||||
private Boolean enableDefault = false;
|
private Boolean enableDefault = false;
|
||||||
|
|
||||||
|
@Schema(description = "是否是平台自动获取模板")
|
||||||
|
private Boolean enablePlatformDefault = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package io.metersphere.project.job;
|
|
||||||
|
|
||||||
import io.metersphere.system.schedule.BaseScheduleJob;
|
|
||||||
import org.quartz.JobExecutionContext;
|
|
||||||
import org.quartz.JobKey;
|
|
||||||
import org.quartz.TriggerKey;
|
|
||||||
|
|
||||||
public class BugSyncJob extends BaseScheduleJob {
|
|
||||||
@Override
|
|
||||||
protected void businessExecute(JobExecutionContext context) {
|
|
||||||
//TODO 定时任务执行 同步issue
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JobKey getJobKey(String projectId) {
|
|
||||||
return new JobKey(projectId, BugSyncJob.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TriggerKey getTriggerKey(String projectId) {
|
|
||||||
return new TriggerKey(projectId, BugSyncJob.class.getName());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,25 +8,26 @@ import io.metersphere.project.domain.Project;
|
||||||
import io.metersphere.project.domain.ProjectApplication;
|
import io.metersphere.project.domain.ProjectApplication;
|
||||||
import io.metersphere.project.domain.ProjectApplicationExample;
|
import io.metersphere.project.domain.ProjectApplicationExample;
|
||||||
import io.metersphere.project.dto.ModuleDTO;
|
import io.metersphere.project.dto.ModuleDTO;
|
||||||
import io.metersphere.project.job.BugSyncJob;
|
|
||||||
import io.metersphere.project.mapper.*;
|
import io.metersphere.project.mapper.*;
|
||||||
import io.metersphere.project.request.ProjectApplicationRequest;
|
import io.metersphere.project.request.ProjectApplicationRequest;
|
||||||
import io.metersphere.project.utils.ModuleSortUtils;
|
import io.metersphere.project.utils.ModuleSortUtils;
|
||||||
import io.metersphere.sdk.constants.OperationLogConstants;
|
import io.metersphere.sdk.constants.OperationLogConstants;
|
||||||
import io.metersphere.sdk.constants.ProjectApplicationType;
|
import io.metersphere.sdk.constants.ProjectApplicationType;
|
||||||
import io.metersphere.sdk.constants.ScheduleResourceType;
|
|
||||||
import io.metersphere.sdk.constants.ScheduleType;
|
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
import io.metersphere.sdk.util.CommonBeanFactory;
|
||||||
import io.metersphere.sdk.util.JSON;
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.sdk.util.Translator;
|
import io.metersphere.sdk.util.Translator;
|
||||||
import io.metersphere.system.domain.*;
|
import io.metersphere.system.domain.Plugin;
|
||||||
|
import io.metersphere.system.domain.ServiceIntegration;
|
||||||
|
import io.metersphere.system.domain.ServiceIntegrationExample;
|
||||||
|
import io.metersphere.system.domain.User;
|
||||||
import io.metersphere.system.dto.sdk.OptionDTO;
|
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||||
import io.metersphere.system.log.constants.OperationLogModule;
|
import io.metersphere.system.log.constants.OperationLogModule;
|
||||||
import io.metersphere.system.log.constants.OperationLogType;
|
import io.metersphere.system.log.constants.OperationLogType;
|
||||||
import io.metersphere.system.log.dto.LogDTO;
|
import io.metersphere.system.log.dto.LogDTO;
|
||||||
import io.metersphere.system.mapper.PluginMapper;
|
import io.metersphere.system.mapper.PluginMapper;
|
||||||
import io.metersphere.system.mapper.ServiceIntegrationMapper;
|
import io.metersphere.system.mapper.ServiceIntegrationMapper;
|
||||||
import io.metersphere.system.schedule.ScheduleService;
|
import io.metersphere.system.service.BaseBugScheduleService;
|
||||||
import io.metersphere.system.service.PlatformPluginService;
|
import io.metersphere.system.service.PlatformPluginService;
|
||||||
import io.metersphere.system.service.PluginLoadService;
|
import io.metersphere.system.service.PluginLoadService;
|
||||||
import io.metersphere.system.service.ServiceIntegrationService;
|
import io.metersphere.system.service.ServiceIntegrationService;
|
||||||
|
@ -49,9 +50,6 @@ public class ProjectApplicationService {
|
||||||
@Resource
|
@Resource
|
||||||
private ProjectApplicationMapper projectApplicationMapper;
|
private ProjectApplicationMapper projectApplicationMapper;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private ScheduleService scheduleService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ExtProjectUserRoleMapper extProjectUserRoleMapper;
|
private ExtProjectUserRoleMapper extProjectUserRoleMapper;
|
||||||
|
|
||||||
|
@ -105,53 +103,13 @@ public class ProjectApplicationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doBeforeUpdate(ProjectApplication application, String currentUser) {
|
private void doBeforeUpdate(ProjectApplication application, String currentUser) {
|
||||||
//TODO 后续清理(合并完没问题再清理)===== 清理报告只有一个定时任务,项目配置时不需要在添加定时任务了
|
BaseBugScheduleService baseBugScheduleService = CommonBeanFactory.getBean(BaseBugScheduleService.class);
|
||||||
/*String type = application.getType();
|
if (StringUtils.equals(ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name(),
|
||||||
if (StringUtils.equals(type, ProjectApplicationType.TEST_PLAN.TEST_PLAN_CLEAN_REPORT.name())
|
application.getType()) && baseBugScheduleService != null) {
|
||||||
|| StringUtils.equals(type, ProjectApplicationType.UI.UI_CLEAN_REPORT.name())
|
// 缺陷同步配置开启或关闭
|
||||||
|| StringUtils.equals(type, ProjectApplicationType.LOAD_TEST.LOAD_TEST_CLEAN_REPORT.name())
|
baseBugScheduleService.enableOrNotBugSyncSchedule(application.getProjectId(), currentUser, Boolean.valueOf(application.getTypeValue()));
|
||||||
|| StringUtils.equals(type, ProjectApplicationType.API.API_CLEAN_REPORT.name())) {
|
}
|
||||||
//清除 测试计划/UI测试/性能测试/接口测试 报告 定时任务
|
|
||||||
this.doHandleSchedule(application, currentUser);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private void doHandleSchedule(ProjectApplication application, String currentUser) {
|
|
||||||
String typeValue = application.getTypeValue();
|
|
||||||
String projectId = application.getProjectId();
|
|
||||||
Boolean enable = BooleanUtils.isTrue(Boolean.valueOf(typeValue));
|
|
||||||
Schedule schedule = scheduleService.getScheduleByResource(application.getProjectId(), CleanUpReportJob.class.getName());
|
|
||||||
Optional<Schedule> optional = Optional.ofNullable(schedule);
|
|
||||||
optional.ifPresentOrElse(s -> {
|
|
||||||
s.setEnable(enable);
|
|
||||||
s.setCreateUser(currentUser);
|
|
||||||
scheduleService.editSchedule(s);
|
|
||||||
scheduleService.addOrUpdateCronJob(s,
|
|
||||||
CleanUpReportJob.getJobKey(projectId),
|
|
||||||
CleanUpReportJob.getTriggerKey(projectId),
|
|
||||||
CleanUpReportJob.class);
|
|
||||||
}, () -> {
|
|
||||||
Schedule request = new Schedule();
|
|
||||||
request.setName("Clean Report Job");
|
|
||||||
request.setResourceId(projectId);
|
|
||||||
request.setKey(projectId);
|
|
||||||
request.setProjectId(projectId);
|
|
||||||
request.setEnable(enable);
|
|
||||||
request.setCreateUser(currentUser);
|
|
||||||
request.setType(ScheduleType.CRON.name());
|
|
||||||
// 每天凌晨2点执行清理任务
|
|
||||||
request.setValue("0 0 2 * * ?");
|
|
||||||
request.setJob(CleanUpReportJob.class.getName());
|
|
||||||
request.setResourceType(ScheduleResourceType.CLEAN_REPORT.name());
|
|
||||||
scheduleService.addSchedule(request);
|
|
||||||
scheduleService.addOrUpdateCronJob(request,
|
|
||||||
CleanUpReportJob.getJobKey(projectId),
|
|
||||||
CleanUpReportJob.getTriggerKey(projectId),
|
|
||||||
CleanUpReportJob.class);
|
|
||||||
});
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取配置信息
|
* 获取配置信息
|
||||||
|
@ -237,10 +195,9 @@ public class ProjectApplicationService {
|
||||||
* @param projectId
|
* @param projectId
|
||||||
* @param configs
|
* @param configs
|
||||||
*/
|
*/
|
||||||
public void syncBugConfig(String projectId, Map<String, String> configs, String currentUser) {
|
public void syncBugConfig(String projectId, Map<String, Object> configs, String currentUser) {
|
||||||
List<ProjectApplication> bugSyncConfigs = configs.entrySet().stream().map(config -> new ProjectApplication(projectId, ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + config.getKey().toUpperCase(), config.getValue())).collect(Collectors.toList());
|
List<ProjectApplication> bugSyncConfigs = configs.entrySet().stream().map(config -> new ProjectApplication(projectId, ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + config.getKey().toUpperCase(),
|
||||||
//处理同步缺陷定时任务配置
|
(config.getValue() instanceof String) ? config.getValue().toString() : JSON.toJSONString(config.getValue()))).toList();
|
||||||
doSaveOrUpdateSchedule(bugSyncConfigs, projectId, currentUser);
|
|
||||||
ProjectApplicationExample example = new ProjectApplicationExample();
|
ProjectApplicationExample example = new ProjectApplicationExample();
|
||||||
example.createCriteria().andProjectIdEqualTo(projectId).andTypeLike(ProjectApplicationType.BUG.BUG_SYNC.name() + "%");
|
example.createCriteria().andProjectIdEqualTo(projectId).andTypeLike(ProjectApplicationType.BUG.BUG_SYNC.name() + "%");
|
||||||
if (projectApplicationMapper.countByExample(example) > 0) {
|
if (projectApplicationMapper.countByExample(example) > 0) {
|
||||||
|
@ -251,47 +208,13 @@ public class ProjectApplicationService {
|
||||||
} else {
|
} else {
|
||||||
projectApplicationMapper.batchInsert(bugSyncConfigs);
|
projectApplicationMapper.batchInsert(bugSyncConfigs);
|
||||||
}
|
}
|
||||||
}
|
// 更新缺陷定时任务配置
|
||||||
|
BaseBugScheduleService baseBugScheduleService = CommonBeanFactory.getBean(BaseBugScheduleService.class);
|
||||||
private void doSaveOrUpdateSchedule(List<ProjectApplication> bugSyncConfigs, String projectId, String currentUser) {
|
if (baseBugScheduleService != null) {
|
||||||
List<ProjectApplication> syncCron = bugSyncConfigs.stream().filter(config -> config.getType().equals(ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.BUG_SYNC_CONFIG.CRON_EXPRESSION.name())).collect(Collectors.toList());
|
baseBugScheduleService.updateBugSyncScheduleConfig(bugSyncConfigs, projectId, currentUser);
|
||||||
List<ProjectApplication> syncEnable = bugSyncConfigs.stream().filter(config -> config.getType().equals(ProjectApplicationType.BUG.BUG_SYNC.name() + "_" + ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name())).collect(Collectors.toList());
|
|
||||||
if (CollectionUtils.isNotEmpty(syncCron)) {
|
|
||||||
Boolean enable = Boolean.valueOf(syncEnable.get(0).getTypeValue());
|
|
||||||
String typeValue = syncCron.get(0).getTypeValue();
|
|
||||||
Schedule schedule = scheduleService.getScheduleByResource(projectId, BugSyncJob.class.getName());
|
|
||||||
Optional<Schedule> optional = Optional.ofNullable(schedule);
|
|
||||||
optional.ifPresentOrElse(s -> {
|
|
||||||
s.setEnable(enable);
|
|
||||||
s.setValue(typeValue);
|
|
||||||
scheduleService.editSchedule(s);
|
|
||||||
scheduleService.addOrUpdateCronJob(s,
|
|
||||||
BugSyncJob.getJobKey(projectId),
|
|
||||||
BugSyncJob.getTriggerKey(projectId),
|
|
||||||
BugSyncJob.class);
|
|
||||||
}, () -> {
|
|
||||||
Schedule request = new Schedule();
|
|
||||||
request.setName("Bug Sync Job");
|
|
||||||
request.setResourceId(projectId);
|
|
||||||
request.setKey(projectId);
|
|
||||||
request.setProjectId(projectId);
|
|
||||||
request.setEnable(enable);
|
|
||||||
request.setCreateUser(currentUser);
|
|
||||||
request.setType(ScheduleType.CRON.name());
|
|
||||||
// 每天凌晨2点执行清理任务
|
|
||||||
request.setValue(typeValue);
|
|
||||||
request.setJob(BugSyncJob.class.getName());
|
|
||||||
request.setResourceType(ScheduleResourceType.BUG_SYNC.name());
|
|
||||||
scheduleService.addSchedule(request);
|
|
||||||
scheduleService.addOrUpdateCronJob(request,
|
|
||||||
BugSyncJob.getJobKey(projectId),
|
|
||||||
BugSyncJob.getTriggerKey(projectId),
|
|
||||||
BugSyncJob.class);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取同步缺陷配置
|
* 获取同步缺陷配置
|
||||||
*
|
*
|
||||||
|
@ -604,26 +527,6 @@ public class ProjectApplicationService {
|
||||||
return getPluginName(platformKeyConfig.getTypeValue());
|
return getPluginName(platformKeyConfig.getTypeValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤出能够同步的项目
|
|
||||||
*
|
|
||||||
* @param projectIds 项目ID集合
|
|
||||||
* @return 同步的项目ID集合
|
|
||||||
*/
|
|
||||||
public List<String> filterNeedSyncProject(List<String> projectIds) {
|
|
||||||
Iterator<String> iterator = projectIds.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
String projectId = iterator.next();
|
|
||||||
ServiceIntegration serviceIntegration = getPlatformServiceIntegrationWithSyncOrDemand(projectId, true);
|
|
||||||
String platformName = getPlatformName(projectId);
|
|
||||||
if (serviceIntegration == null || StringUtils.equals("Local", platformName)) {
|
|
||||||
// 项目未配置第三方平台 或者 项目同步配置为Local
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return projectIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取项目同步机制
|
* 获取项目同步机制
|
||||||
*
|
*
|
||||||
|
|
|
@ -62,10 +62,37 @@ public class ProjectTemplateService extends BaseTemplateService {
|
||||||
public List list(String projectId, String scene) {
|
public List list(String projectId, String scene) {
|
||||||
projectService.checkResourceExist(projectId);
|
projectService.checkResourceExist(projectId);
|
||||||
List<Template> templates = super.list(projectId, scene);
|
List<Template> templates = super.list(projectId, scene);
|
||||||
|
List<ProjectTemplateDTO> templateDTOS = templates.stream().map(item -> BeanUtils.copyBean(new ProjectTemplateDTO(), item)).collect(Collectors.toList());
|
||||||
// 缺陷模板需要获取第三方平台模板
|
// 缺陷模板需要获取第三方平台模板
|
||||||
templates = addPluginBugTemplate(projectId, scene, templates);
|
if (StringUtils.equals(scene, TemplateScene.BUG.name())) {
|
||||||
|
Template pluginBugTemplate = getPluginBugTemplate(projectId);
|
||||||
|
if (pluginBugTemplate != null) {
|
||||||
|
ProjectTemplateDTO pluginTemplate = BeanUtils.copyBean(new ProjectTemplateDTO(), pluginBugTemplate);
|
||||||
|
pluginTemplate.setEnablePlatformDefault(true);
|
||||||
|
templateDTOS.add(pluginTemplate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 标记默认模板
|
// 标记默认模板
|
||||||
return tagDefaultTemplate(projectId, scene, templates);
|
// 查询项目下设置中配置的默认模板
|
||||||
|
String defaultProjectId = getDefaultTemplateId(projectId, scene);
|
||||||
|
ProjectTemplateDTO defaultTemplate = templateDTOS.stream()
|
||||||
|
.filter(t -> StringUtils.equals(defaultProjectId, t.getId()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
// 如果查询不到默认模板,设置内置模板为默认模板
|
||||||
|
if (defaultTemplate == null) {
|
||||||
|
Optional<ProjectTemplateDTO> internalTemplate = templateDTOS.stream()
|
||||||
|
.filter(ProjectTemplateDTO::getInternal).findFirst();
|
||||||
|
if (internalTemplate.isPresent()) {
|
||||||
|
defaultTemplate = internalTemplate.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defaultTemplate != null) {
|
||||||
|
defaultTemplate.setEnableDefault(true);
|
||||||
|
}
|
||||||
|
return templateDTOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,9 +31,7 @@ import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
|
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
|
||||||
|
@ -768,12 +766,5 @@ public class ProjectApplicationControllerTests extends BaseTest {
|
||||||
// 获取同步机制
|
// 获取同步机制
|
||||||
Assertions.assertTrue(projectApplicationService.isPlatformSyncMethodByIncrement("default-project-for-application"));
|
Assertions.assertTrue(projectApplicationService.isPlatformSyncMethodByIncrement("default-project-for-application"));
|
||||||
Assertions.assertFalse(projectApplicationService.isPlatformSyncMethodByIncrement("default-project-for-application-not-exist"));
|
Assertions.assertFalse(projectApplicationService.isPlatformSyncMethodByIncrement("default-project-for-application-not-exist"));
|
||||||
|
|
||||||
// 过滤Local平台项目
|
|
||||||
projectApplicationService.filterNeedSyncProject(new ArrayList<>(new ArrayList<>(List.of("default-project-for-application"))));
|
|
||||||
projectApplicationService.filterNeedSyncProject(new ArrayList<>(new ArrayList<>(List.of("default-project-for-application-not-exist"))));
|
|
||||||
// 移除插件测试
|
|
||||||
basePluginTestService.deleteJiraPlugin();
|
|
||||||
projectApplicationService.filterNeedSyncProject(new ArrayList<>(new ArrayList<>(List.of("default-project-for-application"))));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package io.metersphere.system.service;
|
||||||
|
|
||||||
|
import io.metersphere.project.domain.ProjectApplication;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface BaseBugScheduleService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新项目的缺陷同步定时任务
|
||||||
|
* @param bugSyncConfigs 配置
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @param currentUser 当前用户
|
||||||
|
*/
|
||||||
|
void updateBugSyncScheduleConfig(List<ProjectApplication> bugSyncConfigs, String projectId, String currentUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用或禁用缺陷同步定时任务
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @param currentUser 当前用户
|
||||||
|
* @param enable 开启或禁用
|
||||||
|
*/
|
||||||
|
void enableOrNotBugSyncSchedule(String projectId, String currentUser, Boolean enable);
|
||||||
|
}
|
1
pom.xml
1
pom.xml
|
@ -162,6 +162,7 @@
|
||||||
<exclude>io/metersphere/sdk/**</exclude>
|
<exclude>io/metersphere/sdk/**</exclude>
|
||||||
<exclude>io/metersphere/provider/**</exclude>
|
<exclude>io/metersphere/provider/**</exclude>
|
||||||
<exclude>io/metersphere/plugin/**</exclude>
|
<exclude>io/metersphere/plugin/**</exclude>
|
||||||
|
<exclude>io/metersphere/*/job/**</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
|
Loading…
Reference in New Issue