package com.hubspot.blazar.visitor.modulebuild;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.hubspot.blazar.base.ModuleBuild;
import com.hubspot.blazar.base.RepositoryBuild;
import com.hubspot.blazar.base.visitor.ModuleBuildVisitor;
import com.hubspot.blazar.data.service.ModuleBuildService;
import com.hubspot.blazar.data.service.RepositoryBuildService;
@Singleton
public class RepositoryBuildCompleter implements ModuleBuildVisitor {
private static final Logger LOG = LoggerFactory.getLogger(RepositoryBuildCompleter.class);
private final RepositoryBuildService repositoryBuildService;
private final ModuleBuildService moduleBuildService;
@Inject
public RepositoryBuildCompleter(RepositoryBuildService repositoryBuildService,
ModuleBuildService moduleBuildService) {
this.repositoryBuildService = repositoryBuildService;
this.moduleBuildService = moduleBuildService;
}
@Override
public void visit(ModuleBuild build) throws Exception {
if (!build.getState().isComplete()) {
// repository build can't be done if this module isn't done
return;
}
RepositoryBuild repositoryBuild = repositoryBuildService.get(build.getRepoBuildId()).get();
if (repositoryBuild.getState().isComplete()) {
// already done, this must be a stale ModuleBuild event
return;
}
Set<ModuleBuild> builds = moduleBuildService.getByRepositoryBuild(build.getRepoBuildId());
if (allComplete(builds)) {
LOG.info("All module builds complete, going to complete repository build {}", build.getRepoBuildId());
RepositoryBuild.State finalState = determineRepositoryBuildState(builds);
LOG.info("Final state for repository build {} is {}", build.getRepoBuildId(), finalState);
RepositoryBuild completed = repositoryBuild.toBuilder()
.setState(finalState)
.setEndTimestamp(Optional.of(System.currentTimeMillis()))
.build();
repositoryBuildService.update(completed);
}
}
private RepositoryBuild.State determineRepositoryBuildState(Set<ModuleBuild> builds) {
for (ModuleBuild build : builds) {
if (build.getState() == ModuleBuild.State.FAILED) {
return RepositoryBuild.State.FAILED;
}
}
for (ModuleBuild build : builds) {
if (build.getState() == ModuleBuild.State.CANCELLED) {
return RepositoryBuild.State.CANCELLED;
}
}
// if a module was skipped we need to carry over any previous failure
for (ModuleBuild build : builds) {
if (build.getState() == ModuleBuild.State.SKIPPED) {
if (!lastBuildSucceeded(build)) {
return RepositoryBuild.State.UNSTABLE;
}
}
}
return RepositoryBuild.State.SUCCEEDED;
}
private boolean lastBuildSucceeded(ModuleBuild build) {
Optional<ModuleBuild> previous = moduleBuildService.getPreviousBuild(build);
return previous.isPresent() && previous.get().getState() == ModuleBuild.State.SUCCEEDED;
}
private static boolean allComplete(Set<ModuleBuild> builds) {
for (ModuleBuild build : builds) {
if (!build.getState().isComplete()) {
return false;
}
}
return true;
}
}