Skip to content
This repository was archived by the owner on Feb 22, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
package nl.tudelft.ewi.devhub.server.backend;

import javax.inject.Inject;
import javax.ws.rs.NotFoundException;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Inject;
import javax.ws.rs.NotFoundException;

import com.google.common.base.Preconditions;
import com.google.common.collect.Queues;
import com.google.inject.Provider;
import com.google.inject.persist.Transactional;
import com.google.inject.persist.UnitOfWork;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import nl.tudelft.ewi.build.client.BuildServerBackend;
import nl.tudelft.ewi.build.client.BuildServerBackendImpl;
import nl.tudelft.ewi.build.jaxrs.models.BuildRequest;
import nl.tudelft.ewi.devhub.server.database.controllers.BuildResults;
import nl.tudelft.ewi.devhub.server.database.controllers.BuildServers;
import nl.tudelft.ewi.devhub.server.database.entities.BuildResult;
import nl.tudelft.ewi.devhub.server.database.entities.BuildServer;
import nl.tudelft.ewi.devhub.server.web.errors.ApiError;

import com.google.common.base.Preconditions;
import com.google.common.collect.Queues;
import com.google.inject.Provider;
import com.google.inject.persist.Transactional;
import com.google.inject.persist.UnitOfWork;

/**
* The {@link BuildServerClient} allows you to query and manipulate data from the build-server.
*/
Expand All @@ -32,7 +35,7 @@ public class BuildsBackend {

private final BuildServers buildServers;
private final Provider<BuildSubmitter> submitters;
private final ConcurrentLinkedQueue<BuildRequest> buildQueue;
private final ConcurrentLinkedQueue<BuildRequestWithResultMapping> buildQueue;
private final ScheduledExecutorService executor;
private final AtomicBoolean running;

Expand Down Expand Up @@ -87,9 +90,9 @@ public void deleteBuildServer(long serverId) throws ApiError {
}
}

