From 35fb2948797c451bc49ffa69e516c732fd94ae37 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Mon, 1 Dec 2025 17:54:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9E=84=E5=BB=BA=E9=80=9A?= =?UTF-8?q?=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/JenkinsBuildServiceImpl.java | 130 ++++++++---------- .../impl/JenkinsSyncHistoryServiceImpl.java | 6 +- 2 files changed, 60 insertions(+), 76 deletions(-) diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java index 9a7b7733..59edb558 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java @@ -29,6 +29,7 @@ import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest; import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest; import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum; import com.qqchen.deploy.backend.deploy.dto.sync.JenkinsSyncContext; +import com.qqchen.deploy.backend.deploy.lock.SyncLockManager; import com.qqchen.deploy.backend.framework.enums.ResponseCode; import com.qqchen.deploy.backend.framework.exception.BusinessException; import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl; @@ -108,18 +109,30 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl lastBuild = jenkinsBuildRepository.findTopByExternalSystemIdAndJobIdOrderByBuildNumberDesc( - externalSystem.getId(), job.getId()); + Integer latestBuildNumber = jobResponse.getLastBuild().getNumber(); + Integer lastSyncedBuildNumber = job.getLastBuildNumber(); - // 2. 获取需要同步的构建信息 - List newBuilds = getNewBuilds(externalSystem, job, jobResponse, lastBuild); - if (newBuilds.isEmpty()) { - log.info("No new builds to sync for job: {}", job.getJobName()); + // 1. 判断是否有新构建(对比本地缓存的 lastBuildNumber 和 Jenkins 最新的) + if (lastSyncedBuildNumber != null && latestBuildNumber <= lastSyncedBuildNumber) { + log.info("No new builds to sync for job: {} (last synced: {}, latest: {})", job.getJobName(), lastSyncedBuildNumber, latestBuildNumber); return 0; } - // 3. 保存新的构建信息 + // 2. 确定同步范围 + Integer fromBuildNumber = (lastSyncedBuildNumber != null) ? lastSyncedBuildNumber + 1 : 1; + + // 3. 获取构建信息 + List builds = jenkinsServiceIntegration.listBuilds(externalSystem, job.getJobName()); + + // 4. 过滤出需要同步的构建 + List newBuilds = builds.stream() + .filter(build -> build.getNumber() >= fromBuildNumber && build.getNumber() <= latestBuildNumber) + .collect(Collectors.toList()); + + if (newBuilds.isEmpty()) { + log.info("No new builds found for job: {} (from: {}, to: {})", job.getJobName(), fromBuildNumber, latestBuildNumber); + return 0; + } + + // 5. 保存新的构建信息 saveNewBuilds(externalSystem, job, newBuilds); - // 4. 更新任务的最新构建信息 + // 6. 更新任务的最新构建信息 updateJobLastBuild(job, jobResponse); - log.info("Successfully synchronized {} builds for job: {}", newBuilds.size(), job.getJobName()); + log.info("Successfully synchronized {} builds for job: {} (from: {}, to: {})", + newBuilds.size(), job.getJobName(), fromBuildNumber, latestBuildNumber); return newBuilds.size(); } catch (Exception e) { log.error("Failed to sync job: {}", job.getJobName(), e); @@ -245,50 +273,6 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl getNewBuilds( - ExternalSystem externalSystem, - JenkinsJob job, - JenkinsJobResponse jobResponse, - Optional lastBuild) { - - // 1. 获取最新构建号(从jobResponse中获取,避免额外的API调用) - if (jobResponse.getLastBuild() == null) { - log.info("No builds found for job: {}", job.getJobName()); - return Collections.emptyList(); - } - Integer latestBuildNumber = jobResponse.getLastBuild().getNumber(); - - // 2. 确定同步范围 - Integer fromBuildNumber; - if (lastBuild.isEmpty()) { - // 首次同步,从第一个构建开始 - log.info("First time sync for job: {}, will sync all builds", job.getJobName()); - fromBuildNumber = 1; - } else { - // 增量同步,从上次同步的下一个构建开始 - fromBuildNumber = lastBuild.get().getBuildNumber() + 1; - } - - // 3. 如果没有新的构建,直接返回 - if (fromBuildNumber > latestBuildNumber) { - log.info("No new builds to sync for job: {} (last build: {}, latest build: {})", - job.getJobName(), lastBuild.map(JenkinsBuild::getBuildNumber).orElse(null), latestBuildNumber); - return Collections.emptyList(); - } - - // 4. 获取构建信息 - List builds = jenkinsServiceIntegration.listBuilds(externalSystem, job.getJobName()); - - // 5. 过滤出需要的构建 - List newBuilds = builds.stream() - .filter(build -> build.getNumber() >= fromBuildNumber && build.getNumber() <= latestBuildNumber) - .collect(Collectors.toList()); - - log.info("Found {} new builds for job: {} (from build: {}, to build: {})", - newBuilds.size(), job.getJobName(), fromBuildNumber, latestBuildNumber); - return newBuilds; - } - private void saveNewBuilds( ExternalSystem externalSystem, JenkinsJob job, @@ -437,7 +421,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl核心流程: *
    *
  1. 获取所有绑定了该Jenkins系统的TeamApplication
  2. @@ -477,7 +461,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl teamIds = teamApps.stream().map(TeamApplication::getTeamId).collect(Collectors.toSet()); Set envIds = teamApps.stream().map(TeamApplication::getEnvironmentId).collect(Collectors.toSet()); - + List configs = teamEnvironmentNotificationConfigRepository .findByTeamIdInAndEnvironmentIdInAndBuildNotificationEnabledTrue(teamIds, envIds); if (configs.isEmpty()) { @@ -568,7 +552,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl核心逻辑: *
      *
    • 无记录 = 新构建:超时(>20分钟)直接标记完成,未超时发送"构建中"通知
    • @@ -641,7 +625,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl 0) { log.debug("changeSets 数组大小: {}", changeSets.size()); StringBuilder commitMessages = new StringBuilder(); for (JsonNode changeSet : changeSets) { JsonNode items = changeSet.get("items"); log.debug("items 节点: {}", items); - + if (items != null && items.isArray()) { log.debug("items 数组大小: {}", items.size()); for (JsonNode item : items) { log.debug("处理 item: {}", item); - + // Jenkins API 返回的字段名是 msg String msg = item.has("msg") ? item.get("msg").asText() : ""; - + // author 是一个对象,需要提取 fullName 或其他字段 String author = ""; if (item.has("author")) { JsonNode authorNode = item.get("author"); log.debug("author 节点: {}", authorNode); - + if (authorNode.isTextual()) { // 如果是字符串,直接使用 author = authorNode.asText(); @@ -892,7 +876,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl