diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/JenkinsInstanceDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/JenkinsInstanceDTO.java index a82d207b..a43bf078 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/JenkinsInstanceDTO.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/JenkinsInstanceDTO.java @@ -18,10 +18,16 @@ public class JenkinsInstanceDTO extends BaseDTO { private int totalViews; + private LocalDateTime lastSyncViewsTime; + private int totalJobs; + private LocalDateTime lastSyncJobsTime; + private int totalBuilds; + private LocalDateTime lastSyncBuildsTime; + private List jenkinsViewList; private List jenkinsJobList; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IJenkinsServiceIntegration.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IJenkinsServiceIntegration.java index 73763e93..81d533ba 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IJenkinsServiceIntegration.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IJenkinsServiceIntegration.java @@ -68,6 +68,8 @@ public interface IJenkinsServiceIntegration extends IExternalSystemIntegration { */ List listJobs(ExternalSystem externalSystem, String viewName); + JenkinsJobResponse job(ExternalSystem externalSystem, String jobName); + /** * 查询任务的构建信息 * diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/JenkinsServiceIntegration.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/JenkinsServiceIntegration.java index a17b0f63..aa4aef11 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/JenkinsServiceIntegration.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/JenkinsServiceIntegration.java @@ -1,13 +1,11 @@ package com.qqchen.deploy.backend.deploy.integration.impl; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.qqchen.deploy.backend.deploy.entity.ExternalSystem; import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus; import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration; -import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildInfoResponse; import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildResponse; import com.qqchen.deploy.backend.deploy.integration.response.JenkinsJobResponse; import com.qqchen.deploy.backend.deploy.integration.response.JenkinsQueueBuildInfoResponse; @@ -28,9 +26,6 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import org.apache.commons.lang3.StringUtils; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; import java.util.Base64; import java.util.Collections; import java.util.List; @@ -345,6 +340,48 @@ public class JenkinsServiceIntegration implements IJenkinsServiceIntegration { .toList(); } + @Override + public JenkinsJobResponse job(ExternalSystem externalSystem, String jobName) { + try { + // 1. 构建请求URL + String url = UriComponentsBuilder.fromHttpUrl(externalSystem.getUrl()) + .path("/job/") + .path(jobName) + .path("/api/json") + .queryParam("tree", "name,url,description,buildable,nextBuildNumber,lastBuild[number,timestamp,result],color,healthReport[score,description]") + .build() + .toUriString(); + + // 2. 发送请求 + HttpEntity entity = new HttpEntity<>(createHeaders(externalSystem)); + ResponseEntity response = restTemplate.exchange( + url, + HttpMethod.GET, + entity, + String.class + ); + + // 3. 解析响应 + if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) { + ObjectMapper mapper = new ObjectMapper(); + JenkinsJobResponse jobResponse = mapper.readValue(response.getBody(), JenkinsJobResponse.class); + + // 4. 清理URL,移除基础URL部分 + if (jobResponse.getUrl() != null) { + String baseUrl = StringUtils.removeEnd(externalSystem.getUrl(), "/"); + jobResponse.setUrl(jobResponse.getUrl().replace(baseUrl, "")); + } + + return jobResponse; + } + + return null; + } catch (Exception e) { + log.error("Failed to get Jenkins job: jobName={}, error={}", jobName, e.getMessage(), e); + throw new RuntimeException("获取Jenkins任务失败: " + jobName, e); + } + } + /** * 查询任务的构建信息 * diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IJenkinsSyncHistoryRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IJenkinsSyncHistoryRepository.java index e3d2cd5b..ce23135a 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IJenkinsSyncHistoryRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IJenkinsSyncHistoryRepository.java @@ -2,6 +2,8 @@ package com.qqchen.deploy.backend.deploy.repository; import com.qqchen.deploy.backend.framework.repository.IBaseRepository; import com.qqchen.deploy.backend.deploy.entity.JenkinsSyncHistory; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.JenkinsSyncType; import org.springframework.stereotype.Repository; /** @@ -10,4 +12,18 @@ import org.springframework.stereotype.Repository; @Repository public interface IJenkinsSyncHistoryRepository extends IBaseRepository { JenkinsSyncHistory findByNumber(String number); + + /** + * 查找最后一次成功同步记录 + * + * @param externalSystemId 外部系统ID + * @param syncType 同步类型 + * @param status 同步状态 + * @return 同步历史记录 + */ + JenkinsSyncHistory findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + Long externalSystemId, + JenkinsSyncType syncType, + ExternalSystemSyncStatus status + ); } \ No newline at end of file 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 35728351..9c6e1a33 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 @@ -11,6 +11,7 @@ import com.qqchen.deploy.backend.deploy.dto.JenkinsBuildDTO; import com.qqchen.deploy.backend.deploy.entity.QJenkinsBuild; import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; import com.qqchen.deploy.backend.deploy.enums.JenkinsSyncType; +import com.qqchen.deploy.backend.deploy.integration.response.JenkinsJobResponse; import com.qqchen.deploy.backend.deploy.query.JenkinsBuildQuery; import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration; import com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildResponse; @@ -151,6 +152,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl buildResponses = jenkinsServiceIntegration.listBuilds(externalSystem, job.getJobName()); if (buildResponses.isEmpty()) { log.info("No builds found for job: {}", job.getJobName()); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsManagerServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsManagerServiceImpl.java index 4a768a07..b2a5d505 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsManagerServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsManagerServiceImpl.java @@ -9,6 +9,11 @@ import com.qqchen.deploy.backend.deploy.service.IJenkinsManagerService; import com.qqchen.deploy.backend.deploy.service.IJenkinsViewService; import com.qqchen.deploy.backend.deploy.service.IJenkinsJobService; import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService; +import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService; +import com.qqchen.deploy.backend.deploy.entity.JenkinsSyncHistory; +import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus; +import com.qqchen.deploy.backend.deploy.enums.JenkinsSyncType; +import com.qqchen.deploy.backend.deploy.repository.IJenkinsSyncHistoryRepository; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -31,23 +36,18 @@ public class JenkinsManagerServiceImpl implements IJenkinsManagerService { @Resource private IJenkinsBuildService jenkinsBuildService; + @Resource + private IJenkinsSyncHistoryRepository jenkinsSyncHistoryRepository; + @Override @Transactional(rollbackFor = Exception.class) public void syncAll(Long externalSystemId) { - // 1. 同步视图 - Integer viewCount = jenkinsViewService.syncViews(externalSystemId); - log.info("Synchronized {} views", viewCount); - - // 2. 同步任务 - Integer jobCount = jenkinsJobService.syncJobs(externalSystemId); - log.info("Synchronized {} jobs", jobCount); - - // 3. 同步构建信息 - Integer buildCount = jenkinsBuildService.syncAllBuilds(externalSystemId); - log.info("Synchronized {} builds", buildCount); - - log.info("Successfully synchronized {} views, {} jobs, and {} builds", - viewCount, jobCount, buildCount); + // 同步视图 + syncViews(externalSystemId); + // 同步任务 + syncJobs(externalSystemId); + // 同步构建信息 + syncBuilds(externalSystemId); } @Override @@ -93,6 +93,25 @@ public class JenkinsManagerServiceImpl implements IJenkinsManagerService { Long totalBuilds = jenkinsBuildService.countByExternalSystemId(externalSystemId); instanceDTO.setTotalBuilds(totalBuilds.intValue()); + // 5. 获取最后同步时间 + JenkinsSyncHistory lastViewSync = jenkinsSyncHistoryRepository.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + externalSystemId, JenkinsSyncType.VIEW, ExternalSystemSyncStatus.SUCCESS); + if (lastViewSync != null) { + instanceDTO.setLastSyncViewsTime(lastViewSync.getEndTime()); + } + + JenkinsSyncHistory lastJobSync = jenkinsSyncHistoryRepository.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + externalSystemId, JenkinsSyncType.JOB, ExternalSystemSyncStatus.SUCCESS); + if (lastJobSync != null) { + instanceDTO.setLastSyncJobsTime(lastJobSync.getEndTime()); + } + + JenkinsSyncHistory lastBuildSync = jenkinsSyncHistoryRepository.findTopByExternalSystemIdAndSyncTypeAndStatusOrderByStartTimeDesc( + externalSystemId, JenkinsSyncType.BUILD, ExternalSystemSyncStatus.SUCCESS); + if (lastBuildSync != null) { + instanceDTO.setLastSyncBuildsTime(lastBuildSync.getEndTime()); + } + return instanceDTO; } } \ No newline at end of file