From 5ee5b07db8389bca794af043465931d84939b2ce Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 14 Oct 2024 00:19:58 +0200 Subject: [PATCH 01/53] server side --- .../artemis/buildagent/dto/BuildConfig.java | 3 +- .../buildagent/dto/DockerRunConfig.java | 56 ++++++++++++ .../service/BuildJobContainerService.java | 63 +++++++++++--- .../service/BuildJobExecutionService.java | 18 ++-- .../ProgrammingExerciseBuildConfig.java | 85 +++++++++++++++++++ .../ci/ContinuousIntegrationService.java | 62 ++++++++++++++ .../localci/LocalCITriggerService.java | 5 +- .../service/BuildAgentDockerServiceTest.java | 3 +- .../icl/LocalCIResourceIntegrationTest.java | 4 +- .../programming/icl/LocalCIServiceTest.java | 2 +- 10 files changed, 277 insertions(+), 24 deletions(-) create mode 100644 src/main/java/de/tum/cit/aet/artemis/buildagent/dto/DockerRunConfig.java diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildConfig.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildConfig.java index 9a41fc6fdc20..34d139aa6f19 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildConfig.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/BuildConfig.java @@ -15,7 +15,8 @@ @JsonInclude(JsonInclude.Include.NON_EMPTY) public record BuildConfig(String buildScript, String dockerImage, String commitHashToBuild, String assignmentCommitHash, String testCommitHash, String branch, ProgrammingLanguage programmingLanguage, ProjectType projectType, boolean scaEnabled, boolean sequentialTestRunsEnabled, boolean testwiseCoverageEnabled, - List resultPaths, int timeoutSeconds, String assignmentCheckoutPath, String testCheckoutPath, String solutionCheckoutPath) implements Serializable { + List resultPaths, int timeoutSeconds, String assignmentCheckoutPath, String testCheckoutPath, String solutionCheckoutPath, DockerRunConfig dockerRunConfig) + implements Serializable { @Override public String dockerImage() { diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/DockerRunConfig.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/DockerRunConfig.java new file mode 100644 index 000000000000..f3da3d65f383 --- /dev/null +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/dto/DockerRunConfig.java @@ -0,0 +1,56 @@ +package de.tum.cit.aet.artemis.buildagent.dto; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class DockerRunConfig implements Serializable { + + private boolean isNetworkDisabled; + + private List env; + + public boolean isNetworkDisabled() { + return isNetworkDisabled; + } + + public void setNetworkDisabled(boolean networkDisabled) { + isNetworkDisabled = networkDisabled; + } + + public List getEnv() { + return env; + } + + public void setEnv(List env) { + this.env = env; + } + + public enum AllowedDockerFlags { + + NETWORK("network"), ENV("env"); + + private final String flag; + + AllowedDockerFlags(String flag) { + this.flag = flag; + } + + public String flag() { + return flag; + } + + private static final Set ALLOWED_FLAGS = new HashSet<>(); + + static { + for (AllowedDockerFlags value : values()) { + ALLOWED_FLAGS.add(value.flag()); + } + } + + public static boolean isAllowed(String flag) { + return ALLOWED_FLAGS.contains(flag); + } + } +} diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobContainerService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobContainerService.java index b7c97daa9786..52d8d46f01e1 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobContainerService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobContainerService.java @@ -33,6 +33,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.ExecCreateCmd; import com.github.dockerjava.api.command.ExecCreateCmdResponse; @@ -45,7 +46,9 @@ import de.tum.cit.aet.artemis.core.exception.LocalCIException; import de.tum.cit.aet.artemis.programming.domain.ProgrammingLanguage; +import de.tum.cit.aet.artemis.programming.domain.ProjectType; import de.tum.cit.aet.artemis.programming.domain.build.BuildLogEntry; +import de.tum.cit.aet.artemis.programming.service.ci.ContinuousIntegrationService.DependencyDownloadScript; import de.tum.cit.aet.artemis.programming.service.ci.ContinuousIntegrationService.RepositoryCheckoutPath; /** @@ -85,12 +88,13 @@ public BuildJobContainerService(DockerClient dockerClient, HostConfig hostConfig /** * Configure a container with the Docker image, the container name, optional proxy config variables, and set the command that runs when the container starts. * - * @param containerName the name of the container to be created - * @param image the Docker image to use for the container - * @param buildScript the build script to be executed in the container + * @param containerName the name of the container to be created + * @param image the Docker image to use for the container + * @param buildScript the build script to be executed in the container + * @param exerciseEnvVars the environment variables provided by the instructor * @return {@link CreateContainerResponse} that can be used to start the container */ - public CreateContainerResponse configureContainer(String containerName, String image, String buildScript) { + public CreateContainerResponse configureContainer(String containerName, String image, String buildScript, List exerciseEnvVars) { List envVars = new ArrayList<>(); if (useSystemProxy) { envVars.add("HTTP_PROXY=" + httpProxy); @@ -98,15 +102,21 @@ public CreateContainerResponse configureContainer(String containerName, String i envVars.add("NO_PROXY=" + noProxy); } envVars.add("SCRIPT=" + buildScript); - return dockerClient.createContainerCmd(image).withName(containerName).withHostConfig(hostConfig).withEnv(envVars) + CreateContainerCmd createContainerCmd = dockerClient.createContainerCmd(image).withName(containerName).withHostConfig(hostConfig).withEnv(envVars) // Command to run when the container starts. This is the command that will be executed in the container's main process, which runs in the foreground and blocks the // container from exiting until it finishes. // It waits until the script that is running the tests (see below execCreateCmdResponse) is completed, and until the result files are extracted which is indicated // by the creation of a file "stop_container.txt" in the container's root directory. - .withCmd("sh", "-c", "while [ ! -f " + LOCALCI_WORKING_DIRECTORY + "/stop_container.txt ]; do sleep 0.5; done") - // .withCmd("tail", "-f", "/dev/null") // Activate for debugging purposes instead of the above command to get a running container that you can peek into using - // "docker exec -it /bin/bash". - .exec(); + .withCmd("sh", "-c", "while [ ! -f " + LOCALCI_WORKING_DIRECTORY + "/stop_container.txt ]; do sleep 0.5; done"); + // .withCmd("tail", "-f", "/dev/null"); // Activate for debugging purposes instead of the above command to get a running container that you can peek into using + // "docker exec -it /bin/bash". + + if (exerciseEnvVars != null && !exerciseEnvVars.isEmpty()) { + envVars.addAll(exerciseEnvVars); + createContainerCmd.withEnv(envVars); + } + + return createContainerCmd.exec(); } /** @@ -125,7 +135,14 @@ public void startContainer(String containerId) { * @param buildJobId the id of the build job that is currently being executed */ - public void runScriptInContainer(String containerId, String buildJobId) { + public void runScriptInContainer(String containerId, String buildJobId, boolean isNetworkDisabled) { + if (isNetworkDisabled) { + // The "sh preScript.sh" execution command specified here is need to install dependencies and prepare the environment for the build script. + log.info("Started running the pre-script for build job in container with id {}", containerId); + executeDockerCommand(containerId, buildJobId, true, true, false, "bash", LOCALCI_WORKING_DIRECTORY + "/preScript.sh"); + dockerClient.disconnectFromNetworkCmd().withContainerId(containerId).withNetworkId("bridge").exec(); + } + log.info("Started running the build script for build job in container with id {}", containerId); // The "sh script.sh" execution command specified here is run inside the container as an additional process. This command runs in the background, independent of the // container's @@ -285,7 +302,7 @@ public String getIDOfRunningContainer(String containerName) { */ public void populateBuildJobContainer(String buildJobContainerId, Path assignmentRepositoryPath, Path testRepositoryPath, Path solutionRepositoryPath, Path[] auxiliaryRepositoriesPaths, String[] auxiliaryRepositoryCheckoutDirectories, ProgrammingLanguage programmingLanguage, String assignmentCheckoutPath, - String testCheckoutPath, String solutionCheckoutPath) { + String testCheckoutPath, String solutionCheckoutPath, ProjectType projectType, boolean isNetworkDisabled) { assignmentCheckoutPath = (!StringUtils.isBlank(assignmentCheckoutPath)) ? assignmentCheckoutPath : RepositoryCheckoutPath.ASSIGNMENT.forProgrammingLanguage(programmingLanguage); @@ -312,10 +329,17 @@ public void populateBuildJobContainer(String buildJobContainerId, Path assignmen addAndPrepareDirectory(buildJobContainerId, auxiliaryRepositoriesPaths[i], LOCALCI_WORKING_DIRECTORY + "/testing-dir/" + auxiliaryRepositoryCheckoutDirectories[i]); } - createScriptFile(buildJobContainerId); + createScriptFile(buildJobContainerId, isNetworkDisabled, programmingLanguage, projectType); } - private void createScriptFile(String buildJobContainerId) { + private void createScriptFile(String buildJobContainerId, boolean isNetworkDisabled, ProgrammingLanguage programmingLanguage, ProjectType projectType) { + if (isNetworkDisabled) { + String preScript = getDependencyDownloadScript(programmingLanguage, projectType); + + executeDockerCommand(buildJobContainerId, null, false, false, true, "bash", "-c", "echo '" + preScript + "' > " + LOCALCI_WORKING_DIRECTORY + "/preScript.sh"); + executeDockerCommand(buildJobContainerId, null, false, false, true, "bash", "-c", "chmod +x " + LOCALCI_WORKING_DIRECTORY + "/preScript.sh"); + } + executeDockerCommand(buildJobContainerId, null, false, false, true, "bash", "-c", "echo \"$SCRIPT\" > " + LOCALCI_WORKING_DIRECTORY + "/script.sh"); executeDockerCommand(buildJobContainerId, null, false, false, true, "bash", "-c", "chmod +x " + LOCALCI_WORKING_DIRECTORY + "/script.sh"); } @@ -447,4 +471,17 @@ private String getParentFolderPath(String path) { Path parentPath = Paths.get(path).normalize().getParent(); return parentPath != null ? parentPath.toString() : ""; } + + private String getDependencyDownloadScript(ProgrammingLanguage programmingLanguage, ProjectType projectType) { + return switch (programmingLanguage) { + case JAVA -> switch (projectType) { + case PLAIN_MAVEN, MAVEN_BLACKBOX, MAVEN_MAVEN -> DependencyDownloadScript.MAVEN.getScript(); + case PLAIN_GRADLE, GRADLE_GRADLE -> DependencyDownloadScript.GRADLE.getScript(); + default -> DependencyDownloadScript.OTHER.getScript(); + }; + case RUST -> DependencyDownloadScript.RUST.getScript(); + case JAVASCRIPT -> DependencyDownloadScript.JAVASCRIPT.getScript(); + default -> DependencyDownloadScript.OTHER.getScript(); + }; + } } diff --git a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java index 9c968c453e47..da749243d355 100644 --- a/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java +++ b/src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobExecutionService.java @@ -192,10 +192,18 @@ public BuildResult runBuildJob(BuildJobQueueItem buildJob, String containerName) index++; } - CreateContainerResponse container = buildJobContainerService.configureContainer(containerName, buildJob.buildConfig().dockerImage(), buildJob.buildConfig().buildScript()); + List envVars = new ArrayList<>(); + boolean isNetworkDisabled = false; + if (buildJob.buildConfig().dockerRunConfig() != null) { + envVars = buildJob.buildConfig().dockerRunConfig().getEnv(); + isNetworkDisabled = buildJob.buildConfig().dockerRunConfig().isNetworkDisabled(); + } + + CreateContainerResponse container = buildJobContainerService.configureContainer(containerName, buildJob.buildConfig().dockerImage(), buildJob.buildConfig().buildScript(), + envVars); return runScriptAndParseResults(buildJob, containerName, container.getId(), assignmentRepoUri, testsRepoUri, solutionRepoUri, auxiliaryRepositoriesUris, - assignmentRepositoryPath, testsRepositoryPath, solutionRepositoryPath, auxiliaryRepositoriesPaths, assignmentCommitHash, testCommitHash); + assignmentRepositoryPath, testsRepositoryPath, solutionRepositoryPath, auxiliaryRepositoriesPaths, assignmentCommitHash, testCommitHash, isNetworkDisabled); } /** @@ -230,7 +238,7 @@ public BuildResult runBuildJob(BuildJobQueueItem buildJob, String containerName) private BuildResult runScriptAndParseResults(BuildJobQueueItem buildJob, String containerName, String containerId, VcsRepositoryUri assignmentRepositoryUri, VcsRepositoryUri testRepositoryUri, VcsRepositoryUri solutionRepositoryUri, VcsRepositoryUri[] auxiliaryRepositoriesUris, Path assignmentRepositoryPath, Path testsRepositoryPath, Path solutionRepositoryPath, Path[] auxiliaryRepositoriesPaths, @Nullable String assignmentRepoCommitHash, - @Nullable String testRepoCommitHash) { + @Nullable String testRepoCommitHash, boolean isNetworkDisabled) { long timeNanoStart = System.nanoTime(); @@ -246,13 +254,13 @@ private BuildResult runScriptAndParseResults(BuildJobQueueItem buildJob, String log.debug(msg); buildJobContainerService.populateBuildJobContainer(containerId, assignmentRepositoryPath, testsRepositoryPath, solutionRepositoryPath, auxiliaryRepositoriesPaths, buildJob.repositoryInfo().auxiliaryRepositoryCheckoutDirectories(), buildJob.buildConfig().programmingLanguage(), buildJob.buildConfig().assignmentCheckoutPath(), - buildJob.buildConfig().testCheckoutPath(), buildJob.buildConfig().solutionCheckoutPath()); + buildJob.buildConfig().testCheckoutPath(), buildJob.buildConfig().solutionCheckoutPath(), buildJob.buildConfig().projectType(), isNetworkDisabled); msg = "~~~~~~~~~~~~~~~~~~~~ Executing Build Script for Build job " + buildJob.id() + " ~~~~~~~~~~~~~~~~~~~~"; buildLogsMap.appendBuildLogEntry(buildJob.id(), msg); log.debug(msg); - buildJobContainerService.runScriptInContainer(containerId, buildJob.id()); + buildJobContainerService.runScriptInContainer(containerId, buildJob.id(), isNetworkDisabled); msg = "~~~~~~~~~~~~~~~~~~~~ Finished Executing Build Script for Build job " + buildJob.id() + " ~~~~~~~~~~~~~~~~~~~~"; buildLogsMap.appendBuildLogEntry(buildJob.id(), msg); diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/cit/aet/artemis/programming/domain/ProgrammingExerciseBuildConfig.java index a5ada6708999..ff19e966d6e4 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/domain/ProgrammingExerciseBuildConfig.java @@ -1,7 +1,11 @@ package de.tum.cit.aet.artemis.programming.domain; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import jakarta.annotation.Nullable; import jakarta.persistence.Column; @@ -10,6 +14,7 @@ import jakarta.persistence.Table; import jakarta.validation.constraints.Size; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +22,10 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import de.tum.cit.aet.artemis.buildagent.dto.DockerRunConfig; import de.tum.cit.aet.artemis.core.domain.DomainObject; import de.tum.cit.aet.artemis.programming.service.aeolus.Windfile; import de.tum.cit.aet.artemis.programming.service.vcs.AbstractVersionControlService; @@ -292,6 +300,83 @@ public void setSolutionCheckoutPath(String solutionCheckoutPath) { this.solutionCheckoutPath = solutionCheckoutPath; } + /** + * Converts a JSON string representing Docker flags (in the form of a list of key-value pairs) + * into a {@link DockerRunConfig} instance. + * + *

+ * The JSON string is expected to represent a list of key-value pairs where each + * entry is a list containing two strings: the first being the key and the second being the value. + * Example JSON input: + * + *

+     * [["network", "none"], ["env", "TEST"]]
+     * 
+ * + * @return a {@link DockerRunConfig} object initialized with the parsed flags, or {@code null} if an error occurs + */ + public DockerRunConfig getDockerRunConfigFromString() { + if (StringUtils.isBlank(dockerFlags)) { + return null; + } + + try { + ObjectMapper objectMapper = new ObjectMapper(); + + List> list = objectMapper.readValue(dockerFlags, new TypeReference<>() { + }); + + DockerRunConfig dockerRunConfig = new DockerRunConfig(); + for (List entry : list) { + if (entry.size() != 2 || entry.get(0) == null || entry.get(1) == null || entry.get(0).isBlank() || entry.get(1).isBlank() + || !DockerRunConfig.AllowedDockerFlags.isAllowed(entry.get(0))) { + log.error("Invalid Docker flag entry: {}. Skipping.", entry); + continue; + } + switch (entry.get(0)) { + case "network": + dockerRunConfig.setNetworkDisabled(entry.get(1).equals("none")); + break; + case "env": + dockerRunConfig.setEnv(parseEnvVariableString(entry.get(1))); + break; + default: + log.error("Invalid Docker flag entry: {}. Skipping.", entry); + break; + } + + } + return dockerRunConfig; + } + catch (Exception e) { + log.error("Failed to parse DockerRunConfig from JSON string: {}. Using default settings.", dockerFlags, e); + } + + return null; + } + + private List parseEnvVariableString(String envVariableString) { + Pattern pattern = Pattern.compile( + // match key-value pairs, where the key can be a single word or a string in single or double quotes + // key-value pairs are separated by commas + "(?:'([^']+)'|\"([^\"]+)\"|(\\w+))=(?:'([^']*)'|\"([^\"]*)\"|([^,]+))"); + + Matcher matcher = pattern.matcher(envVariableString); + + List envVars = new ArrayList<>(); + while (matcher.find()) { + // Determine which group matched for value + String key = matcher.group(1) != null ? matcher.group(1) : matcher.group(2) != null ? matcher.group(2) : matcher.group(3); + + // Determine which group matched for value + String value = matcher.group(4) != null ? matcher.group(4) : matcher.group(5) != null ? matcher.group(5) : matcher.group(6); + + envVars.add(key + "=" + value); + } + + return envVars; + } + @Override public String toString() { return "BuildJobConfig{" + "id=" + getId() + ", sequentialTestRuns=" + sequentialTestRuns + ", branch='" + branch + '\'' + ", buildPlanConfiguration='" diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/ci/ContinuousIntegrationService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/ci/ContinuousIntegrationService.java index b9050501c67a..713e9d2889d0 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/ci/ContinuousIntegrationService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/ci/ContinuousIntegrationService.java @@ -263,6 +263,68 @@ interface CustomizableCheckoutPath { String forProgrammingLanguage(ProgrammingLanguage language); } + enum DependencyDownloadScript { + + GRADLE { + + @Override + public String getScript() { + return getBaseScript() + """ + chmod +x ./gradlew + ./gradlew build --refresh-dependencies + """; + } + }, + MAVEN { + + @Override + public String getScript() { + return getBaseScript() + """ + mvn clean install -U + """; + } + }, + RUST { + + @Override + public String getScript() { + return getBaseScript() + """ + cargo build --verbose + """; + } + }, + JAVASCRIPT { + + @Override + public String getScript() { + return getBaseScript() + """ + npm ci --prefer-offline --no-audit + """; + } + }, + OTHER { + + @Override + public String getScript() { + return getBaseScript() + """ + echo "No dependency download script needed for this programming language" + """; + } + }; + + private static String getBaseScript() { + return """ + #!/bin/bash + cd /var/tmp/testing-dir + #!/usr/bin/env bash + set -e + """; + } + + // Abstract method to be implemented by each enum constant. + public abstract String getScript(); + } + /** * Get the checkout directories for the template and submission build plan for a given programming language. * diff --git a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java index 5da2860ba799..e39304a2dc57 100644 --- a/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/cit/aet/artemis/programming/service/localci/LocalCITriggerService.java @@ -24,6 +24,7 @@ import de.tum.cit.aet.artemis.buildagent.dto.BuildConfig; import de.tum.cit.aet.artemis.buildagent.dto.BuildJobQueueItem; +import de.tum.cit.aet.artemis.buildagent.dto.DockerRunConfig; import de.tum.cit.aet.artemis.buildagent.dto.JobTimingInfo; import de.tum.cit.aet.artemis.buildagent.dto.RepositoryInfo; import de.tum.cit.aet.artemis.core.config.ProgrammingLanguageConfiguration; @@ -307,6 +308,8 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio dockerImage = programmingLanguageConfiguration.getImage(programmingExercise.getProgrammingLanguage(), Optional.ofNullable(programmingExercise.getProjectType())); } + DockerRunConfig dockerRunConfig = buildConfig.getDockerRunConfigFromString(); + List resultPaths = getTestResultPaths(windfile); resultPaths = buildScriptProviderService.replaceResultPathsPlaceholders(resultPaths, buildConfig); @@ -316,7 +319,7 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio return new BuildConfig(buildScript, dockerImage, commitHashToBuild, assignmentCommitHash, testCommitHash, branch, programmingLanguage, projectType, staticCodeAnalysisEnabled, sequentialTestRunsEnabled, testwiseCoverageEnabled, resultPaths, buildConfig.getTimeoutSeconds(), - buildConfig.getAssignmentCheckoutPath(), buildConfig.getTestCheckoutPath(), buildConfig.getSolutionCheckoutPath()); + buildConfig.getAssignmentCheckoutPath(), buildConfig.getTestCheckoutPath(), buildConfig.getSolutionCheckoutPath(), dockerRunConfig); } private ProgrammingExerciseBuildConfig loadBuildConfig(ProgrammingExercise programmingExercise) { diff --git a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java index b4012d1f7a6f..22568028f697 100644 --- a/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/buildagent/service/BuildAgentDockerServiceTest.java @@ -91,7 +91,8 @@ void testPullDockerImage() { InspectImageCmd inspectImageCmd = mock(InspectImageCmd.class); doReturn(inspectImageCmd).when(dockerClient).inspectImageCmd(anyString()); doThrow(new NotFoundException("")).when(inspectImageCmd).exec(); - BuildConfig buildConfig = new BuildConfig("echo 'test'", "test-image-name", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); + BuildConfig buildConfig = new BuildConfig("echo 'test'", "test-image-name", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null, + null); var build = new BuildJobQueueItem("1", "job1", "address1", 1, 1, 1, 1, 1, BuildStatus.SUCCESSFUL, null, null, buildConfig, null); // Pull image try { diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java index 3b7ced720320..eb70fcbdcf4a 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java @@ -91,7 +91,7 @@ void createJobs() { JobTimingInfo jobTimingInfo2 = new JobTimingInfo(ZonedDateTime.now(), ZonedDateTime.now().plusMinutes(1), ZonedDateTime.now().plusMinutes(2)); JobTimingInfo jobTimingInfo3 = new JobTimingInfo(ZonedDateTime.now().minusMinutes(10), ZonedDateTime.now().minusMinutes(9), ZonedDateTime.now().plusSeconds(150)); - BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); + BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); job1 = new BuildJobQueueItem("1", "job1", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.SUCCESSFUL, repositoryInfo, jobTimingInfo1, buildConfig, null); @@ -283,7 +283,7 @@ void testGetFinishedBuildJobs_returnsFilteredJobs() throws Exception { // Create a failed job to filter for JobTimingInfo jobTimingInfo = new JobTimingInfo(ZonedDateTime.now().plusDays(1), ZonedDateTime.now().plusDays(1).plusMinutes(2), ZonedDateTime.now().plusDays(1).plusMinutes(10)); - BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); + BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); var failedJob1 = new BuildJobQueueItem("5", "job5", "address1", 1, course.getId(), 1, 1, 1, BuildStatus.FAILED, repositoryInfo, jobTimingInfo, buildConfig, null); var jobResult = new Result().successful(false).rated(true).score(0D).assessmentType(AssessmentType.AUTOMATIC).completionDate(ZonedDateTime.now()); diff --git a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java index 040aef91d87e..c6d912c3398b 100644 --- a/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java +++ b/src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIServiceTest.java @@ -101,7 +101,7 @@ void testReturnCorrectBuildStatus() { ProgrammingExerciseStudentParticipation participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, TEST_PREFIX + "student1"); JobTimingInfo jobTimingInfo = new JobTimingInfo(ZonedDateTime.now(), ZonedDateTime.now().plusMinutes(1), ZonedDateTime.now().plusMinutes(2)); - BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null); + BuildConfig buildConfig = new BuildConfig("echo 'test'", "test", "test", "test", "test", "test", null, null, false, false, false, null, 0, null, null, null, null); RepositoryInfo repositoryInfo = new RepositoryInfo("test", null, RepositoryType.USER, "test", "test", "test", null, null); BuildJobQueueItem job1 = new BuildJobQueueItem("1", "job1", "address1", participation.getId(), course.getId(), 1, 1, 1, From 7660c8b3148cefdcb6be6e63bf6d4cd404a00f36 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 14 Oct 2024 03:13:44 +0200 Subject: [PATCH 02/53] ui --- ...xercise-build-configuration.component.html | 24 +++++++++- ...-exercise-build-configuration.component.ts | 47 +++++++++++++++++-- ...-exercise-custom-build-plan.component.html | 1 + .../webapp/i18n/en/programmingExercise.json | 10 ++++ 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-build-configuration/programming-exercise-build-configuration.component.html b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-build-configuration/programming-exercise-build-configuration.component.html index 6360bb509017..2bd59ba9b78e 100644 --- a/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-build-configuration/programming-exercise-build-configuration.component.html +++ b/src/main/webapp/app/exercises/programming/manage/update/update-components/custom-build-plans/programming-exercise-build-configuration/programming-exercise-build-configuration.component.html @@ -16,7 +16,29 @@ /> @if (!isAeolus()) { -
+
+ +
+ +
+ + + +
+