/**
*
* Copyright (C) norad.fr
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.norad.visuwall.core.business.process.capabilities;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import fr.norad.visuwall.api.domain.BuildState;
import fr.norad.visuwall.api.domain.BuildTime;
import fr.norad.visuwall.api.domain.Commiter;
import fr.norad.visuwall.api.domain.SoftwareProjectId;
import fr.norad.visuwall.api.exception.BuildIdNotFoundException;
import fr.norad.visuwall.api.exception.BuildNotFoundException;
import fr.norad.visuwall.api.exception.ProjectNotFoundException;
import fr.norad.visuwall.core.business.domain.Build;
import fr.norad.visuwall.core.business.domain.Project;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Component;
import com.google.common.base.Preconditions;
@Component
public class BuildCapabilityProcess {
private static final Logger LOG = LoggerFactory.getLogger(BuildCapabilityProcess.class);
@Autowired
TaskScheduler scheduler;
public void updatePreviousCompletedBuild(Project project) throws ProjectNotFoundException {
List<String> buildIds = project.getBuildId();
if (buildIds.size() < 2) {
// with only a build there is no previous completed build
return;
}
try {
int skip = 1;
if (project.getLastBuild().isBuilding()) {
if (buildIds.size() < 3) {
// first build is building so we do not have enough builds to have a previous completed
return;
}
skip = 2;
}
ListIterator<String> reverseBuildIt = project.getBuildId().listIterator(project.getBuildId().size());
for (int i = 0; reverseBuildIt.hasPrevious(); i++) {
String buildId = reverseBuildIt.previous();
if (i < skip) {
continue;
}
Build build = getCreatedWithContentBuild(project, buildId);
if (build == null) {
continue;
}
BuildState state = build.getState();
if (state == BuildState.UNKNOWN || state == BuildState.ABORTED) {
continue;
}
project.setPreviousCompletedBuildId(build.getBuildId());
break;
}
} catch (BuildNotFoundException e) {
LOG.warn("last build not found to update previous completed build", e);
}
}
private Build getCreatedWithContentBuild(Project project, String buildId) throws ProjectNotFoundException {
Build build = project.getBuilds().get(buildId);
if (build == null) {
updateBuild(project, buildId);
build = project.getBuilds().get(buildId);
if (build == null) {
LOG.warn("Build " + buildId + " not found after update for project " + project);
}
}
return build;
}
public void updateLastNotBuildingId(Project project) throws ProjectNotFoundException {
ListIterator<String> reverseBuildIt = project.getBuildId().listIterator(project.getBuildId().size());
while (reverseBuildIt.hasPrevious()) {
String buildId = reverseBuildIt.previous();
Build build = getCreatedWithContentBuild(project, buildId);
if (build.isBuilding()) {
continue;
}
project.setLastNotBuildingId(buildId);
break;
}
}
public void updateBuild(Project project, String buildId) throws ProjectNotFoundException {
try {
LOG.info("Updating build " + buildId + " for project " + project);
SoftwareProjectId projectId = project.getBuildProjectId();
Build build = project.findCreatedBuild(buildId);
BuildState state = project.getBuildConnection().getBuildState(projectId, buildId);
build.setState(state);
// buildTime
BuildTime buildTime = project.getBuildConnection().getBuildTime(projectId, buildId);
build.setStartTime(buildTime.getStartTime());
build.setDuration(buildTime.getDuration());
build.setBuilding(project.getBuildConnection().isBuilding(projectId, buildId));
List<Commiter> commiters = project.getBuildConnection().getBuildCommiters(projectId, buildId);
build.setCommiters(commiters);
} catch (BuildNotFoundException e) {
LOG.warn("BuildId " + buildId + " not found in software to update project " + project, e);
//TODO remove buildId from buildIds as its removed from software
}
}
public String[] updateStatusAndReturnBuildsToUpdate(Project project) throws ProjectNotFoundException,
BuildNotFoundException {
try {
String lastBuildId = project.getBuildConnection().getLastBuildId(project.getBuildProjectId());
boolean lastBuilding = project.getBuildConnection().isBuilding(project.getBuildProjectId(), lastBuildId);
String previousLastBuildId = project.getLastBuildId();
boolean previousBuilding = false;
try {
previousBuilding = project.getLastBuild().isBuilding();
} catch (BuildNotFoundException e) {
LOG.debug("No lastBuild found to say the project was building before refresh " + project);
}
Build lastBuild = project.findCreatedBuild(lastBuildId);
try {
if (previousBuilding == false && lastBuilding == false && !lastBuildId.equals(previousLastBuildId)) {
LOG.info("there is an already finished new build {} {}", lastBuildId, project);
return new String[] { lastBuildId };
}
if (previousBuilding == false && lastBuilding == true) {
LOG.info("Build {} is now running {}", lastBuild.getBuildId(), project);
Runnable finishTimeRunner = getEstimatedFinishTimeRunner(project, lastBuild);
scheduler.schedule(finishTimeRunner, new Date());
}
if (previousBuilding == true && lastBuilding == true) {
if (!lastBuildId.equals(previousLastBuildId)) {
LOG.info("Previous build {} is over and a new build {} is already running {}", new Object[] {
previousLastBuildId, lastBuildId, project });
project.getBuilds().get(previousLastBuildId).setEstimatedFinishTime(null);
project.getBuilds().get(previousLastBuildId).setBuilding(false);
Runnable finishTimeRunner = getEstimatedFinishTimeRunner(project, lastBuild);
scheduler.schedule(finishTimeRunner, new Date());
return new String[] { previousLastBuildId };
}
// building is still running
}
if (previousBuilding == true && lastBuilding == false) {
// build is over
project.getBuilds().get(previousLastBuildId).setEstimatedFinishTime(null);
project.getBuilds().get(previousLastBuildId).setBuilding(false);
if (!lastBuildId.equals(previousLastBuildId)) {
LOG.info("previous build {} is over and a new build {} is also over {}", new Object[] {
previousLastBuildId, lastBuildId, project });
return new String[] { previousLastBuildId, lastBuildId };
}
LOG.info("Previous build {} is over and no new build ", previousLastBuildId, project);
return new String[] { previousLastBuildId };
}
} finally {
lastBuild.setBuilding(lastBuilding);
project.setLastBuildId(lastBuildId);
}
} catch (BuildIdNotFoundException e) {
LOG.debug("No last build id found to update project " + project);
}
return new String[] {};
}
////////////////////////////////////////////////////////////////////////
/**
* @return null if no date could be estimated
* @throws ProjectNotFoundException
*/
Runnable getEstimatedFinishTimeRunner(final Project project, final Build build) throws ProjectNotFoundException {
Preconditions.checkNotNull(project, "project is a mandatory parameter");
return new Runnable() {
@Override
public void run() {
LOG.debug("Running getEstimatedFinishTime for project " + project);
try {
Date estimatedFinishTime = project.getBuildConnection().getEstimatedFinishTime(
project.getBuildProjectId(), build.getBuildId());
if (estimatedFinishTime != null) {
build.setEstimatedFinishTime(estimatedFinishTime);
}
} catch (ProjectNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BuildNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}
}