大声道撒旦
This commit is contained in:
parent
aa2c89261d
commit
5b2dc6145f
@ -32,4 +32,14 @@ public interface IJenkinsBuildRepository extends IBaseRepository<JenkinsBuild, L
|
||||
* @return 构建信息列表
|
||||
*/
|
||||
List<JenkinsBuild> findByExternalSystemIdAndJobId(Long externalSystemId, Long jobId);
|
||||
|
||||
/**
|
||||
* 查询指定任务的最新构建记录
|
||||
*
|
||||
* @param externalSystemId 外部系统ID
|
||||
* @param jobId 任务ID
|
||||
* @return 最新的构建记录
|
||||
*/
|
||||
Optional<JenkinsBuild> findTopByExternalSystemIdAndJobIdOrderByBuildNumberDesc(
|
||||
Long externalSystemId, Long jobId);
|
||||
}
|
||||
@ -13,24 +13,6 @@ import com.qqchen.deploy.backend.deploy.query.JenkinsBuildQuery;
|
||||
*/
|
||||
public interface IJenkinsBuildService extends IBaseService<JenkinsBuild, JenkinsBuildDTO, JenkinsBuildQuery, Long> {
|
||||
|
||||
/**
|
||||
* 同步指定任务的构建信息
|
||||
*
|
||||
* @param externalSystem 外部系统
|
||||
* @param job 任务
|
||||
* @return 同步的构建数量
|
||||
*/
|
||||
Integer syncBuilds(ExternalSystem externalSystem, JenkinsJob job);
|
||||
|
||||
/**
|
||||
* 同步指定视图下所有任务的构建信息
|
||||
*
|
||||
* @param externalSystem 外部系统
|
||||
* @param view 视图
|
||||
* @return 同步的构建总数
|
||||
*/
|
||||
Integer syncBuildsByView(ExternalSystem externalSystem, JenkinsView view);
|
||||
|
||||
/**
|
||||
* 同步外部系统下所有构建信息
|
||||
*
|
||||
|
||||
@ -21,6 +21,7 @@ import com.qqchen.deploy.backend.deploy.repository.IJenkinsJobRepository;
|
||||
import com.qqchen.deploy.backend.deploy.repository.IJenkinsViewRepository;
|
||||
import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService;
|
||||
import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
|
||||
import com.qqchen.deploy.backend.deploy.service.sync.JenkinsSyncContext;
|
||||
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;
|
||||
@ -78,84 +79,50 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
@Override
|
||||
@Transactional
|
||||
public Integer syncAllBuilds(Long externalSystemId) {
|
||||
// 1. 创建同步历史记录
|
||||
// 1. 创建同步上下文
|
||||
JenkinsSyncContext context = createSyncContext(externalSystemId);
|
||||
|
||||
try {
|
||||
// 2. 执行同步
|
||||
return doSync(context);
|
||||
} catch (Exception e) {
|
||||
// 3. 处理异常
|
||||
handleSyncException(context, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private JenkinsSyncContext createSyncContext(Long externalSystemId) {
|
||||
// 1. 查询外部系统
|
||||
ExternalSystem externalSystem = externalSystemRepository.findById(externalSystemId)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND));
|
||||
|
||||
// 2. 创建同步历史
|
||||
JenkinsSyncHistoryDTO syncHistory = new JenkinsSyncHistoryDTO();
|
||||
syncHistory.setExternalSystemId(externalSystemId);
|
||||
syncHistory.setSyncType(JenkinsSyncType.BUILD);
|
||||
syncHistory.setStatus(ExternalSystemSyncStatus.RUNNING);
|
||||
jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
|
||||
|
||||
try {
|
||||
// 2. 查询外部系统
|
||||
ExternalSystem externalSystem = externalSystemRepository.findById(externalSystemId).orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND));
|
||||
// 3. 查询所有视图
|
||||
List<JenkinsView> views = jenkinsViewRepository.findByExternalSystemId(externalSystemId);
|
||||
// 3. 返回同步上下文
|
||||
return new JenkinsSyncContext(externalSystem, syncHistory);
|
||||
}
|
||||
|
||||
private Integer doSync(JenkinsSyncContext context) {
|
||||
// 1. 获取所有视图
|
||||
List<JenkinsView> views = jenkinsViewRepository.findByExternalSystemId(context.getExternalSystem().getId());
|
||||
if (views.isEmpty()) {
|
||||
log.info("No views found for external system: {}", externalSystemId);
|
||||
// 更新同步历史为成功
|
||||
syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
|
||||
jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
|
||||
return 0;
|
||||
}
|
||||
// 4. 同步每个视图下的构建信息
|
||||
int totalSyncedBuilds = 0;
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
for (JenkinsView view : views) {
|
||||
try {
|
||||
Integer syncedBuilds = syncBuildsByView(externalSystem, view);
|
||||
totalSyncedBuilds += syncedBuilds;
|
||||
log.info("Successfully synchronized {} builds for view: {}", syncedBuilds, view.getViewName());
|
||||
} catch (Exception e) {
|
||||
String errorMessage = String.format("Failed to sync builds for view %s: %s", view.getViewName(), e.getMessage());
|
||||
log.error(errorMessage, e);
|
||||
errorMessages.append(errorMessage).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 更新同步历史状态
|
||||
if (errorMessages.length() > 0) {
|
||||
syncHistory.setStatus(ExternalSystemSyncStatus.FAILED);
|
||||
syncHistory.setErrorMessage(errorMessages.toString());
|
||||
} else {
|
||||
syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
|
||||
}
|
||||
jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
|
||||
|
||||
log.info("Successfully synchronized total {} builds for external system: {}",
|
||||
totalSyncedBuilds, externalSystemId);
|
||||
return totalSyncedBuilds;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to sync Jenkins builds for external system: {}", externalSystemId, e);
|
||||
// 更新同步历史为失败
|
||||
syncHistory.setStatus(ExternalSystemSyncStatus.FAILED);
|
||||
syncHistory.setErrorMessage(e.getMessage());
|
||||
jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Integer syncBuildsByView(ExternalSystem externalSystem, JenkinsView view) {
|
||||
// 1. 查询视图下的所有任务
|
||||
List<JenkinsJob> jobs = jenkinsJobRepository.findByExternalSystemIdAndViewId(externalSystem.getId(), view.getId());
|
||||
if (jobs.isEmpty()) {
|
||||
log.info("No jobs found for view: {}", view.getId());
|
||||
log.info("No views found for external system: {}", context.getExternalSystem().getId());
|
||||
updateSyncHistorySuccess(context.getSyncHistory());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 2. 使用线程池并发同步每个任务的构建信息
|
||||
List<CompletableFuture<Integer>> futures = jobs.stream()
|
||||
.map(job -> CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
Integer syncedBuilds = syncBuilds(externalSystem, job);
|
||||
log.info("Successfully synchronized {} builds for job: {}", syncedBuilds, job.getJobName());
|
||||
return syncedBuilds;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to sync builds for job: {}", job.getJobName(), e);
|
||||
return 0;
|
||||
}
|
||||
}, threadPoolTaskExecutor))
|
||||
// 2. 并发同步每个视图
|
||||
List<CompletableFuture<Integer>> futures = views.stream()
|
||||
.map(view -> CompletableFuture.supplyAsync(
|
||||
() -> syncView(context.getExternalSystem(), view),
|
||||
threadPoolTaskExecutor
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 3. 等待所有任务完成并汇总结果
|
||||
@ -171,67 +138,143 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
.mapToInt(Integer::intValue)
|
||||
.sum();
|
||||
|
||||
log.info("Successfully synchronized total {} builds for view: {}", totalSyncedBuilds, view.getViewName());
|
||||
// 4. 更新同步历史
|
||||
updateSyncHistorySuccess(context.getSyncHistory());
|
||||
|
||||
log.info("Successfully synchronized total {} builds for external system: {}",
|
||||
totalSyncedBuilds, context.getExternalSystem().getId());
|
||||
return totalSyncedBuilds;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Integer syncBuilds(ExternalSystem externalSystem, JenkinsJob job) {
|
||||
JenkinsJobResponse queryJob = jenkinsServiceIntegration.job(externalSystem, job.getJobName());
|
||||
if (queryJob == null || queryJob.getLastBuild() == null) {
|
||||
log.info("No builds found for job: {}", job.getJobName());
|
||||
protected Integer syncView(ExternalSystem externalSystem, JenkinsView view) {
|
||||
try {
|
||||
// 1. 获取视图下的所有任务
|
||||
List<JenkinsJob> jobs = jenkinsJobRepository.findByExternalSystemIdAndViewId(
|
||||
externalSystem.getId(), view.getId());
|
||||
|
||||
if (jobs.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if sync is needed
|
||||
if (job.getLastBuildNumber() != null && queryJob.getLastBuild().getNumber() <= job.getLastBuildNumber()) {
|
||||
// 2. 同步每个任务
|
||||
return jobs.stream()
|
||||
.map(job -> syncJob(externalSystem, job))
|
||||
.mapToInt(Integer::intValue)
|
||||
.sum();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to sync view: {}", view.getViewName(), e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
protected Integer syncJob(ExternalSystem externalSystem, JenkinsJob job) {
|
||||
try {
|
||||
// 1. 获取任务最新状态
|
||||
JenkinsJobResponse jobResponse = jenkinsServiceIntegration.job(externalSystem, job.getJobName());
|
||||
if (jobResponse == null || jobResponse.getLastBuild() == null) {
|
||||
log.info("No build information available for job: {}", job.getJobName());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 2. 获取数据库中最后一次构建记录
|
||||
Optional<JenkinsBuild> lastBuild = jenkinsBuildRepository.findTopByExternalSystemIdAndJobIdOrderByBuildNumberDesc(
|
||||
externalSystem.getId(), job.getId());
|
||||
|
||||
// 3. 获取需要同步的构建信息
|
||||
List<JenkinsBuildResponse> newBuilds = getNewBuilds(externalSystem, job, jobResponse, lastBuild);
|
||||
if (newBuilds.isEmpty()) {
|
||||
log.info("No new builds to sync for job: {}", job.getJobName());
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<JenkinsBuildResponse> buildResponses = jenkinsServiceIntegration.listBuilds(externalSystem, job.getJobName());
|
||||
if (buildResponses.isEmpty()) {
|
||||
log.info("No builds found for job: {}", job.getJobName());
|
||||
// 4. 保存新的构建信息
|
||||
saveNewBuilds(externalSystem, job, newBuilds);
|
||||
|
||||
// 5. 更新任务的最新构建信息
|
||||
updateJobLastBuild(job, jobResponse);
|
||||
|
||||
log.info("Successfully synchronized {} builds for job: {}", newBuilds.size(), job.getJobName());
|
||||
return newBuilds.size();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to sync job: {}", job.getJobName(), e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert and save/update build data
|
||||
List<JenkinsBuild> jenkinsBuilds = new ArrayList<>();
|
||||
for (JenkinsBuildResponse buildResponse : buildResponses) {
|
||||
// Skip existing builds
|
||||
if (job.getLastBuildNumber() != null && buildResponse.getNumber() <= job.getLastBuildNumber()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create new build
|
||||
JenkinsBuild jenkinsBuild = new JenkinsBuild();
|
||||
jenkinsBuild.setExternalSystemId(externalSystem.getId());
|
||||
jenkinsBuild.setJobId(job.getId());
|
||||
jenkinsBuild.setBuildNumber(buildResponse.getNumber());
|
||||
updateBuildFromResponse(jenkinsBuild, buildResponse);
|
||||
jenkinsBuilds.add(jenkinsBuild);
|
||||
log.debug("Creating new Jenkins build: {} for job: {}", jenkinsBuild.getBuildNumber(), job.getJobName());
|
||||
private List<JenkinsBuildResponse> getNewBuilds(
|
||||
ExternalSystem externalSystem,
|
||||
JenkinsJob job,
|
||||
JenkinsJobResponse jobResponse,
|
||||
Optional<JenkinsBuild> lastBuild) {
|
||||
// 获取所有构建
|
||||
List<JenkinsBuildResponse> allBuilds = jenkinsServiceIntegration.listBuilds(
|
||||
externalSystem, job.getJobName());
|
||||
|
||||
if (allBuilds.isEmpty()) {
|
||||
return allBuilds;
|
||||
}
|
||||
|
||||
// Batch save
|
||||
if (!jenkinsBuilds.isEmpty()) {
|
||||
// 如果是首次同步,获取所有构建
|
||||
if (lastBuild.isEmpty()) {
|
||||
log.info("First time sync for job: {}, will sync all builds", job.getJobName());
|
||||
return allBuilds;
|
||||
}
|
||||
|
||||
// 获取新的构建
|
||||
Integer lastBuildNumber = lastBuild.get().getBuildNumber();
|
||||
List<JenkinsBuildResponse> newBuilds = allBuilds.stream()
|
||||
.filter(build -> build.getNumber() > lastBuildNumber)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("Found {} new builds for job: {} (last build number: {})",
|
||||
newBuilds.size(), job.getJobName(), lastBuildNumber);
|
||||
return newBuilds;
|
||||
}
|
||||
|
||||
private void saveNewBuilds(
|
||||
ExternalSystem externalSystem,
|
||||
JenkinsJob job,
|
||||
List<JenkinsBuildResponse> builds) {
|
||||
List<JenkinsBuild> jenkinsBuilds = builds.stream()
|
||||
.map(buildResponse -> {
|
||||
JenkinsBuild build = new JenkinsBuild();
|
||||
build.setExternalSystemId(externalSystem.getId());
|
||||
build.setJobId(job.getId());
|
||||
build.setBuildNumber(buildResponse.getNumber());
|
||||
updateBuildFromResponse(build, buildResponse);
|
||||
return build;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("Saving {} builds for job: {}", jenkinsBuilds.size(), job.getJobName());
|
||||
jenkinsBuildRepository.saveAll(jenkinsBuilds);
|
||||
}
|
||||
|
||||
// Update job's last build info
|
||||
job.setLastBuildNumber(queryJob.getLastBuild().getNumber());
|
||||
if (queryJob.getLastBuild().getTimestamp() != null) {
|
||||
private void updateJobLastBuild(JenkinsJob job, JenkinsJobResponse jobResponse) {
|
||||
job.setLastBuildNumber(jobResponse.getLastBuild().getNumber());
|
||||
if (jobResponse.getLastBuild().getTimestamp() != null) {
|
||||
job.setLastBuildTime(LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(queryJob.getLastBuild().getTimestamp()),
|
||||
Instant.ofEpochMilli(jobResponse.getLastBuild().getTimestamp()),
|
||||
ZoneId.systemDefault()
|
||||
));
|
||||
}
|
||||
jenkinsJobRepository.save(job);
|
||||
|
||||
log.info("Successfully synchronized {} builds for job: {}", jenkinsBuilds.size(), job.getJobName());
|
||||
}
|
||||
|
||||
return jenkinsBuilds.size();
|
||||
private void handleSyncException(JenkinsSyncContext context, Exception e) {
|
||||
log.error("Failed to sync Jenkins builds for external system: {}",
|
||||
context.getExternalSystem().getId(), e);
|
||||
|
||||
context.getSyncHistory().setStatus(ExternalSystemSyncStatus.FAILED);
|
||||
context.getSyncHistory().setErrorMessage(e.getMessage());
|
||||
jenkinsSyncHistoryService.saveOrUpdateHistory(context.getSyncHistory());
|
||||
}
|
||||
|
||||
private void updateSyncHistorySuccess(JenkinsSyncHistoryDTO syncHistory) {
|
||||
syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
|
||||
jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -242,7 +285,6 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
jenkinsBuild.setBuildStatus(response.getResult());
|
||||
jenkinsBuild.setDuration(response.getDuration());
|
||||
|
||||
// 转换时间戳为LocalDateTime
|
||||
if (response.getTimestamp() != null) {
|
||||
LocalDateTime startTime = LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(response.getTimestamp()),
|
||||
@ -251,7 +293,6 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
jenkinsBuild.setStarttime(startTime);
|
||||
}
|
||||
|
||||
// 将构建参数转换为JSON字符串
|
||||
try {
|
||||
String actionsJson = objectMapper.writeValueAsString(response.getActions());
|
||||
jenkinsBuild.setActions(actionsJson);
|
||||
@ -264,6 +305,9 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
||||
@Override
|
||||
public Long countByExternalSystemId(Long externalSystemId) {
|
||||
QJenkinsBuild qJenkinsBuild = QJenkinsBuild.jenkinsBuild;
|
||||
return super.repository.count(qJenkinsBuild.externalSystemId.eq(externalSystemId).and(qJenkinsBuild.deleted.eq(false)));
|
||||
return super.repository.count(
|
||||
qJenkinsBuild.externalSystemId.eq(externalSystemId)
|
||||
.and(qJenkinsBuild.deleted.eq(false))
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user