public void offerBuild(BuildRequest request) {
public void offerBuild(BuildRequest request, long buildResultId) {
synchronized (running) {
buildQueue.offer(request);
buildQueue.offer(new BuildRequestWithResultMapping(request, buildResultId));
if (running.compareAndSet(false, true)) {
BuildSubmitter task = submitters.get();
task.initialize(this);
Expand All @@ -103,18 +106,29 @@ public void shutdown() throws InterruptedException {
executor.awaitTermination(1, TimeUnit.MINUTES);
}

@Data
private static class BuildRequestWithResultMapping {
private final BuildRequest request;
private final long id;
}

private static class BuildSubmitter extends RunnableInUnitOfWork {

private static final int NO_CAPACITY_DELAY = 5000;

private final Provider<BuildServers> buildServersProvider;
private final Provider<BuildResults> buildResultsProvider;

private BuildsBackend backend;

@Inject
BuildSubmitter(Provider<BuildServers> buildServersProvider, Provider<UnitOfWork> workProvider) {
BuildSubmitter(Provider<BuildServers> buildServersProvider,
Provider<BuildResults> buildResultsProvider,
Provider<UnitOfWork> workProvider) {

super(workProvider);
this.buildServersProvider = buildServersProvider;
this.buildResultsProvider = buildResultsProvider;
}

void initialize(BuildsBackend backend) {
Expand All @@ -124,14 +138,15 @@ void initialize(BuildsBackend backend) {
@Override
@Transactional
protected void runInUnitOfWork() {
ConcurrentLinkedQueue<BuildRequest> buildQueue = backend.buildQueue;
ConcurrentLinkedQueue<BuildRequestWithResultMapping> buildQueue = backend.buildQueue;
AtomicBoolean running = backend.running;
BuildServers buildServers = buildServersProvider.get();
BuildResults buildResults = buildResultsProvider.get();

try {
while (!buildQueue.isEmpty()) {
boolean delivered = false;
BuildRequest buildRequest = buildQueue.peek();
BuildRequestWithResultMapping buildRequestWithId = buildQueue.peek();
List<BuildServer> allBuildServers = buildServers.listAll();

while (!allBuildServers.isEmpty()) {
Expand All @@ -141,10 +156,14 @@ protected void runInUnitOfWork() {
String secret = buildServer.getSecret();

BuildServerBackend backend = new BuildServerBackendImpl(host, name, secret);
if (backend.offerBuildRequest(buildRequest)) {
if (backend.offerBuildRequest(buildRequestWithId.getRequest())) {
delivered = true;
buildQueue.poll();
log.info("One build request was succesfully handed to: {}", name);

BuildResult result = buildResults.find(buildRequestWithId.getId());
result.setStarted(new Date());
buildResults.merge(result);
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;

import com.google.inject.persist.Transactional;
import lombok.extern.slf4j.Slf4j;
import nl.tudelft.ewi.devhub.server.database.entities.BuildResult;
import nl.tudelft.ewi.devhub.server.database.entities.Group;
import nl.tudelft.ewi.devhub.server.database.entities.QBuildResult;

import com.google.inject.persist.Transactional;

@Slf4j
public class BuildResults extends Controller<BuildResult> {

Expand All @@ -31,6 +30,18 @@ public BuildResult find(Group group, String commitId) {
}
return result;
}

@Transactional
public BuildResult find(long id) {
BuildResult result = query().from(QBuildResult.buildResult)
.where(QBuildResult.buildResult.id.eq(id))
.singleResult(QBuildResult.buildResult);

if (result == null) {
throw new EntityNotFoundException();
}
return result;
}

@Transactional
public boolean exists(Group group, String commitId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

import lombok.Data;
import java.util.Date;

import lombok.Data;
import org.hibernate.validator.constraints.NotEmpty;

@Data
Expand All @@ -21,6 +22,7 @@ public class BuildResult {

public static BuildResult newBuildResult(Group group, String commit) {
BuildResult result = new BuildResult();
result.setQueued(new Date());
result.setRepository(group);
result.setCommitId(commit);
result.setSuccess(null);
Expand All @@ -32,7 +34,7 @@ public static BuildResult newBuildResult(Group group, String commit) {
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@NotNull
@ManyToOne
@JoinColumn(name = "repository_id")
Expand All @@ -42,6 +44,15 @@ public static BuildResult newBuildResult(Group group, String commit) {
@Column(name = "commit_id")
private String commitId;

@Column(name = "queued")
private Date queued;

@Column(name = "started")
private Date started;

@Column(name = "completed")
private Date completed;

@Column(name = "success")
private Boolean success;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package nl.tudelft.ewi.devhub.server.web.resources;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Locale;

import javax.inject.Inject;
import javax.persistence.EntityNotFoundException;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -16,6 +11,13 @@
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Locale;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.inject.persist.Transactional;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import nl.tudelft.ewi.build.jaxrs.models.BuildRequest;
Expand All @@ -34,13 +36,8 @@
import nl.tudelft.ewi.git.client.Repositories;
import nl.tudelft.ewi.git.models.BranchModel;
import nl.tudelft.ewi.git.models.DetailedRepositoryModel;

import org.jboss.resteasy.plugins.guice.RequestScoped;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.inject.persist.Transactional;

@Slf4j
@RequestScoped
@Path("hooks")
Expand Down Expand Up @@ -92,6 +89,9 @@ public void onGitPush(@Context HttpServletRequest request, GitPush push) throws
if (buildResults.exists(group, branch.getCommit())) {
continue;
}

BuildResult buildResult = BuildResult.newBuildResult(group, branch.getCommit());
buildResults.persist(buildResult);

log.info("Submitting a build for branch: {} of repository: {}", branch.getName(), repository.getName());

Expand All @@ -103,51 +103,39 @@ public void onGitPush(@Context HttpServletRequest request, GitPush push) throws
StringBuilder callbackBuilder = new StringBuilder();
callbackBuilder.append(config.getHttpUrl());
callbackBuilder.append("/hooks/build-result");
callbackBuilder.append("?repository=" + URLEncoder.encode(repository.getName(), "UTF-8"));
callbackBuilder.append("&commit=" + URLEncoder.encode(branch.getCommit(), "UTF-8"));
callbackBuilder.append("?buildId=" + buildResult.getId());

BuildRequest buildRequest = new BuildRequest();
buildRequest.setCallbackUrl(callbackBuilder.toString());
buildRequest.setInstruction(instruction);
buildRequest.setSource(source);
buildRequest.setTimeout(group.getBuildTimeout());

buildBackend.offerBuild(buildRequest);
buildResults.persist(BuildResult.newBuildResult(group, branch.getCommit()));

buildBackend.offerBuild(buildRequest, buildResult.getId());
}
}

@POST
@Path("build-result")
@RequireAuthenticatedBuildServer
@Transactional
public void onBuildResult(@QueryParam("repository") String repository, @QueryParam("commit") String commit,
public void onBuildResult(@QueryParam("buildId") long buildId,
nl.tudelft.ewi.build.jaxrs.models.BuildResult buildResult) throws UnsupportedEncodingException {

String repoName = URLDecoder.decode(repository, "UTF-8");
String commitId = URLDecoder.decode(commit, "UTF-8");
Group group = groups.findByRepoName(repoName);

BuildResult result;
try {
result = buildResults.find(group, commitId);
BuildResult result = buildResults.find(buildId);
result.setCompleted(new Date());
result.setSuccess(buildResult.getStatus() == Status.SUCCEEDED);
result.setLog(Joiner.on('\n')
.join(buildResult.getLogLines()));

result.setLog(Joiner.on('\n').join(buildResult.getLogLines()));
buildResults.merge(result);
}
catch (EntityNotFoundException e) {
result = BuildResult.newBuildResult(group, commitId);
result.setSuccess(buildResult.getStatus() == Status.SUCCEEDED);
result.setLog(Joiner.on('\n')
.join(buildResult.getLogLines()));

buildResults.persist(result);
if (!result.getSuccess()) {
mailer.sendFailedBuildResult(Lists.newArrayList(Locale.ENGLISH), result);
}
}

if (!result.getSuccess()) {
mailer.sendFailedBuildResult(Lists.newArrayList(Locale.ENGLISH), result);
catch (EntityNotFoundException e) {
log.error("Could not find build result: " + buildId + ": " + e.getMessage(), e);
return;
}
}

Expand Down