Skip to content

Commit

Permalink
Allow the build script of a build to be downloaded via the `builds/{i…
Browse files Browse the repository at this point in the history
…d}/buildScript` API endpoint
  • Loading branch information
danielflower committed Jun 22, 2024
1 parent 73ae81d commit d00c8a5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 8 deletions.
17 changes: 11 additions & 6 deletions src/main/java/com/danielflower/restabuild/build/BuildProcess.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class BuildProcess {
private File workDir;
private volatile Process process;
private final DeletePolicy instanceDirDeletePolicy;
private File buildScriptFile;

public File workDir() {
return workDir;
Expand All @@ -55,6 +56,10 @@ public ObjectId commitIDBeforeBuild() {
return commitIDBeforeBuild;
}

public File buildScriptFile() {
return buildScriptFile;
}

public ObjectId commitIDAfterBuild() {
return commitIDAfterBuild;
}
Expand Down Expand Up @@ -142,19 +147,19 @@ public boolean isCancelled() {
commitIDBeforeBuild = headBefore.getObjectId();
tagsBefore = RemoteGitRepo.getTagsAt(git, commitIDBeforeBuild);

File f = new File(workDir, BuildResult.buildFile);
if (!f.isFile()) {
buildScriptFile = new File(workDir, BuildResult.buildFile);
if (!buildScriptFile.isFile()) {
logWriter.write("Please place a file called " + BuildResult.buildFile + " in the root of your repo");
changeStatus(BuildStatus.FAILURE, git);
} else {

List<String> commands = new ArrayList<>();
if (Config.isWindows()) {
commands.add(f.getCanonicalPath());
commands.add(buildScriptFile.getCanonicalPath());
} else {
commands.add("bash");
commands.add("-x");
commands.add(f.getName());
commands.add(buildScriptFile.getName());
}
if (buildParam != null) {
// TODO: add support for quoted parameter values
Expand Down Expand Up @@ -209,10 +214,10 @@ public boolean isCancelled() {
} else {
if (!buildCancelled()) {
if (process.exitValue() == 0) {
doubleLog(logWriter, "Completed " + f.getName() + " in " + (System.currentTimeMillis() - buildStartMillis) + "ms");
doubleLog(logWriter, "Completed " + buildScriptFile.getName() + " in " + (System.currentTimeMillis() - buildStartMillis) + "ms");
changeStatus(BuildStatus.SUCCESS, git);
} else {
String message = "Exit code " + process.exitValue() + " returned from " + f.getName();
String message = "Exit code " + process.exitValue() + " returned from " + buildScriptFile.getName();
doubleLog(logWriter, message);
changeStatus(BuildStatus.FAILURE, git);
}
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/danielflower/restabuild/build/BuildResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.Instant;
import java.util.List;
import java.util.Map;
Expand All @@ -39,6 +42,7 @@ public class BuildResult {
private long buildComplete = -1;
private String commitIDBeforeBuild;
private String commitIDAfterBuild;
private volatile File buildScriptFile;
private List<String> createdTags;
private final String buildParam;
private final ExecutorService executorService;
Expand All @@ -64,6 +68,10 @@ public boolean hasFinished() {
}
}

public File buildScriptFile() {
return buildScriptFile;
}

public boolean isCancellable() {
synchronized (lock) {
return status.isCancellable();
Expand Down Expand Up @@ -129,9 +137,16 @@ public void run(@NotNull BuildProcessListener buildProcessListener, int buildTim
status = newStatus;
commitIDBeforeBuild = commitName(buildProcess.commitIDBeforeBuild());
commitIDAfterBuild = commitName(buildProcess.commitIDAfterBuild());
buildScriptFile = buildProcess.buildScriptFile();
if (newStatus.endState()) {
createdTags = buildProcess.createdTags();
FileUtils.write(new File(buildDir, "build.json"), toJson().toString(4), StandardCharsets.UTF_8);
File buildScript = this.buildScriptFile;
if (buildScript != null) {
File target = new File(buildDir, buildScript.getName());
Path newPath = Files.copy(buildScript.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
buildScriptFile = newPath.toFile();
}
buildLog.setLength(0);
this.buildProcess = null;
}
Expand Down
38 changes: 36 additions & 2 deletions src/main/java/com/danielflower/restabuild/web/BuildResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
import io.muserver.rest.ResponseHeader;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.*;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.transport.URIish;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -191,7 +194,9 @@ public Response cancel(@PathParam("id") @Description("The generated build ID whi
private static JSONObject jsonForResult(UriBuilder resourcePath, BuildResult result) {
JSONObject json = result.toJson()
.put("url", resourcePath.replaceQuery(null).build())
.put("logUrl", resourcePath.clone().path("log").replaceQuery(null).build());
.put("logUrl", resourcePath.clone().path("log").replaceQuery(null).build())
.put("buildScriptUrl", resourcePath.clone().path("buildScript").replaceQuery(null).build());

if (result.isCancellable()) {
json.put("cancelUrl", resourcePath.clone().path("cancel").replaceQuery(null).build());
}
Expand Down Expand Up @@ -232,7 +237,7 @@ public void onString(String value) {
});
while (!result.hasFinished()) {
try {
Thread.sleep(500);
Thread.sleep(200);
} catch (InterruptedException e) {
break;
}
Expand All @@ -242,4 +247,33 @@ public void onString(String value) {
throw new NotFoundException();
}
}

@GET
@Path("{id}/buildScript")
@Produces("application/json")
@Description("Gets the file name and contents of the build script used to run a build")
public Response getBuildScript(@PathParam("id") @Description("The generated build ID which is returned when a new build is posted")
String id) throws IOException {
Optional<BuildResult> br = database.get(id);
if (!br.isPresent()) {
throw new NotFoundException("No build with that ID found");
}
File file = br.get().buildScriptFile();
JSONObject resp = new JSONObject();
boolean available;
if (file == null || !file.isFile()) {
available = false;
} else {
available = true;
resp.put("contents", FileUtils.readFileToString(file, StandardCharsets.UTF_8));
}
resp.put("available", available);
if (file != null) {
resp.put("filename", file.getName());
}
return Response.ok()
.entity(resp.toString(4))
.build();
}

}
18 changes: 18 additions & 0 deletions src/test/java/com/danielflower/restabuild/SystemTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,24 @@ public void buildIdAndLogUrlAreAvailableInEnvVars() throws Exception {
));
}


@Test
public void theBuildScriptIsDownloadable() throws Exception {
AppRepo appRepo = AppRepo.create("env-vars");
JSONObject build = new JSONObject(createBuild(appRepo).getContentAsString());
String scriptUrl = build.getString("buildScriptUrl");

// this just causes the test to wait until the build is complete
client.GET(build.getString("logUrl")).getContentAsString();

JSONObject scriptInfo = new JSONObject(client.GET(scriptUrl).getContentAsString());

assertThat(scriptInfo.getBoolean("available"), equalTo(true));
assertThat(scriptInfo.getString("filename"), equalTo(Config.isWindows() ? "build.bat" : "build.sh"));
assertThat(scriptInfo.getString("contents"), containsString("Build Log URL:"));
}


@Test
public void canCancelBuilds() throws Exception {
AppRepo appRepo = AppRepo.create("hung-build");
Expand Down

0 comments on commit d00c8a5

Please sign in to comment.