From ff3fa223b2ec7ca5cff4db7737e4e130292ece93 Mon Sep 17 00:00:00 2001 From: song-cc-rock Date: Sun, 23 Apr 2023 11:28:36 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=B5=8B=E8=AF=95=E8=B7=9F=E8=B8=AA):=20?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=E5=90=8C=E6=AD=A5=E5=BC=82=E6=AD=A5=E6=89=A7?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --bug=1025655 --user=宋昌昌 【测试跟踪】项目集成jira平台,缺陷管理中同步缺陷失败 https://www.tapd.cn/55049933/s/1365554 --- .../base/domain/IssueSyncCheckResult.java | 15 ++ .../controller/IssuesController.java | 11 +- .../io/metersphere/service/IssuesService.java | 137 ++++++++++-------- test-track/frontend/src/api/issue.js | 11 +- .../frontend/src/business/issue/IssueList.vue | 49 ++++--- 5 files changed, 134 insertions(+), 89 deletions(-) create mode 100644 framework/sdk-parent/domain/src/main/java/io/metersphere/base/domain/IssueSyncCheckResult.java diff --git a/framework/sdk-parent/domain/src/main/java/io/metersphere/base/domain/IssueSyncCheckResult.java b/framework/sdk-parent/domain/src/main/java/io/metersphere/base/domain/IssueSyncCheckResult.java new file mode 100644 index 0000000000..edc556f7fe --- /dev/null +++ b/framework/sdk-parent/domain/src/main/java/io/metersphere/base/domain/IssueSyncCheckResult.java @@ -0,0 +1,15 @@ +package io.metersphere.base.domain; + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Builder +public class IssueSyncCheckResult implements Serializable { + + private Boolean syncComplete; + + private String syncResult; +} diff --git a/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java b/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java index c13f8cdb72..5af2b9a1cc 100644 --- a/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java +++ b/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java @@ -2,6 +2,7 @@ package io.metersphere.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.metersphere.base.domain.IssueSyncCheckResult; import io.metersphere.base.domain.Issues; import io.metersphere.base.domain.IssuesWithBLOBs; import io.metersphere.base.domain.Project; @@ -157,17 +158,17 @@ public class IssuesController { } @GetMapping("/sync/{projectId}") - public boolean syncThirdPartyIssues(@PathVariable String projectId) { - return issuesService.syncThirdPartyIssues(projectId); + public void syncThirdPartyIssues(@PathVariable String projectId) { + issuesService.syncThirdPartyIssues(projectId); } @PostMapping("/sync/all") - public boolean syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) { - return issuesService.syncThirdPartyAllIssues(request); + public void syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) { + issuesService.syncThirdPartyAllIssues(request); } @GetMapping("/sync/check/{projectId}") - public boolean checkSync(@PathVariable String projectId) { + public IssueSyncCheckResult checkSync(@PathVariable String projectId) { return issuesService.checkSync(projectId); } diff --git a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java index dd0245828a..31c418b4f4 100644 --- a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java +++ b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java @@ -151,6 +151,7 @@ public class IssuesService { private IssuesService issuesService; private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC"; + private static final String SYNC_THIRD_PARTY_ISSUES_ERROR_KEY = "ISSUE:SYNC:ERROR"; public void testAuth(String workspaceId, String platform) { IssuesRequest issuesRequest = new IssuesRequest(); @@ -899,12 +900,20 @@ public class IssuesService { LogUtil.info("测试计划-测试用例同步缺陷信息结束"); } - public boolean checkSync(String projectId) { + public IssueSyncCheckResult checkSync(String projectId) { + IssueSyncCheckResult issueSyncCheckResult = IssueSyncCheckResult.builder().syncComplete(Boolean.FALSE).syncResult(StringUtils.EMPTY).build(); String syncValue = getSyncKey(projectId); if (StringUtils.isNotEmpty(syncValue)) { - return false; + return issueSyncCheckResult; } - return true; + issueSyncCheckResult.setSyncComplete(Boolean.TRUE); + String syncMsg = getSyncErrorMsg(projectId); + issueSyncCheckResult.setSyncResult(syncMsg); + if (StringUtils.isNotEmpty(syncMsg)) { + // 清空同步异常信息 + deleteSyncErrorMsg(projectId); + } + return issueSyncCheckResult; } public String getSyncKey(String projectId) { @@ -920,45 +929,56 @@ public class IssuesService { stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_KEY + ":" + projectId); } + public void setSyncErrorMsg(String projectId, String errorMsg) { + stringRedisTemplate.opsForValue().set(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId, errorMsg, 30, TimeUnit.SECONDS); + } + + public String getSyncErrorMsg(String projectId) { + return stringRedisTemplate.opsForValue().get(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId); + } + + public void deleteSyncErrorMsg(String projectId) { + stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId); + } + @Transactional(propagation = Propagation.REQUIRES_NEW) - public boolean syncThirdPartyIssues(String projectId) { + public void syncThirdPartyIssues(String projectId) { if (StringUtils.isNotBlank(projectId)) { String syncValue = getSyncKey(projectId); - if (StringUtils.isNotEmpty(syncValue)) { - return false; - } + if (StringUtils.isEmpty(syncValue)) { + setSyncKey(projectId); + Project project = baseProjectService.getProjectById(projectId); + List issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform()); - setSyncKey(projectId); - - Project project = baseProjectService.getProjectById(projectId); - List issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform()); - - if (CollectionUtils.isEmpty(issues)) { - deleteSyncKey(projectId); - return true; - } - - IssuesRequest issuesRequest = new IssuesRequest(); - issuesRequest.setProjectId(projectId); - issuesRequest.setWorkspaceId(project.getWorkspaceId()); - - try { - issuesRequest.setDefaultCustomFields(getDefaultCustomField(project)); - if (PlatformPluginService.isPluginPlatform(project.getPlatform())) { - // 分批处理 - SubListUtil.dealForSubList(issues, 500, (subIssue) -> - syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields())); + if (CollectionUtils.isEmpty(issues)) { + deleteSyncKey(projectId); } else { - IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest); - syncThirdPartyIssues(platform::syncIssues, project, issues); + new Thread(() -> { + IssuesRequest issuesRequest = new IssuesRequest(); + issuesRequest.setProjectId(projectId); + issuesRequest.setWorkspaceId(project.getWorkspaceId()); + try { + issuesRequest.setDefaultCustomFields(getDefaultCustomField(project)); + if (PlatformPluginService.isPluginPlatform(project.getPlatform())) { + // 分批处理 + SubListUtil.dealForSubList(issues, 500, (subIssue) -> + syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields())); + } else { + IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest); + syncThirdPartyIssues(platform::syncIssues, project, issues); + } + } catch (Exception e) { + LogUtil.error(e); + // 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取) + setSyncErrorMsg(projectId, e.getMessage()); + } finally { + // 异常或正常结束都得删除当前项目执行同步的Key + deleteSyncKey(projectId); + } + }).start(); } - } catch (Exception e) { - throw e; - } finally { - deleteSyncKey(projectId); } } - return true; } private String getDefaultCustomField(Project project) { @@ -1918,39 +1938,36 @@ public class IssuesService { && platformPluginService.isThirdPartTemplateSupport(project.getPlatform()); } - public boolean syncThirdPartyAllIssues(IssueSyncRequest syncRequest) { + public void syncThirdPartyAllIssues(IssueSyncRequest syncRequest) { syncRequest.setProjectId(syncRequest.getProjectId()); XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class); if (StringUtils.isNotBlank(syncRequest.getProjectId())) { // 获取当前项目执行同步缺陷Key String syncValue = getSyncKey(syncRequest.getProjectId()); - // 存在即正在同步中 - if (StringUtils.isNotEmpty(syncValue)) { - return false; - } - // 不存在则设置Key, 设置过期时间, 执行完成后delete掉 - setSyncKey(syncRequest.getProjectId()); - - try { - Project project = baseProjectService.getProjectById(syncRequest.getProjectId()); - - if (!isThirdPartTemplate(project)) { - syncRequest.setDefaultCustomFields(getDefaultCustomFields(syncRequest.getProjectId())); - } - - xpackIssueService.syncThirdPartyIssues(project, syncRequest); - - if (platformPluginService.isPluginPlatform(project.getPlatform())) { - syncAllPluginIssueAttachment(project, syncRequest); - } - } catch (Exception e) { - LogUtil.error(e); - MSException.throwException(e); - } finally { - deleteSyncKey(syncRequest.getProjectId()); + if (StringUtils.isEmpty(syncValue)) { + // 同步Key不存在, 设置保证唯一性, 并开始同步 + setSyncKey(syncRequest.getProjectId()); + new Thread(() -> { + try { + Project project = baseProjectService.getProjectById(syncRequest.getProjectId()); + if (!isThirdPartTemplate(project)) { + syncRequest.setDefaultCustomFields(getDefaultCustomFields(syncRequest.getProjectId())); + } + xpackIssueService.syncThirdPartyIssues(project, syncRequest); + if (platformPluginService.isPluginPlatform(project.getPlatform())) { + syncAllPluginIssueAttachment(project, syncRequest); + } + } catch (Exception e) { + LogUtil.error(e); + // 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取) + setSyncErrorMsg(syncRequest.getProjectId(), e.getMessage()); + } finally { + // 异常或正常结束都得删除当前项目执行同步的Key + deleteSyncKey(syncRequest.getProjectId()); + } + }).start(); } } - return true; } /** diff --git a/test-track/frontend/src/api/issue.js b/test-track/frontend/src/api/issue.js index a65f5fb25a..3a8b96130c 100644 --- a/test-track/frontend/src/api/issue.js +++ b/test-track/frontend/src/api/issue.js @@ -184,22 +184,21 @@ export function syncIssues() { } // 轮询同步状态 -export function checkSyncIssues(loading, isNotFirst) { +export function checkSyncIssues(loading, isNotFirst, callback) { let url = 'issues/sync/check/' + getCurrentProjectID() + "?stamp=" + getUUID(); return get(url) .then((response) => { - if (response.data === false) { + if (response.data.syncComplete === false) { if (loading === true) { if (!isNotFirst) { // 第一次才提示 - $warning(i18n.t('test_track.issue.issue_sync_tip')); + $warning(i18n.t('test_track.issue.issue_sync_tip'), false); } - setTimeout(() => checkSyncIssues(loading, true), 1000); + setTimeout(() => checkSyncIssues(loading, true, callback), 1000); } } else { if (loading === true) { - $success(i18n.t('test_track.issue.sync_complete')); - loading = false; + callback(response.data); } } }); diff --git a/test-track/frontend/src/business/issue/IssueList.vue b/test-track/frontend/src/business/issue/IssueList.vue index b7cca7d7d6..bf4ce439aa 100644 --- a/test-track/frontend/src/business/issue/IssueList.vue +++ b/test-track/frontend/src/business/issue/IssueList.vue @@ -12,11 +12,13 @@ @@ -248,6 +250,7 @@ export default { platformStatus: [], platformStatusMap: new Map(), hasLicense: false, + syncDisable: false, columns: { num: { sortable: true, @@ -589,38 +592,48 @@ export default { }, syncConfirm(data) { this.loading = true; + this.syncDisable = true; let param = { "projectId": getCurrentProjectID(), "createTime": data.createTime.getTime(), "pre": data.preValue } syncAllIssues(param) - .then((response) => { - if (response.data === false) { - checkSyncIssues(this.loading); - } else { - this.$success(this.$t('test_track.issue.sync_complete')); - - this.getIssues(); - } + .then(() => { + checkSyncIssues(this.loading, false, (errorData) => { + this.loading = false; + this.syncDisable = false; + if (errorData.syncResult && errorData.syncResult !== '') { + this.$error(errorData.syncResult, false); + } else { + this.$success(this.$t('test_track.issue.sync_complete'), false); + this.getIssues(); + } + }); }) - .catch(() => { - this.loading = false; - }); + .catch(() => { + this.loading = false; + this.syncDisable = false; + }); }, syncIssues() { this.loading = true; + this.syncDisable = false; syncIssues() - .then((response) => { - if (response.data === false) { - checkSyncIssues(this.loading); - } else { - this.$success(this.$t('test_track.issue.sync_complete')); + .then(() => { + checkSyncIssues(this.loading, false, (errorData) => { this.loading = false; - this.getIssues(); - } + this.syncDisable = false; + if (errorData.syncResult && errorData.syncResult !== '') { + this.$error(errorData.syncResult, false); + } else { + this.$success(this.$t('test_track.issue.sync_complete'), false); + this.getIssues(); + } + }); }).catch(() => { this.loading = false; + this.syncDisable = false; }); }, editParam() {