From b5f1fd45ebe9bacf7aa9acc1014a6c28c09ef08c Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Fri, 28 Jun 2024 09:49:46 +0200 Subject: [PATCH 01/78] DB migration and changed domain entities --- .../artemis/domain/ProgrammingExercise.java | 125 ++----------- .../ProgrammingExerciseBuildConfig.java | 175 ++++++++++++++++++ .../changelog/20240626200000_changelog.xml | 64 +++++++ 3 files changed, 252 insertions(+), 112 deletions(-) create mode 100644 src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java create mode 100644 src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java index 4631ad59c6f9..d081da199ee1 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java @@ -37,8 +37,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; import de.tum.in.www1.artemis.domain.enumeration.AssessmentType; import de.tum.in.www1.artemis.domain.enumeration.BuildPlanType; @@ -56,8 +54,6 @@ import de.tum.in.www1.artemis.domain.participation.TemplateProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.submissionpolicy.SubmissionPolicy; import de.tum.in.www1.artemis.service.ExerciseDateService; -import de.tum.in.www1.artemis.service.connectors.aeolus.Windfile; -import de.tum.in.www1.artemis.service.connectors.vcs.AbstractVersionControlService; import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature; import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; @@ -107,9 +103,6 @@ public String getType() { @Column(name = "package_name") private String packageName; - @Column(name = "sequential_test_runs") - private Boolean sequentialTestRuns; - @Column(name = "show_test_names_to_students", table = "programming_exercise_details") private boolean showTestNamesToStudents; @@ -167,24 +160,13 @@ public String getType() { @Column(name = "testwise_coverage_enabled", table = "programming_exercise_details") private boolean testwiseCoverageEnabled; - @Column(name = "branch", table = "programming_exercise_details") - private String branch; - @Column(name = "release_tests_with_example_solution", table = "programming_exercise_details") private boolean releaseTestsWithExampleSolution; - @Column(name = "build_plan_configuration", table = "programming_exercise_details", columnDefinition = "longtext") - private String buildPlanConfiguration; - - @Column(name = "build_script", table = "programming_exercise_details", columnDefinition = "longtext") - private String buildScript; - - /** - * This boolean flag determines whether the solution repository should be checked out during the build (additional to the student's submission). - * This is currently only supported for HASKELL and OCAML, thus the default value is false. - */ - @Column(name = "checkout_solution_repository", table = "programming_exercise_details", columnDefinition = "boolean default false") - private boolean checkoutSolutionRepository; + @OneToOne(cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY) + @JoinColumn(unique = true, name = "programming_exercise_build_config_id", table = "programming_exercise_details") + @JsonIgnoreProperties("programmingExercise") + private ProgrammingExerciseBuildConfig buildConfig; /** * Convenience getter. The actual URL is stored in the {@link TemplateProgrammingExerciseParticipation} @@ -318,21 +300,6 @@ public String getProjectKey() { return this.projectKey; } - public void setBranch(String branch) { - this.branch = branch; - } - - /** - * Getter for the stored default branch of the exercise. - * Use {@link AbstractVersionControlService#getOrRetrieveBranchOfExercise(ProgrammingExercise)} if you are not sure that the value was already set in the Artemis database - * - * @return the name of the default branch or null if not yet stored in Artemis - */ - @JsonIgnore - public String getBranch() { - return branch; - } - public void setReleaseTestsWithExampleSolution(boolean releaseTestsWithExampleSolution) { this.releaseTestsWithExampleSolution = releaseTestsWithExampleSolution; } @@ -482,6 +449,14 @@ public void setSubmissionPolicy(SubmissionPolicy submissionPolicy) { this.submissionPolicy = submissionPolicy; } + public ProgrammingExerciseBuildConfig getBuildConfig() { + return buildConfig; + } + + public void setBuildConfig(ProgrammingExerciseBuildConfig buildConfig) { + this.buildConfig = buildConfig; + } + // jhipster-needle-entity-add-getters-setters - Jhipster will add getters and setters here, do not remove /** @@ -606,15 +581,6 @@ public void addStaticCodeAnalysisCategory(final StaticCodeAnalysisCategory categ staticCodeAnalysisCategories.add(category); } - @JsonProperty("sequentialTestRuns") - public boolean hasSequentialTestRuns() { - return Objects.requireNonNullElse(sequentialTestRuns, false); - } - - public void setSequentialTestRuns(Boolean sequentialTestRuns) { - this.sequentialTestRuns = sequentialTestRuns; - } - public Boolean getShowTestNamesToStudents() { return showTestNamesToStudents; } @@ -675,8 +641,6 @@ public void filterSensitiveInformation() { setTestRepositoryUri(null); setTemplateBuildPlanId(null); setSolutionBuildPlanId(null); - setBuildPlanConfiguration(null); - setBuildScript(null); super.filterSensitiveInformation(); } @@ -765,14 +729,6 @@ public String toString() { + testCasesChanged + "'" + "}"; } - public boolean getCheckoutSolutionRepository() { - return this.checkoutSolutionRepository; - } - - public void setCheckoutSolutionRepository(boolean checkoutSolutionRepository) { - this.checkoutSolutionRepository = checkoutSolutionRepository; - } - /** * Validates general programming exercise settings * 1. Validates the programming language @@ -812,7 +768,7 @@ public void validateStaticCodeAnalysisSettings(ProgrammingLanguageFeature progra } // Check that programming exercise doesn't have sequential test runs and static code analysis enabled - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && hasSequentialTestRuns()) { + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && buildConfig.hasSequentialTestRuns()) { throw new BadRequestAlertException("The static code analysis with sequential test runs is not supported at the moment", "Exercise", "staticCodeAnalysisAndSequential"); } @@ -890,61 +846,6 @@ public void disconnectRelatedEntities() { super.disconnectRelatedEntities(); } - /** - * Returns the JSON encoded custom build plan configuration - * - * @return the JSON encoded custom build plan configuration or null if the default one should be used - */ - public String getBuildPlanConfiguration() { - return buildPlanConfiguration; - } - - /** - * Sets the JSON encoded custom build plan configuration - * - * @param buildPlanConfiguration the JSON encoded custom build plan configuration - */ - public void setBuildPlanConfiguration(String buildPlanConfiguration) { - this.buildPlanConfiguration = buildPlanConfiguration; - } - - /** - * We store the build plan configuration as a JSON string in the database, as it is easier to handle than a complex object structure. - * This method parses the JSON string and returns a {@link Windfile} object. - * - * @return the {@link Windfile} object or null if the JSON string could not be parsed - */ - public Windfile getWindfile() { - if (buildPlanConfiguration == null) { - return null; - } - try { - return Windfile.deserialize(buildPlanConfiguration); - } - catch (JsonProcessingException e) { - log.error("Could not parse build plan configuration for programming exercise {}", this.getId(), e); - } - return null; - } - - /** - * We store the bash script in the database - * - * @return the build script or null if the build script does not exist - */ - public String getBuildScript() { - return buildScript; - } - - /** - * Update the build script - * - * @param buildScript the new build script for the programming exercise - */ - public void setBuildScript(String buildScript) { - this.buildScript = buildScript; - } - /** * In course exercises students shall receive immediate feedback. {@link Visibility#ALWAYS} * In Exams misconfiguration and leaking test results to students during an exam shall be prevented by the default setting. {@link Visibility#AFTER_DUE_DATE} diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java new file mode 100644 index 000000000000..ad385284cda9 --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -0,0 +1,175 @@ +package de.tum.in.www1.artemis.domain; + +import java.util.Objects; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; + +import de.tum.in.www1.artemis.service.connectors.aeolus.Windfile; +import de.tum.in.www1.artemis.service.connectors.vcs.AbstractVersionControlService; + +@Entity +@Table(name = "programming_exercise_build_config") +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class ProgrammingExerciseBuildConfig extends DomainObject { + + private static final Logger log = LoggerFactory.getLogger(ProgrammingExerciseBuildConfig.class); + + @Column(name = "sequential_test_runs") + private Boolean sequentialTestRuns; + + @Column(name = "branch") + private String branch; + + @Column(name = "build_plan_configuration") + private String buildPlanConfiguration; + + @Column(name = "build_script") + private String buildScript; + + /** + * This boolean flag determines whether the solution repository should be checked out during the build (additional to the student's submission). + * This is currently only supported for HASKELL and OCAML, thus the default value is false. + */ + @Column(name = "checkout_solution_repository") + private Boolean checkoutSolutionRepository; + + @Column(name = "checkout_path") + private String checkoutPath; + + @Column(name = "timeout_seconds") + private Integer timeoutSeconds; + + @Column(name = "docker_flags") + private String dockerFlags; + + @JsonProperty("sequentialTestRuns") + public boolean hasSequentialTestRuns() { + return Objects.requireNonNullElse(sequentialTestRuns, false); + } + + public void setSequentialTestRuns(Boolean sequentialTestRuns) { + this.sequentialTestRuns = sequentialTestRuns; + } + + /** + * Getter for the stored default branch of the exercise. + * Use {@link AbstractVersionControlService#getOrRetrieveBranchOfExercise(ProgrammingExercise)} if you are not sure that the value was already set in the Artemis database + * + * @return the name of the default branch or null if not yet stored in Artemis + */ + public String getBranch() { + return branch; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + /** + * Returns the JSON encoded custom build plan configuration + * + * @return the JSON encoded custom build plan configuration or null if the default one should be used + */ + public String getBuildPlanConfiguration() { + return buildPlanConfiguration; + } + + /** + * Sets the JSON encoded custom build plan configuration + * + * @param buildPlanConfiguration the JSON encoded custom build plan configuration + */ + public void setBuildPlanConfiguration(String buildPlanConfiguration) { + this.buildPlanConfiguration = buildPlanConfiguration; + } + + /** + * We store the bash script in the database + * + * @return the build script or null if the build script does not exist + */ + public String getBuildScript() { + return buildScript; + } + + /** + * Update the build script + * + * @param buildScript the new build script for the programming exercise + */ + public void setBuildScript(String buildScript) { + this.buildScript = buildScript; + } + + public Boolean getCheckoutSolutionRepository() { + return checkoutSolutionRepository; + } + + public void setCheckoutSolutionRepository(Boolean checkoutSolutionRepository) { + this.checkoutSolutionRepository = checkoutSolutionRepository; + } + + public String getCheckoutPath() { + return checkoutPath; + } + + public void setCheckoutPath(String checkoutPath) { + this.checkoutPath = checkoutPath; + } + + public Integer getTimeoutSeconds() { + return timeoutSeconds; + } + + public void setTimeoutSeconds(Integer timeoutSeconds) { + this.timeoutSeconds = timeoutSeconds; + } + + public String getDockerFlags() { + return dockerFlags; + } + + public void setDockerFlags(String dockerFlags) { + this.dockerFlags = dockerFlags; + } + + /** + * We store the build plan configuration as a JSON string in the database, as it is easier to handle than a complex object structure. + * This method parses the JSON string and returns a {@link Windfile} object. + * + * @return the {@link Windfile} object or null if the JSON string could not be parsed + */ + public Windfile getWindfile() { + if (buildPlanConfiguration == null) { + return null; + } + try { + return Windfile.deserialize(buildPlanConfiguration); + } + catch (JsonProcessingException e) { + log.error("Could not parse build plan configuration for programming exercise {}", this.getId(), e); + } + return null; + } + + public void filterSensitiveInformation() { + setBuildPlanConfiguration(null); + setBuildScript(null); + } + + @Override + public String toString() { + return "BuildJobConfig{" + "id=" + getId() + ", sequentialTestRuns=" + sequentialTestRuns + ", branch='" + branch + '\'' + ", buildPlanConfiguration='" + + buildPlanConfiguration + '\'' + ", buildScript='" + buildScript + '\'' + ", checkoutSolutionRepository=" + checkoutSolutionRepository + ", checkoutPath='" + + checkoutPath + '\'' + ", timeoutSeconds=" + timeoutSeconds + ", dockerFlags='" + dockerFlags + '\'' + '}'; + } +} diff --git a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml new file mode 100644 index 000000000000..3e5ba5bd3943 --- /dev/null +++ b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, programming_exercise_id) + SELECT e.sequential_test_runs, ped.branch, ped.build_plan_configuration, ped.build_script, ped.checkout_solution_repository, e.id + FROM exercise e JOIN programming_exercise_details ped ON e.id = ped.id + WHERE e.discriminator = 'P'; + + UPDATE programming_exercise_details SET programming_exercise_build_config_id = ( + SELECT id + FROM programming_exercise_build_config + WHERE programming_exercise_id = programming_exercise_details.id + ); + + ALTER TABLE exercise DROP COLUMN sequential_test_runs; + ALTER TABLE programming_exercise_details DROP COLUMN branch; + ALTER TABLE programming_exercise_details DROP COLUMN build_plan_configuration; + ALTER TABLE programming_exercise_details DROP COLUMN build_script; + ALTER TABLE programming_exercise_details DROP COLUMN checkout_solution_repository; + + + From 378c56377309f31d5bb0e56bf2cf4791a7e1b6c0 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Fri, 28 Jun 2024 09:53:26 +0200 Subject: [PATCH 02/78] MUST REVERT - fix errors --- .../BuildScriptProviderService.java | 2 +- .../GenericBuildScriptGenerationService.java | 3 ++- .../AeolusBuildScriptGenerationService.java | 2 +- .../aeolus/AeolusTemplateService.java | 2 +- .../gitlabci/GitLabCIBuildPlanService.java | 2 +- .../connectors/gitlabci/GitLabCIService.java | 4 +-- .../gitlabci/GitLabCITriggerService.java | 2 +- .../connectors/jenkins/JenkinsService.java | 4 +-- .../build_plan/JenkinsBuildPlanService.java | 11 ++++---- .../JenkinsPipelineScriptCreator.java | 2 +- .../LocalCIBuildConfigurationService.java | 4 +-- .../connectors/localci/LocalCIService.java | 4 +-- .../localci/LocalCITriggerService.java | 6 ++--- .../vcs/AbstractVersionControlService.java | 6 ++--- .../JavaTemplateUpgradeService.java | 2 +- ...ProgrammingExerciseImportBasicService.java | 6 ++--- .../ProgrammingExerciseRepositoryService.java | 4 +-- .../ProgrammingExerciseService.java | 26 +++++++++---------- .../ProgrammingExerciseResource.java | 4 +-- .../resources/config/liquibase/master.xml | 1 + .../artemis/BuildPlanIntegrationTest.java | 2 +- ...eolusBuildScriptGenerationServiceTest.java | 8 +++--- .../artemis/connectors/AeolusServiceTest.java | 6 ++--- .../exam/StudentExamIntegrationTest.java | 4 +-- .../programming/GitlabServiceTest.java | 2 +- .../ProgrammingExerciseFactory.java | 12 ++++----- ...rammingExerciseIntegrationTestService.java | 4 +-- .../ProgrammingExerciseResultTestService.java | 2 +- ...rammingExerciseServiceIntegrationTest.java | 2 +- .../ProgrammingExerciseTestService.java | 4 +-- ...AbstractLocalCILocalVCIntegrationTest.java | 2 +- .../localvcci/LocalCIIntegrationTest.java | 2 +- .../artemis/localvcci/LocalCIServiceTest.java | 12 ++++----- ...VCLocalCIParticipationIntegrationTest.java | 2 +- .../artemis/service/GitlabCIServiceTest.java | 2 +- .../JenkinsPipelineScriptCreatorTest.java | 2 +- 36 files changed, 84 insertions(+), 81 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java index 620182f07764..063751c6a771 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java @@ -125,7 +125,7 @@ public String getScriptFor(ProgrammingLanguage programmingLanguage, Optional extractProjectType(String filename) { public Windfile getDefaultWindfileFor(ProgrammingExercise exercise) { try { return getWindfileFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()), exercise.isStaticCodeAnalysisEnabled(), - exercise.hasSequentialTestRuns(), exercise.isTestwiseCoverageEnabled()); + exercise.getBuildConfig().hasSequentialTestRuns(), exercise.isTestwiseCoverageEnabled()); } catch (IOException e) { log.info("No windfile for the settings of exercise {}", exercise.getId(), e); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIBuildPlanService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIBuildPlanService.java index 3b5391c701a0..76a2c01fc4c4 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIBuildPlanService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIBuildPlanService.java @@ -45,7 +45,7 @@ public GitLabCIBuildPlanService(BuildPlanRepository buildPlanRepository, Program @Override public String generateDefaultBuildPlan(ProgrammingExercise programmingExercise) { final Optional projectTypeName = getProjectTypeName(programmingExercise); - final Path resourcePath = buildResourcePath(programmingExercise.getProgrammingLanguage(), projectTypeName, programmingExercise.hasSequentialTestRuns()); + final Path resourcePath = buildResourcePath(programmingExercise.getProgrammingLanguage(), projectTypeName, programmingExercise.getBuildConfig().hasSequentialTestRuns()); final Resource resource = resourceLoaderService.getResource(resourcePath); try { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java index f338a26e910f..e48faa833e42 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java @@ -150,8 +150,8 @@ private void setupGitLabCIConfiguration(VcsRepositoryUri repositoryUri, Programm updateVariable(repositoryPath, VARIABLE_NOTIFICATION_PLUGIN_DOCKER_IMAGE_NAME, notificationPluginDockerImage); updateVariable(repositoryPath, VARIABLE_NOTIFICATION_SECRET_NAME, artemisAuthenticationTokenValue); updateVariable(repositoryPath, VARIABLE_NOTIFICATION_URL_NAME, artemisServerUrl.toExternalForm() + NEW_RESULT_RESOURCE_API_PATH); - updateVariable(repositoryPath, VARIABLE_SUBMISSION_GIT_BRANCH_NAME, exercise.getBranch()); - updateVariable(repositoryPath, VARIABLE_TEST_GIT_BRANCH_NAME, exercise.getBranch()); + updateVariable(repositoryPath, VARIABLE_SUBMISSION_GIT_BRANCH_NAME, exercise.getBuildConfig().getBranch()); + updateVariable(repositoryPath, VARIABLE_TEST_GIT_BRANCH_NAME, exercise.getBuildConfig().getBranch()); updateVariable(repositoryPath, VARIABLE_TEST_GIT_REPOSITORY_SLUG_NAME, uriService.getRepositorySlugFromRepositoryUriString(exercise.getTestRepositoryUri())); // TODO: Use a token that is only valid for the test repository for each programming exercise updateVariable(repositoryPath, VARIABLE_TEST_GIT_TOKEN, gitlabToken); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java index 099e76e55ccd..dd901ddf848e 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java @@ -28,7 +28,7 @@ public GitLabCITriggerService(GitLabApi gitlab, UriService uriService) { @Override public void triggerBuild(ProgrammingExerciseParticipation participation) throws ContinuousIntegrationException { - triggerBuild(participation.getVcsRepositoryUri(), participation.getProgrammingExercise().getBranch()); + triggerBuild(participation.getVcsRepositoryUri(), participation.getProgrammingExercise().getBuildConfig().getBranch()); } private void triggerBuild(VcsRepositoryUri vcsRepositoryUri, String branch) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java index 5f251df9de94..1bace8ee35bd 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java @@ -99,7 +99,7 @@ public void recreateBuildPlansForExercise(ProgrammingExercise exercise) throws J deleteBuildPlan(projectKey, exercise.getTemplateBuildPlanId()); deleteBuildPlan(projectKey, exercise.getSolutionBuildPlanId()); - if (exercise.getBuildPlanConfiguration() != null) { + if (exercise.getBuildConfig().getBuildPlanConfiguration() != null) { resetCustomBuildPlanToTemplate(exercise); } @@ -118,7 +118,7 @@ private void resetCustomBuildPlanToTemplate(ProgrammingExercise exercise) throws } Windfile windfile = aeolusTemplateService.get().getDefaultWindfileFor(exercise); if (windfile != null) { - exercise.setBuildPlanConfiguration(mapper.writeValueAsString(windfile)); + exercise.getBuildConfig().setBuildPlanConfiguration(mapper.writeValueAsString(windfile)); } if (profileService.isAeolusActive()) { programmingExerciseRepository.save(exercise); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java index 0f6cefc61fae..0ea1045173e3 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java @@ -134,7 +134,7 @@ public void createBuildPlanForExercise(ProgrammingExercise exercise, String plan final ProgrammingLanguage programmingLanguage = exercise.getProgrammingLanguage(); final var configBuilder = builderFor(programmingLanguage, exercise.getProjectType()); final String buildPlanUrl = jenkinsPipelineScriptCreator.generateBuildPlanURL(exercise); - final boolean checkoutSolution = exercise.getCheckoutSolutionRepository(); + final boolean checkoutSolution = exercise.getBuildConfig().getCheckoutSolutionRepository(); final Document jobConfig = configBuilder.buildBasicConfig(programmingLanguage, Optional.ofNullable(exercise.getProjectType()), internalRepositoryUris, checkoutSolution, buildPlanUrl); @@ -142,7 +142,7 @@ public void createBuildPlanForExercise(ProgrammingExercise exercise, String plan String job = jobFolder + "-" + planKey; boolean couldCreateBuildPlan = false; - if (aeolusBuildPlanService.isPresent() && exercise.getBuildPlanConfiguration() != null) { + if (aeolusBuildPlanService.isPresent() && exercise.getBuildConfig().getBuildPlanConfiguration() != null) { var createdJob = createCustomAeolusBuildPlanForExercise(exercise, jobFolder + "/" + job, internalRepositoryUris.assignmentRepositoryUri(), internalRepositoryUris.testRepositoryUri(), internalRepositoryUris.solutionRepositoryUri()); couldCreateBuildPlan = createdJob != null; @@ -491,13 +491,14 @@ public void enablePlan(String projectKey, String planKey) { */ private String createCustomAeolusBuildPlanForExercise(ProgrammingExercise programmingExercise, String buildPlanId, VcsRepositoryUri repositoryUri, VcsRepositoryUri testRepositoryUri, VcsRepositoryUri solutionRepositoryUri) throws ContinuousIntegrationBuildPlanException { - if (aeolusBuildPlanService.isEmpty() || programmingExercise.getBuildPlanConfiguration() == null) { + if (aeolusBuildPlanService.isEmpty() || programmingExercise.getBuildConfig().getBuildPlanConfiguration() == null) { return null; } try { - Windfile windfile = programmingExercise.getWindfile(); + Windfile windfile = programmingExercise.getBuildConfig().getWindfile(); Map repositories = aeolusBuildPlanService.get().createRepositoryMapForWindfile(programmingExercise.getProgrammingLanguage(), - programmingExercise.getBranch(), programmingExercise.getCheckoutSolutionRepository(), repositoryUri, testRepositoryUri, solutionRepositoryUri, List.of()); + programmingExercise.getBuildConfig().getBranch(), programmingExercise.getBuildConfig().getCheckoutSolutionRepository(), repositoryUri, testRepositoryUri, + solutionRepositoryUri, List.of()); String resultHookUrl = artemisServerUrl + NEW_RESULT_RESOURCE_API_PATH; windfile.setPreProcessingMetadata(buildPlanId, programmingExercise.getProjectName(), this.vcsCredentials, resultHookUrl, "planDescription", repositories, diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java index 8dcc0183a33e..9f839afdfb4c 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java @@ -73,7 +73,7 @@ protected String generateDefaultBuildPlan(final ProgrammingExercise exercise) { */ private String loadPipelineScript(final ProgrammingExercise exercise, final Optional projectType) { final ProgrammingLanguage programmingLanguage = exercise.getProgrammingLanguage(); - final boolean isSequentialTestRuns = exercise.hasSequentialTestRuns(); + final boolean isSequentialTestRuns = exercise.getBuildConfig().hasSequentialTestRuns(); final Path pipelinePath = buildResourcePath(programmingLanguage, projectType, isSequentialTestRuns); final Resource resource = resourceLoaderService.getResource(pipelinePath); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java index fcea969b3b89..43bdf39226af 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java @@ -39,7 +39,7 @@ public String createBuildScript(ProgrammingExerciseParticipation participation) buildScript.append("#!/bin/bash\n"); buildScript.append("cd ").append(LOCALCI_WORKING_DIRECTORY).append("/testing-dir\n"); - String customScript = programmingExercise.getBuildScript(); + String customScript = programmingExercise.getBuildConfig().getBuildScript(); // Todo: get default script if custom script is null before trying to get actions from windfile if (customScript != null) { buildScript.append(customScript); @@ -47,7 +47,7 @@ public String createBuildScript(ProgrammingExerciseParticipation participation) else { List actions; - Windfile windfile = programmingExercise.getWindfile(); + Windfile windfile = programmingExercise.getBuildConfig().getWindfile(); if (windfile == null) { windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java index c06b74aa03c9..f413f6d1960f 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java @@ -78,8 +78,8 @@ public void recreateBuildPlansForExercise(ProgrammingExercise exercise) throws J } String script = buildScriptProviderService.getScriptFor(exercise); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(exercise); - exercise.setBuildScript(script); - exercise.setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); + exercise.getBuildConfig().setBuildScript(script); + exercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); // recreating the build plans for the exercise means we need to store the updated exercise in the database programmingExerciseRepository.save(exercise); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java index abd1fdd1bd9a..5524fd433fa2 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java @@ -201,7 +201,7 @@ private RepositoryInfo getRepositoryInfo(ProgrammingExerciseParticipation partic String[] auxiliaryRepositoryUris = auxiliaryRepositories.stream().map(AuxiliaryRepository::getRepositoryUri).toArray(String[]::new); String[] auxiliaryRepositoryCheckoutDirectories1 = auxiliaryRepositories.stream().map(AuxiliaryRepository::getCheckoutDirectory).toArray(String[]::new); - if (programmingExercise.getCheckoutSolutionRepository()) { + if (programmingExercise.getBuildConfig().getCheckoutSolutionRepository()) { ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.getProgrammingLanguageFeatures(programmingExercise.getProgrammingLanguage()); if (programmingLanguageFeature.checkoutSolutionRepositoryAllowed()) { var solutionParticipation = solutionProgrammingExerciseParticipationRepository.findByProgrammingExerciseId(participation.getProgrammingExercise().getId()); @@ -250,13 +250,13 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio ProgrammingLanguage programmingLanguage = programmingExercise.getProgrammingLanguage(); ProjectType projectType = programmingExercise.getProjectType(); boolean staticCodeAnalysisEnabled = programmingExercise.isStaticCodeAnalysisEnabled(); - boolean sequentialTestRunsEnabled = programmingExercise.hasSequentialTestRuns(); + boolean sequentialTestRunsEnabled = programmingExercise.getBuildConfig().hasSequentialTestRuns(); boolean testwiseCoverageEnabled = programmingExercise.isTestwiseCoverageEnabled(); Windfile windfile; String dockerImage; try { - windfile = programmingExercise.getWindfile(); + windfile = programmingExercise.getBuildConfig().getWindfile(); dockerImage = windfile.getMetadata().docker().getFullImageName(); } catch (NullPointerException e) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java index fcb98a759d79..053876bbbef0 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java @@ -178,16 +178,16 @@ public String getOrRetrieveBranchOfStudentParticipation(ProgrammingExerciseStude @Override public String getOrRetrieveBranchOfExercise(ProgrammingExercise programmingExercise) { - if (programmingExercise.getBranch() == null) { + if (programmingExercise.getBuildConfig().getBranch() == null) { if (!Hibernate.isInitialized(programmingExercise.getTemplateParticipation())) { programmingExercise.setTemplateParticipation(templateProgrammingExerciseParticipationRepository.findByProgrammingExerciseIdElseThrow(programmingExercise.getId())); } String branch = getDefaultBranchOfRepository(programmingExercise.getVcsTemplateRepositoryUri()); - programmingExercise.setBranch(branch); + programmingExercise.getBuildConfig().setBranch(branch); programmingExerciseRepository.save(programmingExercise); } - return programmingExercise.getBranch(); + return programmingExercise.getBuildConfig().getBranch(); } @Override diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java index 223bf6a42a7a..a4ea308c262a 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java @@ -79,7 +79,7 @@ public JavaTemplateUpgradeService(ProgrammingExerciseRepositoryService programmi @Override public void upgradeTemplate(ProgrammingExercise exercise) { // TODO: Support sequential test runs - if (exercise.hasSequentialTestRuns()) { + if (exercise.getBuildConfig().hasSequentialTestRuns()) { return; } // Template and solution repository can also contain a project object model for some project types diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java index 85d0dc0b2f61..ff30348d7158 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java @@ -127,9 +127,9 @@ public ProgrammingExercise importProgrammingExerciseBasis(final ProgrammingExerc setupTestRepository(newProgrammingExercise); programmingExerciseService.initParticipations(newProgrammingExercise); - if (newProgrammingExercise.getBuildPlanConfiguration() == null) { + if (newProgrammingExercise.getBuildConfig().getBuildPlanConfiguration() == null) { // this means the user did not override the build plan config when importing the exercise and want to reuse it from the existing exercise - newProgrammingExercise.setBuildPlanConfiguration(originalProgrammingExercise.getBuildPlanConfiguration()); + newProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(originalProgrammingExercise.getBuildConfig().getBuildPlanConfiguration()); } // Hints, tasks, test cases and static code analysis categories @@ -197,7 +197,7 @@ private void prepareBasicExerciseInformation(final ProgrammingExercise originalP newProgrammingExercise.generateAndSetBuildPlanAccessSecret(); } - newProgrammingExercise.setBranch(versionControlService.orElseThrow().getDefaultBranchOfArtemis()); + newProgrammingExercise.getBuildConfig().setBranch(versionControlService.orElseThrow().getDefaultBranchOfArtemis()); } /** diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java index f60ddf2fca53..0d9602fa77b4 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java @@ -332,7 +332,7 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi // Keep or delete testwise coverage configuration in the build file sectionsMap.put("record-testwise-coverage", Boolean.TRUE.equals(programmingExercise.isTestwiseCoverageEnabled())); - if (programmingExercise.hasSequentialTestRuns()) { + if (programmingExercise.getBuildConfig().hasSequentialTestRuns()) { setupTestTemplateSequentialTestRuns(resources, templatePath, projectTemplatePath, projectType, sectionsMap); } else { @@ -607,7 +607,7 @@ void replacePlaceholders(final ProgrammingExercise programmingExercise, final Re replacements.put("${exerciseNamePomXml}", programmingExercise.getTitle().replace(" ", "-")); // Used e.g. in artifactId replacements.put("${exerciseName}", programmingExercise.getTitle()); replacements.put("${studentWorkingDirectory}", Constants.STUDENT_WORKING_DIRECTORY); - replacements.put("${packaging}", programmingExercise.hasSequentialTestRuns() ? "pom" : "jar"); + replacements.put("${packaging}", programmingExercise.getBuildConfig().hasSequentialTestRuns() ? "pom" : "jar"); fileService.replaceVariablesInFileRecursive(repository.getLocalPath().toAbsolutePath(), replacements, List.of("gradle-wrapper.jar")); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java index b51e5a47b975..5490341e3e40 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java @@ -269,7 +269,7 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program // Step 1: Setting constant facts for a programming exercise savedProgrammingExercise.generateAndSetProjectKey(); - savedProgrammingExercise.setBranch(versionControl.getDefaultBranchOfArtemis()); + savedProgrammingExercise.getBuildConfig().setBranch(versionControl.getDefaultBranchOfArtemis()); // Step 2: Creating repositories for new exercise programmingExerciseRepositoryService.createRepositoriesForNewExercise(savedProgrammingExercise); @@ -298,10 +298,10 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program // Step 8: For LocalCI and Aeolus, we store the build plan definition in the database as a windfile, we don't do that for Jenkins as // we want to use the default approach of Jenkinsfiles and Build Plans if no customizations are made - if (aeolusTemplateService.isPresent() && savedProgrammingExercise.getBuildPlanConfiguration() == null && !profileService.isJenkinsActive()) { + if (aeolusTemplateService.isPresent() && savedProgrammingExercise.getBuildConfig().getBuildPlanConfiguration() == null && !profileService.isJenkinsActive()) { Windfile windfile = aeolusTemplateService.get().getDefaultWindfileFor(savedProgrammingExercise); if (windfile != null) { - savedProgrammingExercise.setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); + savedProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); savedProgrammingExercise = programmingExerciseRepository.saveForCreation(savedProgrammingExercise); } else { @@ -362,7 +362,7 @@ public void validateNewProgrammingExerciseSettings(ProgrammingExercise programmi validateProjectType(programmingExercise, programmingLanguageFeature); // Check if checkout solution repository is enabled - if (programmingExercise.getCheckoutSolutionRepository() && !programmingLanguageFeature.checkoutSolutionRepositoryAllowed()) { + if (programmingExercise.getBuildConfig().getCheckoutSolutionRepository() && !programmingLanguageFeature.checkoutSolutionRepositoryAllowed()) { throw new BadRequestAlertException("Checkout solution repository is not supported for this programming language", "Exercise", "checkoutSolutionRepositoryNotSupported"); } @@ -457,11 +457,11 @@ public void setupBuildPlansForNewExercise(ProgrammingExercise programmingExercis giveCIProjectPermissions(programmingExercise); - Windfile windfile = programmingExercise.getWindfile(); - if (windfile != null && buildScriptGenerationService.isPresent() && programmingExercise.getBuildScript() == null) { + Windfile windfile = programmingExercise.getBuildConfig().getWindfile(); + if (windfile != null && buildScriptGenerationService.isPresent() && programmingExercise.getBuildConfig().getBuildScript() == null) { String script = buildScriptGenerationService.get().getScript(programmingExercise); - programmingExercise.setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); - programmingExercise.setBuildScript(script); + programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); + programmingExercise.getBuildConfig().setBuildScript(script); programmingExercise = programmingExerciseRepository.saveForCreation(programmingExercise); } @@ -576,13 +576,13 @@ public ProgrammingExercise updateProgrammingExercise(ProgrammingExercise program * @param updatedProgrammingExercise the changed programming exercise with its new values */ private void updateBuildPlanForExercise(ProgrammingExercise programmingExerciseBeforeUpdate, ProgrammingExercise updatedProgrammingExercise) throws JsonProcessingException { - if (continuousIntegrationService.isEmpty() - || Objects.equals(programmingExerciseBeforeUpdate.getBuildPlanConfiguration(), updatedProgrammingExercise.getBuildPlanConfiguration())) { + if (continuousIntegrationService.isEmpty() || Objects.equals(programmingExerciseBeforeUpdate.getBuildConfig().getBuildPlanConfiguration(), + updatedProgrammingExercise.getBuildConfig().getBuildPlanConfiguration())) { return; } // we only update the build plan configuration if it has changed and is not null, otherwise we // do not have a valid exercise anymore - if (updatedProgrammingExercise.getBuildPlanConfiguration() != null) { + if (updatedProgrammingExercise.getBuildConfig().getBuildPlanConfiguration() != null) { if (!profileService.isLocalCiActive()) { continuousIntegrationService.get().deleteProject(updatedProgrammingExercise.getProjectKey()); continuousIntegrationService.get().createProjectForExercise(updatedProgrammingExercise); @@ -591,13 +591,13 @@ private void updateBuildPlanForExercise(ProgrammingExercise programmingExerciseB } if (buildScriptGenerationService.isPresent()) { String script = buildScriptGenerationService.get().getScript(updatedProgrammingExercise); - updatedProgrammingExercise.setBuildScript(script); + updatedProgrammingExercise.getBuildConfig().setBuildScript(script); programmingExerciseRepository.save(updatedProgrammingExercise); } } else { // if the user does not change the build plan configuration, we have to set the old one again - updatedProgrammingExercise.setBuildPlanConfiguration(programmingExerciseBeforeUpdate.getBuildPlanConfiguration()); + updatedProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(programmingExerciseBeforeUpdate.getBuildConfig().getBuildPlanConfiguration()); } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index fdead0c65162..c061cbdfa72a 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -320,7 +320,7 @@ public ResponseEntity updateProgrammingExercise(@RequestBod athenaModuleService.ifPresent(ams -> ams.checkValidAthenaModuleChange(programmingExerciseBeforeUpdate, updatedProgrammingExercise, ENTITY_NAME)); // Ignore changes to the default branch - updatedProgrammingExercise.setBranch(programmingExerciseBeforeUpdate.getBranch()); + updatedProgrammingExercise.getBuildConfig().setBranch(programmingExerciseBeforeUpdate.getBuildConfig().getBranch()); if (updatedProgrammingExercise.getAuxiliaryRepositories() == null) { // make sure the default value is set properly @@ -576,7 +576,7 @@ public ResponseEntity generateStructureOracleForExercise(@PathVariable l try { String testsPath = Path.of("test", programmingExercise.getPackageFolderName()).toString(); // Atm we only have one folder that can have structural tests, but this could change. - testsPath = programmingExercise.hasSequentialTestRuns() ? Path.of("structural", testsPath).toString() : testsPath; + testsPath = programmingExercise.getBuildConfig().hasSequentialTestRuns() ? Path.of("structural", testsPath).toString() : testsPath; boolean didGenerateOracle = programmingExerciseService.generateStructureOracleFile(solutionRepoUri, exerciseRepoUri, testRepoUri, testsPath, user); if (didGenerateOracle) { diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index 729d22ca2a4d..54d84a1d40f5 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -17,6 +17,7 @@ + diff --git a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java index db8ab14bb24a..090a6cd7fd1a 100644 --- a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java @@ -53,7 +53,7 @@ void init() { programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setSequentialTestRuns(false); + programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.setTestwiseCoverageEnabled(false); programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java index 4a041f87b769..1b19377cea9e 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java @@ -90,11 +90,11 @@ void testBuildScriptGenerationUsingBuildPlanGenerationService() throws JsonProce aeolusRequestMockProvider.mockGeneratePreview(AeolusTarget.CLI); aeolusRequestMockProvider.mockGeneratePreview(AeolusTarget.CLI); ProgrammingExercise programmingExercise = new ProgrammingExercise(); - programmingExercise.setBuildPlanConfiguration(getSerializedWindfile()); + programmingExercise.getBuildConfig().setBuildPlanConfiguration(getSerializedWindfile()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setSequentialTestRuns(true); + programmingExercise.getBuildConfig().setSequentialTestRuns(true); programmingExercise.setTestwiseCoverageEnabled(true); String script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNotNull(); @@ -102,9 +102,9 @@ void testBuildScriptGenerationUsingBuildPlanGenerationService() throws JsonProce programmingExercise.setProgrammingLanguage(ProgrammingLanguage.PYTHON); programmingExercise.setProjectType(null); programmingExercise.setStaticCodeAnalysisEnabled(false); - programmingExercise.setSequentialTestRuns(false); + programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.setTestwiseCoverageEnabled(false); - programmingExercise.setBuildPlanConfiguration(null); + programmingExercise.getBuildConfig().setBuildPlanConfiguration(null); script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNotNull(); assertThat(script).isEqualTo("imagine a result here"); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java index ee76413749e0..779944a93bf2 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java @@ -197,11 +197,11 @@ private String getSerializedWindfile() throws JsonProcessingException { @Test void testShouldNotGenerateAnything() throws JsonProcessingException { ProgrammingExercise programmingExercise = new ProgrammingExercise(); - programmingExercise.setBuildPlanConfiguration(getSerializedWindfile()); + programmingExercise.getBuildConfig().setBuildPlanConfiguration(getSerializedWindfile()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setSequentialTestRuns(true); + programmingExercise.getBuildConfig().setSequentialTestRuns(true); programmingExercise.setTestwiseCoverageEnabled(true); String script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNull(); @@ -220,7 +220,7 @@ void testGetDefaultWindfileFor() { ProgrammingExercise programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setSequentialTestRuns(true); + programmingExercise.getBuildConfig().setSequentialTestRuns(true); programmingExercise.setTestwiseCoverageEnabled(true); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); assertThat(windfile).isNull(); diff --git a/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java index b38e349ad4be..696a1795ed20 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java @@ -510,8 +510,8 @@ void testGetStudentExamForConduction() throws Exception { assertThat(exercise.getExerciseGroup().getExercises()).isEmpty(); assertThat(exercise.getExerciseGroup().getExam()).isNull(); if (exercise instanceof ProgrammingExercise) { - assertThat(((ProgrammingExercise) exercise).getBuildScript()).isNull(); - assertThat(((ProgrammingExercise) exercise).getBuildPlanConfiguration()).isNull(); + assertThat(((ProgrammingExercise) exercise).getBuildConfig().getBuildScript()).isNull(); + assertThat(((ProgrammingExercise) exercise).getBuildConfig().getBuildPlanConfiguration()).isNull(); } } assertThat(studentExamRepository.findById(studentExam.getId()).orElseThrow().isStarted()).isTrue(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java index 6da5c47e0c4f..8c2ce909a7a5 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java @@ -137,7 +137,7 @@ void testGetOrRetrieveDefaultBranch() throws GitLabApiException { Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); ProgrammingExercise programmingExercise = (ProgrammingExercise) course.getExercises().stream().findAny().orElseThrow(); - programmingExercise.setBranch(null); + programmingExercise.getBuildConfig().setBranch(null); programmingExercise = programmingExerciseRepository.save(programmingExercise); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java index 179db94a6ce2..00511e431a5d 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java @@ -120,8 +120,8 @@ private static void populateUnreleasedProgrammingExercise(ProgrammingExercise pr programmingExercise.setTestwiseCoverageEnabled(false); programmingExercise.setAssessmentType(AssessmentType.SEMI_AUTOMATIC); programmingExercise.setProgrammingLanguage(programmingLanguage); - programmingExercise.setBuildScript("Some script"); - programmingExercise.setBuildPlanConfiguration("{\"api\":\"v0.0.1\",\"metadata\":{},\"actions\":[]}"); + programmingExercise.getBuildConfig().setBuildScript("Some script"); + programmingExercise.getBuildConfig().setBuildPlanConfiguration("{\"api\":\"v0.0.1\",\"metadata\":{},\"actions\":[]}"); if (programmingLanguage == ProgrammingLanguage.JAVA) { programmingExercise.setProjectType(ProjectType.PLAIN_MAVEN); } @@ -135,7 +135,7 @@ else if (programmingLanguage == ProgrammingLanguage.SWIFT) { final var repoName = programmingExercise.generateRepositoryName(RepositoryType.TESTS); String testRepoUri = String.format("http://some.test.url/scm/%s/%s.git", programmingExercise.getProjectKey(), repoName); programmingExercise.setTestRepositoryUri(testRepoUri); - programmingExercise.setBranch(DEFAULT_BRANCH); + programmingExercise.getBuildConfig().setBranch(DEFAULT_BRANCH); } /** @@ -161,7 +161,7 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setExerciseHints(null); toBeImported.setSolutionParticipation(null); toBeImported.setTemplateParticipation(null); - toBeImported.setSequentialTestRuns(template.hasSequentialTestRuns()); + toBeImported.getBuildConfig().setSequentialTestRuns(template.getBuildConfig().hasSequentialTestRuns()); toBeImported.setProblemStatement(template.getProblemStatement()); toBeImported.setMaxPoints(template.getMaxPoints()); toBeImported.setBonusPoints(template.getBonusPoints()); @@ -188,7 +188,7 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setDueDate(template.getDueDate()); toBeImported.setReleaseDate(template.getReleaseDate()); toBeImported.setExampleSolutionPublicationDate(null); - toBeImported.setSequentialTestRuns(template.hasSequentialTestRuns()); + toBeImported.getBuildConfig().setSequentialTestRuns(template.getBuildConfig().hasSequentialTestRuns()); toBeImported.setBuildAndTestStudentSubmissionsAfterDueDate(template.getBuildAndTestStudentSubmissionsAfterDueDate()); toBeImported.generateAndSetProjectKey(); toBeImported.setPlagiarismDetectionConfig(template.getPlagiarismDetectionConfig()); @@ -434,6 +434,6 @@ else if (programmingLanguage == ProgrammingLanguage.C) { programmingExercise.setCategories(new HashSet<>(Set.of("cat1", "cat2"))); programmingExercise.setTestRepositoryUri("http://nadnasidni.tum/scm/" + programmingExercise.getProjectKey() + "/" + programmingExercise.getProjectKey() + "-tests.git"); programmingExercise.setShowTestNamesToStudents(false); - programmingExercise.setBranch(DEFAULT_BRANCH); + programmingExercise.getBuildConfig().setBranch(DEFAULT_BRANCH); } } diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java index dee9bd7447c1..afdd04cd7d9b 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java @@ -1201,7 +1201,7 @@ void createProgrammingExercise_staticCodeAnalysisAndSequential_badRequest() thro programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setSequentialTestRuns(true); + programmingExercise.getBuildConfig().setSequentialTestRuns(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1291,7 +1291,7 @@ void createProgrammingExercise_checkoutSolutionRepositoryProgrammingLanguageNotS programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(programmingLanguage); - programmingExercise.setCheckoutSolutionRepository(true); + programmingExercise.getBuildConfig().setCheckoutSolutionRepository(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java index 1f860df7e058..05ae7a003cfb 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java @@ -412,7 +412,7 @@ public void shouldIgnoreResultIfNotOnParticipationBranch(AbstractBuildResultNoti // Test public void shouldCreateResultOnCustomDefaultBranch(String defaultBranch, AbstractBuildResultNotificationDTO resultNotification) { - programmingExercise.setBranch(defaultBranch); + programmingExercise.getBuildConfig().setBranch(defaultBranch); programmingExercise = programmingExerciseRepository.save(programmingExercise); solutionParticipation.setProgrammingExercise(programmingExercise); programmingExerciseStudentParticipation.setProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java index bed40a6f56ea..48673dd1b2ec 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java @@ -104,7 +104,7 @@ void importProgrammingExerciseBasis_baseReferencesGotCloned() { assertThat(newlyImported.getProjectKey()).isNotEqualTo(programmingExercise.getProjectKey()); assertThat(newlyImported.getSolutionBuildPlanId()).isNotEqualTo(programmingExercise.getSolutionBuildPlanId()); assertThat(newlyImported.getTemplateBuildPlanId()).isNotEqualTo(programmingExercise.getTemplateBuildPlanId()); - assertThat(newlyImported.hasSequentialTestRuns()).isEqualTo(programmingExercise.hasSequentialTestRuns()); + assertThat(newlyImported.getBuildConfig().hasSequentialTestRuns()).isEqualTo(programmingExercise.getBuildConfig().hasSequentialTestRuns()); assertThat(newlyImported.isAllowOnlineEditor()).isEqualTo(programmingExercise.isAllowOnlineEditor()); assertThat(newlyImported.getTotalNumberOfAssessments()).isNull(); assertThat(newlyImported.getNumberOfComplaints()).isNull(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java index ba295159e0dd..01a94d2eb6be 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java @@ -459,7 +459,7 @@ public void setupRepositoryMocksParticipant(ProgrammingExercise exercise, String // TEST void createProgrammingExercise_sequential_validExercise_created(ProgrammingLanguage programmingLanguage) throws Exception { exercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course, programmingLanguage); - exercise.setSequentialTestRuns(true); + exercise.getBuildConfig().setSequentialTestRuns(true); exercise.setChannelName("testchannel-pe"); setupRepositoryMocks(exercise, exerciseRepo, solutionRepo, testRepo, auxRepo); mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); @@ -497,7 +497,7 @@ void createProgrammingExercise_custom_build_plan_validExercise_created(Programmi ] }"""; - exercise.setBuildPlanConfiguration(validWindfile); + exercise.getBuildConfig().setBuildPlanConfiguration(validWindfile); if (programmingLanguage == C) { exercise.setProjectType(ProjectType.FACT); } diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java index 768f110c4a87..5ddb401c6ccf 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java @@ -149,7 +149,7 @@ void initUsersAndExercise() throws JsonProcessingException { programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setAllowOfflineIde(true); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey1 + "/" + projectKey1.toLowerCase() + "-tests.git"); - programmingExercise.setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(aeolusTemplateService.getDefaultWindfileFor(programmingExercise))); + programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(aeolusTemplateService.getDefaultWindfileFor(programmingExercise))); programmingExerciseRepository.save(programmingExercise); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); staticCodeAnalysisService.createDefaultCategories(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java index 15b47a2a8000..ab3fc809c7d7 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java @@ -161,7 +161,7 @@ void testBuildJobPersistence() { assertThat(buildJob.getCourseId()).isEqualTo(course.getId()); assertThat(buildJob.getExerciseId()).isEqualTo(programmingExercise.getId()); assertThat(buildJob.getParticipationId()).isEqualTo(studentParticipation.getId()); - assertThat(buildJob.getDockerImage()).isEqualTo(programmingExercise.getWindfile().getMetadata().docker().getFullImageName()); + assertThat(buildJob.getDockerImage()).isEqualTo(programmingExercise.getBuildConfig().getWindfile().getMetadata().docker().getFullImageName()); assertThat(buildJob.getRepositoryName()).isEqualTo(assignmentRepositorySlug); assertThat(buildJob.getBuildAgentAddress()).isNotEmpty(); assertThat(buildJob.getPriority()).isEqualTo(2); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java index 01ed24d0a60f..71e56da428a1 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java @@ -134,16 +134,16 @@ void testRecreateBuildPlanForExercise() throws IOException { String script = "echo 'Hello, World!'"; Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); ProgrammingExercise exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); - exercise.setBuildScript(script); - exercise.setBuildPlanConfiguration(null); + exercise.getBuildConfig().setBuildScript(script); + exercise.getBuildConfig().setBuildPlanConfiguration(null); continuousIntegrationService.recreateBuildPlansForExercise(exercise); script = buildScriptProviderService.getScriptFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()), exercise.isStaticCodeAnalysisEnabled(), - exercise.hasSequentialTestRuns(), exercise.isTestwiseCoverageEnabled()); + exercise.getBuildConfig().hasSequentialTestRuns(), exercise.isTestwiseCoverageEnabled()); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(exercise); - String actualBuildConfig = exercise.getBuildPlanConfiguration(); + String actualBuildConfig = exercise.getBuildConfig().getBuildPlanConfiguration(); String expectedBuildConfig = new ObjectMapper().writeValueAsString(windfile); assertThat(actualBuildConfig).isEqualTo(expectedBuildConfig); - assertThat(exercise.getBuildScript()).isEqualTo(script); + assertThat(exercise.getBuildConfig().getBuildScript()).isEqualTo(script); // test that the method does not throw an exception when the exercise is null continuousIntegrationService.recreateBuildPlansForExercise(null); } @@ -155,7 +155,7 @@ void testGetScriptForWithoutCache() { programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); programmingExercise.setProjectType(null); programmingExercise.setStaticCodeAnalysisEnabled(false); - programmingExercise.setSequentialTestRuns(false); + programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.setTestwiseCoverageEnabled(false); String script = buildScriptProviderService.getScriptFor(programmingExercise); assertThat(script).isNotNull(); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java index b730f2936833..bb47c9dcbf07 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java @@ -39,7 +39,7 @@ void testStartParticipation() throws Exception { String projectKey = programmingExercise.getProjectKey(); programmingExercise.setStartDate(ZonedDateTime.now().minusHours(1)); // Set the branch to null to force the usage of LocalVCService#getDefaultBranchOfRepository(). - programmingExercise.setBranch(null); + programmingExercise.getBuildConfig().setBranch(null); programmingExerciseRepository.save(programmingExercise); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java index 94962a9c83f8..bc93bb427a0c 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java @@ -180,7 +180,7 @@ void testExtractAndPersistBuildLogStatistics() { @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void testTriggerBuildSuccess() throws GitLabApiException { final ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(programmingExerciseId); - exercise.setBranch("main"); + exercise.getBuildConfig().setBranch("main"); programmingExerciseRepository.save(exercise); final ProgrammingExerciseStudentParticipation participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, TEST_PREFIX + "student1"); mockTriggerBuild(null); diff --git a/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java b/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java index 28946d26ac85..9f95417de150 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java @@ -41,7 +41,7 @@ void init() { programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setSequentialTestRuns(false); + programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.setTestwiseCoverageEnabled(false); programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); From 73f135767b923ec6811bd8a0aea86842c64b3eda Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Fri, 28 Jun 2024 11:46:09 +0200 Subject: [PATCH 03/78] add ref to prog exercise --- .../domain/ProgrammingExerciseBuildConfig.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java index ad385284cda9..85631b043419 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -4,11 +4,14 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; @@ -51,6 +54,10 @@ public class ProgrammingExerciseBuildConfig extends DomainObject { @Column(name = "docker_flags") private String dockerFlags; + @OneToOne(mappedBy = "buildConfig", fetch = FetchType.LAZY) + @JsonIgnoreProperties(value = "buildConfig", allowSetters = true) + private ProgrammingExercise programmingExercise; + @JsonProperty("sequentialTestRuns") public boolean hasSequentialTestRuns() { return Objects.requireNonNullElse(sequentialTestRuns, false); @@ -142,6 +149,14 @@ public void setDockerFlags(String dockerFlags) { this.dockerFlags = dockerFlags; } + public ProgrammingExercise getProgrammingExercise() { + return programmingExercise; + } + + public void setProgrammingExercise(ProgrammingExercise programmingExercise) { + this.programmingExercise = programmingExercise; + } + /** * We store the build plan configuration as a JSON string in the database, as it is easier to handle than a complex object structure. * This method parses the JSON string and returns a {@link Windfile} object. From 2cadb58fd99928f6a510e2dda0f06c318bf57273 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 7 Jul 2024 16:06:19 +0200 Subject: [PATCH 04/78] order master.xml --- src/main/resources/config/liquibase/master.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index 4f66546a6d05..a41da8b9b35a 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -17,8 +17,8 @@ - + From a5d0b9796dbbc5a2993312f442faf66724ba5603 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 11 Jul 2024 12:18:56 +0200 Subject: [PATCH 05/78] adjust code --- .../artemis/domain/ProgrammingExercise.java | 93 +-------------- .../ProgrammingExerciseBuildConfig.java | 112 ++++++++++++++++-- ...grammingExerciseBuildConfigRepository.java | 14 +++ .../service/ExerciseSpecificationService.java | 3 +- .../BuildScriptProviderService.java | 6 +- .../GenericBuildScriptGenerationService.java | 7 +- .../aeolus/AeolusTemplateService.java | 6 +- ...actContinuousIntegrationResultService.java | 4 +- .../connectors/gitlabci/GitLabCIService.java | 9 +- .../build_plan/JenkinsBuildPlanService.java | 12 +- .../JenkinsPipelineScriptCreator.java | 8 +- .../LocalCIBuildConfigurationService.java | 6 +- .../connectors/localci/LocalCIService.java | 6 +- .../localci/LocalCITriggerService.java | 13 +- .../behavioral/BehavioralTestCaseService.java | 2 +- .../JavaTemplateUpgradeService.java | 10 +- .../ProgrammingExerciseGradingService.java | 9 +- ...ProgrammingExerciseImportBasicService.java | 9 +- ...grammingExerciseImportFromFileService.java | 2 +- .../ProgrammingExerciseRepositoryService.java | 25 ++-- .../ProgrammingExerciseService.java | 16 ++- .../web/rest/StaticCodeAnalysisResource.java | 2 +- .../web/rest/open/PublicResultResource.java | 2 +- ...ogrammingExerciseExportImportResource.java | 5 +- .../ProgrammingExerciseResource.java | 8 +- .../changelog/20240626200000_changelog.xml | 16 ++- .../artemis/BuildPlanIntegrationTest.java | 8 +- ...eolusBuildScriptGenerationServiceTest.java | 14 ++- .../artemis/connectors/AeolusServiceTest.java | 12 +- .../ProgrammingExerciseFactory.java | 38 +++--- ...ProgrammingExerciseGradingServiceTest.java | 8 +- ...rammingExerciseIntegrationTestService.java | 44 +++---- ...ExerciseLocalVCLocalCIIntegrationTest.java | 4 +- .../ProgrammingExerciseResultTestService.java | 2 +- ...ammingExerciseTemplateIntegrationTest.java | 4 +- .../ProgrammingExerciseTestService.java | 56 ++++----- .../ProgrammingExerciseUtilService.java | 7 +- ...AndResultGitlabJenkinsIntegrationTest.java | 4 +- .../BehavioralTestCaseServiceTest.java | 2 +- .../iris/IrisChatMessageIntegrationTest.java | 2 +- ...AbstractLocalCILocalVCIntegrationTest.java | 2 +- .../localvcci/LocalCIIntegrationTest.java | 4 +- .../artemis/localvcci/LocalCIServiceTest.java | 10 +- .../JenkinsPipelineScriptCreatorTest.java | 10 +- ...ngExerciseFeedbackCreationServiceTest.java | 4 +- 45 files changed, 359 insertions(+), 281 deletions(-) create mode 100644 src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java index d081da199ee1..18d2d12a6199 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java @@ -54,7 +54,6 @@ import de.tum.in.www1.artemis.domain.participation.TemplateProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.submissionpolicy.SubmissionPolicy; import de.tum.in.www1.artemis.service.ExerciseDateService; -import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature; import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; /** @@ -90,12 +89,6 @@ public String getType() { @Column(name = "allow_offline_ide", table = "programming_exercise_details") private Boolean allowOfflineIde; - @Column(name = "static_code_analysis_enabled", table = "programming_exercise_details") - private Boolean staticCodeAnalysisEnabled; - - @Column(name = "max_static_code_analysis_penalty", table = "programming_exercise_details") - private Integer maxStaticCodeAnalysisPenalty; - @Enumerated(EnumType.STRING) @Column(name = "programming_language") private ProgrammingLanguage programmingLanguage; @@ -149,17 +142,9 @@ public String getType() { @JsonIgnoreProperties("programmingExercise") private SubmissionPolicy submissionPolicy; - @Nullable - @Enumerated(EnumType.ORDINAL) - @Column(name = "project_type", table = "programming_exercise_details") - private ProjectType projectType; - @OneToMany(mappedBy = "exercise", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY) private Set exerciseHints = new HashSet<>(); - @Column(name = "testwise_coverage_enabled", table = "programming_exercise_details") - private boolean testwiseCoverageEnabled; - @Column(name = "release_tests_with_example_solution", table = "programming_exercise_details") private boolean releaseTestsWithExampleSolution; @@ -280,22 +265,6 @@ public void setAllowOfflineIde(Boolean allowOfflineIde) { this.allowOfflineIde = allowOfflineIde; } - public Boolean isStaticCodeAnalysisEnabled() { - return this.staticCodeAnalysisEnabled; - } - - public void setStaticCodeAnalysisEnabled(Boolean staticCodeAnalysisEnabled) { - this.staticCodeAnalysisEnabled = staticCodeAnalysisEnabled; - } - - public Integer getMaxStaticCodeAnalysisPenalty() { - return maxStaticCodeAnalysisPenalty; - } - - public void setMaxStaticCodeAnalysisPenalty(Integer maxStaticCodeAnalysisPenalty) { - this.maxStaticCodeAnalysisPenalty = maxStaticCodeAnalysisPenalty; - } - public String getProjectKey() { return this.projectKey; } @@ -614,23 +583,6 @@ public AssessmentType getAssessmentType() { return super.getAssessmentType(); } - @Nullable - public ProjectType getProjectType() { - return projectType; - } - - public void setProjectType(@Nullable ProjectType projectType) { - this.projectType = projectType; - } - - public Boolean isTestwiseCoverageEnabled() { - return testwiseCoverageEnabled; - } - - public void setTestwiseCoverageEnabled(Boolean testwiseCoverageEnabled) { - this.testwiseCoverageEnabled = testwiseCoverageEnabled; - } - /** * set all sensitive information to null, so no info with respect to the solution gets leaked to students through json */ @@ -741,7 +693,7 @@ public void validateProgrammingSettings() { } // Check if Xcode has no online code editor enabled - if (ProjectType.XCODE.equals(getProjectType()) && Boolean.TRUE.equals(isAllowOnlineEditor())) { + if (ProjectType.XCODE.equals(getBuildConfig().getProjectType()) && Boolean.TRUE.equals(isAllowOnlineEditor())) { throw new BadRequestAlertException("The online editor is not allowed for Xcode programming exercises", "Exercise", "noParticipationModeAllowed"); } @@ -751,49 +703,6 @@ public void validateProgrammingSettings() { } } - /** - * Validates the static code analysis settings of the programming exercise - * 1. The flag staticCodeAnalysisEnabled must not be null - * 2. Static code analysis and sequential test runs can't be active at the same time - * 3. Static code analysis can only be enabled for supported programming languages - * 4. Static code analysis max penalty must only be set if static code analysis is enabled - * 5. Static code analysis max penalty must be positive - * - * @param programmingLanguageFeature describes the features available for the programming language of the programming exercise - */ - public void validateStaticCodeAnalysisSettings(ProgrammingLanguageFeature programmingLanguageFeature) { - // Check if the static code analysis flag was set - if (isStaticCodeAnalysisEnabled() == null) { - throw new BadRequestAlertException("The static code analysis flag must be set to true or false", "Exercise", "staticCodeAnalysisFlagNotSet"); - } - - // Check that programming exercise doesn't have sequential test runs and static code analysis enabled - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && buildConfig.hasSequentialTestRuns()) { - throw new BadRequestAlertException("The static code analysis with sequential test runs is not supported at the moment", "Exercise", "staticCodeAnalysisAndSequential"); - } - - // Check if the programming language supports static code analysis - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && !programmingLanguageFeature.staticCodeAnalysis()) { - throw new BadRequestAlertException("The static code analysis is not supported for this programming language", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); - } - - // Check that FACT has no SCA enabled - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && ProjectType.FACT.equals(getProjectType())) { - throw new BadRequestAlertException("The static code analysis is not supported for FACT programming exercises", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); - } - - // Static code analysis max penalty must only be set if static code analysis is enabled - if (Boolean.FALSE.equals(isStaticCodeAnalysisEnabled()) && getMaxStaticCodeAnalysisPenalty() != null) { - throw new BadRequestAlertException("Max static code analysis penalty must only be set if static code analysis is enabled", "Exercise", - "staticCodeAnalysisDisabledButPenaltySet"); - } - - // Static code analysis max penalty must be positive - if (getMaxStaticCodeAnalysisPenalty() != null && getMaxStaticCodeAnalysisPenalty() < 0) { - throw new BadRequestAlertException("The static code analysis penalty must not be negative", "Exercise", "staticCodeAnalysisPenaltyNotNegative"); - } - } - /** * Validates settings for exercises, where allowFeedbackRequests is set */ diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java index 85631b043419..25e7706a9209 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -2,22 +2,25 @@ import java.util.Objects; +import jakarta.annotation.Nullable; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.OneToOne; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.Table; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; +import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.service.connectors.aeolus.Windfile; import de.tum.in.www1.artemis.service.connectors.vcs.AbstractVersionControlService; +import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature; +import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; @Entity @Table(name = "programming_exercise_build_config") @@ -54,9 +57,22 @@ public class ProgrammingExerciseBuildConfig extends DomainObject { @Column(name = "docker_flags") private String dockerFlags; - @OneToOne(mappedBy = "buildConfig", fetch = FetchType.LAZY) - @JsonIgnoreProperties(value = "buildConfig", allowSetters = true) - private ProgrammingExercise programmingExercise; + @Column(name = "programming_exercise_id") + private Long programmingExerciseId; + + @Column(name = "static_code_analysis_enabled") + private Boolean staticCodeAnalysisEnabled; + + @Column(name = "max_static_code_analysis_penalty") + private Integer maxStaticCodeAnalysisPenalty; + + @Column(name = "testwise_coverage_enabled") + private boolean testwiseCoverageEnabled; + + @Nullable + @Enumerated(EnumType.ORDINAL) + @Column(name = "project_type") + private ProjectType projectType; @JsonProperty("sequentialTestRuns") public boolean hasSequentialTestRuns() { @@ -149,12 +165,12 @@ public void setDockerFlags(String dockerFlags) { this.dockerFlags = dockerFlags; } - public ProgrammingExercise getProgrammingExercise() { - return programmingExercise; + public Long getProgrammingExerciseId() { + return programmingExerciseId; } - public void setProgrammingExercise(ProgrammingExercise programmingExercise) { - this.programmingExercise = programmingExercise; + public void setProgrammingExerciseId(Long programmingExerciseId) { + this.programmingExerciseId = programmingExerciseId; } /** @@ -181,6 +197,82 @@ public void filterSensitiveInformation() { setBuildScript(null); } + public Boolean isStaticCodeAnalysisEnabled() { + return this.staticCodeAnalysisEnabled; + } + + public void setStaticCodeAnalysisEnabled(Boolean staticCodeAnalysisEnabled) { + this.staticCodeAnalysisEnabled = staticCodeAnalysisEnabled; + } + + public Integer getMaxStaticCodeAnalysisPenalty() { + return maxStaticCodeAnalysisPenalty; + } + + public void setMaxStaticCodeAnalysisPenalty(Integer maxStaticCodeAnalysisPenalty) { + this.maxStaticCodeAnalysisPenalty = maxStaticCodeAnalysisPenalty; + } + + @Nullable + public ProjectType getProjectType() { + return projectType; + } + + public void setProjectType(@Nullable ProjectType projectType) { + this.projectType = projectType; + } + + public Boolean isTestwiseCoverageEnabled() { + return testwiseCoverageEnabled; + } + + public void setTestwiseCoverageEnabled(Boolean testwiseCoverageEnabled) { + this.testwiseCoverageEnabled = testwiseCoverageEnabled; + } + + /** + * Validates the static code analysis settings of the programming exercise + * 1. The flag staticCodeAnalysisEnabled must not be null + * 2. Static code analysis and sequential test runs can't be active at the same time + * 3. Static code analysis can only be enabled for supported programming languages + * 4. Static code analysis max penalty must only be set if static code analysis is enabled + * 5. Static code analysis max penalty must be positive + * + * @param programmingLanguageFeature describes the features available for the programming language of the programming exercise + */ + public void validateStaticCodeAnalysisSettings(ProgrammingLanguageFeature programmingLanguageFeature) { + // Check if the static code analysis flag was set + if (isStaticCodeAnalysisEnabled() == null) { + throw new BadRequestAlertException("The static code analysis flag must be set to true or false", "Exercise", "staticCodeAnalysisFlagNotSet"); + } + + // Check that programming exercise doesn't have sequential test runs and static code analysis enabled + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && hasSequentialTestRuns()) { + throw new BadRequestAlertException("The static code analysis with sequential test runs is not supported at the moment", "Exercise", "staticCodeAnalysisAndSequential"); + } + + // Check if the programming language supports static code analysis + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && !programmingLanguageFeature.staticCodeAnalysis()) { + throw new BadRequestAlertException("The static code analysis is not supported for this programming language", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); + } + + // Check that FACT has no SCA enabled + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && ProjectType.FACT.equals(getProjectType())) { + throw new BadRequestAlertException("The static code analysis is not supported for FACT programming exercises", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); + } + + // Static code analysis max penalty must only be set if static code analysis is enabled + if (Boolean.FALSE.equals(isStaticCodeAnalysisEnabled()) && getMaxStaticCodeAnalysisPenalty() != null) { + throw new BadRequestAlertException("Max static code analysis penalty must only be set if static code analysis is enabled", "Exercise", + "staticCodeAnalysisDisabledButPenaltySet"); + } + + // Static code analysis max penalty must be positive + if (getMaxStaticCodeAnalysisPenalty() != null && getMaxStaticCodeAnalysisPenalty() < 0) { + throw new BadRequestAlertException("The static code analysis penalty must not be negative", "Exercise", "staticCodeAnalysisPenaltyNotNegative"); + } + } + @Override public String toString() { return "BuildJobConfig{" + "id=" + getId() + ", sequentialTestRuns=" + sequentialTestRuns + ", branch='" + branch + '\'' + ", buildPlanConfiguration='" diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java new file mode 100644 index 000000000000..66ab4f184b9c --- /dev/null +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java @@ -0,0 +1,14 @@ +package de.tum.in.www1.artemis.repository; + +import static de.tum.in.www1.artemis.config.Constants.PROFILE_CORE; + +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Repository; + +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; +import de.tum.in.www1.artemis.repository.base.ArtemisJpaRepository; + +@Profile(PROFILE_CORE) +@Repository +public interface ProgrammingExerciseBuildConfigRepository extends ArtemisJpaRepository { +} diff --git a/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java b/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java index d17d6cc7a043..0e930e6d27dc 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java @@ -16,6 +16,7 @@ import de.tum.in.www1.artemis.domain.Exercise; import de.tum.in.www1.artemis.domain.Exercise_; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig_; import de.tum.in.www1.artemis.domain.ProgrammingExercise_; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; @@ -112,7 +113,7 @@ else if (isCourseFilter) { */ public Specification createSCAFilter(ProgrammingLanguage programmingLanguage) { return (root, query, criteriaBuilder) -> { - Predicate scaActive = criteriaBuilder.isTrue(root.get(ProgrammingExercise_.STATIC_CODE_ANALYSIS_ENABLED)); + Predicate scaActive = criteriaBuilder.isTrue(root.get(ProgrammingExerciseBuildConfig_.STATIC_CODE_ANALYSIS_ENABLED)); Predicate sameLanguage = criteriaBuilder.equal(root.get(ProgrammingExercise_.PROGRAMMING_LANGUAGE), programmingLanguage); return criteriaBuilder.and(scaActive, sameLanguage); }; diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java index 063751c6a771..51d467a0cfc0 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java @@ -19,6 +19,7 @@ import org.springframework.stereotype.Service; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.service.ResourceLoaderService; @@ -124,8 +125,9 @@ public String getScriptFor(ProgrammingLanguage programmingLanguage, Optional extractProjectType(String filename) { */ public Windfile getDefaultWindfileFor(ProgrammingExercise exercise) { try { - return getWindfileFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()), exercise.isStaticCodeAnalysisEnabled(), - exercise.getBuildConfig().hasSequentialTestRuns(), exercise.isTestwiseCoverageEnabled()); + ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); + return getWindfileFor(exercise.getProgrammingLanguage(), Optional.ofNullable(buildConfig.getProjectType()), buildConfig.isStaticCodeAnalysisEnabled(), + buildConfig.hasSequentialTestRuns(), buildConfig.isTestwiseCoverageEnabled()); } catch (IOException e) { log.info("No windfile for the settings of exercise {}", exercise.getId(), e); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java index 18925c335d31..1a72b5f8ea4a 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java @@ -94,7 +94,7 @@ private void addTestCaseFeedbacksToResult(Result result, List scaFeedbackList = feedbackCreationService.createFeedbackFromStaticCodeAnalysisReports(staticCodeAnalysisReports); result.addFeedbacks(scaFeedbackList); result.setCodeIssueCount(scaFeedbackList.size()); @@ -102,7 +102,7 @@ private void addStaticCodeAnalysisFeedbackToResult(Result result, AbstractBuildR } private void addTestwiseCoverageReportToResult(Result result, AbstractBuildResultNotificationDTO buildResult, ProgrammingExercise programmingExercise) { - if (Boolean.TRUE.equals(programmingExercise.isTestwiseCoverageEnabled())) { + if (Boolean.TRUE.equals(programmingExercise.getBuildConfig().isTestwiseCoverageEnabled())) { var report = buildResult.getTestwiseCoverageReports(); if (report != null) { // since the test cases are not saved to the database yet, the test case is null for the entries diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java index e48faa833e42..07634c5128ef 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java @@ -26,6 +26,7 @@ import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; import de.tum.in.www1.artemis.domain.BuildPlan; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.ProgrammingSubmission; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; @@ -140,9 +141,9 @@ private void setupGitLabCIConfiguration(VcsRepositoryUri repositoryUri, Programm try { // TODO: Reduce the number of API calls - + ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); updateVariable(repositoryPath, VARIABLE_BUILD_DOCKER_IMAGE_NAME, - programmingLanguageConfiguration.getImage(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()))); + programmingLanguageConfiguration.getImage(exercise.getProgrammingLanguage(), Optional.ofNullable(buildConfig.getProjectType()))); updateVariable(repositoryPath, VARIABLE_BUILD_LOGS_FILE_NAME, "build.log"); updateVariable(repositoryPath, VARIABLE_BUILD_PLAN_ID_NAME, buildPlanId); // TODO: Implement the custom feedback feature @@ -150,8 +151,8 @@ private void setupGitLabCIConfiguration(VcsRepositoryUri repositoryUri, Programm updateVariable(repositoryPath, VARIABLE_NOTIFICATION_PLUGIN_DOCKER_IMAGE_NAME, notificationPluginDockerImage); updateVariable(repositoryPath, VARIABLE_NOTIFICATION_SECRET_NAME, artemisAuthenticationTokenValue); updateVariable(repositoryPath, VARIABLE_NOTIFICATION_URL_NAME, artemisServerUrl.toExternalForm() + NEW_RESULT_RESOURCE_API_PATH); - updateVariable(repositoryPath, VARIABLE_SUBMISSION_GIT_BRANCH_NAME, exercise.getBuildConfig().getBranch()); - updateVariable(repositoryPath, VARIABLE_TEST_GIT_BRANCH_NAME, exercise.getBuildConfig().getBranch()); + updateVariable(repositoryPath, VARIABLE_SUBMISSION_GIT_BRANCH_NAME, buildConfig.getBranch()); + updateVariable(repositoryPath, VARIABLE_TEST_GIT_BRANCH_NAME, buildConfig.getBranch()); updateVariable(repositoryPath, VARIABLE_TEST_GIT_REPOSITORY_SLUG_NAME, uriService.getRepositorySlugFromRepositoryUriString(exercise.getTestRepositoryUri())); // TODO: Use a token that is only valid for the test repository for each programming exercise updateVariable(repositoryPath, VARIABLE_TEST_GIT_TOKEN, gitlabToken); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java index 0ea1045173e3..1f76bf3138c3 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java @@ -37,6 +37,7 @@ import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; import de.tum.in.www1.artemis.domain.enumeration.AeolusTarget; @@ -132,10 +133,11 @@ public void createBuildPlanForExercise(ProgrammingExercise exercise, String plan final JenkinsXmlConfigBuilder.InternalVcsRepositoryURLs internalRepositoryUris = getInternalRepositoryUris(exercise, repositoryUri); final ProgrammingLanguage programmingLanguage = exercise.getProgrammingLanguage(); - final var configBuilder = builderFor(programmingLanguage, exercise.getProjectType()); + final ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); + final var configBuilder = builderFor(programmingLanguage, buildConfig.getProjectType()); final String buildPlanUrl = jenkinsPipelineScriptCreator.generateBuildPlanURL(exercise); final boolean checkoutSolution = exercise.getBuildConfig().getCheckoutSolutionRepository(); - final Document jobConfig = configBuilder.buildBasicConfig(programmingLanguage, Optional.ofNullable(exercise.getProjectType()), internalRepositoryUris, checkoutSolution, + final Document jobConfig = configBuilder.buildBasicConfig(programmingLanguage, Optional.ofNullable(buildConfig.getProjectType()), internalRepositoryUris, checkoutSolution, buildPlanUrl); final String jobFolder = exercise.getProjectKey(); @@ -495,10 +497,10 @@ private String createCustomAeolusBuildPlanForExercise(ProgrammingExercise progra return null; } try { - Windfile windfile = programmingExercise.getBuildConfig().getWindfile(); + ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); + Windfile windfile = buildConfig.getWindfile(); Map repositories = aeolusBuildPlanService.get().createRepositoryMapForWindfile(programmingExercise.getProgrammingLanguage(), - programmingExercise.getBuildConfig().getBranch(), programmingExercise.getBuildConfig().getCheckoutSolutionRepository(), repositoryUri, testRepositoryUri, - solutionRepositoryUri, List.of()); + buildConfig.getBranch(), buildConfig.getCheckoutSolutionRepository(), repositoryUri, testRepositoryUri, solutionRepositoryUri, List.of()); String resultHookUrl = artemisServerUrl + NEW_RESULT_RESOURCE_API_PATH; windfile.setPreProcessingMetadata(buildPlanId, programmingExercise.getProjectName(), this.vcsCredentials, resultHookUrl, "planDescription", repositories, diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java index 9f839afdfb4c..647c6a5d5888 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java @@ -18,6 +18,7 @@ import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.exception.JenkinsException; @@ -53,12 +54,13 @@ public JenkinsPipelineScriptCreator(final BuildPlanRepository buildPlanRepositor @Override protected String generateDefaultBuildPlan(final ProgrammingExercise exercise) { final ProgrammingLanguage programmingLanguage = exercise.getProgrammingLanguage(); - final Optional projectType = Optional.ofNullable(exercise.getProjectType()); + final ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); + final Optional projectType = Optional.ofNullable(buildConfig.getProjectType()); final String pipelineScript = loadPipelineScript(exercise, projectType); - final boolean isStaticCodeAnalysisEnabled = exercise.isStaticCodeAnalysisEnabled(); - final boolean isTestwiseCoverageAnalysisEnabled = exercise.isTestwiseCoverageEnabled(); + final boolean isStaticCodeAnalysisEnabled = buildConfig.isStaticCodeAnalysisEnabled(); + final boolean isTestwiseCoverageAnalysisEnabled = buildConfig.isTestwiseCoverageEnabled(); final var replacements = getReplacements(programmingLanguage, projectType, isStaticCodeAnalysisEnabled, isTestwiseCoverageAnalysisEnabled); return replaceVariablesInBuildPlanTemplate(replacements, pipelineScript); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java index 43bdf39226af..580812f7d8c6 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java @@ -9,6 +9,7 @@ import org.springframework.stereotype.Service; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.exception.LocalCIException; import de.tum.in.www1.artemis.service.connectors.aeolus.AeolusTemplateService; @@ -39,7 +40,8 @@ public String createBuildScript(ProgrammingExerciseParticipation participation) buildScript.append("#!/bin/bash\n"); buildScript.append("cd ").append(LOCALCI_WORKING_DIRECTORY).append("/testing-dir\n"); - String customScript = programmingExercise.getBuildConfig().getBuildScript(); + ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); + String customScript = buildConfig.getBuildScript(); // Todo: get default script if custom script is null before trying to get actions from windfile if (customScript != null) { buildScript.append(customScript); @@ -47,7 +49,7 @@ public String createBuildScript(ProgrammingExerciseParticipation participation) else { List actions; - Windfile windfile = programmingExercise.getBuildConfig().getWindfile(); + Windfile windfile = buildConfig.getWindfile(); if (windfile == null) { windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java index f413f6d1960f..bbfa6dbe12e1 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; @@ -78,8 +79,9 @@ public void recreateBuildPlansForExercise(ProgrammingExercise exercise) throws J } String script = buildScriptProviderService.getScriptFor(exercise); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(exercise); - exercise.getBuildConfig().setBuildScript(script); - exercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); + ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); + buildConfig.setBuildScript(script); + buildConfig.setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); // recreating the build plans for the exercise means we need to store the updated exercise in the database programmingExerciseRepository.save(exercise); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java index 5524fd433fa2..bf5ad6c6b74e 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java @@ -24,6 +24,7 @@ import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.domain.enumeration.RepositoryType; @@ -246,12 +247,14 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio throw new LocalCIException("Error while getting branch of participation", e); } + ProgrammingExerciseBuildConfig buildConfig = participation.getProgrammingExercise().getBuildConfig(); + ProgrammingExercise programmingExercise = participation.getProgrammingExercise(); ProgrammingLanguage programmingLanguage = programmingExercise.getProgrammingLanguage(); - ProjectType projectType = programmingExercise.getProjectType(); - boolean staticCodeAnalysisEnabled = programmingExercise.isStaticCodeAnalysisEnabled(); - boolean sequentialTestRunsEnabled = programmingExercise.getBuildConfig().hasSequentialTestRuns(); - boolean testwiseCoverageEnabled = programmingExercise.isTestwiseCoverageEnabled(); + ProjectType projectType = buildConfig.getProjectType(); + boolean staticCodeAnalysisEnabled = buildConfig.isStaticCodeAnalysisEnabled(); + boolean sequentialTestRunsEnabled = buildConfig.hasSequentialTestRuns(); + boolean testwiseCoverageEnabled = buildConfig.isTestwiseCoverageEnabled(); Windfile windfile; String dockerImage; @@ -262,7 +265,7 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio catch (NullPointerException e) { log.warn("Could not retrieve windfile for programming exercise {}. Using default windfile instead.", programmingExercise.getId()); windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); - dockerImage = programmingLanguageConfiguration.getImage(programmingExercise.getProgrammingLanguage(), Optional.ofNullable(programmingExercise.getProjectType())); + dockerImage = programmingLanguageConfiguration.getImage(programmingExercise.getProgrammingLanguage(), Optional.ofNullable(buildConfig.getProjectType())); } List resultPaths = getTestResultPaths(windfile); diff --git a/src/main/java/de/tum/in/www1/artemis/service/hestia/behavioral/BehavioralTestCaseService.java b/src/main/java/de/tum/in/www1/artemis/service/hestia/behavioral/BehavioralTestCaseService.java index 082b11632ea9..785855686a2b 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/hestia/behavioral/BehavioralTestCaseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/hestia/behavioral/BehavioralTestCaseService.java @@ -82,7 +82,7 @@ public BehavioralTestCaseService(GitService gitService, RepositoryService reposi * @throws BehavioralSolutionEntryGenerationException If there was an error while generating the solution entries */ public List generateBehavioralSolutionEntries(ProgrammingExercise programmingExercise) throws BehavioralSolutionEntryGenerationException { - if (!programmingExercise.isTestwiseCoverageEnabled()) { + if (!programmingExercise.getBuildConfig().isTestwiseCoverageEnabled()) { throw new BehavioralSolutionEntryGenerationException("This feature is only supported for Java Exercises with active Testwise Coverage"); } var testCases = testCaseRepository.findByExerciseIdWithSolutionEntriesAndActive(programmingExercise.getId(), true); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java index a4ea308c262a..ccbb0f4e96a8 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java @@ -108,7 +108,8 @@ private void upgradeTemplateFiles(ProgrammingExercise exercise, RepositoryType r // Validate that template and repository have the same number of pom.xml files, otherwise no upgrade will take place if (templatePoms.length == 1 && repositoryPoms.size() == 1) { - Model updatedRepoModel = upgradeProjectObjectModel(templatePoms[0], repositoryPoms.getFirst(), Boolean.TRUE.equals(exercise.isStaticCodeAnalysisEnabled())); + Model updatedRepoModel = upgradeProjectObjectModel(templatePoms[0], repositoryPoms.getFirst(), + Boolean.TRUE.equals(exercise.getBuildConfig().isStaticCodeAnalysisEnabled())); writeProjectObjectModel(updatedRepoModel, repositoryPoms.getFirst()); } @@ -122,7 +123,7 @@ private void upgradeTemplateFiles(ProgrammingExercise exercise, RepositoryType r programmingExerciseRepositoryService.replacePlaceholders(exercise, repository); // Add the latest static code analysis tool configurations or remove configurations - if (Boolean.TRUE.equals(exercise.isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(exercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { Resource[] staticCodeAnalysisResources = getTemplateResources(exercise, "test/" + SCA_CONFIG_FOLDER + "/**/*.*"); fileService.copyResources(staticCodeAnalysisResources, Path.of("java", "test"), repository.getLocalPath().toAbsolutePath(), true); } @@ -147,8 +148,9 @@ private Resource[] getTemplateResources(ProgrammingExercise exercise, String fil Resource[] templatePoms = resourceLoaderService.getFileResources(programmingLanguageTemplate, filePattern); // Get project type specific template resources - if (exercise.getProjectType() != null) { - final Path projectTypeTemplate = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(exercise.getProgrammingLanguage(), exercise.getProjectType()); + if (exercise.getBuildConfig().getProjectType() != null) { + final Path projectTypeTemplate = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(exercise.getProgrammingLanguage(), + exercise.getBuildConfig().getProjectType()); final Resource[] projectTypePoms = resourceLoaderService.getFileResources(projectTypeTemplate, filePattern); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java index 2118a1453026..ea6002d20ef5 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java @@ -186,7 +186,7 @@ public Result processNewProgrammingExerciseResult(@NotNull ProgrammingExercisePa if (buildResult.hasLogs()) { var programmingLanguage = exercise.getProgrammingLanguage(); - var projectType = exercise.getProjectType(); + var projectType = exercise.getBuildConfig().getProjectType(); var buildLogs = buildResult.extractBuildLogs(); ciResultService.extractAndPersistBuildLogStatistics(latestSubmission, programmingLanguage, projectType, buildLogs); @@ -913,8 +913,8 @@ else if (isWeightSumZero) { private double calculateTotalPenalty(ScoreCalculationData scoreCalculationData, boolean applySubmissionPolicy) { double penalty = 0; var exercise = scoreCalculationData.exercise(); - int maxStaticCodeAnalysisPenalty = Optional.ofNullable(exercise.getMaxStaticCodeAnalysisPenalty()).orElse(100); - if (Boolean.TRUE.equals(exercise.isStaticCodeAnalysisEnabled()) && maxStaticCodeAnalysisPenalty > 0) { + int maxStaticCodeAnalysisPenalty = Optional.ofNullable(exercise.getBuildConfig().getMaxStaticCodeAnalysisPenalty()).orElse(100); + if (Boolean.TRUE.equals(exercise.getBuildConfig().isStaticCodeAnalysisEnabled()) && maxStaticCodeAnalysisPenalty > 0) { penalty += calculateStaticCodeAnalysisPenalty(scoreCalculationData.staticCodeAnalysisFeedback(), exercise); } @@ -936,7 +936,8 @@ private double calculateTotalPenalty(ScoreCalculationData scoreCalculationData, */ private double calculateStaticCodeAnalysisPenalty(final List staticCodeAnalysisFeedback, final ProgrammingExercise programmingExercise) { final var feedbackByCategory = staticCodeAnalysisFeedback.stream().collect(Collectors.groupingBy(Feedback::getStaticCodeAnalysisCategory)); - final double maxExercisePenaltyPoints = Objects.requireNonNullElse(programmingExercise.getMaxStaticCodeAnalysisPenalty(), 100) / 100.0 * programmingExercise.getMaxPoints(); + final double maxExercisePenaltyPoints = Objects.requireNonNullElse(programmingExercise.getBuildConfig().getMaxStaticCodeAnalysisPenalty(), 100) / 100.0 + * programmingExercise.getMaxPoints(); double overallPenaltyPoints = 0; for (var category : staticCodeAnalysisCategoryRepository.findByExerciseId(programmingExercise.getId())) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java index ff30348d7158..26f39561267b 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java @@ -17,6 +17,7 @@ import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.ProgrammingExerciseTestCase; import de.tum.in.www1.artemis.domain.StaticCodeAnalysisCategory; import de.tum.in.www1.artemis.domain.enumeration.ExerciseMode; @@ -127,9 +128,11 @@ public ProgrammingExercise importProgrammingExerciseBasis(final ProgrammingExerc setupTestRepository(newProgrammingExercise); programmingExerciseService.initParticipations(newProgrammingExercise); + ProgrammingExerciseBuildConfig originalBuildConfig = originalProgrammingExercise.getBuildConfig(); + if (newProgrammingExercise.getBuildConfig().getBuildPlanConfiguration() == null) { // this means the user did not override the build plan config when importing the exercise and want to reuse it from the existing exercise - newProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(originalProgrammingExercise.getBuildConfig().getBuildPlanConfiguration()); + newProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(originalBuildConfig.getBuildPlanConfiguration()); } // Hints, tasks, test cases and static code analysis categories @@ -152,10 +155,10 @@ public ProgrammingExercise importProgrammingExerciseBasis(final ProgrammingExerc programmingExerciseTaskService.updateTestIds(importedExercise, newTestCaseIdByOldId); // Copy or create SCA categories - if (Boolean.TRUE.equals(importedExercise.isStaticCodeAnalysisEnabled() && Boolean.TRUE.equals(originalProgrammingExercise.isStaticCodeAnalysisEnabled()))) { + if (Boolean.TRUE.equals(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled() && Boolean.TRUE.equals(originalBuildConfig.isStaticCodeAnalysisEnabled()))) { importStaticCodeAnalysisCategories(originalProgrammingExercise, importedExercise); } - else if (Boolean.TRUE.equals(importedExercise.isStaticCodeAnalysisEnabled()) && !Boolean.TRUE.equals(originalProgrammingExercise.isStaticCodeAnalysisEnabled())) { + else if (Boolean.TRUE.equals(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()) && !Boolean.TRUE.equals(originalBuildConfig.isStaticCodeAnalysisEnabled())) { staticCodeAnalysisService.createDefaultCategories(importedExercise); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java index 4778bc0e45bf..d01297f8c53f 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java @@ -107,7 +107,7 @@ public ProgrammingExercise importProgrammingExerciseFromFile(ProgrammingExercise programmingExerciseService.validateNewProgrammingExerciseSettings(originalProgrammingExercise, course); // TODO: creating the whole exercise (from template) is a bad solution in this case, we do not want the template content, instead we want the file content of the zip newProgrammingExercise = programmingExerciseService.createProgrammingExercise(originalProgrammingExercise, true); - if (Boolean.TRUE.equals(originalProgrammingExercise.isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(originalProgrammingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { staticCodeAnalysisService.createDefaultCategories(newProgrammingExercise); } Path pathToDirectoryWithImportedContent = exerciseFilePath.toAbsolutePath().getParent().resolve(FilenameUtils.getBaseName(exerciseFilePath.toString())); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java index 0d9602fa77b4..42b4ed5f66fb 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java @@ -27,6 +27,7 @@ import de.tum.in.www1.artemis.config.Constants; import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.Repository; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; @@ -127,7 +128,7 @@ private record RepositoryResources(Repository repository, Resource[] resources, */ private RepositoryResources getRepositoryResources(final ProgrammingExercise programmingExercise, final RepositoryType repositoryType) throws GitAPIException { final String programmingLanguage = programmingExercise.getProgrammingLanguage().toString().toLowerCase(Locale.ROOT); - final ProjectType projectType = programmingExercise.getProjectType(); + final ProjectType projectType = programmingExercise.getBuildConfig().getProjectType(); final Path projectTypeTemplateDir = getTemplateDirectoryForRepositoryType(repositoryType); final VcsRepositoryUri repoUri = programmingExercise.getRepositoryURL(repositoryType); @@ -304,7 +305,8 @@ private void setupTestTemplateAndPush(final RepositoryResources resources, final */ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final User user) throws IOException, GitAPIException { - final ProjectType projectType = programmingExercise.getProjectType(); + ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); + final ProjectType projectType = buildConfig.getProjectType(); final Path repoLocalPath = getRepoAbsoluteLocalPath(resources.repository); // First get files that are not dependent on the project type @@ -328,9 +330,9 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi final Map sectionsMap = new HashMap<>(); // Keep or delete static code analysis configuration in the build configuration file - sectionsMap.put("static-code-analysis", Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())); + sectionsMap.put("static-code-analysis", Boolean.TRUE.equals(buildConfig.isStaticCodeAnalysisEnabled())); // Keep or delete testwise coverage configuration in the build file - sectionsMap.put("record-testwise-coverage", Boolean.TRUE.equals(programmingExercise.isTestwiseCoverageEnabled())); + sectionsMap.put("record-testwise-coverage", Boolean.TRUE.equals(buildConfig.isTestwiseCoverageEnabled())); if (programmingExercise.getBuildConfig().hasSequentialTestRuns()) { setupTestTemplateSequentialTestRuns(resources, templatePath, projectTemplatePath, projectType, sectionsMap); @@ -369,7 +371,7 @@ else if (ProjectType.MAVEN_BLACKBOX.equals(projectType)) { */ private void setupJVMTestTemplateProjectTypeResources(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final Path repoLocalPath) throws IOException { - final ProjectType projectType = programmingExercise.getProjectType(); + final ProjectType projectType = programmingExercise.getBuildConfig().getProjectType(); final Path projectTypeTemplatePath = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(programmingExercise.getProgrammingLanguage(), projectType) .resolve(TEST_DIR); final Path projectTypeProjectTemplatePath = projectTypeTemplatePath.resolve("projectTemplate"); @@ -394,7 +396,8 @@ private void setupJVMTestTemplateProjectTypeResources(final RepositoryResources */ private void setupTestTemplateRegularTestRuns(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final Path templatePath, final Map sectionsMap) throws IOException { - final ProjectType projectType = programmingExercise.getProjectType(); + ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); + final ProjectType projectType = buildConfig.getProjectType(); final Path repoLocalPath = getRepoAbsoluteLocalPath(resources.repository); final Path testFilePath = templatePath.resolve(TEST_FILES_PATH); final Resource[] testFileResources = resourceLoaderService.getFileResources(testFilePath); @@ -405,7 +408,7 @@ private void setupTestTemplateRegularTestRuns(final RepositoryResources resource setupBuildToolProjectFile(repoLocalPath, projectType, sectionsMap); - if (programmingExercise.getProjectType() != ProjectType.MAVEN_BLACKBOX) { + if (buildConfig.getProjectType() != ProjectType.MAVEN_BLACKBOX) { fileService.copyResources(testFileResources, resources.prefix, packagePath, false); } @@ -414,7 +417,7 @@ private void setupTestTemplateRegularTestRuns(final RepositoryResources resource } // Copy static code analysis config files - if (Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(buildConfig.isStaticCodeAnalysisEnabled())) { setupStaticCodeAnalysisConfigFiles(resources, templatePath, repoLocalPath); } } @@ -445,7 +448,7 @@ private void setupStaticCodeAnalysisConfigFiles(final RepositoryResources resour } private void overwriteProjectTypeSpecificFiles(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final Path packagePath) throws IOException { - final ProjectType projectType = programmingExercise.getProjectType(); + final ProjectType projectType = programmingExercise.getBuildConfig().getProjectType(); final Path projectTypeTemplatePath = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(programmingExercise.getProgrammingLanguage(), projectType) .resolve(TEST_DIR); @@ -626,13 +629,13 @@ private void replaceSwiftPlaceholders(final Map replacements, fi // So usually, the name should not change. final String cleanPackageName = packageName.replaceAll("[^a-zA-Z\\d]", ""); - if (ProjectType.PLAIN.equals(programmingExercise.getProjectType())) { + if (ProjectType.PLAIN.equals(programmingExercise.getBuildConfig().getProjectType())) { fileService.replaceVariablesInDirectoryName(repositoryLocalPath, PACKAGE_NAME_FOLDER_PLACEHOLDER, cleanPackageName); fileService.replaceVariablesInFilename(repositoryLocalPath, PACKAGE_NAME_FILE_PLACEHOLDER, cleanPackageName); replacements.put(PACKAGE_NAME_PLACEHOLDER, cleanPackageName); } - else if (ProjectType.XCODE.equals(programmingExercise.getProjectType())) { + else if (ProjectType.XCODE.equals(programmingExercise.getBuildConfig().getProjectType())) { fileService.replaceVariablesInDirectoryName(repositoryLocalPath, APP_NAME_PLACEHOLDER, cleanPackageName); fileService.replaceVariablesInFilename(repositoryLocalPath, APP_NAME_PLACEHOLDER, cleanPackageName); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java index 5490341e3e40..d6ab544af3ac 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java @@ -45,6 +45,7 @@ import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.ProgrammingExerciseTestCase; import de.tum.in.www1.artemis.domain.Repository; import de.tum.in.www1.artemis.domain.User; @@ -361,13 +362,15 @@ public void validateNewProgrammingExerciseSettings(ProgrammingExercise programmi validatePackageName(programmingExercise, programmingLanguageFeature); validateProjectType(programmingExercise, programmingLanguageFeature); + ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); + // Check if checkout solution repository is enabled - if (programmingExercise.getBuildConfig().getCheckoutSolutionRepository() && !programmingLanguageFeature.checkoutSolutionRepositoryAllowed()) { + if (buildConfig.getCheckoutSolutionRepository() && !programmingLanguageFeature.checkoutSolutionRepositoryAllowed()) { throw new BadRequestAlertException("Checkout solution repository is not supported for this programming language", "Exercise", "checkoutSolutionRepositoryNotSupported"); } // Check if testwise coverage analysis is enabled - if (Boolean.TRUE.equals(programmingExercise.isTestwiseCoverageEnabled()) && !programmingLanguageFeature.testwiseCoverageAnalysisSupported()) { + if (Boolean.TRUE.equals(buildConfig.isTestwiseCoverageEnabled()) && !programmingLanguageFeature.testwiseCoverageAnalysisSupported()) { throw new BadRequestAlertException("Testwise coverage analysis is not supported for this language", "Exercise", "testwiseCoverageAnalysisNotSupported"); } @@ -382,14 +385,15 @@ public void validateNewProgrammingExerciseSettings(ProgrammingExercise programmi private void validateProjectType(ProgrammingExercise programmingExercise, ProgrammingLanguageFeature programmingLanguageFeature) { // Check if project type is selected if (!programmingLanguageFeature.projectTypes().isEmpty()) { - if (programmingExercise.getProjectType() == null) { + ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); + if (buildConfig.getProjectType() == null) { throw new BadRequestAlertException("The project type is not set", "Exercise", "projectTypeNotSet"); } - if (!programmingLanguageFeature.projectTypes().contains(programmingExercise.getProjectType())) { + if (!programmingLanguageFeature.projectTypes().contains(buildConfig.getProjectType())) { throw new BadRequestAlertException("The project type is not supported for this programming language", "Exercise", "projectTypeNotSupported"); } } - else if (programmingExercise.getProjectType() != null) { + else if (programmingExercise.getBuildConfig().getProjectType() != null) { throw new BadRequestAlertException("The project type is set but not supported", "Exercise", "projectTypeSet"); } } @@ -423,7 +427,7 @@ private void validatePackageName(ProgrammingExercise programmingExercise, Progra public void validateStaticCodeAnalysisSettings(ProgrammingExercise programmingExercise) { ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.orElseThrow() .getProgrammingLanguageFeatures(programmingExercise.getProgrammingLanguage()); - programmingExercise.validateStaticCodeAnalysisSettings(programmingLanguageFeature); + programmingExercise.getBuildConfig().validateStaticCodeAnalysisSettings(programmingLanguageFeature); } /** diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java index caffc53578ab..5793b30e339a 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java @@ -151,7 +151,7 @@ public ResponseEntity> importStaticCodeAnalysisC } private void checkSCAEnabledForExerciseElseThrow(ProgrammingExercise programmingExercise) { - if (!Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())) { + if (!Boolean.TRUE.equals(programmingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { throw new BadRequestAlertException("Static code analysis is not enabled", ENTITY_NAME, "staticCodeAnalysisNotEnabled"); } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicResultResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicResultResource.java index 1286edf0e8e5..bca3e3378b29 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicResultResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicResultResource.java @@ -127,7 +127,7 @@ public ResponseEntity processNewProgrammingExerciseResult(@RequestHeader(" triggerTemplateBuildIfTestCasesChanged(participation.getProgrammingExercise().getId(), programmingSubmission); // the test cases and the submission have been saved to the database previously, therefore we can add the reference to the coverage reports - if (Boolean.TRUE.equals(participation.getProgrammingExercise().isTestwiseCoverageEnabled()) && Boolean.TRUE.equals(result.isSuccessful())) { + if (Boolean.TRUE.equals(participation.getProgrammingExercise().getBuildConfig().isTestwiseCoverageEnabled()) && Boolean.TRUE.equals(result.isSuccessful())) { testwiseCoverageService.createTestwiseCoverageReport(result.getCoverageFileReportsByTestCaseName(), participation.getProgrammingExercise(), programmingSubmission); } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java index 21c0de2c44b9..cd0b097dda31 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java @@ -158,7 +158,7 @@ public ProgrammingExerciseExportImportResource(ProgrammingExerciseRepository pro private void validateStaticCodeAnalysisSettings(ProgrammingExercise programmingExercise) { ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.orElseThrow() .getProgrammingLanguageFeatures(programmingExercise.getProgrammingLanguage()); - programmingExercise.validateStaticCodeAnalysisSettings(programmingLanguageFeature); + programmingExercise.getBuildConfig().validateStaticCodeAnalysisSettings(programmingLanguageFeature); } /** @@ -218,7 +218,8 @@ public ResponseEntity importProgrammingExercise(@PathVariab originalProgrammingExercise.setTasks(new ArrayList<>(templateTasks)); // The static code analysis flag can only change, if the build plans are recreated and the template is upgraded - if (newExercise.isStaticCodeAnalysisEnabled() != originalProgrammingExercise.isStaticCodeAnalysisEnabled() && !(recreateBuildPlans && updateTemplate)) { + if (newExercise.getBuildConfig().isStaticCodeAnalysisEnabled() != originalProgrammingExercise.getBuildConfig().isStaticCodeAnalysisEnabled() + && !(recreateBuildPlans && updateTemplate)) { throw new BadRequestAlertException("Static code analysis can only change, if the recreation of build plans and update of template files is activated", ENTITY_NAME, "staticCodeAnalysisCannotChange"); } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index c061cbdfa72a..ff278ae23517 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -40,6 +40,7 @@ import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.GradingCriterion; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.ProgrammingExerciseTestCase; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.enumeration.AssessmentType; @@ -247,7 +248,7 @@ public ResponseEntity createProgrammingExercise(@RequestBod ProgrammingExercise newProgrammingExercise = programmingExerciseService.createProgrammingExercise(programmingExercise, false); // Create default static code analysis categories - if (Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(programmingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { staticCodeAnalysisService.createDefaultCategories(newProgrammingExercise); } @@ -292,13 +293,14 @@ public ResponseEntity updateProgrammingExercise(@RequestBod checkProgrammingExerciseForError(updatedProgrammingExercise); var programmingExerciseBeforeUpdate = programmingExerciseRepository.findByIdWithAuxiliaryRepositoriesElseThrow(updatedProgrammingExercise.getId()); + ProgrammingExerciseBuildConfig buildConfigBeforeUpdate = programmingExerciseBeforeUpdate.getBuildConfig(); if (!Objects.equals(programmingExerciseBeforeUpdate.getShortName(), updatedProgrammingExercise.getShortName())) { throw new BadRequestAlertException("The programming exercise short name cannot be changed", ENTITY_NAME, "shortNameCannotChange"); } - if (!Objects.equals(programmingExerciseBeforeUpdate.isStaticCodeAnalysisEnabled(), updatedProgrammingExercise.isStaticCodeAnalysisEnabled())) { + if (!Objects.equals(buildConfigBeforeUpdate.isStaticCodeAnalysisEnabled(), updatedProgrammingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { throw new BadRequestAlertException("Static code analysis enabled flag must not be changed", ENTITY_NAME, "staticCodeAnalysisCannotChange"); } - if (!Objects.equals(programmingExerciseBeforeUpdate.isTestwiseCoverageEnabled(), updatedProgrammingExercise.isTestwiseCoverageEnabled())) { + if (!Objects.equals(buildConfigBeforeUpdate.isTestwiseCoverageEnabled(), updatedProgrammingExercise.getBuildConfig().isTestwiseCoverageEnabled())) { throw new BadRequestAlertException("Testwise coverage enabled flag must not be changed", ENTITY_NAME, "testwiseCoverageCannotChange"); } if (!Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOnlineEditor()) && !Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOfflineIde())) { diff --git a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml index 3e5ba5bd3943..b6865f39c298 100644 --- a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml +++ b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml @@ -17,6 +17,10 @@ + + + + @@ -43,10 +47,10 @@ - INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, programming_exercise_id) - SELECT e.sequential_test_runs, ped.branch, ped.build_plan_configuration, ped.build_script, ped.checkout_solution_repository, e.id - FROM exercise e JOIN programming_exercise_details ped ON e.id = ped.id - WHERE e.discriminator = 'P'; + INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, programming_exercise_id, static_code_analysis_enabled, max_static_code_analysis_penalty, project_type, testwise_coverage_enabled) + SELECT exercise.sequential_test_runs, programming_exercise_details.branch, programming_exercise_details.build_plan_configuration, programming_exercise_details.build_script, programming_exercise_details.checkout_solution_repository, exercise.id, programming_exercise_details.static_code_analysis_enabled, programming_exercise_details.max_static_code_analysis_penalty, programming_exercise_details.project_type, programming_exercise_details.testwise_coverage_enabled + FROM exercise JOIN programming_exercise_details ON exercise.id = programming_exercise_details.id + WHERE exercise.discriminator = 'P'; UPDATE programming_exercise_details SET programming_exercise_build_config_id = ( SELECT id @@ -59,6 +63,10 @@ ALTER TABLE programming_exercise_details DROP COLUMN build_plan_configuration; ALTER TABLE programming_exercise_details DROP COLUMN build_script; ALTER TABLE programming_exercise_details DROP COLUMN checkout_solution_repository; + ALTER TABLE programming_exercise_details DROP COLUMN static_code_analysis_enabled; + ALTER TABLE programming_exercise_details DROP COLUMN max_static_code_analysis_penalty; + ALTER TABLE programming_exercise_details DROP COLUMN project_type; + ALTER TABLE programming_exercise_details DROP COLUMN testwise_coverage_enabled; diff --git a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java index 090a6cd7fd1a..c6a0c8f2a333 100644 --- a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java @@ -12,6 +12,7 @@ import de.tum.in.www1.artemis.course.CourseUtilService; import de.tum.in.www1.artemis.domain.BuildPlan; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; @@ -51,10 +52,11 @@ void init() { programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); + programmingExercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(false); - programmingExercise.setTestwiseCoverageEnabled(false); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); programmingExercise = programmingExerciseRepository.save(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java index 1b19377cea9e..f0d33d05eaac 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java @@ -19,6 +19,7 @@ import de.tum.in.www1.artemis.AbstractSpringIntegrationLocalCILocalVCTest; import de.tum.in.www1.artemis.connector.AeolusRequestMockProvider; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.AeolusTarget; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; @@ -90,20 +91,21 @@ void testBuildScriptGenerationUsingBuildPlanGenerationService() throws JsonProce aeolusRequestMockProvider.mockGeneratePreview(AeolusTarget.CLI); aeolusRequestMockProvider.mockGeneratePreview(AeolusTarget.CLI); ProgrammingExercise programmingExercise = new ProgrammingExercise(); + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); programmingExercise.getBuildConfig().setBuildPlanConfiguration(getSerializedWindfile()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); - programmingExercise.setTestwiseCoverageEnabled(true); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); String script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNotNull(); assertThat(script).isEqualTo("imagine a result here"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.PYTHON); - programmingExercise.setProjectType(null); - programmingExercise.setStaticCodeAnalysisEnabled(false); + programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); programmingExercise.getBuildConfig().setSequentialTestRuns(false); - programmingExercise.setTestwiseCoverageEnabled(false); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); programmingExercise.getBuildConfig().setBuildPlanConfiguration(null); script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNotNull(); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java index 779944a93bf2..12b6f93684c2 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java @@ -27,6 +27,7 @@ import de.tum.in.www1.artemis.connector.AeolusRequestMockProvider; import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; import de.tum.in.www1.artemis.domain.enumeration.AeolusTarget; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; @@ -197,12 +198,13 @@ private String getSerializedWindfile() throws JsonProcessingException { @Test void testShouldNotGenerateAnything() throws JsonProcessingException { ProgrammingExercise programmingExercise = new ProgrammingExercise(); + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); programmingExercise.getBuildConfig().setBuildPlanConfiguration(getSerializedWindfile()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); - programmingExercise.setTestwiseCoverageEnabled(true); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); String script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNull(); } @@ -219,9 +221,9 @@ void testGetWindfileFor() throws IOException { void testGetDefaultWindfileFor() { ProgrammingExercise programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); - programmingExercise.setTestwiseCoverageEnabled(true); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); assertThat(windfile).isNull(); } diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java index 00511e431a5d..e4300f02d182 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java @@ -13,6 +13,7 @@ import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.Feedback; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.Result; import de.tum.in.www1.artemis.domain.StaticCodeAnalysisCategory; import de.tum.in.www1.artemis.domain.enumeration.AssessmentType; @@ -116,20 +117,23 @@ public static ProgrammingExercise generateProgrammingExerciseForExam(ExerciseGro private static void populateUnreleasedProgrammingExercise(ProgrammingExercise programmingExercise, ProgrammingLanguage programmingLanguage) { programmingExercise.generateAndSetProjectKey(); programmingExercise.setAllowOfflineIde(true); - programmingExercise.setStaticCodeAnalysisEnabled(false); - programmingExercise.setTestwiseCoverageEnabled(false); + if (programmingExercise.getBuildConfig() == null) { + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); + } + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); programmingExercise.setAssessmentType(AssessmentType.SEMI_AUTOMATIC); programmingExercise.setProgrammingLanguage(programmingLanguage); programmingExercise.getBuildConfig().setBuildScript("Some script"); programmingExercise.getBuildConfig().setBuildPlanConfiguration("{\"api\":\"v0.0.1\",\"metadata\":{},\"actions\":[]}"); if (programmingLanguage == ProgrammingLanguage.JAVA) { - programmingExercise.setProjectType(ProjectType.PLAIN_MAVEN); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_MAVEN); } else if (programmingLanguage == ProgrammingLanguage.SWIFT) { - programmingExercise.setProjectType(ProjectType.PLAIN); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN); } else { - programmingExercise.setProjectType(null); + programmingExercise.getBuildConfig().setProjectType(null); } programmingExercise.setPackageName(programmingLanguage == ProgrammingLanguage.SWIFT ? "swiftTest" : "de.test"); final var repoName = programmingExercise.generateRepositoryName(RepositoryType.TESTS); @@ -149,6 +153,7 @@ else if (programmingLanguage == ProgrammingLanguage.SWIFT) { */ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String title, String shortName, ProgrammingExercise template, Course targetCourse) { ProgrammingExercise toBeImported = new ProgrammingExercise(); + toBeImported.setBuildConfig(new ProgrammingExerciseBuildConfig()); toBeImported.setCourse(targetCourse); toBeImported.setTitle(title); toBeImported.setShortName(shortName); @@ -173,8 +178,8 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setPackageName(template.getPackageName()); toBeImported.setAllowOnlineEditor(template.isAllowOnlineEditor()); toBeImported.setAllowOfflineIde(template.isAllowOfflineIde()); - toBeImported.setStaticCodeAnalysisEnabled(template.isStaticCodeAnalysisEnabled()); - toBeImported.setTestwiseCoverageEnabled(template.isTestwiseCoverageEnabled()); + toBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(template.getBuildConfig().isStaticCodeAnalysisEnabled()); + toBeImported.getBuildConfig().setTestwiseCoverageEnabled(template.getBuildConfig().isTestwiseCoverageEnabled()); toBeImported.setTutorParticipations(null); toBeImported.setPosts(null); toBeImported.setStudentParticipations(null); @@ -182,7 +187,7 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setExampleSubmissions(null); toBeImported.setTestRepositoryUri(template.getTestRepositoryUri()); toBeImported.setProgrammingLanguage(template.getProgrammingLanguage()); - toBeImported.setProjectType(template.getProjectType()); + toBeImported.getBuildConfig().setProjectType(template.getBuildConfig().getProjectType()); toBeImported.setAssessmentDueDate(template.getAssessmentDueDate()); toBeImported.setAttachments(null); toBeImported.setDueDate(template.getDueDate()); @@ -406,24 +411,27 @@ public static void populateUnreleasedProgrammingExercise(ProgrammingExercise pro programmingExercise.setAssessmentType(AssessmentType.AUTOMATIC); programmingExercise.setGradingInstructions("Lorem Ipsum"); programmingExercise.setTitle(title); + if (programmingExercise.getBuildConfig() == null) { + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); + } if (programmingLanguage == ProgrammingLanguage.JAVA) { - programmingExercise.setProjectType(ProjectType.PLAIN_MAVEN); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_MAVEN); } else if (programmingLanguage == ProgrammingLanguage.SWIFT) { - programmingExercise.setProjectType(ProjectType.PLAIN); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN); } else if (programmingLanguage == ProgrammingLanguage.C) { - programmingExercise.setProjectType(ProjectType.GCC); + programmingExercise.getBuildConfig().setProjectType(ProjectType.GCC); } else { - programmingExercise.setProjectType(null); + programmingExercise.getBuildConfig().setProjectType(null); } programmingExercise.setAllowOnlineEditor(true); - programmingExercise.setStaticCodeAnalysisEnabled(enableStaticCodeAnalysis); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(enableStaticCodeAnalysis); if (enableStaticCodeAnalysis) { - programmingExercise.setMaxStaticCodeAnalysisPenalty(40); + programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(40); } - programmingExercise.setTestwiseCoverageEnabled(enableTestwiseCoverageAnalysis); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(enableTestwiseCoverageAnalysis); // Note: no separators are allowed for Swift package names if (programmingLanguage == ProgrammingLanguage.SWIFT) { programmingExercise.setPackageName("swiftTest"); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index ad5350f9264d..bba61a565c88 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -222,7 +222,7 @@ private ProgrammingExercise newExamProgrammingExercise() { ProgrammingExercise programmingExercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(group); // Adjust settings so that exam and course exercises can use the same tests programmingExercise.setMaxPoints(42.0); - programmingExercise.setMaxStaticCodeAnalysisPenalty(40); + programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(40); programmingExercise = super.programmingExerciseRepository.save(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise); @@ -1108,7 +1108,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithoutCaps() { } // Also remove max penalty from exercise - programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); programmingExerciseRepository.save(programmingExerciseSCAEnabled); // create results for tests without any limits @@ -1183,7 +1183,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithBonus() { } // Remove max penalty from exercise - programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); programmingExerciseRepository.save(programmingExerciseSCAEnabled); // Remove category penalty limits @@ -1231,7 +1231,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenalties() { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void shouldCalculateScoreWithStaticCodeAnalysisPenalties_cappedByExerciseMaxPenalty() { - programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(20); + programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(20); programmingExerciseSCAEnabled = exerciseRepository.save(programmingExerciseSCAEnabled); activateAllTestCases(false); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java index afdd04cd7d9b..92288fc112ed 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java @@ -888,15 +888,15 @@ private void mockConfigureRepository(ProgrammingExercise programmingExercise) th void updateProgrammingExercise_staticCodeAnalysisMustNotChange_falseToTrue_badRequest() throws Exception { mockBuildPlanAndRepositoryCheck(programmingExercise); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); request.put("/api/programming-exercises", programmingExercise, HttpStatus.BAD_REQUEST); } void updateProgrammingExercise_staticCodeAnalysisMustNotChange_trueToFalse_badRequest() throws Exception { mockBuildPlanAndRepositoryCheck(programmingExercise); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExerciseRepository.save(programmingExercise); - programmingExercise.setStaticCodeAnalysisEnabled(false); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); request.put("/api/programming-exercises", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -969,7 +969,7 @@ void updateProgrammingExerciseShouldFailWithBadRequestWhenUpdatingSCAOption() th mockBuildPlanAndRepositoryCheck(programmingExercise); ProgrammingExercise updatedExercise = programmingExercise; - updatedExercise.setStaticCodeAnalysisEnabled(true); + updatedExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); request.put("/api/programming-exercises", updatedExercise, HttpStatus.BAD_REQUEST); } @@ -981,7 +981,7 @@ void updateProgrammingExerciseShouldFailWithBadRequestWhenUpdatingCoverageOption mockBuildPlanAndRepositoryCheck(programmingExercise); ProgrammingExercise updatedExercise = programmingExercise; - updatedExercise.setTestwiseCoverageEnabled(true); + updatedExercise.getBuildConfig().setTestwiseCoverageEnabled(true); request.put("/api/programming-exercises", updatedExercise, HttpStatus.BAD_REQUEST); } @@ -1192,7 +1192,7 @@ void createProgrammingExercise_staticCodeAnalysisMustBeSet_badRequest() throws E programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.setStaticCodeAnalysisEnabled(null); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(null); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1200,7 +1200,7 @@ void createProgrammingExercise_staticCodeAnalysisAndSequential_badRequest() thro programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1209,9 +1209,9 @@ void createProgrammingExercise_unsupportedProgrammingLanguageForStaticCodeAnalys programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.programmingLanguage(ProgrammingLanguage.C); - programmingExercise.setProjectType(ProjectType.FACT); + programmingExercise.getBuildConfig().setProjectType(ProjectType.FACT); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1219,8 +1219,8 @@ void createProgrammingExercise_noStaticCodeAnalysisButMaxPenalty_badRequest() th programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.setStaticCodeAnalysisEnabled(false); - programmingExercise.setMaxStaticCodeAnalysisPenalty(20); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(20); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1228,8 +1228,8 @@ void createProgrammingExercise_maxStaticCodePenaltyNegative_badRequest() throws programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.setStaticCodeAnalysisEnabled(true); - programmingExercise.setMaxStaticCodeAnalysisPenalty(-20); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(-20); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1263,7 +1263,7 @@ void createProgrammingExercise_projectTypeMissing_badRequest() throws Exception programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setProjectType(null); + programmingExercise.getBuildConfig().setProjectType(null); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1272,7 +1272,7 @@ void createProgrammingExercise_projectTypeNotExpected_badRequest() throws Except programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.PYTHON); - programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); + programmingExercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1281,7 +1281,7 @@ void createProgrammingExercise_onlineCodeEditorNotExpected_badRequest() throws E programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.SWIFT); - programmingExercise.setProjectType(ProjectType.XCODE); + programmingExercise.getBuildConfig().setProjectType(ProjectType.XCODE); programmingExercise.setAllowOnlineEditor(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1322,11 +1322,11 @@ void createProgrammingExercise_notIncluded_invalidBonusPoints_badRequest() throw void createProgrammingExercise_testwiseCoverageAnalysisNotSupported_badRequest(ProgrammingLanguage programmingLanguage) throws Exception { programmingExercise.setId(null); - programmingExercise.setProjectType(null); + programmingExercise.getBuildConfig().setProjectType(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(programmingLanguage); - programmingExercise.setTestwiseCoverageEnabled(true); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1389,7 +1389,7 @@ void importProgrammingExercise_sameTitleInCourse_badRequest() throws Exception { void importProgrammingExercise_staticCodeAnalysisMustBeSet_badRequest() throws Exception { var id = programmingExercise.getId(); programmingExercise.setId(null); - programmingExercise.setStaticCodeAnalysisEnabled(null); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(null); request.post("/api/programming-exercises/import/" + id, programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1407,14 +1407,14 @@ void importProgrammingExercise_scaChanged_badRequest(boolean recreateBuildPlan, programmingExercise.setId(null); programmingExercise.setTitle("NewTitle1"); programmingExercise.setShortName("NewShortname1"); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); request.postWithResponseBody("/api/programming-exercises/import/" + sourceId, programmingExercise, ProgrammingExercise.class, params, HttpStatus.BAD_REQUEST); // true -> false sourceId = programmingExerciseSca.getId(); programmingExerciseSca.setId(null); - programmingExerciseSca.setStaticCodeAnalysisEnabled(false); - programmingExerciseSca.setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseSca.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExerciseSca.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); programmingExerciseSca.setTitle("NewTitle2"); programmingExerciseSca.setShortName("NewShortname2"); request.postWithResponseBody("/api/programming-exercises/import/" + sourceId, programmingExerciseSca, ProgrammingExercise.class, params, HttpStatus.BAD_REQUEST); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java index 604ed22c0ee5..bdf5b136cda8 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java @@ -96,7 +96,7 @@ void setup() throws Exception { course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); programmingExercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); String projectKey = programmingExercise.getProjectKey(); - programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); programmingExerciseRepository.save(programmingExercise); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); @@ -145,7 +145,7 @@ void testCreateProgrammingExercise() throws Exception { doReturn(ZonedDateTime.now().minusSeconds(2)).when(versionControlService).getPushDate(any(), any(), any()); ProgrammingExercise newExercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course); - newExercise.setProjectType(ProjectType.PLAIN_GRADLE); + newExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); // Mock dockerClient.copyArchiveFromContainerCmd() such that it returns a dummy commitHash for both the assignment and the test repository. // Note: The stub needs to receive the same object twice because there are two requests to the same method (one for the template participation and one for the solution diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java index 05ae7a003cfb..93f70fe3aba5 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java @@ -355,7 +355,7 @@ private void activateFourTests() { // Test public void shouldGenerateTestwiseCoverageFileReports(AbstractBuildResultNotificationDTO resultNotification) throws GitAPIException { // set testwise coverage analysis for programming exercise - programmingExercise.setTestwiseCoverageEnabled(true); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); programmingExerciseRepository.save(programmingExercise); solutionParticipation.setProgrammingExercise(programmingExercise); solutionProgrammingExerciseRepository.save(solutionParticipation); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java index 3e1c06217bfb..ba07499f21c0 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java @@ -273,11 +273,11 @@ void testTemplateSolution(ProgrammingLanguage language, ProjectType projectType, private void runTests(ProgrammingLanguage language, ProjectType projectType, LocalRepository repository, TestResult testResult, boolean testwiseCoverageAnalysis) throws Exception { exercise.setProgrammingLanguage(language); - exercise.setProjectType(projectType); + exercise.getBuildConfig().setProjectType(projectType); mockConnectorRequestsForSetup(exercise, false, true, false); exercise.setChannelName("exercise-pe"); if (testwiseCoverageAnalysis) { - exercise.setTestwiseCoverageEnabled(true); + exercise.getBuildConfig().setTestwiseCoverageEnabled(true); } request.postWithResponseBody("/api/programming-exercises/setup", exercise, ProgrammingExercise.class, HttpStatus.CREATED); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java index 01a94d2eb6be..ed79a2706d51 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java @@ -499,7 +499,7 @@ void createProgrammingExercise_custom_build_plan_validExercise_created(Programmi exercise.getBuildConfig().setBuildPlanConfiguration(validWindfile); if (programmingLanguage == C) { - exercise.setProjectType(ProjectType.FACT); + exercise.getBuildConfig().setProjectType(ProjectType.FACT); } exercise.setChannelName("testchannel-pe"); setupRepositoryMocks(exercise, exerciseRepo, solutionRepo, testRepo, auxRepo); @@ -521,7 +521,7 @@ void createProgrammingExercise_programmingLanguage_validExercise_created(Program if (language == SWIFT) { exercise.setPackageName("swiftTest"); } - exercise.setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); + exercise.getBuildConfig().setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); exercise.setChannelName("testchannel-pe"); validateProgrammingExercise(request.postWithResponseBody("/api/programming-exercises/setup", exercise, ProgrammingExercise.class, HttpStatus.CREATED)); @@ -542,7 +542,7 @@ void importFromFile_validJavaExercise_isSuccessfullyImported(boolean scaEnabled) mockDelegate.mockConnectorRequestForImportFromFile(exercise); Resource resource = new ClassPathResource("test-data/import-from-file/valid-import.zip"); if (scaEnabled) { - exercise.setStaticCodeAnalysisEnabled(true); + exercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); } var file = new MockMultipartFile("file", "test.zip", "application/zip", resource.getInputStream()); @@ -553,23 +553,23 @@ void importFromFile_validJavaExercise_isSuccessfullyImported(boolean scaEnabled) assertThat(importedExercise).isNotNull(); assertThat(importedExercise.getProgrammingLanguage()).isEqualTo(JAVA); assertThat(importedExercise.getMode()).isEqualTo(ExerciseMode.INDIVIDUAL); - assertThat(importedExercise.getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); + assertThat(importedExercise.getBuildConfig().getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); if (scaEnabled) { - assertThat(importedExercise.isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); } else { - assertThat(importedExercise.isStaticCodeAnalysisEnabled()).isFalse(); + assertThat(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isFalse(); } var savedExercise = programmingExerciseRepository.findById(importedExercise.getId()).orElseThrow(); assertThat(savedExercise).isNotNull(); assertThat(savedExercise.getProgrammingLanguage()).isEqualTo(JAVA); assertThat(savedExercise.getMode()).isEqualTo(ExerciseMode.INDIVIDUAL); - assertThat(savedExercise.getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); + assertThat(savedExercise.getBuildConfig().getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); if (scaEnabled) { - assertThat(savedExercise.isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(savedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); } else { - assertThat(savedExercise.isStaticCodeAnalysisEnabled()).isFalse(); + assertThat(savedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isFalse(); } assertThat(importedExercise.getCourseViaExerciseGroupOrCourseMember()).isEqualTo(course); } @@ -578,12 +578,12 @@ void importFromFile_validExercise_isSuccessfullyImported(ProgrammingLanguage lan mockDelegate.mockConnectorRequestForImportFromFile(exercise); Resource resource = null; exercise.programmingLanguage(language); - exercise.setProjectType(null); + exercise.getBuildConfig().setProjectType(null); switch (language) { case PYTHON -> resource = new ClassPathResource("test-data/import-from-file/valid-import-python.zip"); case C -> { resource = new ClassPathResource("test-data/import-from-file/valid-import-c.zip"); - exercise.setProjectType(ProjectType.FACT); + exercise.getBuildConfig().setProjectType(ProjectType.FACT); } case HASKELL -> resource = new ClassPathResource("test-data/import-from-file/valid-import-haskell.zip"); case OCAML -> resource = new ClassPathResource("test-data/import-from-file/valid-import-ocaml.zip"); @@ -676,17 +676,17 @@ public void importFromFile_exception_DirectoryDeleted() throws Exception { // TEST void createProgrammingExercise_validExercise_withStaticCodeAnalysis(ProgrammingLanguage language, ProgrammingLanguageFeature programmingLanguageFeature) throws Exception { - exercise.setStaticCodeAnalysisEnabled(true); + exercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); exercise.setProgrammingLanguage(language); if (language == SWIFT) { exercise.setPackageName("swiftTest"); } // Exclude ProjectType FACT as SCA is not supported if (language == C) { - exercise.setProjectType(ProjectType.GCC); + exercise.getBuildConfig().setProjectType(ProjectType.GCC); } else { - exercise.setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); + exercise.getBuildConfig().setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); } mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); exercise.setChannelName("testchannel-pe"); @@ -755,8 +755,8 @@ private AuxiliaryRepository addAuxiliaryRepositoryToProgrammingExercise(Programm void createAndImportJavaProgrammingExercise(boolean staticCodeAnalysisEnabled) throws Exception { setupRepositoryMocks(exercise, sourceExerciseRepo, sourceSolutionRepo, sourceTestRepo, sourceAuxRepo); mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); - exercise.setProjectType(ProjectType.MAVEN_MAVEN); - exercise.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + exercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); + exercise.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); exercise.setChannelName("testchannel-pe"); var sourceExercise = request.postWithResponseBody("/api/programming-exercises/setup", exercise, ProgrammingExercise.class, HttpStatus.CREATED); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); @@ -781,7 +781,7 @@ void createAndImportJavaProgrammingExercise(boolean staticCodeAnalysisEnabled) t ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", exercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.setStaticCodeAnalysisEnabled(false); + exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(false); // TODO: at the moment, it does not work that the copied repositories include the same files as ones that have been created originally // this is probably the case, because the actual copy is not executed due to mocks @@ -819,13 +819,13 @@ void importExercise_created(ProgrammingLanguage programmingLanguage, boolean rec ProgrammingExercise sourceExercise = programmingExerciseUtilService.addCourseWithOneProgrammingExerciseAndStaticCodeAnalysisCategories(programmingLanguage); sourceExercise.setPlagiarismDetectionConfig(PlagiarismDetectionConfig.createDefault()); sourceExercise = programmingExerciseRepository.save(sourceExercise); - sourceExercise.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + sourceExercise.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); programmingExerciseUtilService.addTestCasesToProgrammingExercise(sourceExercise); programmingExerciseUtilService.addHintsToExercise(sourceExercise); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", sourceExercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); if (addAuxRepos) { addAuxiliaryRepositoryToProgrammingExercise(sourceExercise); } @@ -882,14 +882,14 @@ void updateBuildPlanURL() throws Exception { boolean staticCodeAnalysisEnabled = true; // Setup exercises for import ProgrammingExercise sourceExercise = programmingExerciseUtilService.addCourseWithOneProgrammingExerciseAndStaticCodeAnalysisCategories(JAVA); - sourceExercise.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + sourceExercise.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); sourceExercise.generateAndSetBuildPlanAccessSecret(); programmingExerciseUtilService.addTestCasesToProgrammingExercise(sourceExercise); programmingExerciseUtilService.addHintsToExercise(sourceExercise); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", sourceExercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); // Mock requests setupRepositoryMocks(sourceExercise, sourceExerciseRepo, sourceSolutionRepo, sourceTestRepo, sourceAuxRepo); @@ -1067,9 +1067,9 @@ void testImportProgrammingExercise_scaChange() throws Exception { HttpStatus.OK); // Assertions - assertThat(exerciseToBeImported.isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(exerciseToBeImported.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); assertThat(exerciseToBeImported.getStaticCodeAnalysisCategories()).isEmpty(); - assertThat(exerciseToBeImported.getMaxStaticCodeAnalysisPenalty()).isNull(); + assertThat(exerciseToBeImported.getBuildConfig().getMaxStaticCodeAnalysisPenalty()).isNull(); } void testImportProgrammingExercise_scaChange_activated() throws Exception { @@ -1079,8 +1079,8 @@ void testImportProgrammingExercise_scaChange_activated() throws Exception { sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", sourceExercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.setStaticCodeAnalysisEnabled(true); - exerciseToBeImported.setMaxStaticCodeAnalysisPenalty(80); + exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(true); + exerciseToBeImported.getBuildConfig().setMaxStaticCodeAnalysisPenalty(80); // Mock requests mockDelegate.mockConnectorRequestsForImport(sourceExercise, exerciseToBeImported, true, false); @@ -1097,13 +1097,13 @@ void testImportProgrammingExercise_scaChange_activated() throws Exception { // Assertions var staticCodeAnalysisCategories = staticCodeAnalysisCategoryRepository.findByExerciseId(exerciseToBeImported.getId()); - assertThat(exerciseToBeImported.isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(exerciseToBeImported.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); ProgrammingExercise finalSourceExercise = sourceExercise; var defaultCategories = StaticCodeAnalysisConfigurer.staticCodeAnalysisConfiguration().get(sourceExercise.getProgrammingLanguage()).stream() .map(s -> s.toStaticCodeAnalysisCategory(finalSourceExercise)).collect(Collectors.toSet()); assertThat(staticCodeAnalysisCategories).usingRecursiveFieldByFieldElementComparatorOnFields("name", "state", "penalty", "maxPenalty") .containsExactlyInAnyOrderElementsOf(defaultCategories); - assertThat(exerciseToBeImported.getMaxStaticCodeAnalysisPenalty()).isEqualTo(80); + assertThat(exerciseToBeImported.getBuildConfig().getMaxStaticCodeAnalysisPenalty()).isEqualTo(80); } void testImportProgrammingExerciseLockRepositorySubmissionPolicyChange() throws Exception { @@ -1173,7 +1173,7 @@ public void importProgrammingExerciseAsPartOfExamImport() throws Exception { Exam sourceExam = examUtilService.addExamWithExerciseGroup(course, true); ProgrammingExercise sourceExercise = programmingExerciseUtilService.addProgrammingExerciseToExam(sourceExam, 0); - sourceExercise.setStaticCodeAnalysisEnabled(false); + sourceExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); programmingExerciseUtilService.addTestCasesToProgrammingExercise(sourceExercise); programmingExerciseUtilService.addHintsToExercise(sourceExercise); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java index 39f65ec770c1..9cf49473acdc 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java @@ -61,6 +61,7 @@ import de.tum.in.www1.artemis.repository.BuildPlanRepository; import de.tum.in.www1.artemis.repository.CourseRepository; import de.tum.in.www1.artemis.repository.ExamRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestRepository; @@ -100,6 +101,9 @@ public class ProgrammingExerciseUtilService { @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseParticipationRepo; @@ -460,6 +464,7 @@ public ProgrammingExercise addProgrammingExerciseToCourse(Course course, boolean programmingExercise.setAssessmentDueDate(assessmentDueDate); programmingExercise.setPresentationScoreEnabled(course.getPresentationScore() != 0); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.save(programmingExercise); course.addExercises(programmingExercise); programmingExercise = addSolutionParticipationForProgrammingExercise(programmingExercise); @@ -542,7 +547,7 @@ public ProgrammingExercise addCourseWithOneProgrammingExerciseAndStaticCodeAnaly * @param programmingExercise The programming exercise to which static code analysis categories should be added. */ public void addStaticCodeAnalysisCategoriesToProgrammingExercise(ProgrammingExercise programmingExercise) { - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExerciseRepository.save(programmingExercise); var category1 = ProgrammingExerciseFactory.generateStaticCodeAnalysisCategory(programmingExercise, "Bad Practice", CategoryState.GRADED, 3D, 10D); var category2 = ProgrammingExerciseFactory.generateStaticCodeAnalysisCategory(programmingExercise, "Code Style", CategoryState.GRADED, 5D, 10D); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java index 079826795e24..9fc610d15fb1 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java @@ -181,7 +181,7 @@ void shouldExtractBuildLogAnalytics_noSca_gradle() throws Exception { Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, false, ProgrammingLanguage.JAVA); ProgrammingExercise exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); exercise = programmingExerciseRepository.findWithEagerStudentParticipationsStudentAndLegalSubmissionsById(exercise.getId()).orElseThrow(); - exercise.setProjectType(ProjectType.GRADLE_GRADLE); + exercise.getBuildConfig().setProjectType(ProjectType.GRADLE_GRADLE); programmingExerciseRepository.save(exercise); var participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, userLogin); programmingExerciseUtilService.createProgrammingSubmission(participation, false); @@ -382,7 +382,7 @@ void shouldCreateGradleFeedback() throws Exception { String userLogin = TEST_PREFIX + "student1"; var course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, false, JAVA); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); - exercise.setProjectType(ProjectType.GRADLE_GRADLE); + exercise.getBuildConfig().setProjectType(ProjectType.GRADLE_GRADLE); exercise = programmingExerciseRepository.save(exercise); var participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, userLogin); diff --git a/src/test/java/de/tum/in/www1/artemis/hestia/behavioral/BehavioralTestCaseServiceTest.java b/src/test/java/de/tum/in/www1/artemis/hestia/behavioral/BehavioralTestCaseServiceTest.java index ff0521bbd561..78f6c97be9a5 100644 --- a/src/test/java/de/tum/in/www1/artemis/hestia/behavioral/BehavioralTestCaseServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/hestia/behavioral/BehavioralTestCaseServiceTest.java @@ -83,7 +83,7 @@ void initTestCase() { userUtilService.addUsers(TEST_PREFIX, 0, 0, 0, 1); final Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, true, ProgrammingLanguage.JAVA); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); - exercise.setTestwiseCoverageEnabled(true); + exercise.getBuildConfig().setTestwiseCoverageEnabled(true); } @AfterEach diff --git a/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java index 2726328b19bf..01a01cbc74f2 100644 --- a/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java @@ -81,7 +81,7 @@ void initTestCase() throws GitAPIException, IOException, URISyntaxException { final Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); String projectKey = exercise.getProjectKey(); - exercise.setProjectType(ProjectType.PLAIN_GRADLE); + exercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); exercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); programmingExerciseRepository.save(exercise); exercise = programmingExerciseRepository.findWithAllParticipationsById(exercise.getId()).orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java index 5ddb401c6ccf..44033aa4113c 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java @@ -146,7 +146,7 @@ void initUsersAndExercise() throws JsonProcessingException { programmingExercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); projectKey1 = programmingExercise.getProjectKey(); programmingExercise.setReleaseDate(ZonedDateTime.now().minusDays(1)); - programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setAllowOfflineIde(true); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey1 + "/" + projectKey1.toLowerCase() + "-tests.git"); programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(aeolusTemplateService.getDefaultWindfileFor(programmingExercise))); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java index 8e68a76549fd..a4447f3ebd32 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java @@ -268,7 +268,7 @@ void testNoExceptionWhenResolvingWrongCommitHash() { @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void testProjectTypeIsNull() { ProgrammingExerciseStudentParticipation participation = localVCLocalCITestService.createParticipation(programmingExercise, student1Login); - programmingExercise.setProjectType(null); + programmingExercise.getBuildConfig().setProjectType(null); programmingExerciseRepository.save(programmingExercise); localVCServletService.processNewPush(commitHash, studentAssignmentRepository.originGit.getRepository()); @@ -361,7 +361,7 @@ void testLegacyResultFormat() throws IOException { @Test @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void testStaticCodeAnalysis() throws IOException { - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExerciseRepository.save(programmingExercise); ProgrammingExerciseStudentParticipation studentParticipation = localVCLocalCITestService.createParticipation(programmingExercise, student1Login); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java index 71e56da428a1..a651ef2a3967 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java @@ -137,8 +137,8 @@ void testRecreateBuildPlanForExercise() throws IOException { exercise.getBuildConfig().setBuildScript(script); exercise.getBuildConfig().setBuildPlanConfiguration(null); continuousIntegrationService.recreateBuildPlansForExercise(exercise); - script = buildScriptProviderService.getScriptFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()), exercise.isStaticCodeAnalysisEnabled(), - exercise.getBuildConfig().hasSequentialTestRuns(), exercise.isTestwiseCoverageEnabled()); + script = buildScriptProviderService.getScriptFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getBuildConfig().getProjectType()), + exercise.getBuildConfig().isStaticCodeAnalysisEnabled(), exercise.getBuildConfig().hasSequentialTestRuns(), exercise.getBuildConfig().isTestwiseCoverageEnabled()); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(exercise); String actualBuildConfig = exercise.getBuildConfig().getBuildPlanConfiguration(); String expectedBuildConfig = new ObjectMapper().writeValueAsString(windfile); @@ -153,10 +153,10 @@ void testGetScriptForWithoutCache() { ReflectionTestUtils.setField(buildScriptProviderService, "scriptCache", new ConcurrentHashMap<>()); ProgrammingExercise programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); - programmingExercise.setProjectType(null); - programmingExercise.setStaticCodeAnalysisEnabled(false); + programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); programmingExercise.getBuildConfig().setSequentialTestRuns(false); - programmingExercise.setTestwiseCoverageEnabled(false); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); String script = buildScriptProviderService.getScriptFor(programmingExercise); assertThat(script).isNotNull(); } diff --git a/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java b/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java index 9f95417de150..cafe19c865e2 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java @@ -12,6 +12,7 @@ import de.tum.in.www1.artemis.course.CourseUtilService; import de.tum.in.www1.artemis.domain.BuildPlan; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.repository.BuildPlanRepository; @@ -39,10 +40,11 @@ void init() { programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); - programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); + programmingExercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(false); - programmingExercise.setTestwiseCoverageEnabled(false); + programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); @@ -73,7 +75,7 @@ void testBuildPlanRecreation() { assertThat(oldBuildPlan.getBuildPlan()).contains("isStaticCodeAnalysisEnabled = true"); // change exercise attributes - programmingExercise.setStaticCodeAnalysisEnabled(false); + programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); jenkinsPipelineScriptCreator.createBuildPlanForExercise(programmingExercise); BuildPlan newBuildPlan = buildPlanRepository.findByProgrammingExercises_IdWithProgrammingExercises(programmingExercise.getId()).orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java index 73c3546c9a62..2cad331741a5 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java @@ -57,7 +57,7 @@ void init() { Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); programmingExercise = (ProgrammingExercise) course.getExercises().iterator().next(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setProjectType(ProjectType.PLAIN_MAVEN); + programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_MAVEN); programmingExercise = programmingExerciseRepository.save(programmingExercise); programmingExerciseUtilService.addTestCasesToProgrammingExercise(programmingExercise); } @@ -114,7 +114,7 @@ void createFeedbackFromTestCaseMatchMultiple() { org.opentest4j.AssertionFailedError: expected: something else"""; programmingExercise.setProgrammingLanguage(ProgrammingLanguage.KOTLIN); - programmingExercise.setProjectType(null); + programmingExercise.getBuildConfig().setProjectType(null); programmingExercise = programmingExerciseRepository.save(programmingExercise); String actualFeedback = createFeedbackFromTestCase("test2", List.of(msgMatchMultiple), false); assertThat(actualFeedback).isEqualTo(""" From 5cb286d505dd0248a7456b011bbcf64391f9f238 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 11 Jul 2024 16:45:10 +0200 Subject: [PATCH 06/78] adjust code --- .../ProgrammingExerciseBuildConfigRepository.java | 1 + .../service/connectors/jenkins/JenkinsService.java | 9 +++++++-- .../service/connectors/localci/LocalCIService.java | 9 +++++++-- .../vcs/AbstractVersionControlService.java | 8 +++++++- .../ProgrammingExerciseImportBasicService.java | 8 +++++++- .../programming/ProgrammingExerciseService.java | 14 +++++++++++--- .../ProgrammingExerciseGradingServiceTest.java | 5 +++++ .../ProgrammingExerciseUtilService.java | 1 + 8 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java index 66ab4f184b9c..7ab56328c0b7 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java @@ -11,4 +11,5 @@ @Profile(PROFILE_CORE) @Repository public interface ProgrammingExerciseBuildConfigRepository extends ArtemisJpaRepository { + } diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java index 1bace8ee35bd..c877c13c2221 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java @@ -27,6 +27,7 @@ import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.exception.ContinuousIntegrationException; import de.tum.in.www1.artemis.exception.JenkinsException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.ProfileService; import de.tum.in.www1.artemis.service.connectors.ConnectorHealth; @@ -69,9 +70,12 @@ public class JenkinsService extends AbstractContinuousIntegrationService { private final ProgrammingExerciseRepository programmingExerciseRepository; + private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + public JenkinsService(JenkinsServer jenkinsServer, @Qualifier("shortTimeoutJenkinsRestTemplate") RestTemplate shortTimeoutRestTemplate, JenkinsBuildPlanService jenkinsBuildPlanService, JenkinsJobService jenkinsJobService, JenkinsInternalUrlService jenkinsInternalUrlService, - Optional aeolusTemplateService, ProfileService profileService, ProgrammingExerciseRepository programmingExerciseRepository) { + Optional aeolusTemplateService, ProfileService profileService, ProgrammingExerciseRepository programmingExerciseRepository, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.jenkinsServer = jenkinsServer; this.jenkinsBuildPlanService = jenkinsBuildPlanService; this.jenkinsJobService = jenkinsJobService; @@ -80,6 +84,7 @@ public JenkinsService(JenkinsServer jenkinsServer, @Qualifier("shortTimeoutJenki this.aeolusTemplateService = aeolusTemplateService; this.profileService = profileService; this.programmingExerciseRepository = programmingExerciseRepository; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } @Override @@ -121,7 +126,7 @@ private void resetCustomBuildPlanToTemplate(ProgrammingExercise exercise) throws exercise.getBuildConfig().setBuildPlanConfiguration(mapper.writeValueAsString(windfile)); } if (profileService.isAeolusActive()) { - programmingExerciseRepository.save(exercise); + programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); } } diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java index bbfa6dbe12e1..617ca0ac76a0 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIService.java @@ -22,6 +22,7 @@ import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.exception.LocalCIException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.connectors.BuildScriptProviderService; import de.tum.in.www1.artemis.service.connectors.ConnectorHealth; @@ -52,12 +53,16 @@ public class LocalCIService extends AbstractContinuousIntegrationService { private final SharedQueueManagementService sharedQueueManagementService; + private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + public LocalCIService(BuildScriptProviderService buildScriptProviderService, AeolusTemplateService aeolusTemplateService, - ProgrammingExerciseRepository programmingExerciseRepository, SharedQueueManagementService sharedQueueManagementService) { + ProgrammingExerciseRepository programmingExerciseRepository, SharedQueueManagementService sharedQueueManagementService, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.buildScriptProviderService = buildScriptProviderService; this.aeolusTemplateService = aeolusTemplateService; this.programmingExerciseRepository = programmingExerciseRepository; this.sharedQueueManagementService = sharedQueueManagementService; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } @Override @@ -83,7 +88,7 @@ public void recreateBuildPlansForExercise(ProgrammingExercise exercise) throws J buildConfig.setBuildScript(script); buildConfig.setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); // recreating the build plans for the exercise means we need to store the updated exercise in the database - programmingExerciseRepository.save(exercise); + programmingExerciseBuildConfigRepository.save(buildConfig); } @Override diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java index 053876bbbef0..a48836477ff7 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java @@ -19,6 +19,7 @@ import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; import de.tum.in.www1.artemis.exception.VersionControlException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.TemplateProgrammingExerciseParticipationRepository; @@ -43,15 +44,19 @@ public abstract class AbstractVersionControlService implements VersionControlSer protected final ProgrammingExerciseRepository programmingExerciseRepository; + protected final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + protected final TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository; public AbstractVersionControlService(GitService gitService, UriService uriService, ProgrammingExerciseStudentParticipationRepository studentParticipationRepository, - ProgrammingExerciseRepository programmingExerciseRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository) { + ProgrammingExerciseRepository programmingExerciseRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.gitService = gitService; this.uriService = uriService; this.studentParticipationRepository = studentParticipationRepository; this.programmingExerciseRepository = programmingExerciseRepository; this.templateProgrammingExerciseParticipationRepository = templateProgrammingExerciseParticipationRepository; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } /** @@ -184,6 +189,7 @@ public String getOrRetrieveBranchOfExercise(ProgrammingExercise programmingExerc } String branch = getDefaultBranchOfRepository(programmingExercise.getVcsTemplateRepositoryUri()); programmingExercise.getBuildConfig().setBranch(branch); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java index 26f39561267b..950fb443019a 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java @@ -28,6 +28,7 @@ import de.tum.in.www1.artemis.domain.plagiarism.PlagiarismDetectionConfig; import de.tum.in.www1.artemis.domain.submissionpolicy.SubmissionPolicy; import de.tum.in.www1.artemis.repository.AuxiliaryRepositoryRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.repository.StaticCodeAnalysisCategoryRepository; @@ -59,6 +60,8 @@ public class ProgrammingExerciseImportBasicService { private final ProgrammingExerciseRepository programmingExerciseRepository; + private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + private final ProgrammingExerciseService programmingExerciseService; private final StaticCodeAnalysisService staticCodeAnalysisService; @@ -81,7 +84,8 @@ public ProgrammingExerciseImportBasicService(ExerciseHintService exerciseHintSer ProgrammingExerciseRepository programmingExerciseRepository, ProgrammingExerciseService programmingExerciseService, StaticCodeAnalysisService staticCodeAnalysisService, AuxiliaryRepositoryRepository auxiliaryRepositoryRepository, SubmissionPolicyRepository submissionPolicyRepository, ProgrammingExerciseTaskRepository programmingExerciseTaskRepository, ProgrammingExerciseTaskService programmingExerciseTaskService, - ProgrammingExerciseSolutionEntryRepository solutionEntryRepository, ChannelService channelService) { + ProgrammingExerciseSolutionEntryRepository solutionEntryRepository, ChannelService channelService, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.exerciseHintService = exerciseHintService; this.exerciseHintRepository = exerciseHintRepository; this.versionControlService = versionControlService; @@ -97,6 +101,7 @@ public ProgrammingExerciseImportBasicService(ExerciseHintService exerciseHintSer this.programmingExerciseTaskService = programmingExerciseTaskService; this.solutionEntryRepository = solutionEntryRepository; this.channelService = channelService; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } /** @@ -138,6 +143,7 @@ public ProgrammingExercise importProgrammingExerciseBasis(final ProgrammingExerc // Hints, tasks, test cases and static code analysis categories final Map newHintIdByOldId = exerciseHintService.copyExerciseHints(originalProgrammingExercise, newProgrammingExercise); + programmingExerciseBuildConfigRepository.save(newProgrammingExercise.getBuildConfig()); final ProgrammingExercise importedExercise = programmingExerciseRepository.save(newProgrammingExercise); final Map newTestCaseIdByOldId = importTestCases(originalProgrammingExercise, importedExercise); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java index d6ab544af3ac..2f22e80b46ad 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java @@ -60,6 +60,7 @@ import de.tum.in.www1.artemis.domain.participation.TemplateProgrammingExerciseParticipation; import de.tum.in.www1.artemis.repository.AuxiliaryRepositoryRepository; import de.tum.in.www1.artemis.repository.ParticipationRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ResultRepository; @@ -121,6 +122,8 @@ public class ProgrammingExerciseService { private final ProgrammingExerciseRepository programmingExerciseRepository; + private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + private final GitService gitService; private final Optional versionControlService; @@ -196,7 +199,8 @@ public ProgrammingExerciseService(ProgrammingExerciseRepository programmingExerc SubmissionPolicyService submissionPolicyService, Optional programmingLanguageFeatureService, ChannelService channelService, ProgrammingSubmissionService programmingSubmissionService, Optional irisSettingsService, Optional aeolusTemplateService, Optional buildScriptGenerationService, - ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository, ProfileService profileService, ExerciseService exerciseService) { + ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository, ProfileService profileService, ExerciseService exerciseService, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.programmingExerciseRepository = programmingExerciseRepository; this.gitService = gitService; this.versionControlService = versionControlService; @@ -229,6 +233,7 @@ public ProgrammingExerciseService(ProgrammingExerciseRepository programmingExerc this.programmingExerciseStudentParticipationRepository = programmingExerciseStudentParticipationRepository; this.profileService = profileService; this.exerciseService = exerciseService; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } /** @@ -266,6 +271,8 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program programmingExercise.setTemplateParticipation(null); // We save once in order to generate an id for the programming exercise + var buildConfig = programmingExerciseBuildConfigRepository.saveAndFlush(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(buildConfig); var savedProgrammingExercise = programmingExerciseRepository.saveForCreation(programmingExercise); // Step 1: Setting constant facts for a programming exercise @@ -283,6 +290,7 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program // Step 4b: Connecting base participations with the exercise connectBaseParticipationsToExerciseAndSave(savedProgrammingExercise); + programmingExerciseBuildConfigRepository.saveAndFlush(savedProgrammingExercise.getBuildConfig()); savedProgrammingExercise = programmingExerciseRepository.saveForCreation(savedProgrammingExercise); // Step 4c: Connect auxiliary repositories @@ -303,7 +311,7 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program Windfile windfile = aeolusTemplateService.get().getDefaultWindfileFor(savedProgrammingExercise); if (windfile != null) { savedProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); - savedProgrammingExercise = programmingExerciseRepository.saveForCreation(savedProgrammingExercise); + programmingExerciseBuildConfigRepository.saveAndFlush(savedProgrammingExercise.getBuildConfig()); } else { log.warn("No windfile for the settings of exercise {}", savedProgrammingExercise.getId()); @@ -466,7 +474,7 @@ public void setupBuildPlansForNewExercise(ProgrammingExercise programmingExercis String script = buildScriptGenerationService.get().getScript(programmingExercise); programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); programmingExercise.getBuildConfig().setBuildScript(script); - programmingExercise = programmingExerciseRepository.saveForCreation(programmingExercise); + programmingExerciseBuildConfigRepository.saveAndFlush(programmingExercise.getBuildConfig()); } // if the exercise is imported from a file, the changes fixing the project name will trigger a first build anyway, so diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index bba61a565c88..308163140fec 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -54,6 +54,7 @@ import de.tum.in.www1.artemis.participation.ParticipationUtilService; import de.tum.in.www1.artemis.repository.ExamRepository; import de.tum.in.www1.artemis.repository.ExerciseRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.repository.ResultRepository; @@ -100,6 +101,9 @@ abstract class ProgrammingExerciseGradingServiceTest extends AbstractSpringInteg @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ProgrammingExerciseGradingService gradingService; @@ -223,6 +227,7 @@ private ProgrammingExercise newExamProgrammingExercise() { // Adjust settings so that exam and course exercises can use the same tests programmingExercise.setMaxPoints(42.0); programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(40); + super.programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = super.programmingExerciseRepository.save(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java index 9cf49473acdc..e607033b892f 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java @@ -548,6 +548,7 @@ public ProgrammingExercise addCourseWithOneProgrammingExerciseAndStaticCodeAnaly */ public void addStaticCodeAnalysisCategoriesToProgrammingExercise(ProgrammingExercise programmingExercise) { programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); var category1 = ProgrammingExerciseFactory.generateStaticCodeAnalysisCategory(programmingExercise, "Bad Practice", CategoryState.GRADED, 3D, 10D); var category2 = ProgrammingExerciseFactory.generateStaticCodeAnalysisCategory(programmingExercise, "Code Style", CategoryState.GRADED, 5D, 10D); From f07c62a722eda328a40944f04c4d8880c9ebac16 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 14 Jul 2024 18:33:48 +0200 Subject: [PATCH 07/78] save config --- .../service/connectors/jenkins/JenkinsService.java | 1 + .../connectors/vcs/AbstractVersionControlService.java | 1 + .../ProgrammingExerciseImportBasicService.java | 3 ++- .../service/programming/ProgrammingExerciseService.java | 8 +++++++- .../web/rest/programming/ProgrammingExerciseResource.java | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java index c877c13c2221..9bf4d8c36ef8 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java @@ -123,6 +123,7 @@ private void resetCustomBuildPlanToTemplate(ProgrammingExercise exercise) throws } Windfile windfile = aeolusTemplateService.get().getDefaultWindfileFor(exercise); if (windfile != null) { + // saved exercise.getBuildConfig().setBuildPlanConfiguration(mapper.writeValueAsString(windfile)); } if (profileService.isAeolusActive()) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java index a48836477ff7..76db1891fa54 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java @@ -188,6 +188,7 @@ public String getOrRetrieveBranchOfExercise(ProgrammingExercise programmingExerc programmingExercise.setTemplateParticipation(templateProgrammingExerciseParticipationRepository.findByProgrammingExerciseIdElseThrow(programmingExercise.getId())); } String branch = getDefaultBranchOfRepository(programmingExercise.getVcsTemplateRepositoryUri()); + // saved programmingExercise.getBuildConfig().setBranch(branch); programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java index 950fb443019a..76d7316550a7 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java @@ -137,6 +137,7 @@ public ProgrammingExercise importProgrammingExerciseBasis(final ProgrammingExerc if (newProgrammingExercise.getBuildConfig().getBuildPlanConfiguration() == null) { // this means the user did not override the build plan config when importing the exercise and want to reuse it from the existing exercise + // saved newProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(originalBuildConfig.getBuildPlanConfiguration()); } @@ -205,7 +206,7 @@ private void prepareBasicExerciseInformation(final ProgrammingExercise originalP if (originalProgrammingExercise.hasBuildPlanAccessSecretSet()) { newProgrammingExercise.generateAndSetBuildPlanAccessSecret(); } - + // saved newProgrammingExercise.getBuildConfig().setBranch(versionControlService.orElseThrow().getDefaultBranchOfArtemis()); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java index 2f22e80b46ad..c995f252228e 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java @@ -277,6 +277,7 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program // Step 1: Setting constant facts for a programming exercise savedProgrammingExercise.generateAndSetProjectKey(); + // saved savedProgrammingExercise.getBuildConfig().setBranch(versionControl.getDefaultBranchOfArtemis()); // Step 2: Creating repositories for new exercise @@ -310,6 +311,7 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program if (aeolusTemplateService.isPresent() && savedProgrammingExercise.getBuildConfig().getBuildPlanConfiguration() == null && !profileService.isJenkinsActive()) { Windfile windfile = aeolusTemplateService.get().getDefaultWindfileFor(savedProgrammingExercise); if (windfile != null) { + // saved savedProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); programmingExerciseBuildConfigRepository.saveAndFlush(savedProgrammingExercise.getBuildConfig()); } @@ -472,6 +474,7 @@ public void setupBuildPlansForNewExercise(ProgrammingExercise programmingExercis Windfile windfile = programmingExercise.getBuildConfig().getWindfile(); if (windfile != null && buildScriptGenerationService.isPresent() && programmingExercise.getBuildConfig().getBuildScript() == null) { String script = buildScriptGenerationService.get().getScript(programmingExercise); + // saved programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(windfile)); programmingExercise.getBuildConfig().setBuildScript(script); programmingExerciseBuildConfigRepository.saveAndFlush(programmingExercise.getBuildConfig()); @@ -564,6 +567,7 @@ public ProgrammingExercise updateProgrammingExercise(ProgrammingExercise program String problemStatementWithTestNames = updatedProgrammingExercise.getProblemStatement(); programmingExerciseTaskService.replaceTestNamesWithIds(updatedProgrammingExercise); + programmingExerciseBuildConfigRepository.save(updatedProgrammingExercise.getBuildConfig()); ProgrammingExercise savedProgrammingExercise = programmingExerciseRepository.save(updatedProgrammingExercise); // The returned value should use test case names since it gets send back to the client savedProgrammingExercise.setProblemStatement(problemStatementWithTestNames); @@ -603,12 +607,14 @@ private void updateBuildPlanForExercise(ProgrammingExercise programmingExerciseB } if (buildScriptGenerationService.isPresent()) { String script = buildScriptGenerationService.get().getScript(updatedProgrammingExercise); + // saved updatedProgrammingExercise.getBuildConfig().setBuildScript(script); - programmingExerciseRepository.save(updatedProgrammingExercise); + programmingExerciseBuildConfigRepository.save(updatedProgrammingExercise.getBuildConfig()); } } else { // if the user does not change the build plan configuration, we have to set the old one again + // save updatedProgrammingExercise.getBuildConfig().setBuildPlanConfiguration(programmingExerciseBeforeUpdate.getBuildConfig().getBuildPlanConfiguration()); } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index ff278ae23517..e14f570b1168 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -322,6 +322,7 @@ public ResponseEntity updateProgrammingExercise(@RequestBod athenaModuleService.ifPresent(ams -> ams.checkValidAthenaModuleChange(programmingExerciseBeforeUpdate, updatedProgrammingExercise, ENTITY_NAME)); // Ignore changes to the default branch + // saved updatedProgrammingExercise.getBuildConfig().setBranch(programmingExerciseBeforeUpdate.getBuildConfig().getBranch()); if (updatedProgrammingExercise.getAuxiliaryRepositories() == null) { From d4fa2c9c00ce6ab07eeb998f6fe47362257c16dd Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 14 Jul 2024 18:35:20 +0200 Subject: [PATCH 08/78] save config --- .../artemis/service/connectors/jenkins/JenkinsService.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java index 9bf4d8c36ef8..36f256d990cc 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsService.java @@ -28,7 +28,6 @@ import de.tum.in.www1.artemis.exception.ContinuousIntegrationException; import de.tum.in.www1.artemis.exception.JenkinsException; import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; -import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.ProfileService; import de.tum.in.www1.artemis.service.connectors.ConnectorHealth; import de.tum.in.www1.artemis.service.connectors.aeolus.AeolusTemplateService; @@ -68,13 +67,11 @@ public class JenkinsService extends AbstractContinuousIntegrationService { private final ProfileService profileService; - private final ProgrammingExerciseRepository programmingExerciseRepository; - private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; public JenkinsService(JenkinsServer jenkinsServer, @Qualifier("shortTimeoutJenkinsRestTemplate") RestTemplate shortTimeoutRestTemplate, JenkinsBuildPlanService jenkinsBuildPlanService, JenkinsJobService jenkinsJobService, JenkinsInternalUrlService jenkinsInternalUrlService, - Optional aeolusTemplateService, ProfileService profileService, ProgrammingExerciseRepository programmingExerciseRepository, + Optional aeolusTemplateService, ProfileService profileService, ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.jenkinsServer = jenkinsServer; this.jenkinsBuildPlanService = jenkinsBuildPlanService; @@ -83,7 +80,6 @@ public JenkinsService(JenkinsServer jenkinsServer, @Qualifier("shortTimeoutJenki this.shortTimeoutRestTemplate = shortTimeoutRestTemplate; this.aeolusTemplateService = aeolusTemplateService; this.profileService = profileService; - this.programmingExerciseRepository = programmingExerciseRepository; this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } From 6c6b7951d1c71f629bcc958d53b3d205b5e3078c Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 14 Jul 2024 19:59:01 +0200 Subject: [PATCH 09/78] adjust tests --- .../de/tum/in/www1/artemis/BuildPlanIntegrationTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java index c6a0c8f2a333..a8dc3bad72ea 100644 --- a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java @@ -17,6 +17,7 @@ import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; import de.tum.in.www1.artemis.repository.BuildPlanRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.programming.ProgrammingTriggerService; import de.tum.in.www1.artemis.user.UserUtilService; @@ -28,6 +29,9 @@ class BuildPlanIntegrationTest extends AbstractSpringIntegrationJenkinsGitlabTes @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private BuildPlanRepository buildPlanRepository; @@ -52,11 +56,14 @@ void init() { programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); + var buildConfig = new ProgrammingExerciseBuildConfig(); programmingExercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + + programmingExercise.setBuildConfig(buildConfig); programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); programmingExercise = programmingExerciseRepository.save(programmingExercise); From ba7900274ae116f943d2e24a799e0145accf08d8 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Mon, 15 Jul 2024 10:32:53 +0200 Subject: [PATCH 10/78] TODO: remove personal comments fix error and remove unused method --- .../service/connectors/gitlab/GitLabService.java | 7 +++++-- .../service/connectors/localvc/LocalVCService.java | 7 +++++-- .../AbstractSpringIntegrationLocalCILocalVCTest.java | 4 ++++ .../in/www1/artemis/BuildPlanIntegrationTest.java | 12 ++++++------ .../in/www1/artemis/course/CourseUtilService.java | 6 ++++++ .../exercise/programming/GitlabServiceTest.java | 5 +++++ .../ProgrammingExerciseGradingServiceTest.java | 3 +++ .../ProgrammingExerciseIntegrationTestService.java | 6 +++++- ...rammingExerciseLocalVCLocalCIIntegrationTest.java | 1 + .../ProgrammingExerciseResultTestService.java | 6 ++++++ .../programming/ProgrammingExerciseUtilService.java | 9 ++++++++- ...missionAndResultGitlabJenkinsIntegrationTest.java | 6 ++++++ .../artemis/iris/IrisChatMessageIntegrationTest.java | 1 + .../AbstractLocalCILocalVCIntegrationTest.java | 1 + .../artemis/localvcci/LocalCIIntegrationTest.java | 2 ++ .../LocalVCLocalCIParticipationIntegrationTest.java | 1 + .../in/www1/artemis/service/GitlabCIServiceTest.java | 5 +++++ .../build_plan/JenkinsPipelineScriptCreatorTest.java | 6 ++++++ ...ogrammingExerciseFeedbackCreationServiceTest.java | 6 ++++++ 19 files changed, 82 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlab/GitLabService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlab/GitLabService.java index 487b87bd16d4..103a58652025 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlab/GitLabService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlab/GitLabService.java @@ -53,6 +53,7 @@ import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; import de.tum.in.www1.artemis.exception.VersionControlException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.TemplateProgrammingExerciseParticipationRepository; @@ -89,8 +90,10 @@ public class GitLabService extends AbstractVersionControlService { public GitLabService(UserRepository userRepository, @Qualifier("shortTimeoutGitlabRestTemplate") RestTemplate shortTimeoutRestTemplate, GitLabApi gitlab, UriService uriService, GitLabUserManagementService gitLabUserManagementService, GitService gitService, ProgrammingExerciseStudentParticipationRepository studentParticipationRepository, - ProgrammingExerciseRepository programmingExerciseRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository) { - super(gitService, uriService, studentParticipationRepository, programmingExerciseRepository, templateProgrammingExerciseParticipationRepository); + ProgrammingExerciseRepository programmingExerciseRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { + super(gitService, uriService, studentParticipationRepository, programmingExerciseRepository, templateProgrammingExerciseParticipationRepository, + programmingExerciseBuildConfigRepository); this.userRepository = userRepository; this.shortTimeoutRestTemplate = shortTimeoutRestTemplate; this.gitlab = gitlab; diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localvc/LocalVCService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localvc/LocalVCService.java index b33ab1d53e9b..8233efc27944 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localvc/LocalVCService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localvc/LocalVCService.java @@ -37,6 +37,7 @@ import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; import de.tum.in.www1.artemis.exception.localvc.LocalVCInternalException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.TemplateProgrammingExerciseParticipationRepository; @@ -66,8 +67,10 @@ public void setLocalVCBasePath(String localVCBasePath) { } public LocalVCService(UriService uriService, GitService gitService, ProgrammingExerciseStudentParticipationRepository studentParticipationRepository, - ProgrammingExerciseRepository programmingExerciseRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository) { - super(gitService, uriService, studentParticipationRepository, programmingExerciseRepository, templateProgrammingExerciseParticipationRepository); + ProgrammingExerciseRepository programmingExerciseRepository, TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { + super(gitService, uriService, studentParticipationRepository, programmingExerciseRepository, templateProgrammingExerciseParticipationRepository, + programmingExerciseBuildConfigRepository); } @Override diff --git a/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java b/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java index e6a814bf82ec..645366d51207 100644 --- a/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java +++ b/src/test/java/de/tum/in/www1/artemis/AbstractSpringIntegrationLocalCILocalVCTest.java @@ -36,6 +36,7 @@ import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; import de.tum.in.www1.artemis.localvcci.LocalVCLocalCITestService; import de.tum.in.www1.artemis.localvcci.TestBuildAgentConfiguration; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.SolutionProgrammingExerciseParticipationRepository; @@ -85,6 +86,9 @@ public abstract class AbstractSpringIntegrationLocalCILocalVCTest extends Abstra @Autowired protected ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + protected ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired protected TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository; diff --git a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java index a8dc3bad72ea..56065c46a637 100644 --- a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java @@ -57,13 +57,13 @@ void init() { programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); var buildConfig = new ProgrammingExerciseBuildConfig(); - programmingExercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); - programmingExercise.getBuildConfig().setSequentialTestRuns(false); - programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); - programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + buildConfig.setProjectType(ProjectType.MAVEN_MAVEN); + buildConfig.setStaticCodeAnalysisEnabled(true); + buildConfig.setSequentialTestRuns(false); + buildConfig.setTestwiseCoverageEnabled(false); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(buildConfig); - programmingExercise.setBuildConfig(buildConfig); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); programmingExercise = programmingExerciseRepository.save(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java index cbb73f0115c3..adbf5d5ccadb 100644 --- a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java @@ -76,6 +76,7 @@ import de.tum.in.www1.artemis.repository.FileUploadSubmissionRepository; import de.tum.in.www1.artemis.repository.LectureRepository; import de.tum.in.www1.artemis.repository.ModelingSubmissionRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ResultRepository; import de.tum.in.www1.artemis.repository.StudentParticipationRepository; @@ -133,6 +134,9 @@ public class CourseUtilService { @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ModelingSubmissionRepository modelingSubmissionRepo; @@ -696,6 +700,8 @@ public Course addCourseInOtherInstructionGroupAndExercise(String title) { ProgrammingExerciseFactory.populateUnreleasedProgrammingExercise(programmingExercise, "TSTEXC", "Programming", false); programmingExercise.setPresentationScoreEnabled(course.getPresentationScore() != 0); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise = programmingExerciseRepository.save(programmingExercise); course.addExercises(programmingExercise); programmingExercise = programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java index 8c2ce909a7a5..cef27005d980 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/GitlabServiceTest.java @@ -34,6 +34,7 @@ import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; import de.tum.in.www1.artemis.exception.VersionControlException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; class GitlabServiceTest extends AbstractSpringIntegrationJenkinsGitlabTest { @@ -41,6 +42,9 @@ class GitlabServiceTest extends AbstractSpringIntegrationJenkinsGitlabTest { @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ProgrammingExerciseUtilService programmingExerciseUtilService; @@ -138,6 +142,7 @@ void testGetOrRetrieveDefaultBranch() throws GitLabApiException { ProgrammingExercise programmingExercise = (ProgrammingExercise) course.getExercises().stream().findAny().orElseThrow(); programmingExercise.getBuildConfig().setBranch(null); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.save(programmingExercise); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index 308163140fec..6c179d586834 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -1114,6 +1114,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithoutCaps() { // Also remove max penalty from exercise programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); programmingExerciseRepository.save(programmingExerciseSCAEnabled); // create results for tests without any limits @@ -1189,6 +1190,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithBonus() { // Remove max penalty from exercise programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); programmingExerciseRepository.save(programmingExerciseSCAEnabled); // Remove category penalty limits @@ -1237,6 +1239,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenalties() { @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void shouldCalculateScoreWithStaticCodeAnalysisPenalties_cappedByExerciseMaxPenalty() { programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(20); + programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); programmingExerciseSCAEnabled = exerciseRepository.save(programmingExerciseSCAEnabled); activateAllTestCases(false); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java index 92288fc112ed..f20078b8910f 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java @@ -97,6 +97,7 @@ import de.tum.in.www1.artemis.repository.AuxiliaryRepositoryRepository; import de.tum.in.www1.artemis.repository.CourseRepository; import de.tum.in.www1.artemis.repository.GradingCriterionRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; @@ -152,6 +153,9 @@ class ProgrammingExerciseIntegrationTestService { @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository; @@ -895,7 +899,7 @@ void updateProgrammingExercise_staticCodeAnalysisMustNotChange_falseToTrue_badRe void updateProgrammingExercise_staticCodeAnalysisMustNotChange_trueToFalse_badRequest() throws Exception { mockBuildPlanAndRepositoryCheck(programmingExercise); programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); - programmingExerciseRepository.save(programmingExercise); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); request.put("/api/programming-exercises", programmingExercise, HttpStatus.BAD_REQUEST); } diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java index bdf5b136cda8..209094a20d46 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java @@ -98,6 +98,7 @@ void setup() throws Exception { String projectKey = programmingExercise.getProjectKey(); programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java index 93f70fe3aba5..5d8aaa83e03d 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseResultTestService.java @@ -50,6 +50,7 @@ import de.tum.in.www1.artemis.participation.ParticipationUtilService; import de.tum.in.www1.artemis.repository.BuildLogEntryRepository; import de.tum.in.www1.artemis.repository.FeedbackRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; @@ -80,6 +81,9 @@ public class ProgrammingExerciseResultTestService { @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseRepository; @@ -356,6 +360,7 @@ private void activateFourTests() { public void shouldGenerateTestwiseCoverageFileReports(AbstractBuildResultNotificationDTO resultNotification) throws GitAPIException { // set testwise coverage analysis for programming exercise programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); solutionParticipation.setProgrammingExercise(programmingExercise); solutionProgrammingExerciseRepository.save(solutionParticipation); @@ -413,6 +418,7 @@ public void shouldIgnoreResultIfNotOnParticipationBranch(AbstractBuildResultNoti // Test public void shouldCreateResultOnCustomDefaultBranch(String defaultBranch, AbstractBuildResultNotificationDTO resultNotification) { programmingExercise.getBuildConfig().setBranch(defaultBranch); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.save(programmingExercise); solutionParticipation.setProgrammingExercise(programmingExercise); programmingExerciseStudentParticipation.setProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java index e607033b892f..f43b6116f684 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java @@ -249,6 +249,8 @@ public ProgrammingExercise addCourseExamExerciseGroupWithOneProgrammingExercise( programmingExercise.setExerciseGroup(exerciseGroup); ProgrammingExerciseFactory.populateUnreleasedProgrammingExercise(programmingExercise, shortName, title, false); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise = programmingExerciseRepository.save(programmingExercise); programmingExercise = addSolutionParticipationForProgrammingExercise(programmingExercise); programmingExercise = addTemplateParticipationForProgrammingExercise(programmingExercise); @@ -280,6 +282,8 @@ public ProgrammingExercise addProgrammingExerciseToExam(Exam exam, int exerciseG programmingExercise.setExerciseGroup(exam.getExerciseGroups().get(exerciseGroupNumber)); ProgrammingExerciseFactory.populateUnreleasedProgrammingExercise(programmingExercise, "TESTEXFOREXAM", "Testtitle", false); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise = programmingExerciseRepository.save(programmingExercise); programmingExercise = addSolutionParticipationForProgrammingExercise(programmingExercise); programmingExercise = addTemplateParticipationForProgrammingExercise(programmingExercise); @@ -464,7 +468,8 @@ public ProgrammingExercise addProgrammingExerciseToCourse(Course course, boolean programmingExercise.setAssessmentDueDate(assessmentDueDate); programmingExercise.setPresentationScoreEnabled(course.getPresentationScore() != 0); - programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise = programmingExerciseRepository.save(programmingExercise); course.addExercises(programmingExercise); programmingExercise = addSolutionParticipationForProgrammingExercise(programmingExercise); @@ -487,6 +492,8 @@ public Course addCourseWithNamedProgrammingExercise(String programmingExerciseTi ProgrammingExerciseFactory.populateUnreleasedProgrammingExercise(programmingExercise, "TSTEXC", programmingExerciseTitle, scaActive); programmingExercise.setPresentationScoreEnabled(course.getPresentationScore() != 0); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise = programmingExerciseRepository.save(programmingExercise); course.addExercises(programmingExercise); programmingExercise = addSolutionParticipationForProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java index 9fc610d15fb1..64c900f1a435 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java @@ -38,6 +38,7 @@ import de.tum.in.www1.artemis.exercise.ExerciseUtilService; import de.tum.in.www1.artemis.participation.ParticipationUtilService; import de.tum.in.www1.artemis.repository.BuildLogStatisticsEntryRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionTestRepository; import de.tum.in.www1.artemis.repository.ResultRepository; @@ -61,6 +62,9 @@ class ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest extends Abstrac @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository; @@ -182,6 +186,7 @@ void shouldExtractBuildLogAnalytics_noSca_gradle() throws Exception { ProgrammingExercise exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); exercise = programmingExerciseRepository.findWithEagerStudentParticipationsStudentAndLegalSubmissionsById(exercise.getId()).orElseThrow(); exercise.getBuildConfig().setProjectType(ProjectType.GRADLE_GRADLE); + programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); programmingExerciseRepository.save(exercise); var participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, userLogin); programmingExerciseUtilService.createProgrammingSubmission(participation, false); @@ -383,6 +388,7 @@ void shouldCreateGradleFeedback() throws Exception { var course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, false, JAVA); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); exercise.getBuildConfig().setProjectType(ProjectType.GRADLE_GRADLE); + programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); exercise = programmingExerciseRepository.save(exercise); var participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, userLogin); diff --git a/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java index 01a01cbc74f2..d7f9b8111970 100644 --- a/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java @@ -83,6 +83,7 @@ void initTestCase() throws GitAPIException, IOException, URISyntaxException { String projectKey = exercise.getProjectKey(); exercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); exercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); + programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); programmingExerciseRepository.save(exercise); exercise = programmingExerciseRepository.findWithAllParticipationsById(exercise.getId()).orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java index 44033aa4113c..b33bc0455a47 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java @@ -150,6 +150,7 @@ void initUsersAndExercise() throws JsonProcessingException { programmingExercise.setAllowOfflineIde(true); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey1 + "/" + projectKey1.toLowerCase() + "-tests.git"); programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(aeolusTemplateService.getDefaultWindfileFor(programmingExercise))); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); staticCodeAnalysisService.createDefaultCategories(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java index a4447f3ebd32..367bc1373191 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java @@ -269,6 +269,7 @@ void testNoExceptionWhenResolvingWrongCommitHash() { void testProjectTypeIsNull() { ProgrammingExerciseStudentParticipation participation = localVCLocalCITestService.createParticipation(programmingExercise, student1Login); programmingExercise.getBuildConfig().setProjectType(null); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); localVCServletService.processNewPush(commitHash, studentAssignmentRepository.originGit.getRepository()); @@ -362,6 +363,7 @@ void testLegacyResultFormat() throws IOException { @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void testStaticCodeAnalysis() throws IOException { programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); ProgrammingExerciseStudentParticipation studentParticipation = localVCLocalCITestService.createParticipation(programmingExercise, student1Login); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java index bb47c9dcbf07..104ce081d402 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalVCLocalCIParticipationIntegrationTest.java @@ -40,6 +40,7 @@ void testStartParticipation() throws Exception { programmingExercise.setStartDate(ZonedDateTime.now().minusHours(1)); // Set the branch to null to force the usage of LocalVCService#getDefaultBranchOfRepository(). programmingExercise.getBuildConfig().setBranch(null); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java index bc93bb427a0c..5a1db365f557 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java @@ -43,6 +43,7 @@ import de.tum.in.www1.artemis.repository.BuildLogStatisticsEntryRepository; import de.tum.in.www1.artemis.repository.BuildPlanRepository; import de.tum.in.www1.artemis.repository.ParticipationRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.connectors.ci.ContinuousIntegrationService; import de.tum.in.www1.artemis.service.connectors.gitlabci.GitLabCIResultService; @@ -58,6 +59,9 @@ class GitlabCIServiceTest extends AbstractSpringIntegrationGitlabCIGitlabSamlTes @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ParticipationRepository participationRepository; @@ -181,6 +185,7 @@ void testExtractAndPersistBuildLogStatistics() { void testTriggerBuildSuccess() throws GitLabApiException { final ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(programmingExerciseId); exercise.getBuildConfig().setBranch("main"); + programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); programmingExerciseRepository.save(exercise); final ProgrammingExerciseStudentParticipation participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, TEST_PREFIX + "student1"); mockTriggerBuild(null); diff --git a/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java b/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java index cafe19c865e2..5b361f37000e 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreatorTest.java @@ -16,6 +16,7 @@ import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.repository.BuildPlanRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; class JenkinsPipelineScriptCreatorTest extends AbstractSpringIntegrationJenkinsGitlabTest { @@ -29,6 +30,9 @@ class JenkinsPipelineScriptCreatorTest extends AbstractSpringIntegrationJenkinsG @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private CourseUtilService courseUtilService; @@ -48,6 +52,8 @@ void init() { programmingExercise.setReleaseDate(null); course.addExercises(programmingExercise); + var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); programmingExercise = programmingExerciseRepository.save(programmingExercise); } diff --git a/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java index 2cad331741a5..f6e0fa2c33e4 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseFeedbackCreationServiceTest.java @@ -27,6 +27,7 @@ import de.tum.in.www1.artemis.exam.ExamUtilService; import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseFactory; import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.service.dto.AbstractBuildResultNotificationDTO; @@ -41,6 +42,9 @@ class ProgrammingExerciseFeedbackCreationServiceTest extends AbstractSpringInteg @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ProgrammingExerciseTestCaseRepository testCaseRepository; @@ -58,6 +62,7 @@ void init() { programmingExercise = (ProgrammingExercise) course.getExercises().iterator().next(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_MAVEN); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.save(programmingExercise); programmingExerciseUtilService.addTestCasesToProgrammingExercise(programmingExercise); } @@ -115,6 +120,7 @@ void createFeedbackFromTestCaseMatchMultiple() { something else"""; programmingExercise.setProgrammingLanguage(ProgrammingLanguage.KOTLIN); programmingExercise.getBuildConfig().setProjectType(null); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.save(programmingExercise); String actualFeedback = createFeedbackFromTestCase("test2", List.of(msgMatchMultiple), false); assertThat(actualFeedback).isEqualTo(""" From c5304627ab6ee2747af14f5fbec1f34782f9d6f0 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 16 Jul 2024 12:57:11 +0200 Subject: [PATCH 11/78] TODO: remove personal comments adjust tests --- .../repository/ProgrammingExerciseRepository.java | 5 ++++- .../programming/ProgrammingExerciseFactory.java | 13 +++++++------ ...ammingExerciseLocalVCLocalCIIntegrationTest.java | 1 + .../programming/ProgrammingExerciseUtilService.java | 9 ++++++++- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index 41cd1ffb5ba5..ec9a60767c7a 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -83,7 +83,7 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos Optional findWithTemplateAndSolutionParticipationById(long exerciseId); @EntityGraph(type = LOAD, attributePaths = { "categories", "teamAssignmentConfig", "templateParticipation.submissions.results", "solutionParticipation.submissions.results", - "auxiliaryRepositories", "plagiarismDetectionConfig", "buildPlanConfiguration", "buildScript", "templateParticipation", "solutionParticipation" }) + "auxiliaryRepositories", "plagiarismDetectionConfig", "templateParticipation", "solutionParticipation", "buildConfig" }) Optional findForCreationById(long exerciseId); @EntityGraph(type = LOAD, attributePaths = "testCases") @@ -471,6 +471,9 @@ SELECT COUNT (DISTINCT p) @EntityGraph(type = LOAD, attributePaths = { "plagiarismDetectionConfig" }) Optional findWithPlagiarismDetectionConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "buildConfig" }) + Optional findWithBuildConfigById(long exerciseId); + long countByShortNameAndCourse(String shortName, Course course); long countByTitleAndCourse(String shortName, Course course); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java index e4300f02d182..ff7d97ccf726 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java @@ -153,7 +153,7 @@ else if (programmingLanguage == ProgrammingLanguage.SWIFT) { */ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String title, String shortName, ProgrammingExercise template, Course targetCourse) { ProgrammingExercise toBeImported = new ProgrammingExercise(); - toBeImported.setBuildConfig(new ProgrammingExerciseBuildConfig()); + var buildConfig = new ProgrammingExerciseBuildConfig(); toBeImported.setCourse(targetCourse); toBeImported.setTitle(title); toBeImported.setShortName(shortName); @@ -166,7 +166,7 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setExerciseHints(null); toBeImported.setSolutionParticipation(null); toBeImported.setTemplateParticipation(null); - toBeImported.getBuildConfig().setSequentialTestRuns(template.getBuildConfig().hasSequentialTestRuns()); + buildConfig.setSequentialTestRuns(template.getBuildConfig().hasSequentialTestRuns()); toBeImported.setProblemStatement(template.getProblemStatement()); toBeImported.setMaxPoints(template.getMaxPoints()); toBeImported.setBonusPoints(template.getBonusPoints()); @@ -178,8 +178,8 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setPackageName(template.getPackageName()); toBeImported.setAllowOnlineEditor(template.isAllowOnlineEditor()); toBeImported.setAllowOfflineIde(template.isAllowOfflineIde()); - toBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(template.getBuildConfig().isStaticCodeAnalysisEnabled()); - toBeImported.getBuildConfig().setTestwiseCoverageEnabled(template.getBuildConfig().isTestwiseCoverageEnabled()); + buildConfig.setStaticCodeAnalysisEnabled(template.getBuildConfig().isStaticCodeAnalysisEnabled()); + buildConfig.setTestwiseCoverageEnabled(template.getBuildConfig().isTestwiseCoverageEnabled()); toBeImported.setTutorParticipations(null); toBeImported.setPosts(null); toBeImported.setStudentParticipations(null); @@ -187,17 +187,18 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setExampleSubmissions(null); toBeImported.setTestRepositoryUri(template.getTestRepositoryUri()); toBeImported.setProgrammingLanguage(template.getProgrammingLanguage()); - toBeImported.getBuildConfig().setProjectType(template.getBuildConfig().getProjectType()); + buildConfig.setProjectType(template.getBuildConfig().getProjectType()); toBeImported.setAssessmentDueDate(template.getAssessmentDueDate()); toBeImported.setAttachments(null); toBeImported.setDueDate(template.getDueDate()); toBeImported.setReleaseDate(template.getReleaseDate()); toBeImported.setExampleSolutionPublicationDate(null); - toBeImported.getBuildConfig().setSequentialTestRuns(template.getBuildConfig().hasSequentialTestRuns()); + buildConfig.setSequentialTestRuns(template.getBuildConfig().hasSequentialTestRuns()); toBeImported.setBuildAndTestStudentSubmissionsAfterDueDate(template.getBuildAndTestStudentSubmissionsAfterDueDate()); toBeImported.generateAndSetProjectKey(); toBeImported.setPlagiarismDetectionConfig(template.getPlagiarismDetectionConfig()); + toBeImported.setBuildConfig(buildConfig); return toBeImported; } diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java index 209094a20d46..bc3ddcce51d5 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java @@ -243,6 +243,7 @@ void testImportProgrammingExercise() throws Exception { localVCLocalCITestService.mockInputStreamReturnedFromContainer(dockerClient, LOCALCI_WORKING_DIRECTORY + LOCALCI_RESULTS_DIRECTORY, templateBuildTestResults, solutionBuildTestResults); + programmingExercise = programmingExerciseRepository.findWithBuildConfigById(programmingExercise.getId()).orElseThrow(); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", programmingExercise, courseUtilService.addEmptyCourse()); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java index f43b6116f684..25bab3b107cf 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java @@ -382,7 +382,14 @@ public Course addCourseWithOneProgrammingExercise(boolean enableStaticCodeAnalys var course = CourseFactory.generateCourse(null, PAST_TIMESTAMP, FUTURE_FUTURE_TIMESTAMP, new HashSet<>(), "tumuser", "tutor", "editor", "instructor"); course = courseRepo.save(course); addProgrammingExerciseToCourse(course, enableStaticCodeAnalysis, enableTestwiseCoverageAnalysis, programmingLanguage, title, shortName, null); - return courseRepo.findByIdWithExercisesAndExerciseDetailsAndLecturesElseThrow(course.getId()); + course = courseRepo.findByIdWithExercisesAndExerciseDetailsAndLecturesElseThrow(course.getId()); + for (var exercise : course.getExercises()) { + if (exercise instanceof ProgrammingExercise) { + course.getExercises().remove(exercise); + course.addExercises(programmingExerciseRepository.findForCreationByIdElseThrow(exercise.getId())); + } + } + return course; } /** From e08743da79fc88fdea363f8d4712371370b13d55 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 16 Jul 2024 13:38:29 +0200 Subject: [PATCH 12/78] TODO: remove personal comments fix columns --- .../www1/artemis/domain/ProgrammingExerciseBuildConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java index 25e7706a9209..49e4d36f7b4e 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -35,17 +35,17 @@ public class ProgrammingExerciseBuildConfig extends DomainObject { @Column(name = "branch") private String branch; - @Column(name = "build_plan_configuration") + @Column(name = "build_plan_configuration", columnDefinition = "longtext") private String buildPlanConfiguration; - @Column(name = "build_script") + @Column(name = "build_script", columnDefinition = "longtext") private String buildScript; /** * This boolean flag determines whether the solution repository should be checked out during the build (additional to the student's submission). * This is currently only supported for HASKELL and OCAML, thus the default value is false. */ - @Column(name = "checkout_solution_repository") + @Column(name = "checkout_solution_repository", columnDefinition = "boolean default false") private Boolean checkoutSolutionRepository; @Column(name = "checkout_path") From f33c52e06b293e5ad553832d082cac8721a332ff Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 16 Jul 2024 14:37:50 +0200 Subject: [PATCH 13/78] TODO: remove personal comments fix columns --- .../in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java index 49e4d36f7b4e..be0ac2706a91 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -46,7 +46,7 @@ public class ProgrammingExerciseBuildConfig extends DomainObject { * This is currently only supported for HASKELL and OCAML, thus the default value is false. */ @Column(name = "checkout_solution_repository", columnDefinition = "boolean default false") - private Boolean checkoutSolutionRepository; + private boolean checkoutSolutionRepository; @Column(name = "checkout_path") private String checkoutPath; From 3287fed18ab58c6cfe658b17e4801f39247b2b0d Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Tue, 16 Jul 2024 19:18:37 +0200 Subject: [PATCH 14/78] TODO: remove personal comments adjust code --- .../ProgrammingExerciseBuildConfig.java | 23 ++++++----- ...grammingExerciseBuildConfigRepository.java | 15 +++++++ .../ProgrammingExerciseRepository.java | 40 ++++++++++++++++++- .../LocalCIResultProcessingService.java | 13 +++++- .../ProgrammingExerciseService.java | 7 ++-- ...ogrammingExerciseExportImportResource.java | 2 +- .../ProgrammingExerciseResource.java | 2 +- .../changelog/20240626200000_changelog.xml | 6 +-- ...ExerciseLocalVCLocalCIIntegrationTest.java | 3 +- 9 files changed, 90 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java index be0ac2706a91..423de480ec0a 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -7,11 +7,13 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; @@ -57,8 +59,9 @@ public class ProgrammingExerciseBuildConfig extends DomainObject { @Column(name = "docker_flags") private String dockerFlags; - @Column(name = "programming_exercise_id") - private Long programmingExerciseId; + @OneToOne(mappedBy = "buildConfig") + @JsonIgnoreProperties("buildConfig") + private ProgrammingExercise programmingExercise; @Column(name = "static_code_analysis_enabled") private Boolean staticCodeAnalysisEnabled; @@ -165,14 +168,6 @@ public void setDockerFlags(String dockerFlags) { this.dockerFlags = dockerFlags; } - public Long getProgrammingExerciseId() { - return programmingExerciseId; - } - - public void setProgrammingExerciseId(Long programmingExerciseId) { - this.programmingExerciseId = programmingExerciseId; - } - /** * We store the build plan configuration as a JSON string in the database, as it is easier to handle than a complex object structure. * This method parses the JSON string and returns a {@link Windfile} object. @@ -230,6 +225,14 @@ public void setTestwiseCoverageEnabled(Boolean testwiseCoverageEnabled) { this.testwiseCoverageEnabled = testwiseCoverageEnabled; } + public ProgrammingExercise getProgrammingExercise() { + return programmingExercise; + } + + public void setProgrammingExercise(ProgrammingExercise programmingExercise) { + this.programmingExercise = programmingExercise; + } + /** * Validates the static code analysis settings of the programming exercise * 1. The flag staticCodeAnalysisEnabled must not be null diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java index 7ab56328c0b7..ab99a59b2d41 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseBuildConfigRepository.java @@ -2,9 +2,15 @@ import static de.tum.in.www1.artemis.config.Constants.PROFILE_CORE; +import java.util.Optional; + +import jakarta.annotation.Nullable; + +import org.hibernate.Hibernate; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Repository; +import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.repository.base.ArtemisJpaRepository; @@ -12,4 +18,13 @@ @Repository public interface ProgrammingExerciseBuildConfigRepository extends ArtemisJpaRepository { + Optional findByProgrammingExerciseId(Long programmingExerciseId); + + @Nullable + default ProgrammingExerciseBuildConfig getProgrammingExerciseWithBuildConfig(ProgrammingExercise programmingExercise) { + if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { + return findByProgrammingExerciseId(programmingExercise.getId()).orElse(null); + } + return programmingExercise.getBuildConfig(); + } } diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index ec9a60767c7a..76dcc45c3a8f 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -92,6 +92,9 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos @EntityGraph(type = LOAD, attributePaths = "auxiliaryRepositories") Optional findWithAuxiliaryRepositoriesById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "auxiliaryRepositories", "buildConfig" }) + Optional findWithAuxiliaryRepositoriesAndBuildConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = "submissionPolicy") Optional findWithSubmissionPolicyById(long exerciseId); @@ -252,7 +255,7 @@ default ProgrammingExercise findOneByProjectKeyOrThrow(String projectKey, boolea """) Optional findWithEagerStudentParticipationsStudentAndLegalSubmissionsById(@Param("exerciseId") long exerciseId); - @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "studentParticipations.team.students" }) + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "studentParticipations.team.students", "buildConfig" }) Optional findWithAllParticipationsById(long exerciseId); @Query(""" @@ -300,6 +303,22 @@ default ProgrammingExercise findOneByProjectKeyOrThrow(String projectKey, boolea """) Optional findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(@Param("exerciseId") long exerciseId); + @Query(""" + SELECT p + FROM ProgrammingExercise p + LEFT JOIN FETCH p.testCases tc + LEFT JOIN FETCH p.staticCodeAnalysisCategories + LEFT JOIN FETCH p.exerciseHints + LEFT JOIN FETCH p.templateParticipation + LEFT JOIN FETCH p.solutionParticipation + LEFT JOIN FETCH p.auxiliaryRepositories + LEFT JOIN FETCH tc.solutionEntries + LEFT JOIN FETCH p.buildConfig + WHERE p.id = :exerciseId + """) + Optional findByIdWithEagerBuildConfigTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos( + @Param("exerciseId") long exerciseId); + /** * Returns all programming exercises that have a due date after {@code now} and have tests marked with * {@link de.tum.in.www1.artemis.domain.enumeration.Visibility#AFTER_DUE_DATE} but no buildAndTestStudentSubmissionsAfterDueDate. @@ -523,6 +542,17 @@ default ProgrammingExercise findByIdWithAuxiliaryRepositoriesElseThrow(long prog return findWithAuxiliaryRepositoriesById(programmingExerciseId).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); } + /** + * Find a programming exercise with auxiliary repositories and build config by its id and throw an EntityNotFoundException if it cannot be found + * + * @param programmingExerciseId of the programming exercise. + * @return The programming exercise related to the given id + */ + @NotNull + default ProgrammingExercise findWithAuxiliaryRepositoriesAndBuildConfigElseThrow(long programmingExerciseId) throws EntityNotFoundException { + return findWithAuxiliaryRepositoriesAndBuildConfigById(programmingExerciseId).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); + } + /** * Find a programming exercise with the submission policy by its id and throw an EntityNotFoundException if it cannot be found * @@ -681,6 +711,14 @@ default ProgrammingExercise findWithEagerStudentParticipationsByIdElseThrow(long return findWithEagerStudentParticipationsById(programmingExerciseId).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); } + @Nullable + default ProgrammingExercise getProgrammingExerciseWithBuildConfig(ProgrammingExercise programmingExercise) { + if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { + return findWithBuildConfigById(programmingExercise.getId()).orElse(null); + } + return programmingExercise; + } + /** * Retrieves the associated ProgrammingExercise for a given ProgrammingExerciseParticipation. * If the ProgrammingExercise is not already loaded, it is fetched from the database and linked diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultProcessingService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultProcessingService.java index 82af39694374..167f07103ccd 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultProcessingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultProcessingService.java @@ -33,6 +33,7 @@ import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.repository.BuildJobRepository; import de.tum.in.www1.artemis.repository.ParticipationRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.security.SecurityUtils; import de.tum.in.www1.artemis.service.BuildLogEntryService; @@ -69,6 +70,8 @@ public class LocalCIResultProcessingService { private final BuildLogEntryService buildLogEntryService; + private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + private IQueue resultQueue; private IMap buildAgentInformation; @@ -79,7 +82,8 @@ public class LocalCIResultProcessingService { public LocalCIResultProcessingService(@Qualifier("hazelcastInstance") HazelcastInstance hazelcastInstance, ProgrammingExerciseGradingService programmingExerciseGradingService, ProgrammingMessagingService programmingMessagingService, BuildJobRepository buildJobRepository, ProgrammingExerciseRepository programmingExerciseRepository, - ParticipationRepository participationRepository, ProgrammingTriggerService programmingTriggerService, BuildLogEntryService buildLogEntryService) { + ParticipationRepository participationRepository, ProgrammingTriggerService programmingTriggerService, BuildLogEntryService buildLogEntryService, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository) { this.hazelcastInstance = hazelcastInstance; this.programmingExerciseRepository = programmingExerciseRepository; this.participationRepository = participationRepository; @@ -88,6 +92,7 @@ public LocalCIResultProcessingService(@Qualifier("hazelcastInstance") HazelcastI this.buildJobRepository = buildJobRepository; this.programmingTriggerService = programmingTriggerService; this.buildLogEntryService = buildLogEntryService; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; } /** @@ -141,6 +146,12 @@ public void processResult() { if (participation.getProgrammingExercise() == null) { participation.setProgrammingExercise(programmingExerciseRepository.getProgrammingExerciseFromParticipationElseThrow(participation)); } + // TODO: Add new method instead of this + var debug = programmingExerciseBuildConfigRepository.findAll(); + var buildConfig = programmingExerciseBuildConfigRepository.getProgrammingExerciseWithBuildConfig(participation.getProgrammingExercise()); + if (buildConfig != null) { + participation.getProgrammingExercise().setBuildConfig(buildConfig); + } result = programmingExerciseGradingService.processNewProgrammingExerciseResult(participation, buildResult); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java index c995f252228e..004838b88b90 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java @@ -271,10 +271,11 @@ public ProgrammingExercise createProgrammingExercise(ProgrammingExercise program programmingExercise.setTemplateParticipation(null); // We save once in order to generate an id for the programming exercise - var buildConfig = programmingExerciseBuildConfigRepository.saveAndFlush(programmingExercise.getBuildConfig()); - programmingExercise.setBuildConfig(buildConfig); + var savedBuildConfig = programmingExerciseBuildConfigRepository.saveAndFlush(programmingExercise.getBuildConfig()); + programmingExercise.setBuildConfig(savedBuildConfig); var savedProgrammingExercise = programmingExerciseRepository.saveForCreation(programmingExercise); - + savedProgrammingExercise.getBuildConfig().setProgrammingExercise(savedProgrammingExercise); + programmingExerciseBuildConfigRepository.save(savedProgrammingExercise.getBuildConfig()); // Step 1: Setting constant facts for a programming exercise savedProgrammingExercise.generateAndSetProjectKey(); // saved diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java index cd0b097dda31..d0e1f1827c2e 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java @@ -205,7 +205,7 @@ public ResponseEntity importProgrammingExercise(@PathVariab programmingExerciseRepository.validateCourseSettings(newExercise, course); final var originalProgrammingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(sourceExerciseId) + .findByIdWithEagerBuildConfigTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(sourceExerciseId) .orElseThrow(() -> new EntityNotFoundException("ProgrammingExercise", sourceExerciseId)); var consistencyErrors = consistencyCheckService.checkConsistencyOfProgrammingExercise(originalProgrammingExercise); diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index e14f570b1168..cc8c08136759 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -292,7 +292,7 @@ public ResponseEntity updateProgrammingExercise(@RequestBod checkProgrammingExerciseForError(updatedProgrammingExercise); - var programmingExerciseBeforeUpdate = programmingExerciseRepository.findByIdWithAuxiliaryRepositoriesElseThrow(updatedProgrammingExercise.getId()); + var programmingExerciseBeforeUpdate = programmingExerciseRepository.findWithAuxiliaryRepositoriesAndBuildConfigElseThrow(updatedProgrammingExercise.getId()); ProgrammingExerciseBuildConfig buildConfigBeforeUpdate = programmingExerciseBeforeUpdate.getBuildConfig(); if (!Objects.equals(programmingExerciseBeforeUpdate.getShortName(), updatedProgrammingExercise.getShortName())) { throw new BadRequestAlertException("The programming exercise short name cannot be changed", ENTITY_NAME, "shortNameCannotChange"); diff --git a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml index b6865f39c298..9069d0afce6d 100644 --- a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml +++ b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml @@ -16,7 +16,7 @@ - + @@ -47,7 +47,7 @@ - INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, programming_exercise_id, static_code_analysis_enabled, max_static_code_analysis_penalty, project_type, testwise_coverage_enabled) + INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, common_key_id, static_code_analysis_enabled, max_static_code_analysis_penalty, project_type, testwise_coverage_enabled) SELECT exercise.sequential_test_runs, programming_exercise_details.branch, programming_exercise_details.build_plan_configuration, programming_exercise_details.build_script, programming_exercise_details.checkout_solution_repository, exercise.id, programming_exercise_details.static_code_analysis_enabled, programming_exercise_details.max_static_code_analysis_penalty, programming_exercise_details.project_type, programming_exercise_details.testwise_coverage_enabled FROM exercise JOIN programming_exercise_details ON exercise.id = programming_exercise_details.id WHERE exercise.discriminator = 'P'; @@ -55,7 +55,7 @@ UPDATE programming_exercise_details SET programming_exercise_build_config_id = ( SELECT id FROM programming_exercise_build_config - WHERE programming_exercise_id = programming_exercise_details.id + WHERE common_key_id = programming_exercise_details.id ); ALTER TABLE exercise DROP COLUMN sequential_test_runs; diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java index bc3ddcce51d5..2c998bc5d3c3 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java @@ -100,6 +100,8 @@ void setup() throws Exception { programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); + programmingExercise.getBuildConfig().setProgrammingExercise(programmingExercise); + programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); // Set the correct repository URIs for the template and the solution participation. @@ -243,7 +245,6 @@ void testImportProgrammingExercise() throws Exception { localVCLocalCITestService.mockInputStreamReturnedFromContainer(dockerClient, LOCALCI_WORKING_DIRECTORY + LOCALCI_RESULTS_DIRECTORY, templateBuildTestResults, solutionBuildTestResults); - programmingExercise = programmingExerciseRepository.findWithBuildConfigById(programmingExercise.getId()).orElseThrow(); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", programmingExercise, courseUtilService.addEmptyCourse()); From 53dd42b6d73f0fa7b7e70095a49e60088a97e63b Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Wed, 17 Jul 2024 13:14:51 +0200 Subject: [PATCH 15/78] TODO: remove personal comments adjust code --- .../config/liquibase/changelog/20240626200000_changelog.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml index 9069d0afce6d..3db6e204dd48 100644 --- a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml +++ b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml @@ -67,6 +67,7 @@ ALTER TABLE programming_exercise_details DROP COLUMN max_static_code_analysis_penalty; ALTER TABLE programming_exercise_details DROP COLUMN project_type; ALTER TABLE programming_exercise_details DROP COLUMN testwise_coverage_enabled; +-- ALTER TABLE programming_exercise_build_config DROP COLUMN common_key_id; From 354abd44489f78420dced3c128231dfe2fdbfe52 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Wed, 17 Jul 2024 14:22:01 +0200 Subject: [PATCH 16/78] TODO: remove personal comments adjust code --- .../artemis/domain/ProgrammingExercise.java | 82 +++++++++++++++++- .../ProgrammingExerciseBuildConfig.java | 85 ------------------- .../ProgrammingExerciseRepository.java | 8 -- .../service/ExerciseSpecificationService.java | 3 +- .../BuildScriptProviderService.java | 2 +- .../GenericBuildScriptGenerationService.java | 4 +- .../aeolus/AeolusTemplateService.java | 2 +- ...actContinuousIntegrationResultService.java | 2 +- .../connectors/gitlabci/GitLabCIService.java | 2 +- .../build_plan/JenkinsBuildPlanService.java | 5 +- .../JenkinsPipelineScriptCreator.java | 8 +- .../localci/LocalCITriggerService.java | 13 ++- .../vcs/AbstractVersionControlService.java | 3 + .../JavaTemplateUpgradeService.java | 10 +-- .../ProgrammingExerciseGradingService.java | 9 +- ...ProgrammingExerciseImportBasicService.java | 4 +- ...grammingExerciseImportFromFileService.java | 2 +- .../ProgrammingExerciseRepositoryService.java | 25 +++--- .../ProgrammingExerciseService.java | 9 +- .../web/rest/StaticCodeAnalysisResource.java | 2 +- ...ogrammingExerciseExportImportResource.java | 5 +- .../ProgrammingExerciseResource.java | 9 +- .../changelog/20240626200000_changelog.xml | 10 +-- .../artemis/BuildPlanIntegrationTest.java | 4 +- ...eolusBuildScriptGenerationServiceTest.java | 8 +- .../artemis/connectors/AeolusServiceTest.java | 6 +- .../artemis/course/CourseUtilService.java | 1 + .../in/www1/artemis/exam/ExamUtilService.java | 6 ++ .../exam/StudentExamIntegrationTest.java | 3 +- .../ProgrammingExerciseFactory.java | 24 +++--- ...ProgrammingExerciseGradingServiceTest.java | 12 ++- ...rammingExerciseIntegrationTestService.java | 46 +++++----- ...ExerciseLocalVCLocalCIIntegrationTest.java | 7 +- ...ammingExerciseTemplateIntegrationTest.java | 2 +- .../ProgrammingExerciseTestService.java | 56 ++++++------ .../ProgrammingExerciseUtilService.java | 8 +- ...AndResultGitlabJenkinsIntegrationTest.java | 4 +- .../iris/IrisChatMessageIntegrationTest.java | 2 +- ...AbstractLocalCILocalVCIntegrationTest.java | 2 +- .../localvcci/LocalCIIntegrationTest.java | 4 +- .../artemis/localvcci/LocalCIServiceTest.java | 8 +- .../ProgrammingExerciseTestRepository.java | 1 + .../JenkinsPipelineScriptCreatorTest.java | 6 +- ...ngExerciseFeedbackCreationServiceTest.java | 4 +- 44 files changed, 243 insertions(+), 275 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java index 18d2d12a6199..46838b63b0ec 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExercise.java @@ -54,6 +54,7 @@ import de.tum.in.www1.artemis.domain.participation.TemplateProgrammingExerciseParticipation; import de.tum.in.www1.artemis.domain.submissionpolicy.SubmissionPolicy; import de.tum.in.www1.artemis.service.ExerciseDateService; +import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature; import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; /** @@ -89,6 +90,12 @@ public String getType() { @Column(name = "allow_offline_ide", table = "programming_exercise_details") private Boolean allowOfflineIde; + @Column(name = "static_code_analysis_enabled", table = "programming_exercise_details") + private Boolean staticCodeAnalysisEnabled; + + @Column(name = "max_static_code_analysis_penalty", table = "programming_exercise_details") + private Integer maxStaticCodeAnalysisPenalty; + @Enumerated(EnumType.STRING) @Column(name = "programming_language") private ProgrammingLanguage programmingLanguage; @@ -142,6 +149,11 @@ public String getType() { @JsonIgnoreProperties("programmingExercise") private SubmissionPolicy submissionPolicy; + @Nullable + @Enumerated(EnumType.ORDINAL) + @Column(name = "project_type", table = "programming_exercise_details") + private ProjectType projectType; + @OneToMany(mappedBy = "exercise", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY) private Set exerciseHints = new HashSet<>(); @@ -269,6 +281,22 @@ public String getProjectKey() { return this.projectKey; } + public Boolean isStaticCodeAnalysisEnabled() { + return this.staticCodeAnalysisEnabled; + } + + public void setStaticCodeAnalysisEnabled(Boolean staticCodeAnalysisEnabled) { + this.staticCodeAnalysisEnabled = staticCodeAnalysisEnabled; + } + + public Integer getMaxStaticCodeAnalysisPenalty() { + return maxStaticCodeAnalysisPenalty; + } + + public void setMaxStaticCodeAnalysisPenalty(Integer maxStaticCodeAnalysisPenalty) { + this.maxStaticCodeAnalysisPenalty = maxStaticCodeAnalysisPenalty; + } + public void setReleaseTestsWithExampleSolution(boolean releaseTestsWithExampleSolution) { this.releaseTestsWithExampleSolution = releaseTestsWithExampleSolution; } @@ -583,6 +611,15 @@ public AssessmentType getAssessmentType() { return super.getAssessmentType(); } + @Nullable + public ProjectType getProjectType() { + return projectType; + } + + public void setProjectType(@Nullable ProjectType projectType) { + this.projectType = projectType; + } + /** * set all sensitive information to null, so no info with respect to the solution gets leaked to students through json */ @@ -693,7 +730,7 @@ public void validateProgrammingSettings() { } // Check if Xcode has no online code editor enabled - if (ProjectType.XCODE.equals(getBuildConfig().getProjectType()) && Boolean.TRUE.equals(isAllowOnlineEditor())) { + if (ProjectType.XCODE.equals(getProjectType()) && Boolean.TRUE.equals(isAllowOnlineEditor())) { throw new BadRequestAlertException("The online editor is not allowed for Xcode programming exercises", "Exercise", "noParticipationModeAllowed"); } @@ -703,6 +740,49 @@ public void validateProgrammingSettings() { } } + /** + * Validates the static code analysis settings of the programming exercise + * 1. The flag staticCodeAnalysisEnabled must not be null + * 2. Static code analysis and sequential test runs can't be active at the same time + * 3. Static code analysis can only be enabled for supported programming languages + * 4. Static code analysis max penalty must only be set if static code analysis is enabled + * 5. Static code analysis max penalty must be positive + * + * @param programmingLanguageFeature describes the features available for the programming language of the programming exercise + */ + public void validateStaticCodeAnalysisSettings(ProgrammingLanguageFeature programmingLanguageFeature) { + // Check if the static code analysis flag was set + if (isStaticCodeAnalysisEnabled() == null) { + throw new BadRequestAlertException("The static code analysis flag must be set to true or false", "Exercise", "staticCodeAnalysisFlagNotSet"); + } + + // Check that programming exercise doesn't have sequential test runs and static code analysis enabled + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && getBuildConfig().hasSequentialTestRuns()) { + throw new BadRequestAlertException("The static code analysis with sequential test runs is not supported at the moment", "Exercise", "staticCodeAnalysisAndSequential"); + } + + // Check if the programming language supports static code analysis + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && !programmingLanguageFeature.staticCodeAnalysis()) { + throw new BadRequestAlertException("The static code analysis is not supported for this programming language", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); + } + + // Check that FACT has no SCA enabled + if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && ProjectType.FACT.equals(getProjectType())) { + throw new BadRequestAlertException("The static code analysis is not supported for FACT programming exercises", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); + } + + // Static code analysis max penalty must only be set if static code analysis is enabled + if (Boolean.FALSE.equals(isStaticCodeAnalysisEnabled()) && getMaxStaticCodeAnalysisPenalty() != null) { + throw new BadRequestAlertException("Max static code analysis penalty must only be set if static code analysis is enabled", "Exercise", + "staticCodeAnalysisDisabledButPenaltySet"); + } + + // Static code analysis max penalty must be positive + if (getMaxStaticCodeAnalysisPenalty() != null && getMaxStaticCodeAnalysisPenalty() < 0) { + throw new BadRequestAlertException("The static code analysis penalty must not be negative", "Exercise", "staticCodeAnalysisPenaltyNotNegative"); + } + } + /** * Validates settings for exercises, where allowFeedbackRequests is set */ diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java index 423de480ec0a..466e0552c68d 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ProgrammingExerciseBuildConfig.java @@ -2,11 +2,8 @@ import java.util.Objects; -import jakarta.annotation.Nullable; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; @@ -18,11 +15,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; -import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.service.connectors.aeolus.Windfile; import de.tum.in.www1.artemis.service.connectors.vcs.AbstractVersionControlService; -import de.tum.in.www1.artemis.service.programming.ProgrammingLanguageFeature; -import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException; @Entity @Table(name = "programming_exercise_build_config") @@ -63,20 +57,9 @@ public class ProgrammingExerciseBuildConfig extends DomainObject { @JsonIgnoreProperties("buildConfig") private ProgrammingExercise programmingExercise; - @Column(name = "static_code_analysis_enabled") - private Boolean staticCodeAnalysisEnabled; - - @Column(name = "max_static_code_analysis_penalty") - private Integer maxStaticCodeAnalysisPenalty; - @Column(name = "testwise_coverage_enabled") private boolean testwiseCoverageEnabled; - @Nullable - @Enumerated(EnumType.ORDINAL) - @Column(name = "project_type") - private ProjectType projectType; - @JsonProperty("sequentialTestRuns") public boolean hasSequentialTestRuns() { return Objects.requireNonNullElse(sequentialTestRuns, false); @@ -192,31 +175,6 @@ public void filterSensitiveInformation() { setBuildScript(null); } - public Boolean isStaticCodeAnalysisEnabled() { - return this.staticCodeAnalysisEnabled; - } - - public void setStaticCodeAnalysisEnabled(Boolean staticCodeAnalysisEnabled) { - this.staticCodeAnalysisEnabled = staticCodeAnalysisEnabled; - } - - public Integer getMaxStaticCodeAnalysisPenalty() { - return maxStaticCodeAnalysisPenalty; - } - - public void setMaxStaticCodeAnalysisPenalty(Integer maxStaticCodeAnalysisPenalty) { - this.maxStaticCodeAnalysisPenalty = maxStaticCodeAnalysisPenalty; - } - - @Nullable - public ProjectType getProjectType() { - return projectType; - } - - public void setProjectType(@Nullable ProjectType projectType) { - this.projectType = projectType; - } - public Boolean isTestwiseCoverageEnabled() { return testwiseCoverageEnabled; } @@ -233,49 +191,6 @@ public void setProgrammingExercise(ProgrammingExercise programmingExercise) { this.programmingExercise = programmingExercise; } - /** - * Validates the static code analysis settings of the programming exercise - * 1. The flag staticCodeAnalysisEnabled must not be null - * 2. Static code analysis and sequential test runs can't be active at the same time - * 3. Static code analysis can only be enabled for supported programming languages - * 4. Static code analysis max penalty must only be set if static code analysis is enabled - * 5. Static code analysis max penalty must be positive - * - * @param programmingLanguageFeature describes the features available for the programming language of the programming exercise - */ - public void validateStaticCodeAnalysisSettings(ProgrammingLanguageFeature programmingLanguageFeature) { - // Check if the static code analysis flag was set - if (isStaticCodeAnalysisEnabled() == null) { - throw new BadRequestAlertException("The static code analysis flag must be set to true or false", "Exercise", "staticCodeAnalysisFlagNotSet"); - } - - // Check that programming exercise doesn't have sequential test runs and static code analysis enabled - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && hasSequentialTestRuns()) { - throw new BadRequestAlertException("The static code analysis with sequential test runs is not supported at the moment", "Exercise", "staticCodeAnalysisAndSequential"); - } - - // Check if the programming language supports static code analysis - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && !programmingLanguageFeature.staticCodeAnalysis()) { - throw new BadRequestAlertException("The static code analysis is not supported for this programming language", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); - } - - // Check that FACT has no SCA enabled - if (Boolean.TRUE.equals(isStaticCodeAnalysisEnabled()) && ProjectType.FACT.equals(getProjectType())) { - throw new BadRequestAlertException("The static code analysis is not supported for FACT programming exercises", "Exercise", "staticCodeAnalysisNotSupportedForLanguage"); - } - - // Static code analysis max penalty must only be set if static code analysis is enabled - if (Boolean.FALSE.equals(isStaticCodeAnalysisEnabled()) && getMaxStaticCodeAnalysisPenalty() != null) { - throw new BadRequestAlertException("Max static code analysis penalty must only be set if static code analysis is enabled", "Exercise", - "staticCodeAnalysisDisabledButPenaltySet"); - } - - // Static code analysis max penalty must be positive - if (getMaxStaticCodeAnalysisPenalty() != null && getMaxStaticCodeAnalysisPenalty() < 0) { - throw new BadRequestAlertException("The static code analysis penalty must not be negative", "Exercise", "staticCodeAnalysisPenaltyNotNegative"); - } - } - @Override public String toString() { return "BuildJobConfig{" + "id=" + getId() + ", sequentialTestRuns=" + sequentialTestRuns + ", branch='" + branch + '\'' + ", buildPlanConfiguration='" diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index 76dcc45c3a8f..b5e43dbb3a8c 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -711,14 +711,6 @@ default ProgrammingExercise findWithEagerStudentParticipationsByIdElseThrow(long return findWithEagerStudentParticipationsById(programmingExerciseId).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); } - @Nullable - default ProgrammingExercise getProgrammingExerciseWithBuildConfig(ProgrammingExercise programmingExercise) { - if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { - return findWithBuildConfigById(programmingExercise.getId()).orElse(null); - } - return programmingExercise; - } - /** * Retrieves the associated ProgrammingExercise for a given ProgrammingExerciseParticipation. * If the ProgrammingExercise is not already loaded, it is fetched from the database and linked diff --git a/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java b/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java index 0e930e6d27dc..d17d6cc7a043 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/ExerciseSpecificationService.java @@ -16,7 +16,6 @@ import de.tum.in.www1.artemis.domain.Exercise; import de.tum.in.www1.artemis.domain.Exercise_; import de.tum.in.www1.artemis.domain.ProgrammingExercise; -import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig_; import de.tum.in.www1.artemis.domain.ProgrammingExercise_; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; @@ -113,7 +112,7 @@ else if (isCourseFilter) { */ public Specification createSCAFilter(ProgrammingLanguage programmingLanguage) { return (root, query, criteriaBuilder) -> { - Predicate scaActive = criteriaBuilder.isTrue(root.get(ProgrammingExerciseBuildConfig_.STATIC_CODE_ANALYSIS_ENABLED)); + Predicate scaActive = criteriaBuilder.isTrue(root.get(ProgrammingExercise_.STATIC_CODE_ANALYSIS_ENABLED)); Predicate sameLanguage = criteriaBuilder.equal(root.get(ProgrammingExercise_.PROGRAMMING_LANGUAGE), programmingLanguage); return criteriaBuilder.and(scaActive, sameLanguage); }; diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java index 51d467a0cfc0..2975cf69b2a4 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/BuildScriptProviderService.java @@ -126,7 +126,7 @@ public String getScriptFor(ProgrammingLanguage programmingLanguage, Optional extractProjectType(String filename) { public Windfile getDefaultWindfileFor(ProgrammingExercise exercise) { try { ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); - return getWindfileFor(exercise.getProgrammingLanguage(), Optional.ofNullable(buildConfig.getProjectType()), buildConfig.isStaticCodeAnalysisEnabled(), + return getWindfileFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()), exercise.isStaticCodeAnalysisEnabled(), buildConfig.hasSequentialTestRuns(), buildConfig.isTestwiseCoverageEnabled()); } catch (IOException e) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java index 1a72b5f8ea4a..85ba04c21db3 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java @@ -94,7 +94,7 @@ private void addTestCaseFeedbacksToResult(Result result, List scaFeedbackList = feedbackCreationService.createFeedbackFromStaticCodeAnalysisReports(staticCodeAnalysisReports); result.addFeedbacks(scaFeedbackList); result.setCodeIssueCount(scaFeedbackList.size()); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java index 07634c5128ef..756adc7f2a79 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java @@ -143,7 +143,7 @@ private void setupGitLabCIConfiguration(VcsRepositoryUri repositoryUri, Programm // TODO: Reduce the number of API calls ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); updateVariable(repositoryPath, VARIABLE_BUILD_DOCKER_IMAGE_NAME, - programmingLanguageConfiguration.getImage(exercise.getProgrammingLanguage(), Optional.ofNullable(buildConfig.getProjectType()))); + programmingLanguageConfiguration.getImage(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()))); updateVariable(repositoryPath, VARIABLE_BUILD_LOGS_FILE_NAME, "build.log"); updateVariable(repositoryPath, VARIABLE_BUILD_PLAN_ID_NAME, buildPlanId); // TODO: Implement the custom feedback feature diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java index 1f76bf3138c3..13c75e7f5539 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsBuildPlanService.java @@ -133,11 +133,10 @@ public void createBuildPlanForExercise(ProgrammingExercise exercise, String plan final JenkinsXmlConfigBuilder.InternalVcsRepositoryURLs internalRepositoryUris = getInternalRepositoryUris(exercise, repositoryUri); final ProgrammingLanguage programmingLanguage = exercise.getProgrammingLanguage(); - final ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); - final var configBuilder = builderFor(programmingLanguage, buildConfig.getProjectType()); + final var configBuilder = builderFor(programmingLanguage, exercise.getProjectType()); final String buildPlanUrl = jenkinsPipelineScriptCreator.generateBuildPlanURL(exercise); final boolean checkoutSolution = exercise.getBuildConfig().getCheckoutSolutionRepository(); - final Document jobConfig = configBuilder.buildBasicConfig(programmingLanguage, Optional.ofNullable(buildConfig.getProjectType()), internalRepositoryUris, checkoutSolution, + final Document jobConfig = configBuilder.buildBasicConfig(programmingLanguage, Optional.ofNullable(exercise.getProjectType()), internalRepositoryUris, checkoutSolution, buildPlanUrl); final String jobFolder = exercise.getProjectKey(); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java index 647c6a5d5888..e7acf23da041 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/build_plan/JenkinsPipelineScriptCreator.java @@ -18,7 +18,6 @@ import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; import de.tum.in.www1.artemis.domain.ProgrammingExercise; -import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.exception.JenkinsException; @@ -54,13 +53,12 @@ public JenkinsPipelineScriptCreator(final BuildPlanRepository buildPlanRepositor @Override protected String generateDefaultBuildPlan(final ProgrammingExercise exercise) { final ProgrammingLanguage programmingLanguage = exercise.getProgrammingLanguage(); - final ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); - final Optional projectType = Optional.ofNullable(buildConfig.getProjectType()); + final Optional projectType = Optional.ofNullable(exercise.getProjectType()); final String pipelineScript = loadPipelineScript(exercise, projectType); - final boolean isStaticCodeAnalysisEnabled = buildConfig.isStaticCodeAnalysisEnabled(); - final boolean isTestwiseCoverageAnalysisEnabled = buildConfig.isTestwiseCoverageEnabled(); + final boolean isStaticCodeAnalysisEnabled = exercise.isStaticCodeAnalysisEnabled(); + final boolean isTestwiseCoverageAnalysisEnabled = exercise.getBuildConfig().isTestwiseCoverageEnabled(); final var replacements = getReplacements(programmingLanguage, projectType, isStaticCodeAnalysisEnabled, isTestwiseCoverageAnalysisEnabled); return replaceVariablesInBuildPlanTemplate(replacements, pipelineScript); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java index bf5ad6c6b74e..368598630311 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java @@ -24,7 +24,6 @@ import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; -import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.domain.enumeration.RepositoryType; @@ -247,14 +246,12 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio throw new LocalCIException("Error while getting branch of participation", e); } - ProgrammingExerciseBuildConfig buildConfig = participation.getProgrammingExercise().getBuildConfig(); - ProgrammingExercise programmingExercise = participation.getProgrammingExercise(); ProgrammingLanguage programmingLanguage = programmingExercise.getProgrammingLanguage(); - ProjectType projectType = buildConfig.getProjectType(); - boolean staticCodeAnalysisEnabled = buildConfig.isStaticCodeAnalysisEnabled(); - boolean sequentialTestRunsEnabled = buildConfig.hasSequentialTestRuns(); - boolean testwiseCoverageEnabled = buildConfig.isTestwiseCoverageEnabled(); + ProjectType projectType = programmingExercise.getProjectType(); + boolean staticCodeAnalysisEnabled = programmingExercise.isStaticCodeAnalysisEnabled(); + boolean sequentialTestRunsEnabled = programmingExercise.getBuildConfig().hasSequentialTestRuns(); + boolean testwiseCoverageEnabled = programmingExercise.getBuildConfig().isTestwiseCoverageEnabled(); Windfile windfile; String dockerImage; @@ -265,7 +262,7 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio catch (NullPointerException e) { log.warn("Could not retrieve windfile for programming exercise {}. Using default windfile instead.", programmingExercise.getId()); windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); - dockerImage = programmingLanguageConfiguration.getImage(programmingExercise.getProgrammingLanguage(), Optional.ofNullable(buildConfig.getProjectType())); + dockerImage = programmingLanguageConfiguration.getImage(programmingExercise.getProgrammingLanguage(), Optional.ofNullable(programmingExercise.getProjectType())); } List resultPaths = getTestResultPaths(windfile); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java index 76db1891fa54..49d31e3b59ae 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java @@ -183,6 +183,9 @@ public String getOrRetrieveBranchOfStudentParticipation(ProgrammingExerciseStude @Override public String getOrRetrieveBranchOfExercise(ProgrammingExercise programmingExercise) { + if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.getProgrammingExerciseWithBuildConfig(programmingExercise)); + } if (programmingExercise.getBuildConfig().getBranch() == null) { if (!Hibernate.isInitialized(programmingExercise.getTemplateParticipation())) { programmingExercise.setTemplateParticipation(templateProgrammingExerciseParticipationRepository.findByProgrammingExerciseIdElseThrow(programmingExercise.getId())); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java index ccbb0f4e96a8..a4ea308c262a 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/JavaTemplateUpgradeService.java @@ -108,8 +108,7 @@ private void upgradeTemplateFiles(ProgrammingExercise exercise, RepositoryType r // Validate that template and repository have the same number of pom.xml files, otherwise no upgrade will take place if (templatePoms.length == 1 && repositoryPoms.size() == 1) { - Model updatedRepoModel = upgradeProjectObjectModel(templatePoms[0], repositoryPoms.getFirst(), - Boolean.TRUE.equals(exercise.getBuildConfig().isStaticCodeAnalysisEnabled())); + Model updatedRepoModel = upgradeProjectObjectModel(templatePoms[0], repositoryPoms.getFirst(), Boolean.TRUE.equals(exercise.isStaticCodeAnalysisEnabled())); writeProjectObjectModel(updatedRepoModel, repositoryPoms.getFirst()); } @@ -123,7 +122,7 @@ private void upgradeTemplateFiles(ProgrammingExercise exercise, RepositoryType r programmingExerciseRepositoryService.replacePlaceholders(exercise, repository); // Add the latest static code analysis tool configurations or remove configurations - if (Boolean.TRUE.equals(exercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(exercise.isStaticCodeAnalysisEnabled())) { Resource[] staticCodeAnalysisResources = getTemplateResources(exercise, "test/" + SCA_CONFIG_FOLDER + "/**/*.*"); fileService.copyResources(staticCodeAnalysisResources, Path.of("java", "test"), repository.getLocalPath().toAbsolutePath(), true); } @@ -148,9 +147,8 @@ private Resource[] getTemplateResources(ProgrammingExercise exercise, String fil Resource[] templatePoms = resourceLoaderService.getFileResources(programmingLanguageTemplate, filePattern); // Get project type specific template resources - if (exercise.getBuildConfig().getProjectType() != null) { - final Path projectTypeTemplate = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(exercise.getProgrammingLanguage(), - exercise.getBuildConfig().getProjectType()); + if (exercise.getProjectType() != null) { + final Path projectTypeTemplate = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(exercise.getProgrammingLanguage(), exercise.getProjectType()); final Resource[] projectTypePoms = resourceLoaderService.getFileResources(projectTypeTemplate, filePattern); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java index ea6002d20ef5..2118a1453026 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseGradingService.java @@ -186,7 +186,7 @@ public Result processNewProgrammingExerciseResult(@NotNull ProgrammingExercisePa if (buildResult.hasLogs()) { var programmingLanguage = exercise.getProgrammingLanguage(); - var projectType = exercise.getBuildConfig().getProjectType(); + var projectType = exercise.getProjectType(); var buildLogs = buildResult.extractBuildLogs(); ciResultService.extractAndPersistBuildLogStatistics(latestSubmission, programmingLanguage, projectType, buildLogs); @@ -913,8 +913,8 @@ else if (isWeightSumZero) { private double calculateTotalPenalty(ScoreCalculationData scoreCalculationData, boolean applySubmissionPolicy) { double penalty = 0; var exercise = scoreCalculationData.exercise(); - int maxStaticCodeAnalysisPenalty = Optional.ofNullable(exercise.getBuildConfig().getMaxStaticCodeAnalysisPenalty()).orElse(100); - if (Boolean.TRUE.equals(exercise.getBuildConfig().isStaticCodeAnalysisEnabled()) && maxStaticCodeAnalysisPenalty > 0) { + int maxStaticCodeAnalysisPenalty = Optional.ofNullable(exercise.getMaxStaticCodeAnalysisPenalty()).orElse(100); + if (Boolean.TRUE.equals(exercise.isStaticCodeAnalysisEnabled()) && maxStaticCodeAnalysisPenalty > 0) { penalty += calculateStaticCodeAnalysisPenalty(scoreCalculationData.staticCodeAnalysisFeedback(), exercise); } @@ -936,8 +936,7 @@ private double calculateTotalPenalty(ScoreCalculationData scoreCalculationData, */ private double calculateStaticCodeAnalysisPenalty(final List staticCodeAnalysisFeedback, final ProgrammingExercise programmingExercise) { final var feedbackByCategory = staticCodeAnalysisFeedback.stream().collect(Collectors.groupingBy(Feedback::getStaticCodeAnalysisCategory)); - final double maxExercisePenaltyPoints = Objects.requireNonNullElse(programmingExercise.getBuildConfig().getMaxStaticCodeAnalysisPenalty(), 100) / 100.0 - * programmingExercise.getMaxPoints(); + final double maxExercisePenaltyPoints = Objects.requireNonNullElse(programmingExercise.getMaxStaticCodeAnalysisPenalty(), 100) / 100.0 * programmingExercise.getMaxPoints(); double overallPenaltyPoints = 0; for (var category : staticCodeAnalysisCategoryRepository.findByExerciseId(programmingExercise.getId())) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java index 76d7316550a7..9bf39cfa3de0 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportBasicService.java @@ -162,10 +162,10 @@ public ProgrammingExercise importProgrammingExerciseBasis(final ProgrammingExerc programmingExerciseTaskService.updateTestIds(importedExercise, newTestCaseIdByOldId); // Copy or create SCA categories - if (Boolean.TRUE.equals(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled() && Boolean.TRUE.equals(originalBuildConfig.isStaticCodeAnalysisEnabled()))) { + if (Boolean.TRUE.equals(importedExercise.isStaticCodeAnalysisEnabled() && Boolean.TRUE.equals(originalProgrammingExercise.isStaticCodeAnalysisEnabled()))) { importStaticCodeAnalysisCategories(originalProgrammingExercise, importedExercise); } - else if (Boolean.TRUE.equals(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()) && !Boolean.TRUE.equals(originalBuildConfig.isStaticCodeAnalysisEnabled())) { + else if (Boolean.TRUE.equals(importedExercise.isStaticCodeAnalysisEnabled()) && !Boolean.TRUE.equals(originalProgrammingExercise.isStaticCodeAnalysisEnabled())) { staticCodeAnalysisService.createDefaultCategories(importedExercise); } diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java index d01297f8c53f..4778bc0e45bf 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseImportFromFileService.java @@ -107,7 +107,7 @@ public ProgrammingExercise importProgrammingExerciseFromFile(ProgrammingExercise programmingExerciseService.validateNewProgrammingExerciseSettings(originalProgrammingExercise, course); // TODO: creating the whole exercise (from template) is a bad solution in this case, we do not want the template content, instead we want the file content of the zip newProgrammingExercise = programmingExerciseService.createProgrammingExercise(originalProgrammingExercise, true); - if (Boolean.TRUE.equals(originalProgrammingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(originalProgrammingExercise.isStaticCodeAnalysisEnabled())) { staticCodeAnalysisService.createDefaultCategories(newProgrammingExercise); } Path pathToDirectoryWithImportedContent = exerciseFilePath.toAbsolutePath().getParent().resolve(FilenameUtils.getBaseName(exerciseFilePath.toString())); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java index 42b4ed5f66fb..3da8a6924ed6 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseRepositoryService.java @@ -27,7 +27,6 @@ import de.tum.in.www1.artemis.config.Constants; import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; -import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.Repository; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; @@ -128,7 +127,7 @@ private record RepositoryResources(Repository repository, Resource[] resources, */ private RepositoryResources getRepositoryResources(final ProgrammingExercise programmingExercise, final RepositoryType repositoryType) throws GitAPIException { final String programmingLanguage = programmingExercise.getProgrammingLanguage().toString().toLowerCase(Locale.ROOT); - final ProjectType projectType = programmingExercise.getBuildConfig().getProjectType(); + final ProjectType projectType = programmingExercise.getProjectType(); final Path projectTypeTemplateDir = getTemplateDirectoryForRepositoryType(repositoryType); final VcsRepositoryUri repoUri = programmingExercise.getRepositoryURL(repositoryType); @@ -305,8 +304,7 @@ private void setupTestTemplateAndPush(final RepositoryResources resources, final */ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final User user) throws IOException, GitAPIException { - ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); - final ProjectType projectType = buildConfig.getProjectType(); + final ProjectType projectType = programmingExercise.getProjectType(); final Path repoLocalPath = getRepoAbsoluteLocalPath(resources.repository); // First get files that are not dependent on the project type @@ -330,9 +328,9 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi final Map sectionsMap = new HashMap<>(); // Keep or delete static code analysis configuration in the build configuration file - sectionsMap.put("static-code-analysis", Boolean.TRUE.equals(buildConfig.isStaticCodeAnalysisEnabled())); + sectionsMap.put("static-code-analysis", Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())); // Keep or delete testwise coverage configuration in the build file - sectionsMap.put("record-testwise-coverage", Boolean.TRUE.equals(buildConfig.isTestwiseCoverageEnabled())); + sectionsMap.put("record-testwise-coverage", Boolean.TRUE.equals(programmingExercise.getBuildConfig().isTestwiseCoverageEnabled())); if (programmingExercise.getBuildConfig().hasSequentialTestRuns()) { setupTestTemplateSequentialTestRuns(resources, templatePath, projectTemplatePath, projectType, sectionsMap); @@ -371,7 +369,7 @@ else if (ProjectType.MAVEN_BLACKBOX.equals(projectType)) { */ private void setupJVMTestTemplateProjectTypeResources(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final Path repoLocalPath) throws IOException { - final ProjectType projectType = programmingExercise.getBuildConfig().getProjectType(); + final ProjectType projectType = programmingExercise.getProjectType(); final Path projectTypeTemplatePath = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(programmingExercise.getProgrammingLanguage(), projectType) .resolve(TEST_DIR); final Path projectTypeProjectTemplatePath = projectTypeTemplatePath.resolve("projectTemplate"); @@ -396,8 +394,7 @@ private void setupJVMTestTemplateProjectTypeResources(final RepositoryResources */ private void setupTestTemplateRegularTestRuns(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final Path templatePath, final Map sectionsMap) throws IOException { - ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); - final ProjectType projectType = buildConfig.getProjectType(); + final ProjectType projectType = programmingExercise.getProjectType(); final Path repoLocalPath = getRepoAbsoluteLocalPath(resources.repository); final Path testFilePath = templatePath.resolve(TEST_FILES_PATH); final Resource[] testFileResources = resourceLoaderService.getFileResources(testFilePath); @@ -408,7 +405,7 @@ private void setupTestTemplateRegularTestRuns(final RepositoryResources resource setupBuildToolProjectFile(repoLocalPath, projectType, sectionsMap); - if (buildConfig.getProjectType() != ProjectType.MAVEN_BLACKBOX) { + if (programmingExercise.getProjectType() != ProjectType.MAVEN_BLACKBOX) { fileService.copyResources(testFileResources, resources.prefix, packagePath, false); } @@ -417,7 +414,7 @@ private void setupTestTemplateRegularTestRuns(final RepositoryResources resource } // Copy static code analysis config files - if (Boolean.TRUE.equals(buildConfig.isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())) { setupStaticCodeAnalysisConfigFiles(resources, templatePath, repoLocalPath); } } @@ -448,7 +445,7 @@ private void setupStaticCodeAnalysisConfigFiles(final RepositoryResources resour } private void overwriteProjectTypeSpecificFiles(final RepositoryResources resources, final ProgrammingExercise programmingExercise, final Path packagePath) throws IOException { - final ProjectType projectType = programmingExercise.getBuildConfig().getProjectType(); + final ProjectType projectType = programmingExercise.getProjectType(); final Path projectTypeTemplatePath = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(programmingExercise.getProgrammingLanguage(), projectType) .resolve(TEST_DIR); @@ -629,13 +626,13 @@ private void replaceSwiftPlaceholders(final Map replacements, fi // So usually, the name should not change. final String cleanPackageName = packageName.replaceAll("[^a-zA-Z\\d]", ""); - if (ProjectType.PLAIN.equals(programmingExercise.getBuildConfig().getProjectType())) { + if (ProjectType.PLAIN.equals(programmingExercise.getProjectType())) { fileService.replaceVariablesInDirectoryName(repositoryLocalPath, PACKAGE_NAME_FOLDER_PLACEHOLDER, cleanPackageName); fileService.replaceVariablesInFilename(repositoryLocalPath, PACKAGE_NAME_FILE_PLACEHOLDER, cleanPackageName); replacements.put(PACKAGE_NAME_PLACEHOLDER, cleanPackageName); } - else if (ProjectType.XCODE.equals(programmingExercise.getBuildConfig().getProjectType())) { + else if (ProjectType.XCODE.equals(programmingExercise.getProjectType())) { fileService.replaceVariablesInDirectoryName(repositoryLocalPath, APP_NAME_PLACEHOLDER, cleanPackageName); fileService.replaceVariablesInFilename(repositoryLocalPath, APP_NAME_PLACEHOLDER, cleanPackageName); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java index 004838b88b90..d05544ae0809 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingExerciseService.java @@ -396,15 +396,14 @@ public void validateNewProgrammingExerciseSettings(ProgrammingExercise programmi private void validateProjectType(ProgrammingExercise programmingExercise, ProgrammingLanguageFeature programmingLanguageFeature) { // Check if project type is selected if (!programmingLanguageFeature.projectTypes().isEmpty()) { - ProgrammingExerciseBuildConfig buildConfig = programmingExercise.getBuildConfig(); - if (buildConfig.getProjectType() == null) { + if (programmingExercise.getProjectType() == null) { throw new BadRequestAlertException("The project type is not set", "Exercise", "projectTypeNotSet"); } - if (!programmingLanguageFeature.projectTypes().contains(buildConfig.getProjectType())) { + if (!programmingLanguageFeature.projectTypes().contains(programmingExercise.getProjectType())) { throw new BadRequestAlertException("The project type is not supported for this programming language", "Exercise", "projectTypeNotSupported"); } } - else if (programmingExercise.getBuildConfig().getProjectType() != null) { + else if (programmingExercise.getProjectType() != null) { throw new BadRequestAlertException("The project type is set but not supported", "Exercise", "projectTypeSet"); } } @@ -438,7 +437,7 @@ private void validatePackageName(ProgrammingExercise programmingExercise, Progra public void validateStaticCodeAnalysisSettings(ProgrammingExercise programmingExercise) { ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.orElseThrow() .getProgrammingLanguageFeatures(programmingExercise.getProgrammingLanguage()); - programmingExercise.getBuildConfig().validateStaticCodeAnalysisSettings(programmingLanguageFeature); + programmingExercise.validateStaticCodeAnalysisSettings(programmingLanguageFeature); } /** diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java index 5793b30e339a..caffc53578ab 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/StaticCodeAnalysisResource.java @@ -151,7 +151,7 @@ public ResponseEntity> importStaticCodeAnalysisC } private void checkSCAEnabledForExerciseElseThrow(ProgrammingExercise programmingExercise) { - if (!Boolean.TRUE.equals(programmingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { + if (!Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())) { throw new BadRequestAlertException("Static code analysis is not enabled", ENTITY_NAME, "staticCodeAnalysisNotEnabled"); } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java index d0e1f1827c2e..27472e0004c6 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseExportImportResource.java @@ -158,7 +158,7 @@ public ProgrammingExerciseExportImportResource(ProgrammingExerciseRepository pro private void validateStaticCodeAnalysisSettings(ProgrammingExercise programmingExercise) { ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.orElseThrow() .getProgrammingLanguageFeatures(programmingExercise.getProgrammingLanguage()); - programmingExercise.getBuildConfig().validateStaticCodeAnalysisSettings(programmingLanguageFeature); + programmingExercise.validateStaticCodeAnalysisSettings(programmingLanguageFeature); } /** @@ -218,8 +218,7 @@ public ResponseEntity importProgrammingExercise(@PathVariab originalProgrammingExercise.setTasks(new ArrayList<>(templateTasks)); // The static code analysis flag can only change, if the build plans are recreated and the template is upgraded - if (newExercise.getBuildConfig().isStaticCodeAnalysisEnabled() != originalProgrammingExercise.getBuildConfig().isStaticCodeAnalysisEnabled() - && !(recreateBuildPlans && updateTemplate)) { + if (newExercise.isStaticCodeAnalysisEnabled() != originalProgrammingExercise.isStaticCodeAnalysisEnabled() && !(recreateBuildPlans && updateTemplate)) { throw new BadRequestAlertException("Static code analysis can only change, if the recreation of build plans and update of template files is activated", ENTITY_NAME, "staticCodeAnalysisCannotChange"); } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index cc8c08136759..429d94419a19 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -40,7 +40,6 @@ import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.GradingCriterion; import de.tum.in.www1.artemis.domain.ProgrammingExercise; -import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.ProgrammingExerciseTestCase; import de.tum.in.www1.artemis.domain.User; import de.tum.in.www1.artemis.domain.enumeration.AssessmentType; @@ -248,7 +247,7 @@ public ResponseEntity createProgrammingExercise(@RequestBod ProgrammingExercise newProgrammingExercise = programmingExerciseService.createProgrammingExercise(programmingExercise, false); // Create default static code analysis categories - if (Boolean.TRUE.equals(programmingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { + if (Boolean.TRUE.equals(programmingExercise.isStaticCodeAnalysisEnabled())) { staticCodeAnalysisService.createDefaultCategories(newProgrammingExercise); } @@ -293,14 +292,14 @@ public ResponseEntity updateProgrammingExercise(@RequestBod checkProgrammingExerciseForError(updatedProgrammingExercise); var programmingExerciseBeforeUpdate = programmingExerciseRepository.findWithAuxiliaryRepositoriesAndBuildConfigElseThrow(updatedProgrammingExercise.getId()); - ProgrammingExerciseBuildConfig buildConfigBeforeUpdate = programmingExerciseBeforeUpdate.getBuildConfig(); if (!Objects.equals(programmingExerciseBeforeUpdate.getShortName(), updatedProgrammingExercise.getShortName())) { throw new BadRequestAlertException("The programming exercise short name cannot be changed", ENTITY_NAME, "shortNameCannotChange"); } - if (!Objects.equals(buildConfigBeforeUpdate.isStaticCodeAnalysisEnabled(), updatedProgrammingExercise.getBuildConfig().isStaticCodeAnalysisEnabled())) { + if (!Objects.equals(programmingExerciseBeforeUpdate.isStaticCodeAnalysisEnabled(), updatedProgrammingExercise.isStaticCodeAnalysisEnabled())) { throw new BadRequestAlertException("Static code analysis enabled flag must not be changed", ENTITY_NAME, "staticCodeAnalysisCannotChange"); } - if (!Objects.equals(buildConfigBeforeUpdate.isTestwiseCoverageEnabled(), updatedProgrammingExercise.getBuildConfig().isTestwiseCoverageEnabled())) { + if (!Objects.equals(programmingExerciseBeforeUpdate.getBuildConfig().isTestwiseCoverageEnabled(), + updatedProgrammingExercise.getBuildConfig().isTestwiseCoverageEnabled())) { throw new BadRequestAlertException("Testwise coverage enabled flag must not be changed", ENTITY_NAME, "testwiseCoverageCannotChange"); } if (!Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOnlineEditor()) && !Boolean.TRUE.equals(updatedProgrammingExercise.isAllowOfflineIde())) { diff --git a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml index 3db6e204dd48..08f54d6ec0ac 100644 --- a/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml +++ b/src/main/resources/config/liquibase/changelog/20240626200000_changelog.xml @@ -17,9 +17,6 @@ - - - @@ -47,8 +44,8 @@ - INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, common_key_id, static_code_analysis_enabled, max_static_code_analysis_penalty, project_type, testwise_coverage_enabled) - SELECT exercise.sequential_test_runs, programming_exercise_details.branch, programming_exercise_details.build_plan_configuration, programming_exercise_details.build_script, programming_exercise_details.checkout_solution_repository, exercise.id, programming_exercise_details.static_code_analysis_enabled, programming_exercise_details.max_static_code_analysis_penalty, programming_exercise_details.project_type, programming_exercise_details.testwise_coverage_enabled + INSERT INTO programming_exercise_build_config (sequential_test_runs, branch, build_plan_configuration, build_script, checkout_solution_repository, common_key_id, testwise_coverage_enabled) + SELECT exercise.sequential_test_runs, programming_exercise_details.branch, programming_exercise_details.build_plan_configuration, programming_exercise_details.build_script, programming_exercise_details.checkout_solution_repository, exercise.id, programming_exercise_details.testwise_coverage_enabled FROM exercise JOIN programming_exercise_details ON exercise.id = programming_exercise_details.id WHERE exercise.discriminator = 'P'; @@ -63,9 +60,6 @@ ALTER TABLE programming_exercise_details DROP COLUMN build_plan_configuration; ALTER TABLE programming_exercise_details DROP COLUMN build_script; ALTER TABLE programming_exercise_details DROP COLUMN checkout_solution_repository; - ALTER TABLE programming_exercise_details DROP COLUMN static_code_analysis_enabled; - ALTER TABLE programming_exercise_details DROP COLUMN max_static_code_analysis_penalty; - ALTER TABLE programming_exercise_details DROP COLUMN project_type; ALTER TABLE programming_exercise_details DROP COLUMN testwise_coverage_enabled; -- ALTER TABLE programming_exercise_build_config DROP COLUMN common_key_id; diff --git a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java index 56065c46a637..e7ca1b012f91 100644 --- a/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/BuildPlanIntegrationTest.java @@ -57,8 +57,8 @@ void init() { programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); var buildConfig = new ProgrammingExerciseBuildConfig(); - buildConfig.setProjectType(ProjectType.MAVEN_MAVEN); - buildConfig.setStaticCodeAnalysisEnabled(true); + programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); + programmingExercise.setStaticCodeAnalysisEnabled(true); buildConfig.setSequentialTestRuns(false); buildConfig.setTestwiseCoverageEnabled(false); var savedBuildConfig = programmingExerciseBuildConfigRepository.save(buildConfig); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java index f0d33d05eaac..d8829db9ed65 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusBuildScriptGenerationServiceTest.java @@ -94,16 +94,16 @@ void testBuildScriptGenerationUsingBuildPlanGenerationService() throws JsonProce programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); programmingExercise.getBuildConfig().setBuildPlanConfiguration(getSerializedWindfile()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); String script = aeolusBuildScriptGenerationService.getScript(programmingExercise); assertThat(script).isNotNull(); assertThat(script).isEqualTo("imagine a result here"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.PYTHON); - programmingExercise.getBuildConfig().setProjectType(null); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExercise.setProjectType(null); + programmingExercise.setStaticCodeAnalysisEnabled(false); programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); programmingExercise.getBuildConfig().setBuildPlanConfiguration(null); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java index 12b6f93684c2..b7ca6b08497c 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java @@ -201,8 +201,8 @@ void testShouldNotGenerateAnything() throws JsonProcessingException { programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); programmingExercise.getBuildConfig().setBuildPlanConfiguration(getSerializedWindfile()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); String script = aeolusBuildScriptGenerationService.getScript(programmingExercise); @@ -221,7 +221,7 @@ void testGetWindfileFor() throws IOException { void testGetDefaultWindfileFor() { ProgrammingExercise programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(true); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java index adbf5d5ccadb..af259e98fd56 100644 --- a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java @@ -394,6 +394,7 @@ public List createCoursesWithExercisesAndLectures(String userPrefix, boo modelingExercise = exerciseRepo.save(modelingExercise); textExercise = exerciseRepo.save(textExercise); exerciseRepo.save(fileUploadExercise); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); exerciseRepo.save(programmingExercise); exerciseRepo.save(quizExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exam/ExamUtilService.java b/src/test/java/de/tum/in/www1/artemis/exam/ExamUtilService.java index fb7aa3290af8..d9c43d6aa0a7 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/ExamUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/ExamUtilService.java @@ -58,6 +58,7 @@ import de.tum.in.www1.artemis.repository.ExamUserRepository; import de.tum.in.www1.artemis.repository.ExerciseGroupRepository; import de.tum.in.www1.artemis.repository.ExerciseRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.StudentExamRepository; import de.tum.in.www1.artemis.repository.StudentParticipationRepository; import de.tum.in.www1.artemis.repository.SubmissionRepository; @@ -94,6 +95,9 @@ public class ExamUtilService { @Autowired private ExerciseRepository exerciseRepo; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ExamUserRepository examUserRepository; @@ -812,6 +816,7 @@ public Exam addExerciseGroupsAndExercisesToExam(Exam exam, boolean withProgrammi var exerciseGroup6 = exam.getExerciseGroups().get(6); // Programming exercises need a proper setup for 'prepare exam start' to work ProgrammingExercise programmingExercise1 = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup6, "Programming"); + programmingExerciseBuildConfigRepository.save(programmingExercise1.getBuildConfig()); exerciseRepo.save(programmingExercise1); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise1); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise1); @@ -859,6 +864,7 @@ public Exam addTextModelingProgrammingExercisesToExam(Exam initialExam, boolean var exerciseGroup2 = exam.getExerciseGroups().get(2); // Programming exercises need a proper setup for 'prepare exam start' to work ProgrammingExercise programmingExercise1 = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup2); + programmingExerciseBuildConfigRepository.save(programmingExercise1.getBuildConfig()); exerciseRepo.save(programmingExercise1); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise1); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise1); diff --git a/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java index 696a1795ed20..21b2a874524d 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/StudentExamIntegrationTest.java @@ -510,8 +510,7 @@ void testGetStudentExamForConduction() throws Exception { assertThat(exercise.getExerciseGroup().getExercises()).isEmpty(); assertThat(exercise.getExerciseGroup().getExam()).isNull(); if (exercise instanceof ProgrammingExercise) { - assertThat(((ProgrammingExercise) exercise).getBuildConfig().getBuildScript()).isNull(); - assertThat(((ProgrammingExercise) exercise).getBuildConfig().getBuildPlanConfiguration()).isNull(); + assertThat(((ProgrammingExercise) exercise).getBuildConfig()).isNull(); } } assertThat(studentExamRepository.findById(studentExam.getId()).orElseThrow().isStarted()).isTrue(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java index ff7d97ccf726..2aa5caf6f3bb 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseFactory.java @@ -120,20 +120,20 @@ private static void populateUnreleasedProgrammingExercise(ProgrammingExercise pr if (programmingExercise.getBuildConfig() == null) { programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); } - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExercise.setStaticCodeAnalysisEnabled(false); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); programmingExercise.setAssessmentType(AssessmentType.SEMI_AUTOMATIC); programmingExercise.setProgrammingLanguage(programmingLanguage); programmingExercise.getBuildConfig().setBuildScript("Some script"); programmingExercise.getBuildConfig().setBuildPlanConfiguration("{\"api\":\"v0.0.1\",\"metadata\":{},\"actions\":[]}"); if (programmingLanguage == ProgrammingLanguage.JAVA) { - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_MAVEN); + programmingExercise.setProjectType(ProjectType.PLAIN_MAVEN); } else if (programmingLanguage == ProgrammingLanguage.SWIFT) { - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN); + programmingExercise.setProjectType(ProjectType.PLAIN); } else { - programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.setProjectType(null); } programmingExercise.setPackageName(programmingLanguage == ProgrammingLanguage.SWIFT ? "swiftTest" : "de.test"); final var repoName = programmingExercise.generateRepositoryName(RepositoryType.TESTS); @@ -178,7 +178,7 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setPackageName(template.getPackageName()); toBeImported.setAllowOnlineEditor(template.isAllowOnlineEditor()); toBeImported.setAllowOfflineIde(template.isAllowOfflineIde()); - buildConfig.setStaticCodeAnalysisEnabled(template.getBuildConfig().isStaticCodeAnalysisEnabled()); + toBeImported.setStaticCodeAnalysisEnabled(template.isStaticCodeAnalysisEnabled()); buildConfig.setTestwiseCoverageEnabled(template.getBuildConfig().isTestwiseCoverageEnabled()); toBeImported.setTutorParticipations(null); toBeImported.setPosts(null); @@ -187,7 +187,7 @@ public static ProgrammingExercise generateToBeImportedProgrammingExercise(String toBeImported.setExampleSubmissions(null); toBeImported.setTestRepositoryUri(template.getTestRepositoryUri()); toBeImported.setProgrammingLanguage(template.getProgrammingLanguage()); - buildConfig.setProjectType(template.getBuildConfig().getProjectType()); + toBeImported.setProjectType(template.getProjectType()); toBeImported.setAssessmentDueDate(template.getAssessmentDueDate()); toBeImported.setAttachments(null); toBeImported.setDueDate(template.getDueDate()); @@ -416,21 +416,21 @@ public static void populateUnreleasedProgrammingExercise(ProgrammingExercise pro programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); } if (programmingLanguage == ProgrammingLanguage.JAVA) { - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_MAVEN); + programmingExercise.setProjectType(ProjectType.PLAIN_MAVEN); } else if (programmingLanguage == ProgrammingLanguage.SWIFT) { - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN); + programmingExercise.setProjectType(ProjectType.PLAIN); } else if (programmingLanguage == ProgrammingLanguage.C) { - programmingExercise.getBuildConfig().setProjectType(ProjectType.GCC); + programmingExercise.setProjectType(ProjectType.GCC); } else { - programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.setProjectType(null); } programmingExercise.setAllowOnlineEditor(true); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(enableStaticCodeAnalysis); + programmingExercise.setStaticCodeAnalysisEnabled(enableStaticCodeAnalysis); if (enableStaticCodeAnalysis) { - programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(40); + programmingExercise.setMaxStaticCodeAnalysisPenalty(40); } programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(enableTestwiseCoverageAnalysis); // Note: no separators are allowed for Swift package names diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index 6c179d586834..efddbc439892 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -226,8 +226,7 @@ private ProgrammingExercise newExamProgrammingExercise() { ProgrammingExercise programmingExercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(group); // Adjust settings so that exam and course exercises can use the same tests programmingExercise.setMaxPoints(42.0); - programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(40); - super.programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + programmingExercise.setMaxStaticCodeAnalysisPenalty(40); programmingExercise = super.programmingExerciseRepository.save(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise); @@ -924,6 +923,7 @@ private Result updateAndSaveAutomaticResult(Result result, boolean test1Passes, var feedback3 = new Feedback().result(result).testCase(tests.get("test3")).positive(test3Passes).type(FeedbackType.AUTOMATIC); result.addFeedback(feedback3); result.rated(true).successful(test1Passes && test2Passes && test3Passes).completionDate(ZonedDateTime.now()).assessmentType(AssessmentType.AUTOMATIC); + programmingExercise = programmingExerciseRepository.findWithBuildConfigById(programmingExercise.getId()).orElseThrow(); gradingService.calculateScoreForResult(result, programmingExercise, true); return resultRepository.save(result); } @@ -1113,8 +1113,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithoutCaps() { } // Also remove max penalty from exercise - programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); - programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); + programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(null); programmingExerciseRepository.save(programmingExerciseSCAEnabled); // create results for tests without any limits @@ -1189,7 +1188,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithBonus() { } // Remove max penalty from exercise - programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(null); programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); programmingExerciseRepository.save(programmingExerciseSCAEnabled); @@ -1238,8 +1237,7 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenalties() { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void shouldCalculateScoreWithStaticCodeAnalysisPenalties_cappedByExerciseMaxPenalty() { - programmingExerciseSCAEnabled.getBuildConfig().setMaxStaticCodeAnalysisPenalty(20); - programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); + programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(20); programmingExerciseSCAEnabled = exerciseRepository.save(programmingExerciseSCAEnabled); activateAllTestCases(false); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java index f20078b8910f..60007e88b0a3 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java @@ -97,7 +97,6 @@ import de.tum.in.www1.artemis.repository.AuxiliaryRepositoryRepository; import de.tum.in.www1.artemis.repository.CourseRepository; import de.tum.in.www1.artemis.repository.GradingCriterionRepository; -import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; @@ -153,9 +152,6 @@ class ProgrammingExerciseIntegrationTestService { @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; - @Autowired - private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; - @Autowired private ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository; @@ -892,15 +888,15 @@ private void mockConfigureRepository(ProgrammingExercise programmingExercise) th void updateProgrammingExercise_staticCodeAnalysisMustNotChange_falseToTrue_badRequest() throws Exception { mockBuildPlanAndRepositoryCheck(programmingExercise); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setStaticCodeAnalysisEnabled(true); request.put("/api/programming-exercises", programmingExercise, HttpStatus.BAD_REQUEST); } void updateProgrammingExercise_staticCodeAnalysisMustNotChange_trueToFalse_badRequest() throws Exception { mockBuildPlanAndRepositoryCheck(programmingExercise); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); - programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExerciseRepository.save(programmingExercise); + programmingExercise.setStaticCodeAnalysisEnabled(false); request.put("/api/programming-exercises", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -973,7 +969,7 @@ void updateProgrammingExerciseShouldFailWithBadRequestWhenUpdatingSCAOption() th mockBuildPlanAndRepositoryCheck(programmingExercise); ProgrammingExercise updatedExercise = programmingExercise; - updatedExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + updatedExercise.setStaticCodeAnalysisEnabled(true); request.put("/api/programming-exercises", updatedExercise, HttpStatus.BAD_REQUEST); } @@ -1196,7 +1192,7 @@ void createProgrammingExercise_staticCodeAnalysisMustBeSet_badRequest() throws E programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(null); + programmingExercise.setStaticCodeAnalysisEnabled(null); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1204,7 +1200,7 @@ void createProgrammingExercise_staticCodeAnalysisAndSequential_badRequest() thro programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1213,9 +1209,9 @@ void createProgrammingExercise_unsupportedProgrammingLanguageForStaticCodeAnalys programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExercise.programmingLanguage(ProgrammingLanguage.C); - programmingExercise.getBuildConfig().setProjectType(ProjectType.FACT); + programmingExercise.setProjectType(ProjectType.FACT); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1223,8 +1219,8 @@ void createProgrammingExercise_noStaticCodeAnalysisButMaxPenalty_badRequest() th programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); - programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(20); + programmingExercise.setStaticCodeAnalysisEnabled(false); + programmingExercise.setMaxStaticCodeAnalysisPenalty(20); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1232,8 +1228,8 @@ void createProgrammingExercise_maxStaticCodePenaltyNegative_badRequest() throws programmingExercise.setId(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); - programmingExercise.getBuildConfig().setMaxStaticCodeAnalysisPenalty(-20); + programmingExercise.setStaticCodeAnalysisEnabled(true); + programmingExercise.setMaxStaticCodeAnalysisPenalty(-20); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1267,7 +1263,7 @@ void createProgrammingExercise_projectTypeMissing_badRequest() throws Exception programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.JAVA); - programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.setProjectType(null); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1276,7 +1272,7 @@ void createProgrammingExercise_projectTypeNotExpected_badRequest() throws Except programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.PYTHON); - programmingExercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); + programmingExercise.setProjectType(ProjectType.MAVEN_MAVEN); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1285,7 +1281,7 @@ void createProgrammingExercise_onlineCodeEditorNotExpected_badRequest() throws E programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.SWIFT); - programmingExercise.getBuildConfig().setProjectType(ProjectType.XCODE); + programmingExercise.setProjectType(ProjectType.XCODE); programmingExercise.setAllowOnlineEditor(true); request.post("/api/programming-exercises/setup", programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1326,7 +1322,7 @@ void createProgrammingExercise_notIncluded_invalidBonusPoints_badRequest() throw void createProgrammingExercise_testwiseCoverageAnalysisNotSupported_badRequest(ProgrammingLanguage programmingLanguage) throws Exception { programmingExercise.setId(null); - programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.setProjectType(null); programmingExercise.setTitle("New title"); programmingExercise.setShortName("NewShortname"); programmingExercise.setProgrammingLanguage(programmingLanguage); @@ -1393,7 +1389,7 @@ void importProgrammingExercise_sameTitleInCourse_badRequest() throws Exception { void importProgrammingExercise_staticCodeAnalysisMustBeSet_badRequest() throws Exception { var id = programmingExercise.getId(); programmingExercise.setId(null); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(null); + programmingExercise.setStaticCodeAnalysisEnabled(null); request.post("/api/programming-exercises/import/" + id, programmingExercise, HttpStatus.BAD_REQUEST); } @@ -1411,14 +1407,14 @@ void importProgrammingExercise_scaChanged_badRequest(boolean recreateBuildPlan, programmingExercise.setId(null); programmingExercise.setTitle("NewTitle1"); programmingExercise.setShortName("NewShortname1"); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setStaticCodeAnalysisEnabled(true); request.postWithResponseBody("/api/programming-exercises/import/" + sourceId, programmingExercise, ProgrammingExercise.class, params, HttpStatus.BAD_REQUEST); // true -> false sourceId = programmingExerciseSca.getId(); programmingExerciseSca.setId(null); - programmingExerciseSca.getBuildConfig().setStaticCodeAnalysisEnabled(false); - programmingExerciseSca.getBuildConfig().setMaxStaticCodeAnalysisPenalty(null); + programmingExerciseSca.setStaticCodeAnalysisEnabled(false); + programmingExerciseSca.setMaxStaticCodeAnalysisPenalty(null); programmingExerciseSca.setTitle("NewTitle2"); programmingExerciseSca.setShortName("NewShortname2"); request.postWithResponseBody("/api/programming-exercises/import/" + sourceId, programmingExerciseSca, ProgrammingExercise.class, params, HttpStatus.BAD_REQUEST); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java index 2c998bc5d3c3..604ed22c0ee5 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseLocalVCLocalCIIntegrationTest.java @@ -96,12 +96,9 @@ void setup() throws Exception { course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); programmingExercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); String projectKey = programmingExercise.getProjectKey(); - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); - programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); - programmingExercise.getBuildConfig().setProgrammingExercise(programmingExercise); - programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExercise = programmingExerciseRepository.findWithAllParticipationsById(programmingExercise.getId()).orElseThrow(); // Set the correct repository URIs for the template and the solution participation. @@ -148,7 +145,7 @@ void testCreateProgrammingExercise() throws Exception { doReturn(ZonedDateTime.now().minusSeconds(2)).when(versionControlService).getPushDate(any(), any(), any()); ProgrammingExercise newExercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course); - newExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); + newExercise.setProjectType(ProjectType.PLAIN_GRADLE); // Mock dockerClient.copyArchiveFromContainerCmd() such that it returns a dummy commitHash for both the assignment and the test repository. // Note: The stub needs to receive the same object twice because there are two requests to the same method (one for the template participation and one for the solution diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java index ba07499f21c0..121ee822b60b 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTemplateIntegrationTest.java @@ -273,7 +273,7 @@ void testTemplateSolution(ProgrammingLanguage language, ProjectType projectType, private void runTests(ProgrammingLanguage language, ProjectType projectType, LocalRepository repository, TestResult testResult, boolean testwiseCoverageAnalysis) throws Exception { exercise.setProgrammingLanguage(language); - exercise.getBuildConfig().setProjectType(projectType); + exercise.setProjectType(projectType); mockConnectorRequestsForSetup(exercise, false, true, false); exercise.setChannelName("exercise-pe"); if (testwiseCoverageAnalysis) { diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java index ed79a2706d51..01a94d2eb6be 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java @@ -499,7 +499,7 @@ void createProgrammingExercise_custom_build_plan_validExercise_created(Programmi exercise.getBuildConfig().setBuildPlanConfiguration(validWindfile); if (programmingLanguage == C) { - exercise.getBuildConfig().setProjectType(ProjectType.FACT); + exercise.setProjectType(ProjectType.FACT); } exercise.setChannelName("testchannel-pe"); setupRepositoryMocks(exercise, exerciseRepo, solutionRepo, testRepo, auxRepo); @@ -521,7 +521,7 @@ void createProgrammingExercise_programmingLanguage_validExercise_created(Program if (language == SWIFT) { exercise.setPackageName("swiftTest"); } - exercise.getBuildConfig().setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); + exercise.setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); exercise.setChannelName("testchannel-pe"); validateProgrammingExercise(request.postWithResponseBody("/api/programming-exercises/setup", exercise, ProgrammingExercise.class, HttpStatus.CREATED)); @@ -542,7 +542,7 @@ void importFromFile_validJavaExercise_isSuccessfullyImported(boolean scaEnabled) mockDelegate.mockConnectorRequestForImportFromFile(exercise); Resource resource = new ClassPathResource("test-data/import-from-file/valid-import.zip"); if (scaEnabled) { - exercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + exercise.setStaticCodeAnalysisEnabled(true); } var file = new MockMultipartFile("file", "test.zip", "application/zip", resource.getInputStream()); @@ -553,23 +553,23 @@ void importFromFile_validJavaExercise_isSuccessfullyImported(boolean scaEnabled) assertThat(importedExercise).isNotNull(); assertThat(importedExercise.getProgrammingLanguage()).isEqualTo(JAVA); assertThat(importedExercise.getMode()).isEqualTo(ExerciseMode.INDIVIDUAL); - assertThat(importedExercise.getBuildConfig().getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); + assertThat(importedExercise.getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); if (scaEnabled) { - assertThat(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(importedExercise.isStaticCodeAnalysisEnabled()).isTrue(); } else { - assertThat(importedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isFalse(); + assertThat(importedExercise.isStaticCodeAnalysisEnabled()).isFalse(); } var savedExercise = programmingExerciseRepository.findById(importedExercise.getId()).orElseThrow(); assertThat(savedExercise).isNotNull(); assertThat(savedExercise.getProgrammingLanguage()).isEqualTo(JAVA); assertThat(savedExercise.getMode()).isEqualTo(ExerciseMode.INDIVIDUAL); - assertThat(savedExercise.getBuildConfig().getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); + assertThat(savedExercise.getProjectType()).isEqualTo(ProjectType.PLAIN_MAVEN); if (scaEnabled) { - assertThat(savedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(savedExercise.isStaticCodeAnalysisEnabled()).isTrue(); } else { - assertThat(savedExercise.getBuildConfig().isStaticCodeAnalysisEnabled()).isFalse(); + assertThat(savedExercise.isStaticCodeAnalysisEnabled()).isFalse(); } assertThat(importedExercise.getCourseViaExerciseGroupOrCourseMember()).isEqualTo(course); } @@ -578,12 +578,12 @@ void importFromFile_validExercise_isSuccessfullyImported(ProgrammingLanguage lan mockDelegate.mockConnectorRequestForImportFromFile(exercise); Resource resource = null; exercise.programmingLanguage(language); - exercise.getBuildConfig().setProjectType(null); + exercise.setProjectType(null); switch (language) { case PYTHON -> resource = new ClassPathResource("test-data/import-from-file/valid-import-python.zip"); case C -> { resource = new ClassPathResource("test-data/import-from-file/valid-import-c.zip"); - exercise.getBuildConfig().setProjectType(ProjectType.FACT); + exercise.setProjectType(ProjectType.FACT); } case HASKELL -> resource = new ClassPathResource("test-data/import-from-file/valid-import-haskell.zip"); case OCAML -> resource = new ClassPathResource("test-data/import-from-file/valid-import-ocaml.zip"); @@ -676,17 +676,17 @@ public void importFromFile_exception_DirectoryDeleted() throws Exception { // TEST void createProgrammingExercise_validExercise_withStaticCodeAnalysis(ProgrammingLanguage language, ProgrammingLanguageFeature programmingLanguageFeature) throws Exception { - exercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + exercise.setStaticCodeAnalysisEnabled(true); exercise.setProgrammingLanguage(language); if (language == SWIFT) { exercise.setPackageName("swiftTest"); } // Exclude ProjectType FACT as SCA is not supported if (language == C) { - exercise.getBuildConfig().setProjectType(ProjectType.GCC); + exercise.setProjectType(ProjectType.GCC); } else { - exercise.getBuildConfig().setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); + exercise.setProjectType(programmingLanguageFeature.projectTypes().isEmpty() ? null : programmingLanguageFeature.projectTypes().getFirst()); } mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); exercise.setChannelName("testchannel-pe"); @@ -755,8 +755,8 @@ private AuxiliaryRepository addAuxiliaryRepositoryToProgrammingExercise(Programm void createAndImportJavaProgrammingExercise(boolean staticCodeAnalysisEnabled) throws Exception { setupRepositoryMocks(exercise, sourceExerciseRepo, sourceSolutionRepo, sourceTestRepo, sourceAuxRepo); mockDelegate.mockConnectorRequestsForSetup(exercise, false, false, false); - exercise.getBuildConfig().setProjectType(ProjectType.MAVEN_MAVEN); - exercise.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + exercise.setProjectType(ProjectType.MAVEN_MAVEN); + exercise.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); exercise.setChannelName("testchannel-pe"); var sourceExercise = request.postWithResponseBody("/api/programming-exercises/setup", exercise, ProgrammingExercise.class, HttpStatus.CREATED); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); @@ -781,7 +781,7 @@ void createAndImportJavaProgrammingExercise(boolean staticCodeAnalysisEnabled) t ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", exercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(false); + exerciseToBeImported.setStaticCodeAnalysisEnabled(false); // TODO: at the moment, it does not work that the copied repositories include the same files as ones that have been created originally // this is probably the case, because the actual copy is not executed due to mocks @@ -819,13 +819,13 @@ void importExercise_created(ProgrammingLanguage programmingLanguage, boolean rec ProgrammingExercise sourceExercise = programmingExerciseUtilService.addCourseWithOneProgrammingExerciseAndStaticCodeAnalysisCategories(programmingLanguage); sourceExercise.setPlagiarismDetectionConfig(PlagiarismDetectionConfig.createDefault()); sourceExercise = programmingExerciseRepository.save(sourceExercise); - sourceExercise.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + sourceExercise.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); programmingExerciseUtilService.addTestCasesToProgrammingExercise(sourceExercise); programmingExerciseUtilService.addHintsToExercise(sourceExercise); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", sourceExercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + exerciseToBeImported.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); if (addAuxRepos) { addAuxiliaryRepositoryToProgrammingExercise(sourceExercise); } @@ -882,14 +882,14 @@ void updateBuildPlanURL() throws Exception { boolean staticCodeAnalysisEnabled = true; // Setup exercises for import ProgrammingExercise sourceExercise = programmingExerciseUtilService.addCourseWithOneProgrammingExerciseAndStaticCodeAnalysisCategories(JAVA); - sourceExercise.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + sourceExercise.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); sourceExercise.generateAndSetBuildPlanAccessSecret(); programmingExerciseUtilService.addTestCasesToProgrammingExercise(sourceExercise); programmingExerciseUtilService.addHintsToExercise(sourceExercise); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", sourceExercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); + exerciseToBeImported.setStaticCodeAnalysisEnabled(staticCodeAnalysisEnabled); // Mock requests setupRepositoryMocks(sourceExercise, sourceExerciseRepo, sourceSolutionRepo, sourceTestRepo, sourceAuxRepo); @@ -1067,9 +1067,9 @@ void testImportProgrammingExercise_scaChange() throws Exception { HttpStatus.OK); // Assertions - assertThat(exerciseToBeImported.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(exerciseToBeImported.isStaticCodeAnalysisEnabled()).isTrue(); assertThat(exerciseToBeImported.getStaticCodeAnalysisCategories()).isEmpty(); - assertThat(exerciseToBeImported.getBuildConfig().getMaxStaticCodeAnalysisPenalty()).isNull(); + assertThat(exerciseToBeImported.getMaxStaticCodeAnalysisPenalty()).isNull(); } void testImportProgrammingExercise_scaChange_activated() throws Exception { @@ -1079,8 +1079,8 @@ void testImportProgrammingExercise_scaChange_activated() throws Exception { sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "imported", sourceExercise, courseUtilService.addEmptyCourse()); - exerciseToBeImported.getBuildConfig().setStaticCodeAnalysisEnabled(true); - exerciseToBeImported.getBuildConfig().setMaxStaticCodeAnalysisPenalty(80); + exerciseToBeImported.setStaticCodeAnalysisEnabled(true); + exerciseToBeImported.setMaxStaticCodeAnalysisPenalty(80); // Mock requests mockDelegate.mockConnectorRequestsForImport(sourceExercise, exerciseToBeImported, true, false); @@ -1097,13 +1097,13 @@ void testImportProgrammingExercise_scaChange_activated() throws Exception { // Assertions var staticCodeAnalysisCategories = staticCodeAnalysisCategoryRepository.findByExerciseId(exerciseToBeImported.getId()); - assertThat(exerciseToBeImported.getBuildConfig().isStaticCodeAnalysisEnabled()).isTrue(); + assertThat(exerciseToBeImported.isStaticCodeAnalysisEnabled()).isTrue(); ProgrammingExercise finalSourceExercise = sourceExercise; var defaultCategories = StaticCodeAnalysisConfigurer.staticCodeAnalysisConfiguration().get(sourceExercise.getProgrammingLanguage()).stream() .map(s -> s.toStaticCodeAnalysisCategory(finalSourceExercise)).collect(Collectors.toSet()); assertThat(staticCodeAnalysisCategories).usingRecursiveFieldByFieldElementComparatorOnFields("name", "state", "penalty", "maxPenalty") .containsExactlyInAnyOrderElementsOf(defaultCategories); - assertThat(exerciseToBeImported.getBuildConfig().getMaxStaticCodeAnalysisPenalty()).isEqualTo(80); + assertThat(exerciseToBeImported.getMaxStaticCodeAnalysisPenalty()).isEqualTo(80); } void testImportProgrammingExerciseLockRepositorySubmissionPolicyChange() throws Exception { @@ -1173,7 +1173,7 @@ public void importProgrammingExerciseAsPartOfExamImport() throws Exception { Exam sourceExam = examUtilService.addExamWithExerciseGroup(course, true); ProgrammingExercise sourceExercise = programmingExerciseUtilService.addProgrammingExerciseToExam(sourceExam, 0); - sourceExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + sourceExercise.setStaticCodeAnalysisEnabled(false); programmingExerciseUtilService.addTestCasesToProgrammingExercise(sourceExercise); programmingExerciseUtilService.addHintsToExercise(sourceExercise); sourceExercise = programmingExerciseUtilService.loadProgrammingExerciseWithEagerReferences(sourceExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java index 25bab3b107cf..f54fb3842a8d 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java @@ -549,7 +549,7 @@ public ProgrammingExercise addCourseWithOneProgrammingExerciseAndStaticCodeAnaly Course course = addCourseWithOneProgrammingExercise(true, false, programmingLanguage); ProgrammingExercise programmingExercise = exerciseUtilService.findProgrammingExerciseWithTitle(course.getExercises(), "Programming"); programmingExercise = programmingExerciseRepository.save(programmingExercise); - + programmingExercise = programmingExerciseRepository.findWithBuildConfigById(programmingExercise.getId()).orElseThrow(); addStaticCodeAnalysisCategoriesToProgrammingExercise(programmingExercise); return programmingExercise; @@ -561,8 +561,10 @@ public ProgrammingExercise addCourseWithOneProgrammingExerciseAndStaticCodeAnaly * @param programmingExercise The programming exercise to which static code analysis categories should be added. */ public void addStaticCodeAnalysisCategoriesToProgrammingExercise(ProgrammingExercise programmingExercise) { - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); - programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); + if (programmingExercise.getBuildConfig() == null) { + programmingExercise = programmingExerciseRepository.findWithBuildConfigById(programmingExercise.getId()).orElseThrow(); + } + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExerciseRepository.save(programmingExercise); var category1 = ProgrammingExerciseFactory.generateStaticCodeAnalysisCategory(programmingExercise, "Bad Practice", CategoryState.GRADED, 3D, 10D); var category2 = ProgrammingExerciseFactory.generateStaticCodeAnalysisCategory(programmingExercise, "Code Style", CategoryState.GRADED, 5D, 10D); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java index 64c900f1a435..afc89acb21bd 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java @@ -185,7 +185,7 @@ void shouldExtractBuildLogAnalytics_noSca_gradle() throws Exception { Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, false, ProgrammingLanguage.JAVA); ProgrammingExercise exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); exercise = programmingExerciseRepository.findWithEagerStudentParticipationsStudentAndLegalSubmissionsById(exercise.getId()).orElseThrow(); - exercise.getBuildConfig().setProjectType(ProjectType.GRADLE_GRADLE); + exercise.setProjectType(ProjectType.GRADLE_GRADLE); programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); programmingExerciseRepository.save(exercise); var participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, userLogin); @@ -387,7 +387,7 @@ void shouldCreateGradleFeedback() throws Exception { String userLogin = TEST_PREFIX + "student1"; var course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, false, JAVA); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); - exercise.getBuildConfig().setProjectType(ProjectType.GRADLE_GRADLE); + exercise.setProjectType(ProjectType.GRADLE_GRADLE); programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); exercise = programmingExerciseRepository.save(exercise); diff --git a/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java index d7f9b8111970..4123ce083df6 100644 --- a/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/iris/IrisChatMessageIntegrationTest.java @@ -81,7 +81,7 @@ void initTestCase() throws GitAPIException, IOException, URISyntaxException { final Course course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); String projectKey = exercise.getProjectKey(); - exercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); + exercise.setProjectType(ProjectType.PLAIN_GRADLE); exercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey + "/" + projectKey.toLowerCase() + "-tests.git"); programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); programmingExerciseRepository.save(exercise); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java index b33bc0455a47..e9a015ffc37f 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/AbstractLocalCILocalVCIntegrationTest.java @@ -146,7 +146,7 @@ void initUsersAndExercise() throws JsonProcessingException { programmingExercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); projectKey1 = programmingExercise.getProjectKey(); programmingExercise.setReleaseDate(ZonedDateTime.now().minusDays(1)); - programmingExercise.getBuildConfig().setProjectType(ProjectType.PLAIN_GRADLE); + programmingExercise.setProjectType(ProjectType.PLAIN_GRADLE); programmingExercise.setAllowOfflineIde(true); programmingExercise.setTestRepositoryUri(localVCBaseUrl + "/git/" + projectKey1 + "/" + projectKey1.toLowerCase() + "-tests.git"); programmingExercise.getBuildConfig().setBuildPlanConfiguration(new ObjectMapper().writeValueAsString(aeolusTemplateService.getDefaultWindfileFor(programmingExercise))); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java index 367bc1373191..038b365a1076 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIIntegrationTest.java @@ -268,7 +268,7 @@ void testNoExceptionWhenResolvingWrongCommitHash() { @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void testProjectTypeIsNull() { ProgrammingExerciseStudentParticipation participation = localVCLocalCITestService.createParticipation(programmingExercise, student1Login); - programmingExercise.getBuildConfig().setProjectType(null); + programmingExercise.setProjectType(null); programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); @@ -362,7 +362,7 @@ void testLegacyResultFormat() throws IOException { @Test @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void testStaticCodeAnalysis() throws IOException { - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(true); + programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); programmingExerciseRepository.save(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java index a651ef2a3967..b5c7e3911116 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java @@ -137,8 +137,8 @@ void testRecreateBuildPlanForExercise() throws IOException { exercise.getBuildConfig().setBuildScript(script); exercise.getBuildConfig().setBuildPlanConfiguration(null); continuousIntegrationService.recreateBuildPlansForExercise(exercise); - script = buildScriptProviderService.getScriptFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getBuildConfig().getProjectType()), - exercise.getBuildConfig().isStaticCodeAnalysisEnabled(), exercise.getBuildConfig().hasSequentialTestRuns(), exercise.getBuildConfig().isTestwiseCoverageEnabled()); + script = buildScriptProviderService.getScriptFor(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()), exercise.isStaticCodeAnalysisEnabled(), + exercise.getBuildConfig().hasSequentialTestRuns(), exercise.getBuildConfig().isTestwiseCoverageEnabled()); Windfile windfile = aeolusTemplateService.getDefaultWindfileFor(exercise); String actualBuildConfig = exercise.getBuildConfig().getBuildPlanConfiguration(); String expectedBuildConfig = new ObjectMapper().writeValueAsString(windfile); @@ -153,8 +153,8 @@ void testGetScriptForWithoutCache() { ReflectionTestUtils.setField(buildScriptProviderService, "scriptCache", new ConcurrentHashMap<>()); ProgrammingExercise programmingExercise = new ProgrammingExercise(); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); - programmingExercise.getBuildConfig().setProjectType(null); - programmingExercise.getBuildConfig().setStaticCodeAnalysisEnabled(false); + programmingExercise.setProjectType(null); + programmingExercise.setStaticCodeAnalysisEnabled(false); programmingExercise.getBuildConfig().setSequentialTestRuns(false); programmingExercise.getBuildConfig().setTestwiseCoverageEnabled(false); String script = buildScriptProviderService.getScriptFor(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseTestRepository.java b/src/test/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseTestRepository.java index af3b3f6a158b..92c2da54143a 100644 --- a/src/test/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseTestRepository.java +++ b/src/test/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseTestRepository.java @@ -38,6 +38,7 @@ public interface ProgrammingExerciseTestRepository extends JpaRepository Date: Wed, 17 Jul 2024 17:13:22 +0200 Subject: [PATCH 17/78] TODO: remove personal comments adjust code --- .../ProgrammingExerciseRepository.java | 16 ++++++++++++ ...actContinuousIntegrationResultService.java | 7 +++++- .../gitlabci/GitLabCIResultService.java | 6 +++-- .../jenkins/JenkinsResultService.java | 6 +++-- .../LocalCIBuildConfigurationService.java | 6 ++--- .../localci/LocalCIResultService.java | 6 +++-- .../localci/LocalCITriggerService.java | 25 ++++++++++++++++--- .../vcs/AbstractVersionControlService.java | 4 +-- .../ProgrammingTriggerService.java | 2 +- .../artemis/course/CourseUtilService.java | 1 + ...ProgrammingExerciseGradingServiceTest.java | 2 +- ...rammingExerciseIntegrationTestService.java | 3 ++- ...rammingExerciseServiceIntegrationTest.java | 1 + ...AndResultGitlabJenkinsIntegrationTest.java | 1 - .../StaticCodeAnalysisIntegrationTest.java | 2 ++ ...TestRepositoryResourceIntegrationTest.java | 5 ++++ .../ParticipationIntegrationTest.java | 10 +++++++- .../artemis/util/HestiaUtilTestService.java | 7 +++++- 18 files changed, 87 insertions(+), 23 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index b5e43dbb3a8c..0c1fc585e5f8 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -82,6 +82,9 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation" }) Optional findWithTemplateAndSolutionParticipationById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "buildConfig" }) + Optional findWithTemplateAndSolutionParticipationAndBuildConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "categories", "teamAssignmentConfig", "templateParticipation.submissions.results", "solutionParticipation.submissions.results", "auxiliaryRepositories", "plagiarismDetectionConfig", "templateParticipation", "solutionParticipation", "buildConfig" }) Optional findForCreationById(long exerciseId); @@ -756,6 +759,19 @@ default ProgrammingExercise getProgrammingExerciseFromParticipationElseThrow(Pro return programmingExercise; } + /** + * Fetch the programming exercise with the build config, or throw an EntityNotFoundException if it cannot be found. + * + * @param programmingExercise The programming exercise to fetch the build config for. + * @return The programming exercise with the build config. + */ + default ProgrammingExercise getProgrammingExerciseWithBuildConfigElseThrow(ProgrammingExercise programmingExercise) { + if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { + return findWithBuildConfigById(programmingExercise.getId()).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExercise.getId())); + } + return programmingExercise; + } + /** * Validate the programming exercise title. * 1. Check presence and length of exercise title diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java index 85ba04c21db3..18c28eb0dbff 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/ci/AbstractContinuousIntegrationResultService.java @@ -12,6 +12,7 @@ import de.tum.in.www1.artemis.domain.participation.Participation; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.repository.BuildLogStatisticsEntryRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.service.dto.AbstractBuildResultNotificationDTO; import de.tum.in.www1.artemis.service.dto.BuildJobDTOInterface; @@ -28,13 +29,16 @@ public abstract class AbstractContinuousIntegrationResultService implements Cont protected final ProgrammingExerciseFeedbackCreationService feedbackCreationService; + protected final ProgrammingExerciseRepository programmingExerciseRepository; + protected AbstractContinuousIntegrationResultService(ProgrammingExerciseTestCaseRepository testCaseRepository, BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository, TestwiseCoverageService testwiseCoverageService, - ProgrammingExerciseFeedbackCreationService feedbackCreationService) { + ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseRepository programmingExerciseRepository) { this.testCaseRepository = testCaseRepository; this.buildLogStatisticsEntryRepository = buildLogStatisticsEntryRepository; this.testwiseCoverageService = testwiseCoverageService; this.feedbackCreationService = feedbackCreationService; + this.programmingExerciseRepository = programmingExerciseRepository; } @Override @@ -102,6 +106,7 @@ private void addStaticCodeAnalysisFeedbackToResult(Result result, AbstractBuildR } private void addTestwiseCoverageReportToResult(Result result, AbstractBuildResultNotificationDTO buildResult, ProgrammingExercise programmingExercise) { + programmingExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(programmingExercise); if (Boolean.TRUE.equals(programmingExercise.getBuildConfig().isTestwiseCoverageEnabled())) { var report = buildResult.getTestwiseCoverageReports(); if (report != null) { diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIResultService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIResultService.java index 906167dc0375..17e4c61e0f24 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIResultService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIResultService.java @@ -15,6 +15,7 @@ import de.tum.in.www1.artemis.domain.statistics.BuildLogStatisticsEntry; import de.tum.in.www1.artemis.repository.BuildLogStatisticsEntryRepository; import de.tum.in.www1.artemis.repository.FeedbackRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionRepository; import de.tum.in.www1.artemis.service.BuildLogEntryService; @@ -32,8 +33,9 @@ public class GitLabCIResultService extends AbstractContinuousIntegrationResultSe public GitLabCIResultService(ProgrammingSubmissionRepository programmingSubmissionRepository, FeedbackRepository feedbackRepository, BuildLogEntryService buildLogService, BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository, TestwiseCoverageService testwiseCoverageService, - ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseTestCaseRepository testCaseRepository) { - super(testCaseRepository, buildLogStatisticsEntryRepository, testwiseCoverageService, feedbackCreationService); + ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseTestCaseRepository testCaseRepository, + ProgrammingExerciseRepository programmingExerciseRepository) { + super(testCaseRepository, buildLogStatisticsEntryRepository, testwiseCoverageService, feedbackCreationService, programmingExerciseRepository); } @Override diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsResultService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsResultService.java index 43723d289f09..71104b29b18d 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsResultService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/jenkins/JenkinsResultService.java @@ -16,6 +16,7 @@ import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.repository.BuildLogStatisticsEntryRepository; import de.tum.in.www1.artemis.repository.FeedbackRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionRepository; import de.tum.in.www1.artemis.service.BuildLogEntryService; @@ -33,8 +34,9 @@ public class JenkinsResultService extends AbstractContinuousIntegrationResultSer public JenkinsResultService(ProgrammingSubmissionRepository programmingSubmissionRepository, FeedbackRepository feedbackRepository, BuildLogEntryService buildLogService, BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository, TestwiseCoverageService testwiseCoverageService, - ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseTestCaseRepository testCaseRepository) { - super(testCaseRepository, buildLogStatisticsEntryRepository, testwiseCoverageService, feedbackCreationService); + ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseTestCaseRepository testCaseRepository, + ProgrammingExerciseRepository programmingExerciseRepository) { + super(testCaseRepository, buildLogStatisticsEntryRepository, testwiseCoverageService, feedbackCreationService, programmingExerciseRepository); } @Override diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java index 580812f7d8c6..8a0f499466d8 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIBuildConfigurationService.java @@ -10,7 +10,6 @@ import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; -import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.exception.LocalCIException; import de.tum.in.www1.artemis.service.connectors.aeolus.AeolusTemplateService; import de.tum.in.www1.artemis.service.connectors.aeolus.ScriptAction; @@ -30,11 +29,10 @@ public LocalCIBuildConfigurationService(AeolusTemplateService aeolusTemplateServ * Creates a build script for a given programming exercise. * The build script is used to build the programming exercise in a Docker container. * - * @param participation the participation for which to create the build script + * @param programmingExercise the programming exercise for which the build script should be created * @return the build script */ - public String createBuildScript(ProgrammingExerciseParticipation participation) { - ProgrammingExercise programmingExercise = participation.getProgrammingExercise(); + public String createBuildScript(ProgrammingExercise programmingExercise) { StringBuilder buildScript = new StringBuilder(); buildScript.append("#!/bin/bash\n"); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultService.java index a4a7e9b32955..5dbd9731355b 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCIResultService.java @@ -13,6 +13,7 @@ import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.exception.LocalCIException; import de.tum.in.www1.artemis.repository.BuildLogStatisticsEntryRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseTestCaseRepository; import de.tum.in.www1.artemis.service.connectors.ci.AbstractContinuousIntegrationResultService; import de.tum.in.www1.artemis.service.connectors.localci.dto.BuildResult; @@ -28,8 +29,9 @@ public class LocalCIResultService extends AbstractContinuousIntegrationResultService { public LocalCIResultService(TestwiseCoverageService testwiseCoverageService, BuildLogStatisticsEntryRepository buildLogStatisticsEntryRepository, - ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseTestCaseRepository testCaseRepository) { - super(testCaseRepository, buildLogStatisticsEntryRepository, testwiseCoverageService, feedbackCreationService); + ProgrammingExerciseFeedbackCreationService feedbackCreationService, ProgrammingExerciseTestCaseRepository testCaseRepository, + ProgrammingExerciseRepository programmingExerciseRepository) { + super(testCaseRepository, buildLogStatisticsEntryRepository, testwiseCoverageService, feedbackCreationService, programmingExerciseRepository); } @Override diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java index 368598630311..77849ea3b6fb 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/localci/LocalCITriggerService.java @@ -24,6 +24,7 @@ import de.tum.in.www1.artemis.config.ProgrammingLanguageConfiguration; import de.tum.in.www1.artemis.domain.AuxiliaryRepository; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.ProjectType; import de.tum.in.www1.artemis.domain.enumeration.RepositoryType; @@ -31,6 +32,8 @@ import de.tum.in.www1.artemis.exception.LocalCIException; import de.tum.in.www1.artemis.exception.localvc.LocalVCInternalException; import de.tum.in.www1.artemis.repository.AuxiliaryRepositoryRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.SolutionProgrammingExerciseParticipationRepository; import de.tum.in.www1.artemis.service.connectors.GitService; import de.tum.in.www1.artemis.service.connectors.aeolus.AeolusResult; @@ -71,6 +74,10 @@ public class LocalCITriggerService implements ContinuousIntegrationTriggerServic private final GitService gitService; + private final ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + + private final ProgrammingExerciseRepository programmingExerciseRepository; + private IQueue queue; private IMap dockerImageCleanupInfo; @@ -79,7 +86,8 @@ public LocalCITriggerService(@Qualifier("hazelcastInstance") HazelcastInstance h ProgrammingLanguageConfiguration programmingLanguageConfiguration, AuxiliaryRepositoryRepository auxiliaryRepositoryRepository, LocalCIProgrammingLanguageFeatureService programmingLanguageFeatureService, Optional versionControlService, SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseParticipationRepository, - LocalCIBuildConfigurationService localCIBuildConfigurationService, GitService gitService) { + LocalCIBuildConfigurationService localCIBuildConfigurationService, GitService gitService, + ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository, ProgrammingExerciseRepository programmingExerciseRepository) { this.hazelcastInstance = hazelcastInstance; this.aeolusTemplateService = aeolusTemplateService; this.programmingLanguageConfiguration = programmingLanguageConfiguration; @@ -89,6 +97,8 @@ public LocalCITriggerService(@Qualifier("hazelcastInstance") HazelcastInstance h this.solutionProgrammingExerciseParticipationRepository = solutionProgrammingExerciseParticipationRepository; this.localCIBuildConfigurationService = localCIBuildConfigurationService; this.gitService = gitService; + this.programmingExerciseBuildConfigRepository = programmingExerciseBuildConfigRepository; + this.programmingExerciseRepository = programmingExerciseRepository; } @PostConstruct @@ -201,7 +211,15 @@ private RepositoryInfo getRepositoryInfo(ProgrammingExerciseParticipation partic String[] auxiliaryRepositoryUris = auxiliaryRepositories.stream().map(AuxiliaryRepository::getRepositoryUri).toArray(String[]::new); String[] auxiliaryRepositoryCheckoutDirectories1 = auxiliaryRepositories.stream().map(AuxiliaryRepository::getCheckoutDirectory).toArray(String[]::new); - if (programmingExercise.getBuildConfig().getCheckoutSolutionRepository()) { + ProgrammingExerciseBuildConfig buildConfig; + if (Hibernate.isInitialized(programmingExercise.getBuildConfig())) { + buildConfig = programmingExercise.getBuildConfig(); + } + else { + buildConfig = programmingExerciseBuildConfigRepository.findByProgrammingExerciseId(programmingExercise.getId()).orElseThrow(); + } + + if (buildConfig.getCheckoutSolutionRepository()) { ProgrammingLanguageFeature programmingLanguageFeature = programmingLanguageFeatureService.getProgrammingLanguageFeatures(programmingExercise.getProgrammingLanguage()); if (programmingLanguageFeature.checkoutSolutionRepositoryAllowed()) { var solutionParticipation = solutionProgrammingExerciseParticipationRepository.findByProgrammingExerciseId(participation.getProgrammingExercise().getId()); @@ -247,6 +265,7 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio } ProgrammingExercise programmingExercise = participation.getProgrammingExercise(); + programmingExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(programmingExercise); ProgrammingLanguage programmingLanguage = programmingExercise.getProgrammingLanguage(); ProjectType projectType = programmingExercise.getProjectType(); boolean staticCodeAnalysisEnabled = programmingExercise.isStaticCodeAnalysisEnabled(); @@ -268,7 +287,7 @@ private BuildConfig getBuildConfig(ProgrammingExerciseParticipation participatio List resultPaths = getTestResultPaths(windfile); // Todo: If build agent does not have access to filesystem, we need to send the build script to the build agent and execute it there. - String buildScript = localCIBuildConfigurationService.createBuildScript(participation); + String buildScript = localCIBuildConfigurationService.createBuildScript(programmingExercise); return new BuildConfig(buildScript, dockerImage, commitHashToBuild, assignmentCommitHash, testCommitHash, branch, programmingLanguage, projectType, staticCodeAnalysisEnabled, sequentialTestRunsEnabled, testwiseCoverageEnabled, resultPaths); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java index 49d31e3b59ae..f61528a79230 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/vcs/AbstractVersionControlService.java @@ -183,9 +183,7 @@ public String getOrRetrieveBranchOfStudentParticipation(ProgrammingExerciseStude @Override public String getOrRetrieveBranchOfExercise(ProgrammingExercise programmingExercise) { - if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { - programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.getProgrammingExerciseWithBuildConfig(programmingExercise)); - } + programmingExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(programmingExercise); if (programmingExercise.getBuildConfig().getBranch() == null) { if (!Hibernate.isInitialized(programmingExercise.getTemplateParticipation())) { programmingExercise.setTemplateParticipation(templateProgrammingExerciseParticipationRepository.findByProgrammingExerciseIdElseThrow(programmingExercise.getId())); diff --git a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingTriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingTriggerService.java index 3b35cd32acd0..649181556f28 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingTriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/programming/ProgrammingTriggerService.java @@ -104,7 +104,7 @@ public ProgrammingTriggerService(ProgrammingSubmissionRepository programmingSubm */ public void setTestCasesChangedAndTriggerTestCaseUpdate(long programmingExerciseId) throws EntityNotFoundException { setTestCasesChanged(programmingExerciseId, true); - var programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationById(programmingExerciseId).orElseThrow(); + var programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationAndBuildConfigById(programmingExerciseId).orElseThrow(); try { ContinuousIntegrationTriggerService ciTriggerService = continuousIntegrationTriggerService.orElseThrow(); diff --git a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java index af259e98fd56..34f0b1f87637 100644 --- a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java @@ -525,6 +525,7 @@ public Course createCourseWithAllExerciseTypesAndParticipationsAndSubmissionsAnd modelingExercise = exerciseRepo.save(modelingExercise); textExercise = exerciseRepo.save(textExercise); fileUploadExercise = exerciseRepo.save(fileUploadExercise); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExercise = exerciseRepo.save(programmingExercise); quizExercise = exerciseRepo.save(quizExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index efddbc439892..3b817d84b532 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -227,6 +227,7 @@ private ProgrammingExercise newExamProgrammingExercise() { // Adjust settings so that exam and course exercises can use the same tests programmingExercise.setMaxPoints(42.0); programmingExercise.setMaxStaticCodeAnalysisPenalty(40); + programmingExercise.setBuildConfig(super.programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExercise = super.programmingExerciseRepository.save(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); programmingExercise = super.programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(programmingExercise); @@ -1189,7 +1190,6 @@ void shouldCalculateScoreWithStaticCodeAnalysisPenaltiesWithBonus() { // Remove max penalty from exercise programmingExerciseSCAEnabled.setMaxStaticCodeAnalysisPenalty(null); - programmingExerciseBuildConfigRepository.save(programmingExerciseSCAEnabled.getBuildConfig()); programmingExerciseRepository.save(programmingExerciseSCAEnabled); // Remove category penalty limits diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java index 60007e88b0a3..1e979b93db4b 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java @@ -252,7 +252,7 @@ void setup(String userPrefix, MockDelegate mockDelegate, VersionControlService v userUtilService.addUsers(userPrefix, 3, 2, 2, 2); course = programmingExerciseUtilService.addCourseWithOneProgrammingExerciseAndTestCases(); programmingExercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); - programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationById(programmingExercise.getId()).orElseThrow(); + programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationAndBuildConfigById(programmingExercise.getId()).orElseThrow(); programmingExerciseInExam = programmingExerciseUtilService.addCourseExamExerciseGroupWithOneProgrammingExerciseAndTestCases(); programmingExerciseInExam = programmingExerciseRepository.findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(programmingExerciseInExam.getId()) .orElseThrow(); @@ -1450,6 +1450,7 @@ void importProgrammingExercise_updatesTestCaseIds() throws Exception { String problemStatement = "[task][Taskname](test1)"; programmingExercise.setProblemStatement(problemStatementWithId); programmingExerciseRepository.save(programmingExercise); + programmingExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(programmingExercise); String sourceId = programmingExercise.getId().toString(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java index 48673dd1b2ec..81134b6e8e01 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseServiceIntegrationTest.java @@ -207,6 +207,7 @@ private void testSearchTermMatchesId() throws Exception { final var now = ZonedDateTime.now(); ProgrammingExercise exercise = ProgrammingExerciseFactory.generateProgrammingExercise(now.minusDays(1), now.minusHours(2), course); exercise.setTitle("LoremIpsum"); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); var exerciseId = exercise.getId(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java index afc89acb21bd..10a625e7c176 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingSubmissionAndResultGitlabJenkinsIntegrationTest.java @@ -388,7 +388,6 @@ void shouldCreateGradleFeedback() throws Exception { var course = programmingExerciseUtilService.addCourseWithOneProgrammingExercise(false, false, JAVA); exercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); exercise.setProjectType(ProjectType.GRADLE_GRADLE); - programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); exercise = programmingExerciseRepository.save(exercise); var participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, userLogin); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/StaticCodeAnalysisIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/StaticCodeAnalysisIntegrationTest.java index d859d4b65e18..c60b05e7f805 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/StaticCodeAnalysisIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/StaticCodeAnalysisIntegrationTest.java @@ -80,6 +80,7 @@ void initTestCase() { course = courseRepository.findWithEagerExercisesById(programmingExerciseSCAEnabled.getCourseViaExerciseGroupOrCourseMember().getId()); var tempProgrammingEx = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now(), ZonedDateTime.now().plusDays(1), programmingExerciseSCAEnabled.getCourseViaExerciseGroupOrCourseMember()); + tempProgrammingEx.setBuildConfig(programmingExerciseBuildConfigRepository.save(tempProgrammingEx.getBuildConfig())); programmingExercise = programmingExerciseRepository.save(tempProgrammingEx); } @@ -112,6 +113,7 @@ void testGetStaticCodeAnalysisCategories() throws Exception { void testCreateDefaultCategories(ProgrammingLanguage programmingLanguage) { var testExercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now(), ZonedDateTime.now().plusDays(1), programmingExerciseSCAEnabled.getCourseViaExerciseGroupOrCourseMember(), programmingLanguage); + testExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(testExercise.getBuildConfig())); testExercise = programmingExerciseRepository.save(testExercise); staticCodeAnalysisService.createDefaultCategories(testExercise); // Swift has only one default category at the time of creation of this test diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/TestRepositoryResourceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/TestRepositoryResourceIntegrationTest.java index 562bdce2d5e6..a2077976d499 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/TestRepositoryResourceIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/TestRepositoryResourceIntegrationTest.java @@ -38,6 +38,7 @@ import de.tum.in.www1.artemis.domain.FileType; import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.Repository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.connectors.GitService; import de.tum.in.www1.artemis.user.UserUtilService; @@ -54,6 +55,9 @@ class TestRepositoryResourceIntegrationTest extends AbstractSpringIntegrationJen @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private UserUtilService userUtilService; @@ -77,6 +81,7 @@ void setup() throws Exception { userUtilService.addUsers(TEST_PREFIX, 1, 1, 0, 1); Course course = courseUtilService.addEmptyCourse(); programmingExercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); // Instantiate the remote repository as non-bare so its files can be manipulated testRepo.configureRepos("testLocalRepo", "testOriginRepo", false); diff --git a/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java index 302efa3f8a5a..46beb1f80b8e 100644 --- a/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java @@ -86,6 +86,7 @@ import de.tum.in.www1.artemis.repository.CourseRepository; import de.tum.in.www1.artemis.repository.ExamRepository; import de.tum.in.www1.artemis.repository.ExerciseRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ResultRepository; import de.tum.in.www1.artemis.repository.StudentParticipationRepository; import de.tum.in.www1.artemis.repository.SubmissionRepository; @@ -137,6 +138,9 @@ class ParticipationIntegrationTest extends AbstractAthenaTest { @Autowired private ProgrammingExerciseTestService programmingExerciseTestService; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private GradingScaleService gradingScaleService; @@ -203,6 +207,7 @@ void initTestData() throws Exception { exerciseRepo.save(modelingExercise); programmingExercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(1), course); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExercise = exerciseRepo.save(programmingExercise); course.addExercises(programmingExercise); course = courseRepo.save(course); @@ -701,6 +706,7 @@ void resumeProgrammingExerciseParticipation_wrongExerciseId() throws Exception { @WithMockUser(username = TEST_PREFIX + "student1", roles = "USER") void resumeProgrammingExerciseParticipation_forbidden() throws Exception { var exercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(2), ZonedDateTime.now().minusDays(1), course); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = exerciseRepo.save(exercise); var participation = ParticipationFactory.generateProgrammingExerciseStudentParticipation(InitializationState.INACTIVE, exercise, userUtilService.getUserByLogin(TEST_PREFIX + "student1")); @@ -1470,7 +1476,9 @@ void whenRequestFeedbackForExam_thenFail() throws Exception { Exam examWithExerciseGroups = ExamFactory.generateExamWithExerciseGroup(course, false); examRepository.save(examWithExerciseGroups); var exerciseGroup1 = examWithExerciseGroups.getExerciseGroups().get(0); - programmingExercise = exerciseRepo.save(ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1)); + programmingExercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); + programmingExercise = exerciseRepo.save(programmingExercise); course.addExercises(programmingExercise); course = courseRepo.save(course); diff --git a/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java b/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java index 71fa38f28211..75f55c81b4e9 100644 --- a/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java @@ -25,6 +25,7 @@ import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; import de.tum.in.www1.artemis.participation.ParticipationFactory; import de.tum.in.www1.artemis.participation.ParticipationUtilService; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionTestRepository; @@ -68,6 +69,9 @@ public class HestiaUtilTestService { @Autowired private ProgrammingExerciseStudentParticipationRepository programmingExerciseStudentParticipationRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + /** * Sets up the template repository of a programming exercise with a single file * @@ -113,7 +117,7 @@ public ProgrammingExercise setupTemplate(Map files, ProgrammingE doReturn(gitService.getExistingCheckedOutRepositoryByLocalPath(templateRepo.localRepoFile.toPath(), null)).when(gitService).getOrCheckoutRepository(eq(templateRepoUri), eq(false), any()); doNothing().when(gitService).pullIgnoreConflicts(any(Repository.class)); - + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); var savedExercise = exerciseRepository.save(exercise); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(savedExercise); var templateParticipation = templateProgrammingExerciseParticipationRepository.findByProgrammingExerciseId(savedExercise.getId()).orElseThrow(); @@ -172,6 +176,7 @@ public ProgrammingExercise setupSolution(Map files, ProgrammingE doReturn(gitService.getExistingCheckedOutRepositoryByLocalPath(solutionRepo.localRepoFile.toPath(), null)).when(gitService).getOrCheckoutRepository(eq(solutionRepoUri), eq(false), any()); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); var savedExercise = exerciseRepository.save(exercise); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(savedExercise); var solutionParticipation = solutionProgrammingExerciseParticipationRepository.findByProgrammingExerciseId(savedExercise.getId()).orElseThrow(); From 9a80dcd9b1ec7531aee6612823cc54793c9cedfc Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 00:45:23 +0200 Subject: [PATCH 18/78] TODO: remove personal comments adjust code --- .../ProgrammingExerciseRepository.java | 39 +++++++++++++++++- .../service/exam/ExamImportService.java | 2 +- .../ProgrammingExerciseResource.java | 4 +- .../ManagementResourceIntegrationTest.java | 1 + .../artemis/connectors/AeolusServiceTest.java | 1 + .../in/www1/artemis/exam/ExamStartTest.java | 1 + ...ciseGroupIntegrationJenkinsGitlabTest.java | 5 +++ .../exam/ProgrammingExamIntegrationTest.java | 9 +++++ .../ProgrammingAssessmentIntegrationTest.java | 5 +++ ...rammingExerciseIntegrationTestService.java | 2 +- ...rogrammingExerciseTestCaseServiceTest.java | 3 +- .../ProgrammingExerciseTestService.java | 40 +++++++++++++++---- .../ProgrammingExerciseUtilService.java | 3 +- .../ProgrammingExerciseTaskServiceTest.java | 12 ++++-- .../lecture/CompetencyIntegrationTest.java | 1 + .../artemis/localvcci/LocalCIServiceTest.java | 2 + .../artemis/service/GitlabCIServiceTest.java | 6 +-- .../artemis/util/HestiaUtilTestService.java | 4 +- 18 files changed, 117 insertions(+), 23 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index 0c1fc585e5f8..b774fed97b2e 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -68,6 +68,10 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos "submissionPolicy" }) Optional findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "teamAssignmentConfig", "categories", "auxiliaryRepositories", + "submissionPolicy", "buildConfig" }) + Optional findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "teamAssignmentConfig", "categories", "competencies", "auxiliaryRepositories", "submissionPolicy" }) Optional findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndCompetenciesById(long exerciseId); @@ -79,6 +83,9 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "auxiliaryRepositories" }) Optional findWithTemplateAndSolutionParticipationAndAuxiliaryRepositoriesById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation", "auxiliaryRepositories", "buildConfig" }) + Optional findWithTemplateAndSolutionParticipationAndAuxiliaryRepositoriesAndBuildConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "templateParticipation", "solutionParticipation" }) Optional findWithTemplateAndSolutionParticipationById(long exerciseId); @@ -302,9 +309,11 @@ default ProgrammingExercise findOneByProjectKeyOrThrow(String projectKey, boolea LEFT JOIN FETCH p.solutionParticipation LEFT JOIN FETCH p.auxiliaryRepositories LEFT JOIN FETCH tc.solutionEntries + LEFT JOIN FETCH p.buildConfig WHERE p.id = :exerciseId """) - Optional findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(@Param("exerciseId") long exerciseId); + Optional findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig( + @Param("exerciseId") long exerciseId); @Query(""" SELECT p @@ -597,6 +606,20 @@ default ProgrammingExercise findByIdWithTemplateAndSolutionParticipationAndAuxil return programmingExercise.orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); } + /** + * Find a programming exercise by its id, including auxiliary repositories, template and solution participation, + * their latest results and build config. + * + * @param programmingExerciseId of the programming exercise. + * @return The programming exercise related to the given id + * @throws EntityNotFoundException the programming exercise could not be found. + */ + @NotNull + default ProgrammingExercise findWithTemplateAndSolutionParticipationAndAuxiliaryRepositoriesAndBuildConfigElseThrow(long programmingExerciseId) throws EntityNotFoundException { + Optional programmingExercise = findWithTemplateAndSolutionParticipationAndAuxiliaryRepositoriesAndBuildConfigById(programmingExerciseId); + return programmingExercise.orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); + } + /** * Find a programming exercise by its id, with eagerly loaded template and solution participation and auxiliary repositories * @@ -641,6 +664,20 @@ default ProgrammingExercise findByIdWithTemplateAndSolutionParticipationTeamAssi return programmingExercise.orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); } + /** + * Find a programming exercise by its id, with eagerly loaded template and solution participation, team assignment config, categories and build config + * + * @param programmingExerciseId of the programming exercise. + * @return The programming exercise related to the given id + * @throws EntityNotFoundException the programming exercise could not be found. + */ + @NotNull + default ProgrammingExercise findByIdWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigElseThrow(long programmingExerciseId) + throws EntityNotFoundException { + Optional programmingExercise = findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(programmingExerciseId); + return programmingExercise.orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); + } + @NotNull default ProgrammingExercise findByIdWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndCompetenciesElseThrow(long programmingExerciseId) throws EntityNotFoundException { diff --git a/src/main/java/de/tum/in/www1/artemis/service/exam/ExamImportService.java b/src/main/java/de/tum/in/www1/artemis/service/exam/ExamImportService.java index ba38ee1df128..84a2309239f5 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/exam/ExamImportService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/exam/ExamImportService.java @@ -309,7 +309,7 @@ private void addExercisesToExerciseGroup(ExerciseGroup exerciseGroupToCopy, Exer case PROGRAMMING -> { final Optional optionalOriginalProgrammingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(exerciseToCopy.getId()); + .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig(exerciseToCopy.getId()); if (optionalOriginalProgrammingExercise.isEmpty()) { yield Optional.empty(); } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index 429d94419a19..9fc59198525f 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -563,7 +563,7 @@ public ResponseEntity combineTemplateRepositoryCommits(@PathVariable long @FeatureToggle(Feature.ProgrammingExercises) public ResponseEntity generateStructureOracleForExercise(@PathVariable long exerciseId) { log.debug("REST request to generate the structure oracle for ProgrammingExercise with id: {}", exerciseId); - var programmingExercise = programmingExerciseRepository.findByIdWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesElseThrow(exerciseId); + var programmingExercise = programmingExerciseRepository.findByIdWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigElseThrow(exerciseId); User user = userRepository.getUserWithGroupsAndAuthorities(); authCheckService.checkHasAtLeastRoleForExerciseElseThrow(Role.EDITOR, programmingExercise, user); if (programmingExercise.getPackageName() == null || programmingExercise.getPackageName().length() < 3) { @@ -689,7 +689,7 @@ public ResponseEntity> getAuxiliaryRepositories(@PathV public ResponseEntity reset(@PathVariable Long exerciseId, @RequestBody ProgrammingExerciseResetOptionsDTO programmingExerciseResetOptionsDTO) throws JsonProcessingException { log.debug("REST request to reset programming exercise {} with options {}", exerciseId, programmingExerciseResetOptionsDTO); - var programmingExercise = programmingExerciseRepository.findByIdWithTemplateAndSolutionParticipationAndAuxiliaryRepositoriesElseThrow(exerciseId); + var programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationAndAuxiliaryRepositoriesAndBuildConfigElseThrow(exerciseId); final var user = userRepository.getUserWithGroupsAndAuthorities(); if (programmingExerciseResetOptionsDTO.recreateBuildPlans()) { diff --git a/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java index 330b833a888d..b84aa8b418fc 100644 --- a/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java @@ -111,6 +111,7 @@ void toggleFeatures() throws Exception { request.put("/api/exercises/" + programmingExercise1.getId() + "/resume-programming-participation/" + participation.getId(), null, HttpStatus.OK); request.put("/api/participations/" + participation.getId() + "/cleanupBuildPlan", null, HttpStatus.OK); request.postWithoutLocation("/api/programming-submissions/" + participation.getId() + "/trigger-failed-build", null, HttpStatus.OK, null); + programmingExercise2.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise2.getBuildConfig())); programmingExercise2 = programmingExerciseRepository.save(programmingExercise2); request.delete("/api/programming-exercises/" + programmingExercise2.getId(), HttpStatus.OK, deleteProgrammingExerciseParamsFalse()); diff --git a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java index b7ca6b08497c..6764e7617e84 100644 --- a/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/connectors/AeolusServiceTest.java @@ -220,6 +220,7 @@ void testGetWindfileFor() throws IOException { @Test void testGetDefaultWindfileFor() { ProgrammingExercise programmingExercise = new ProgrammingExercise(); + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); programmingExercise.setStaticCodeAnalysisEnabled(true); programmingExercise.getBuildConfig().setSequentialTestRuns(true); diff --git a/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java b/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java index 0ee993d98e50..abbe9468b602 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/ExamStartTest.java @@ -270,6 +270,7 @@ private void createStudentExams(Exercise exercise) { private ProgrammingExercise createProgrammingExercise() { ProgrammingExercise programmingExercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exam.getExerciseGroups().get(0)); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExercise = exerciseRepo.save(programmingExercise); programmingExercise = programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(programmingExercise); exam.getExerciseGroups().get(0).addExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exam/ExerciseGroupIntegrationJenkinsGitlabTest.java b/src/test/java/de/tum/in/www1/artemis/exam/ExerciseGroupIntegrationJenkinsGitlabTest.java index 2d2ba57cc4a8..810cc0e49c21 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/ExerciseGroupIntegrationJenkinsGitlabTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/ExerciseGroupIntegrationJenkinsGitlabTest.java @@ -33,6 +33,7 @@ import de.tum.in.www1.artemis.exercise.text.TextExerciseUtilService; import de.tum.in.www1.artemis.repository.ExamRepository; import de.tum.in.www1.artemis.repository.ExerciseRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.TextExerciseRepository; import de.tum.in.www1.artemis.security.Role; import de.tum.in.www1.artemis.user.UserUtilService; @@ -47,6 +48,9 @@ class ExerciseGroupIntegrationJenkinsGitlabTest extends AbstractSpringIntegratio @Autowired private ExerciseRepository exerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ExamRepository examRepository; @@ -275,6 +279,7 @@ void importExerciseGroup_preCheckFailed() throws Exception { exam = examRepository.save(exam); ProgrammingExercise programming = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(programmingGroup, ProgrammingLanguage.JAVA); programmingGroup.addExercise(programming); + programming.setBuildConfig(programmingExerciseBuildConfigRepository.save(programming.getBuildConfig())); exerciseRepository.save(programming); doReturn(true).when(versionControlService).checkIfProjectExists(any(), any()); diff --git a/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java index b19d093a153f..1eab8a815fa7 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java @@ -42,6 +42,7 @@ import de.tum.in.www1.artemis.participation.ParticipationUtilService; import de.tum.in.www1.artemis.repository.ExamRepository; import de.tum.in.www1.artemis.repository.ExerciseRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.StudentExamRepository; import de.tum.in.www1.artemis.service.scheduled.ParticipantScoreScheduleService; @@ -64,6 +65,9 @@ class ProgrammingExamIntegrationTest extends AbstractSpringIntegrationJenkinsGit @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ObjectMapper objectMapper; @@ -239,9 +243,11 @@ void lockAllRepositories() throws Exception { ExerciseGroup exerciseGroup1 = examWithExerciseGroups.getExerciseGroups().get(0); ProgrammingExercise programmingExercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExerciseRepository.save(programmingExercise); ProgrammingExercise programmingExercise2 = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1); + programmingExercise2.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise2.getBuildConfig())); programmingExerciseRepository.save(programmingExercise2); Integer numOfLockedExercises = request.postWithResponseBody("/api/courses/" + course1.getId() + "/exams/" + exam.getId() + "/lock-all-repositories", Optional.empty(), @@ -275,9 +281,11 @@ void unlockAllRepositories() throws Exception { ExerciseGroup exerciseGroup1 = exam.getExerciseGroups().get(0); ProgrammingExercise programmingExercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExerciseRepository.save(programmingExercise); ProgrammingExercise programmingExercise2 = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1); + programmingExercise2.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise2.getBuildConfig())); programmingExerciseRepository.save(programmingExercise2); User student2 = userUtilService.getUserByLogin(TEST_PREFIX + "student2"); @@ -339,6 +347,7 @@ void testImportExamWithProgrammingExercise_preCheckFailed() throws Exception { exam.setId(null); ProgrammingExercise programming = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(programmingGroup, ProgrammingLanguage.JAVA); programmingGroup.addExercise(programming); + programming.setBuildConfig(programmingExerciseBuildConfigRepository.save(programming.getBuildConfig())); exerciseRepo.save(programming); doReturn(true).when(versionControlService).checkIfProjectExists(any(), any()); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java index 817de43f831f..942eeb9a4155 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java @@ -56,6 +56,7 @@ import de.tum.in.www1.artemis.repository.ComplaintRepository; import de.tum.in.www1.artemis.repository.ExamRepository; import de.tum.in.www1.artemis.repository.ExerciseRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionTestRepository; import de.tum.in.www1.artemis.repository.ResultRepository; @@ -78,6 +79,9 @@ class ProgrammingAssessmentIntegrationTest extends AbstractSpringIntegrationInde @Autowired private ProgrammingExerciseRepository programmingExerciseRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + @Autowired private ComplaintRepository complaintRepo; @@ -768,6 +772,7 @@ void multipleCorrectionRoundsForExam() throws Exception { Exam examWithExerciseGroups = examRepository.findWithExerciseGroupsAndExercisesById(exam.getId()).orElseThrow(); exerciseGroup1 = examWithExerciseGroups.getExerciseGroups().get(0); ProgrammingExercise exercise = ProgrammingExerciseFactory.generateProgrammingExerciseForExam(exerciseGroup1); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); exerciseGroup1.addExercise(exercise); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java index 1e979b93db4b..2b82816e9a5b 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseIntegrationTestService.java @@ -1450,7 +1450,7 @@ void importProgrammingExercise_updatesTestCaseIds() throws Exception { String problemStatement = "[task][Taskname](test1)"; programmingExercise.setProblemStatement(problemStatementWithId); programmingExerciseRepository.save(programmingExercise); - programmingExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(programmingExercise); + programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationAndBuildConfigById(programmingExercise.getId()).orElseThrow(); String sourceId = programmingExercise.getId().toString(); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestCaseServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestCaseServiceTest.java index f1213082e8f1..90c0441765d1 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestCaseServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestCaseServiceTest.java @@ -74,7 +74,8 @@ void setUp() { programmingExercise = exerciseUtilService.getFirstExerciseWithType(course, ProgrammingExercise.class); SecurityUtils.setAuthorizationObject(); programmingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(programmingExercise.getId()).orElseThrow(); + .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig(programmingExercise.getId()) + .orElseThrow(); } @Test diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java index 01a94d2eb6be..31c0ceec7dee 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTestService.java @@ -113,6 +113,7 @@ import de.tum.in.www1.artemis.repository.ExamRepository; import de.tum.in.www1.artemis.repository.ExamUserRepository; import de.tum.in.www1.artemis.repository.ParticipationRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseStudentParticipationTestRepository; @@ -313,6 +314,9 @@ public class ProgrammingExerciseTestService { @Autowired private ProgrammingExerciseTestRepository programmingExerciseTestRepository; + @Autowired + private ProgrammingExerciseBuildConfigRepository programmingExerciseBuildConfigRepository; + public void setupTestUsers(String userPrefix, int additionalStudents, int additionalTutors, int additionalEditors, int additionalInstructors) { this.userPrefix = userPrefix; userUtilService.addUsers(userPrefix, NUMBER_OF_STUDENTS + additionalStudents, additionalTutors + 1, additionalEditors + 1, additionalInstructors + 1); @@ -1303,6 +1307,7 @@ void startProgrammingExercise_correctInitializationState() throws Exception { void startProgrammingExercise(Boolean offlineIde) throws Exception { exercise.setAllowOnlineEditor(true); exercise.setAllowOfflineIde(offlineIde); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); startProgrammingExercise_correctInitializationState(INDIVIDUAL); @@ -1323,6 +1328,7 @@ void startProgrammingExercise(Boolean offlineIde) throws Exception { private Course setupCourseWithProgrammingExercise(ExerciseMode exerciseMode) { final var course = exercise.getCourseViaExerciseGroupOrCourseMember(); exercise.setMode(exerciseMode); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(exercise); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(exercise); @@ -1651,6 +1657,7 @@ void exportProgrammingExerciseInstructorMaterial_problemStatementNull_success() // Test void exportProgrammingExerciseInstructorMaterial_problemStatementShouldContainTestNames() throws Exception { + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); var tests = programmingExerciseUtilService.addTestCasesToProgrammingExercise(exercise); var test = tests.getFirst(); @@ -1729,6 +1736,7 @@ private File exportProgrammingExerciseInstructorMaterial(HttpStatus expectedStat private void generateProgrammingExerciseWithProblemStatementNullForExport() { exercise.setProblemStatement(null); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); exercise = programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(exercise); exercise = programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(exercise); @@ -1753,6 +1761,7 @@ private void generateProgrammingExerciseForExport(boolean saveEmbeddedFiles, boo FileUtils.copyToFile(new ClassPathResource("test-data/repository-export/" + embeddedFileName2).getInputStream(), FilePathService.getMarkdownFilePath().resolve(embeddedFileName2).toFile()); } + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); if (shouldIncludeBuildPlan) { buildPlanRepository.setBuildPlanForExercise("my build plan", exercise); @@ -1779,7 +1788,8 @@ void testArchiveCourseWithProgrammingExercise() throws Exception { course.setExercises(Set.of(exercise)); courseRepository.save(course); - // Create a programming exercise with solution, template, and tests participations + // Create a programming exercise with solution, template, tests participation and build config + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); exercise = programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(exercise); exercise = programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(exercise); @@ -2192,6 +2202,7 @@ private Team setupTeamForBadRequestForStartExercise() throws Exception { private void setupTeamExercise() { exercise.setMode(TEAM); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(exercise); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(exercise); @@ -2216,18 +2227,23 @@ void automaticCleanupBuildPlans() throws Exception { // Otherwise participations with an unexpected buildPlanId are retrieved when calling cleanupBuildPlansOnContinuousIntegrationServer() below programmingExerciseParticipationTestRepository.updateBuildPlanIdOfAll(null); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); + examExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(examExercise.getBuildConfig())); examExercise = programmingExerciseRepository.save(examExercise); var exercise2 = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(5), ZonedDateTime.now().minusDays(4), course); exercise2.setBuildAndTestStudentSubmissionsAfterDueDate(ZonedDateTime.now().plusDays(1)); + exercise2.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise2.getBuildConfig())); exercise2 = programmingExerciseRepository.save(exercise2); var exercise3 = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(5), ZonedDateTime.now().minusDays(4), course); exercise3.setBuildAndTestStudentSubmissionsAfterDueDate(ZonedDateTime.now().minusDays(3)); + exercise3.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise3.getBuildConfig())); exercise3 = programmingExerciseRepository.save(exercise3); var exercise4 = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(5), ZonedDateTime.now().minusDays(4), course); + exercise4.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise4.getBuildConfig())); exercise4 = programmingExerciseRepository.save(exercise4); // Note participationXa will always be cleaned up, while participationXb will NOT be cleaned up @@ -2304,11 +2320,13 @@ void automaticCleanupGitRepositories() { var endDate = startDate.plusDays(5L); exercise.setReleaseDate(startDate); exercise.setDueDate(endDate); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); exercise = programmingExerciseRepository.save(exercise); exercise.getCourseViaExerciseGroupOrCourseMember().setStartDate(startDate); exercise.getCourseViaExerciseGroupOrCourseMember().setEndDate(endDate); courseRepository.save(exercise.getCourseViaExerciseGroupOrCourseMember()); + examExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(examExercise.getBuildConfig())); examExercise = programmingExerciseRepository.save(examExercise); examExercise.getExerciseGroup().getExam().setStartDate(startDate); examExercise.getExerciseGroup().getExam().setEndDate(endDate); @@ -2348,6 +2366,7 @@ private void validateProgrammingExercise(ProgrammingExercise generatedExercise) } private void persistProgrammingExercise() { + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); programmingExerciseUtilService.addTemplateParticipationForProgrammingExercise(exercise); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(exercise); @@ -2382,6 +2401,7 @@ void importProgrammingExerciseFromCourseToCourse_exampleSolutionPublicationDate( Course course2 = courseUtilService.addEmptyCourse(); ProgrammingExercise sourceExercise = programmingExerciseUtilService.addProgrammingExerciseToCourse(course1, false); + sourceExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(sourceExercise); ProgrammingExercise exerciseToBeImported = ProgrammingExerciseFactory.generateToBeImportedProgrammingExercise("ImportTitle", "Imported", sourceExercise, course2); exerciseToBeImported.setExampleSolutionPublicationDate(sourceExercise.getDueDate().plusDays(1)); @@ -2453,6 +2473,7 @@ void testGetProgrammingExercise_exampleSolutionVisibility(boolean isStudent, Str // Test example solution publication date not set. exercise.setExampleSolutionPublicationDate(null); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); CourseForDashboardDTO courseForDashboardFromServer = request.get("/api/courses/" + exercise.getCourseViaExerciseGroupOrCourseMember().getId() + "/for-dashboard", @@ -2490,6 +2511,7 @@ void testGetProgrammingExercise_exampleSolutionVisibility(boolean isStudent, Str void exportSolutionRepository_shouldReturnFileOrForbidden() throws Exception { // Test example solution publication date not set. exercise.setExampleSolutionPublicationDate(null); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); exportStudentRequestedRepository(HttpStatus.FORBIDDEN, false); @@ -2542,6 +2564,7 @@ void exportExamSolutionRepository_shouldReturnFileOrForbidden() throws Exception // Test include tests exercise.setReleaseTestsWithExampleSolution(true); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); programmingExerciseRepository.save(exercise); zip = exportStudentRequestedRepository(HttpStatus.OK, true); @@ -2556,15 +2579,17 @@ void exportExamSolutionRepository_shouldReturnFileOrForbidden() throws Exception // TEST void buildLogStatistics_unauthorized() throws Exception { - exercise = programmingExerciseRepository - .save(ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course)); + exercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); + exercise = programmingExerciseRepository.save(exercise); request.get("/api/programming-exercises/" + exercise.getId() + "/build-log-statistics", HttpStatus.FORBIDDEN, BuildLogStatisticsDTO.class); } // TEST void buildLogStatistics_noStatistics() throws Exception { - exercise = programmingExerciseRepository - .save(ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course)); + exercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); + exercise = programmingExerciseRepository.save(exercise); var statistics = request.get("/api/programming-exercises/" + exercise.getId() + "/build-log-statistics", HttpStatus.OK, BuildLogStatisticsDTO.class); assertThat(statistics.buildCount()).isZero(); assertThat(statistics.agentSetupDuration()).isNull(); @@ -2576,8 +2601,9 @@ void buildLogStatistics_noStatistics() throws Exception { // TEST void buildLogStatistics() throws Exception { - exercise = programmingExerciseRepository - .save(ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course)); + exercise = ProgrammingExerciseFactory.generateProgrammingExercise(ZonedDateTime.now().minusDays(1), ZonedDateTime.now().plusDays(7), course); + exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); + exercise = programmingExerciseRepository.save(exercise); var participation = createStudentParticipationWithSubmission(INDIVIDUAL); var submission1 = programmingExerciseUtilService.createProgrammingSubmission(participation, false); var submission2 = programmingExerciseUtilService.createProgrammingSubmission(participation, false); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java index f54fb3842a8d..dcc606a7bdb5 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseUtilService.java @@ -475,8 +475,7 @@ public ProgrammingExercise addProgrammingExerciseToCourse(Course course, boolean programmingExercise.setAssessmentDueDate(assessmentDueDate); programmingExercise.setPresentationScoreEnabled(course.getPresentationScore() != 0); - var savedBuildConfig = programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig()); - programmingExercise.setBuildConfig(savedBuildConfig); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExercise = programmingExerciseRepository.save(programmingExercise); course.addExercises(programmingExercise); programmingExercise = addSolutionParticipationForProgrammingExercise(programmingExercise); diff --git a/src/test/java/de/tum/in/www1/artemis/hestia/ProgrammingExerciseTaskServiceTest.java b/src/test/java/de/tum/in/www1/artemis/hestia/ProgrammingExerciseTaskServiceTest.java index 8fed8584a4d3..20db67bf2423 100644 --- a/src/test/java/de/tum/in/www1/artemis/hestia/ProgrammingExerciseTaskServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/hestia/ProgrammingExerciseTaskServiceTest.java @@ -192,7 +192,8 @@ void testDeleteWithCodeHints() { @WithMockUser(username = "instructor1", roles = "INSTRUCTOR") void getTasksWithoutInactiveFiltersOutInactive() { programmingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(programmingExercise.getId()).orElseThrow(); + .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig(programmingExercise.getId()) + .orElseThrow(); programmingExerciseTestCaseRepository.deleteAll(programmingExercise.getTestCases()); String[] testCaseNames = { "testClass[BubbleSort]", "testParametrized(Parameter1, 2)[1]" }; @@ -211,7 +212,8 @@ void getTasksWithoutInactiveFiltersOutInactive() { programmingExerciseTestCaseRepository.save(testCase); programmingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(programmingExercise.getId()).orElseThrow(); + .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig(programmingExercise.getId()) + .orElseThrow(); updateProblemStatement(""" [task][Task 1](testClass[BubbleSort],testWithBraces(),testParametrized(Parameter1, 2)[1]) @@ -228,7 +230,8 @@ void getTasksWithoutInactiveFiltersOutInactive() { @WithMockUser(username = "instructor1", roles = "INSTRUCTOR") void testParseTestCaseNames() { programmingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(programmingExercise.getId()).orElseThrow(); + .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig(programmingExercise.getId()) + .orElseThrow(); programmingExerciseTestCaseRepository.deleteAll(programmingExercise.getTestCases()); String[] testCaseNames = new String[] { "testClass[BubbleSort]", "testWithBraces()", "testParametrized(Parameter1, 2)[1]" }; @@ -240,7 +243,8 @@ void testParseTestCaseNames() { programmingExerciseTestCaseRepository.save(testCase); } programmingExercise = programmingExerciseRepository - .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxRepos(programmingExercise.getId()).orElseThrow(); + .findByIdWithEagerTestCasesStaticCodeAnalysisCategoriesHintsAndTemplateAndSolutionParticipationsAndAuxReposAndBuildConfig(programmingExercise.getId()) + .orElseThrow(); updateProblemStatement(""" [task][Task 1](testClass[BubbleSort],testWithBraces(),testParametrized(Parameter1, 2)[1]) diff --git a/src/test/java/de/tum/in/www1/artemis/lecture/CompetencyIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/lecture/CompetencyIntegrationTest.java index 12f558586287..d632fb955429 100644 --- a/src/test/java/de/tum/in/www1/artemis/lecture/CompetencyIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/lecture/CompetencyIntegrationTest.java @@ -286,6 +286,7 @@ private ProgrammingExercise createProgrammingExercise(int i, Set com programmingExercise.setCompetencies(competencies); programmingExercise.setDifficulty(i == 1 ? DifficultyLevel.EASY : i == 2 ? DifficultyLevel.MEDIUM : DifficultyLevel.HARD); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); return programmingExerciseRepository.save(programmingExercise); } diff --git a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java index b5c7e3911116..4771cfd27156 100644 --- a/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/localvcci/LocalCIServiceTest.java @@ -25,6 +25,7 @@ import de.tum.in.www1.artemis.AbstractSpringIntegrationLocalCILocalVCTest; import de.tum.in.www1.artemis.domain.Course; import de.tum.in.www1.artemis.domain.ProgrammingExercise; +import de.tum.in.www1.artemis.domain.ProgrammingExerciseBuildConfig; import de.tum.in.www1.artemis.domain.enumeration.ProgrammingLanguage; import de.tum.in.www1.artemis.domain.enumeration.RepositoryType; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseStudentParticipation; @@ -152,6 +153,7 @@ void testRecreateBuildPlanForExercise() throws IOException { void testGetScriptForWithoutCache() { ReflectionTestUtils.setField(buildScriptProviderService, "scriptCache", new ConcurrentHashMap<>()); ProgrammingExercise programmingExercise = new ProgrammingExercise(); + programmingExercise.setBuildConfig(new ProgrammingExerciseBuildConfig()); programmingExercise.setProgrammingLanguage(ProgrammingLanguage.HASKELL); programmingExercise.setProjectType(null); programmingExercise.setStaticCodeAnalysisEnabled(false); diff --git a/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java index 5a1db365f557..9ac24fc685c7 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/GitlabCIServiceTest.java @@ -183,7 +183,7 @@ void testExtractAndPersistBuildLogStatistics() { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void testTriggerBuildSuccess() throws GitLabApiException { - final ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(programmingExerciseId); + final ProgrammingExercise exercise = programmingExerciseRepository.findWithBuildConfigById(programmingExerciseId).orElseThrow(); exercise.getBuildConfig().setBranch("main"); programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); programmingExerciseRepository.save(exercise); @@ -215,7 +215,7 @@ void testTriggerBuildFails() throws GitLabApiException { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void testConfigureBuildPlanSuccess() throws Exception { - final ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(programmingExerciseId); + final ProgrammingExercise exercise = programmingExerciseRepository.findWithBuildConfigById(programmingExerciseId).orElseThrow(); final ProgrammingExerciseStudentParticipation participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, TEST_PREFIX + "student1"); mockConfigureBuildPlan(participation, defaultBranch); continuousIntegrationService.configureBuildPlan(participation, defaultBranch); @@ -235,7 +235,7 @@ void testConfigureBuildPlanFails() throws GitLabApiException { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void testCreateBuildPlanForExercise() throws GitLabApiException { - final ProgrammingExercise exercise = programmingExerciseRepository.findByIdElseThrow(programmingExerciseId); + final ProgrammingExercise exercise = programmingExerciseRepository.findWithBuildConfigById(programmingExerciseId).orElseThrow(); final ProgrammingExerciseStudentParticipation participation = participationUtilService.addStudentParticipationForProgrammingExercise(exercise, TEST_PREFIX + "student1"); final String repositoryPath = uriService.getRepositoryPathFromRepositoryUri(participation.getVcsRepositoryUri()); mockAddBuildPlanToGitLabRepositoryConfiguration(false); diff --git a/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java b/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java index 75f55c81b4e9..86655153c697 100644 --- a/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java +++ b/src/test/java/de/tum/in/www1/artemis/util/HestiaUtilTestService.java @@ -176,8 +176,10 @@ public ProgrammingExercise setupSolution(Map files, ProgrammingE doReturn(gitService.getExistingCheckedOutRepositoryByLocalPath(solutionRepo.localRepoFile.toPath(), null)).when(gitService).getOrCheckoutRepository(eq(solutionRepoUri), eq(false), any()); - exercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig())); + var buildConfig = programmingExerciseBuildConfigRepository.save(exercise.getBuildConfig()); + exercise.setBuildConfig(buildConfig); var savedExercise = exerciseRepository.save(exercise); + savedExercise.setBuildConfig(buildConfig); programmingExerciseUtilService.addSolutionParticipationForProgrammingExercise(savedExercise); var solutionParticipation = solutionProgrammingExerciseParticipationRepository.findByProgrammingExerciseId(savedExercise.getId()).orElseThrow(); solutionParticipation.setRepositoryUri(solutionRepoUri.toString()); From f474828572cd161661ad7a4fe70fa1995d49a558 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 01:59:53 +0200 Subject: [PATCH 19/78] TODO: remove personal comments adjust code --- .../connectors/gitlabci/GitLabCIService.java | 10 +++++++++- .../gitlabci/GitLabCITriggerService.java | 14 +++++++++++-- .../ManagementResourceIntegrationTest.java | 1 + .../programming/ProgrammingExerciseTest.java | 20 +++++++++---------- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java index 756adc7f2a79..771d6495836c 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCIService.java @@ -16,6 +16,7 @@ import org.gitlab4j.api.models.PipelineStatus; import org.gitlab4j.api.models.Project; import org.gitlab4j.api.models.Variable; +import org.hibernate.Hibernate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -34,6 +35,7 @@ import de.tum.in.www1.artemis.exception.ContinuousIntegrationException; import de.tum.in.www1.artemis.exception.GitLabCIException; import de.tum.in.www1.artemis.repository.BuildPlanRepository; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.UriService; import de.tum.in.www1.artemis.service.connectors.ConnectorHealth; import de.tum.in.www1.artemis.service.connectors.ci.AbstractContinuousIntegrationService; @@ -85,6 +87,8 @@ public class GitLabCIService extends AbstractContinuousIntegrationService { private final ProgrammingLanguageConfiguration programmingLanguageConfiguration; + private final ProgrammingExerciseRepository programmingExerciseRepository; + @Value("${artemis.version-control.url}") private URL gitlabServerUrl; @@ -104,12 +108,13 @@ public class GitLabCIService extends AbstractContinuousIntegrationService { private String gitlabToken; public GitLabCIService(GitLabApi gitlab, UriService uriService, BuildPlanRepository buildPlanRepository, GitLabCIBuildPlanService buildPlanService, - ProgrammingLanguageConfiguration programmingLanguageConfiguration) { + ProgrammingLanguageConfiguration programmingLanguageConfiguration, ProgrammingExerciseRepository programmingExerciseRepository) { this.gitlab = gitlab; this.uriService = uriService; this.buildPlanRepository = buildPlanRepository; this.buildPlanService = buildPlanService; this.programmingLanguageConfiguration = programmingLanguageConfiguration; + this.programmingExerciseRepository = programmingExerciseRepository; } @Override @@ -141,6 +146,9 @@ private void setupGitLabCIConfiguration(VcsRepositoryUri repositoryUri, Programm try { // TODO: Reduce the number of API calls + if (exercise.getBuildConfig() == null || !Hibernate.isInitialized(exercise.getBuildConfig())) { + exercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(exercise); + } ProgrammingExerciseBuildConfig buildConfig = exercise.getBuildConfig(); updateVariable(repositoryPath, VARIABLE_BUILD_DOCKER_IMAGE_NAME, programmingLanguageConfiguration.getImage(exercise.getProgrammingLanguage(), Optional.ofNullable(exercise.getProjectType()))); diff --git a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java index dd901ddf848e..00f6743c3c1a 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/connectors/gitlabci/GitLabCITriggerService.java @@ -3,13 +3,16 @@ import org.gitlab4j.api.GitLabApi; import org.gitlab4j.api.GitLabApiException; import org.gitlab4j.api.models.Trigger; +import org.hibernate.Hibernate; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; +import de.tum.in.www1.artemis.domain.ProgrammingExercise; import de.tum.in.www1.artemis.domain.VcsRepositoryUri; import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation; import de.tum.in.www1.artemis.exception.ContinuousIntegrationException; import de.tum.in.www1.artemis.exception.GitLabCIException; +import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.service.UriService; import de.tum.in.www1.artemis.service.connectors.ci.ContinuousIntegrationTriggerService; @@ -21,14 +24,21 @@ public class GitLabCITriggerService implements ContinuousIntegrationTriggerServi private final UriService uriService; - public GitLabCITriggerService(GitLabApi gitlab, UriService uriService) { + private final ProgrammingExerciseRepository programmingExerciseRepository; + + public GitLabCITriggerService(GitLabApi gitlab, UriService uriService, ProgrammingExerciseRepository programmingExerciseRepository) { this.gitlab = gitlab; this.uriService = uriService; + this.programmingExerciseRepository = programmingExerciseRepository; } @Override public void triggerBuild(ProgrammingExerciseParticipation participation) throws ContinuousIntegrationException { - triggerBuild(participation.getVcsRepositoryUri(), participation.getProgrammingExercise().getBuildConfig().getBranch()); + ProgrammingExercise programmingExercise = participation.getProgrammingExercise(); + if (programmingExercise.getBuildConfig() == null || !Hibernate.isInitialized(programmingExercise.getBuildConfig())) { + programmingExercise = programmingExerciseRepository.getProgrammingExerciseWithBuildConfigElseThrow(programmingExercise); + } + triggerBuild(participation.getVcsRepositoryUri(), programmingExercise.getBuildConfig().getBranch()); } private void triggerBuild(VcsRepositoryUri vcsRepositoryUri, String branch) { diff --git a/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java index b84aa8b418fc..118d4e639398 100644 --- a/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/ManagementResourceIntegrationTest.java @@ -125,6 +125,7 @@ void toggleFeatures() throws Exception { request.put("/api/exercises/" + programmingExercise1.getId() + "/resume-programming-participation/" + participation.getId(), null, HttpStatus.FORBIDDEN); request.put("/api/participations/" + participation.getId() + "/cleanupBuildPlan", null, HttpStatus.FORBIDDEN); request.postWithoutLocation("/api/programming-submissions/" + participation.getId() + "/trigger-failed-build", null, HttpStatus.FORBIDDEN, null); + programmingExercise2.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise2.getBuildConfig())); programmingExercise2 = programmingExerciseRepository.save(programmingExercise2); request.delete("/api/programming-exercises/" + programmingExercise2.getId(), HttpStatus.FORBIDDEN); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTest.java index 99d15a62d3c2..610861230601 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseTest.java @@ -113,16 +113,16 @@ void updateProgrammingExercise(ProgrammingExercise programmingExercise, String n @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void updateProgrammingExerciseOnce() throws Exception { - ProgrammingExercise programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(programmingExerciseId) - .orElseThrow(); + ProgrammingExercise programmingExercise = programmingExerciseRepository + .findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(programmingExerciseId).orElseThrow(); updateProgrammingExercise(programmingExercise, "new problem 1", "new title 1"); } @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void updateProgrammingExerciseTwice() throws Exception { - ProgrammingExercise programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(programmingExerciseId) - .orElseThrow(); + ProgrammingExercise programmingExercise = programmingExerciseRepository + .findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(programmingExerciseId).orElseThrow(); updateProgrammingExercise(programmingExercise, "new problem 1", "new title 1"); updateProgrammingExercise(programmingExercise, "new problem 2", "new title 2"); } @@ -166,8 +166,8 @@ void updateProblemStatement_examExercise() throws Exception { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void updateExerciseAutomaticFeedbackNoTestCases() throws Exception { - ProgrammingExercise programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(programmingExerciseId) - .orElseThrow(); + ProgrammingExercise programmingExercise = programmingExerciseRepository + .findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(programmingExerciseId).orElseThrow(); Set testCases = programmingExerciseTestCaseRepository.findByExerciseId(programmingExercise.getId()); assertThat(testCases).isEmpty(); @@ -180,8 +180,8 @@ void updateExerciseAutomaticFeedbackNoTestCases() throws Exception { @Test @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void updateExerciseAutomaticFeedbackTestCasesPositiveWeight() throws Exception { - ProgrammingExercise programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(programmingExerciseId) - .orElseThrow(); + ProgrammingExercise programmingExercise = programmingExerciseRepository + .findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(programmingExerciseId).orElseThrow(); programmingExerciseUtilService.addTestCasesToProgrammingExercise(programmingExercise); // test cases with weights > 0, changing to automatic feedback: update should work @@ -193,8 +193,8 @@ void updateExerciseAutomaticFeedbackTestCasesPositiveWeight() throws Exception { @EnumSource(AssessmentType.class) @WithMockUser(username = TEST_PREFIX + "instructor1", roles = "INSTRUCTOR") void updateExerciseTestCasesZeroWeight(AssessmentType assessmentType) throws Exception { - ProgrammingExercise programmingExercise = programmingExerciseRepository.findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesById(programmingExerciseId) - .orElseThrow(); + ProgrammingExercise programmingExercise = programmingExerciseRepository + .findWithTemplateAndSolutionParticipationTeamAssignmentConfigCategoriesAndBuildConfigById(programmingExerciseId).orElseThrow(); programmingExerciseUtilService.addTestCasesToProgrammingExercise(programmingExercise); Set testCases = programmingExerciseTestCaseRepository.findByExerciseId(programmingExercise.getId()); From 93ea90f83094491be249a343c933def2df004445 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 02:15:32 +0200 Subject: [PATCH 20/78] TODO: remove personal comments adjust code --- .../programming/ProgrammingExerciseGradingServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index 3b817d84b532..ffb2f7f113a3 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -924,7 +924,6 @@ private Result updateAndSaveAutomaticResult(Result result, boolean test1Passes, var feedback3 = new Feedback().result(result).testCase(tests.get("test3")).positive(test3Passes).type(FeedbackType.AUTOMATIC); result.addFeedback(feedback3); result.rated(true).successful(test1Passes && test2Passes && test3Passes).completionDate(ZonedDateTime.now()).assessmentType(AssessmentType.AUTOMATIC); - programmingExercise = programmingExerciseRepository.findWithBuildConfigById(programmingExercise.getId()).orElseThrow(); gradingService.calculateScoreForResult(result, programmingExercise, true); return resultRepository.save(result); } From ac1011398bce00edb9766531b5801cc735f23c19 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 13:09:47 +0200 Subject: [PATCH 21/78] merge --- .../repository/ProgrammingExerciseRepository.java | 14 ++++++++++++++ .../DataExportResourceIntegrationTest.java | 4 ---- .../www1/artemis/exercise/ExerciseUtilService.java | 4 ++-- .../ProgrammingExerciseGradingServiceTest.java | 8 ++++---- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index b774fed97b2e..ad3f116a335b 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -102,6 +102,9 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos @EntityGraph(type = LOAD, attributePaths = "auxiliaryRepositories") Optional findWithAuxiliaryRepositoriesById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "auxiliaryRepositories", "competencies" }) + Optional findWithAuxiliaryRepositoriesAndCompetenciesById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "auxiliaryRepositories", "buildConfig" }) Optional findWithAuxiliaryRepositoriesAndBuildConfigById(long exerciseId); @@ -554,6 +557,17 @@ default ProgrammingExercise findByIdWithAuxiliaryRepositoriesElseThrow(long prog return findWithAuxiliaryRepositoriesById(programmingExerciseId).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); } + /** + * Find a programming exercise with auxiliary repositories and competencies by its id and throw an {@link EntityNotFoundException} if it cannot be found + * + * @param programmingExerciseId of the programming exercise. + * @return The programming exercise related to the given id + */ + @NotNull + default ProgrammingExercise findByIdWithAuxiliaryRepositoriesAndCompetenciesElseThrow(long programmingExerciseId) throws EntityNotFoundException { + return getValueElseThrow(findWithAuxiliaryRepositoriesAndCompetenciesById(programmingExerciseId), programmingExerciseId); + } + /** * Find a programming exercise with auxiliary repositories and build config by its id and throw an EntityNotFoundException if it cannot be found * diff --git a/src/test/java/de/tum/in/www1/artemis/dataexport/DataExportResourceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/dataexport/DataExportResourceIntegrationTest.java index ca6f6dd00a24..a6df69ce91cc 100644 --- a/src/test/java/de/tum/in/www1/artemis/dataexport/DataExportResourceIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/dataexport/DataExportResourceIntegrationTest.java @@ -31,7 +31,6 @@ import de.tum.in.www1.artemis.domain.enumeration.DataExportState; import de.tum.in.www1.artemis.repository.DataExportRepository; import de.tum.in.www1.artemis.service.export.DataExportService; -import de.tum.in.www1.artemis.user.UserUtilService; import de.tum.in.www1.artemis.web.rest.dto.DataExportDTO; import de.tum.in.www1.artemis.web.rest.dto.RequestDataExportDTO; @@ -45,9 +44,6 @@ class DataExportResourceIntegrationTest extends AbstractSpringIntegrationIndepen @Autowired private DataExportRepository dataExportRepository; - @Autowired - private UserUtilService userUtilService; - @Autowired private DataExportService dataExportService; diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/ExerciseUtilService.java b/src/test/java/de/tum/in/www1/artemis/exercise/ExerciseUtilService.java index de62774ce12f..2f352897184d 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/ExerciseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/ExerciseUtilService.java @@ -274,7 +274,7 @@ public Course addCourseWithOneExerciseAndSubmissions(String userPrefix, String e public void addAutomaticAssessmentToExercise(Exercise exercise) { var participations = studentParticipationRepo.findByExerciseIdAndTestRunWithEagerSubmissionsResultAssessor(exercise.getId(), false); participations.forEach(participation -> { - Submission submission = submissionRepository.findAllByParticipationId(participation.getId()).get(0); + Submission submission = submissionRepository.findAllByParticipationId(participation.getId()).getFirst(); submission = submissionRepository.findOneWithEagerResultAndFeedbackAndAssessmentNote(submission.getId()); participation = studentParticipationRepo.findWithEagerResultsById(participation.getId()).orElseThrow(); Result result = participationUtilService.generateResult(submission, null); @@ -295,7 +295,7 @@ public void addAutomaticAssessmentToExercise(Exercise exercise) { public void addAssessmentToExercise(Exercise exercise, User assessor) { var participations = studentParticipationRepo.findByExerciseIdAndTestRunWithEagerSubmissionsResultAssessor(exercise.getId(), false); participations.forEach(participation -> { - Submission submission = submissionRepository.findAllByParticipationId(participation.getId()).get(0); + Submission submission = submissionRepository.findAllByParticipationId(participation.getId()).getFirst(); submission = submissionRepository.findOneWithEagerResultAndFeedbackAndAssessmentNote(submission.getId()); participation = studentParticipationRepo.findWithEagerResultsById(participation.getId()).orElseThrow(); Result result = participationUtilService.generateResult(submission, assessor); diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java index ffb2f7f113a3..38efb03ef3ff 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingExerciseGradingServiceTest.java @@ -327,7 +327,7 @@ void shouldRecalculateScoreBasedOnTestCasesWeightManual() { tests.add(programmingExerciseUtilService.addTestCaseToProgrammingExercise(programmingExercise, "test4")); List feedbacks = new ArrayList<>(); // we deliberately don't set the credits here, null must work as well - feedbacks.add(new Feedback().testCase(tests.get(0)).positive(true).type(FeedbackType.AUTOMATIC)); + feedbacks.add(new Feedback().testCase(tests.getFirst()).positive(true).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(1)).positive(true).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(2)).positive(false).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(3)).positive(false).type(FeedbackType.AUTOMATIC)); @@ -526,7 +526,7 @@ void shouldRemoveTestsWithAfterDueDateFlagIfDueDateHasNotPassed() { var tests = programmingExerciseUtilService.addTestCasesToProgrammingExercise(programmingExercise); List feedbacks = new ArrayList<>(); - feedbacks.add(new Feedback().testCase(tests.get(0)).positive(true).type(FeedbackType.AUTOMATIC)); + feedbacks.add(new Feedback().testCase(tests.getFirst()).positive(true).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(1)).positive(true).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(2)).positive(false).type(FeedbackType.AUTOMATIC)); result.feedbacks(feedbacks); @@ -555,7 +555,7 @@ void shouldNotIncludeTestsInResultWithAfterDueDateFlagIfDueDateHasNotPassedForNo var tests = programmingExerciseUtilService.addTestCasesToProgrammingExercise(programmingExercise); List feedbacks = new ArrayList<>(); - feedbacks.add(new Feedback().testCase(tests.get(0)).positive(true).type(FeedbackType.AUTOMATIC)); + feedbacks.add(new Feedback().testCase(tests.getFirst()).positive(true).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(1)).positive(true).type(FeedbackType.AUTOMATIC)); feedbacks.add(new Feedback().testCase(tests.get(2)).positive(false).type(FeedbackType.AUTOMATIC)); result.feedbacks(feedbacks); @@ -1329,7 +1329,7 @@ private void activateAllTestCases(boolean withBonus) { var testCases = new ArrayList<>(testCaseRepository.findByExerciseId(programmingExerciseSCAEnabled.getId())); var bonusMultiplier = withBonus ? 2D : null; var bonusPoints = withBonus ? 4D : null; - testCases.get(0).active(true).visibility(Visibility.ALWAYS).bonusMultiplier(bonusMultiplier).bonusPoints(bonusPoints); + testCases.getFirst().active(true).visibility(Visibility.ALWAYS).bonusMultiplier(bonusMultiplier).bonusPoints(bonusPoints); testCases.get(1).active(true).visibility(Visibility.ALWAYS).bonusMultiplier(bonusMultiplier).bonusPoints(bonusPoints); testCases.get(2).active(true).visibility(Visibility.ALWAYS).bonusMultiplier(bonusMultiplier).bonusPoints(bonusPoints); testCaseRepository.saveAll(testCases); From e213422ef83e043235b2f88eb37e705600d13653 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 13:12:04 +0200 Subject: [PATCH 22/78] merge --- .../ProgrammingExerciseRepository.java | 24 ++++--------------- .../ProgrammingExerciseResource.java | 6 ++--- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java index ad3f116a335b..f3e81d6a2d08 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java @@ -102,11 +102,8 @@ public interface ProgrammingExerciseRepository extends DynamicSpecificationRepos @EntityGraph(type = LOAD, attributePaths = "auxiliaryRepositories") Optional findWithAuxiliaryRepositoriesById(long exerciseId); - @EntityGraph(type = LOAD, attributePaths = { "auxiliaryRepositories", "competencies" }) - Optional findWithAuxiliaryRepositoriesAndCompetenciesById(long exerciseId); - - @EntityGraph(type = LOAD, attributePaths = { "auxiliaryRepositories", "buildConfig" }) - Optional findWithAuxiliaryRepositoriesAndBuildConfigById(long exerciseId); + @EntityGraph(type = LOAD, attributePaths = { "auxiliaryRepositories", "competencies", "buildConfig" }) + Optional findWithAuxiliaryRepositoriesCompetenciesAndBuildConfigById(long exerciseId); @EntityGraph(type = LOAD, attributePaths = "submissionPolicy") Optional findWithSubmissionPolicyById(long exerciseId); @@ -558,25 +555,14 @@ default ProgrammingExercise findByIdWithAuxiliaryRepositoriesElseThrow(long prog } /** - * Find a programming exercise with auxiliary repositories and competencies by its id and throw an {@link EntityNotFoundException} if it cannot be found - * - * @param programmingExerciseId of the programming exercise. - * @return The programming exercise related to the given id - */ - @NotNull - default ProgrammingExercise findByIdWithAuxiliaryRepositoriesAndCompetenciesElseThrow(long programmingExerciseId) throws EntityNotFoundException { - return getValueElseThrow(findWithAuxiliaryRepositoriesAndCompetenciesById(programmingExerciseId), programmingExerciseId); - } - - /** - * Find a programming exercise with auxiliary repositories and build config by its id and throw an EntityNotFoundException if it cannot be found + * Find a programming exercise with auxiliary repositories competencies, and buildConfig by its id and throw an {@link EntityNotFoundException} if it cannot be found * * @param programmingExerciseId of the programming exercise. * @return The programming exercise related to the given id */ @NotNull - default ProgrammingExercise findWithAuxiliaryRepositoriesAndBuildConfigElseThrow(long programmingExerciseId) throws EntityNotFoundException { - return findWithAuxiliaryRepositoriesAndBuildConfigById(programmingExerciseId).orElseThrow(() -> new EntityNotFoundException("Programming Exercise", programmingExerciseId)); + default ProgrammingExercise findByIdWithAuxiliaryRepositoriesCompetenciesAndBuildConfigElseThrow(long programmingExerciseId) throws EntityNotFoundException { + return getValueElseThrow(findWithAuxiliaryRepositoriesCompetenciesAndBuildConfigById(programmingExerciseId), programmingExerciseId); } /** diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index fd18aa1c8ef8..03b4d6d1f836 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -291,9 +291,9 @@ public ResponseEntity updateProgrammingExercise(@RequestBod checkProgrammingExerciseForError(updatedProgrammingExercise); - //TODO: Check Develop and fix merge - var programmingExerciseBeforeUpdate = programmingExerciseRepository.findByIdWithAuxiliaryRepositoriesAndCompetenciesElseThrow(updatedProgrammingExercise.getId()); - //var programmingExerciseBeforeUpdate = programmingExerciseRepository.findWithAuxiliaryRepositoriesAndBuildConfigElseThrow(updatedProgrammingExercise.getId()); + // TODO: Check Develop and fix merge + var programmingExerciseBeforeUpdate = programmingExerciseRepository + .findByIdWithAuxiliaryRepositoriesCompetenciesAndBuildConfigElseThrow(updatedProgrammingExercise.getId()); if (!Objects.equals(programmingExerciseBeforeUpdate.getShortName(), updatedProgrammingExercise.getShortName())) { throw new BadRequestAlertException("The programming exercise short name cannot be changed", ENTITY_NAME, "shortNameCannotChange"); } From 0edbb486a69ba7fa4eb13f2cc877eda3e1206522 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 14:39:26 +0200 Subject: [PATCH 23/78] merge --- .../in/www1/artemis/exam/ProgrammingExamIntegrationTest.java | 1 - .../programming/ProgrammingAssessmentIntegrationTest.java | 1 - .../artemis/participation/ParticipationIntegrationTest.java | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java index 5bc7c18f821d..d364d0cdbc31 100644 --- a/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exam/ProgrammingExamIntegrationTest.java @@ -40,7 +40,6 @@ import de.tum.in.www1.artemis.exercise.programming.ProgrammingExerciseUtilService; import de.tum.in.www1.artemis.participation.ParticipationUtilService; import de.tum.in.www1.artemis.repository.ExamRepository; -import de.tum.in.www1.artemis.repository.ExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.StudentExamRepository; diff --git a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java index cf2151712cfe..f152723375ea 100644 --- a/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/exercise/programming/ProgrammingAssessmentIntegrationTest.java @@ -54,7 +54,6 @@ import de.tum.in.www1.artemis.participation.ParticipationUtilService; import de.tum.in.www1.artemis.repository.ComplaintRepository; import de.tum.in.www1.artemis.repository.ExamRepository; -import de.tum.in.www1.artemis.repository.ExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingSubmissionTestRepository; diff --git a/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java index c7a75553540e..6119d63f23f8 100644 --- a/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/participation/ParticipationIntegrationTest.java @@ -83,9 +83,7 @@ import de.tum.in.www1.artemis.exercise.text.TextExerciseFactory; import de.tum.in.www1.artemis.exercise.text.TextExerciseUtilService; import de.tum.in.www1.artemis.repository.ExamRepository; -import de.tum.in.www1.artemis.repository.ExerciseRepository; import de.tum.in.www1.artemis.repository.ProgrammingExerciseBuildConfigRepository; -import de.tum.in.www1.artemis.repository.ResultRepository; import de.tum.in.www1.artemis.repository.StudentParticipationRepository; import de.tum.in.www1.artemis.repository.SubmissionRepository; import de.tum.in.www1.artemis.repository.TeamRepository; From 0064a29bc218b069576717f72cd1b5ee6dac3626 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Thu, 18 Jul 2024 14:40:01 +0200 Subject: [PATCH 24/78] merge --- .../web/rest/programming/ProgrammingExerciseResource.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java index 03b4d6d1f836..1b27bf485d76 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/programming/ProgrammingExerciseResource.java @@ -291,7 +291,6 @@ public ResponseEntity updateProgrammingExercise(@RequestBod checkProgrammingExerciseForError(updatedProgrammingExercise); - // TODO: Check Develop and fix merge var programmingExerciseBeforeUpdate = programmingExerciseRepository .findByIdWithAuxiliaryRepositoriesCompetenciesAndBuildConfigElseThrow(updatedProgrammingExercise.getId()); if (!Objects.equals(programmingExerciseBeforeUpdate.getShortName(), updatedProgrammingExercise.getShortName())) { From 1c25d508a58f76bab09519ab074f5a827dc6bb0c Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sat, 20 Jul 2024 12:54:34 +0200 Subject: [PATCH 25/78] fix server tests --- .../java/de/tum/in/www1/artemis/course/CourseUtilService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java index 6a560125a227..5320cf9a7f85 100644 --- a/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java +++ b/src/test/java/de/tum/in/www1/artemis/course/CourseUtilService.java @@ -691,6 +691,7 @@ public Course createCourseWithAllExerciseTypesAndParticipationsAndSubmissionsAnd modelingExercise = exerciseRepo.save(modelingExercise); textExercise = exerciseRepo.save(textExercise); fileUploadExercise = exerciseRepo.save(fileUploadExercise); + programmingExercise.setBuildConfig(programmingExerciseBuildConfigRepository.save(programmingExercise.getBuildConfig())); programmingExercise = exerciseRepo.save(programmingExercise); quizExercise = exerciseRepo.save(quizExercise); From 81d8a92c7ba607a401d38e74245fbaa69ebbe956 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 21 Jul 2024 19:37:55 +0200 Subject: [PATCH 26/78] adjust client code --- .../detail-overview-list.component.html | 2 +- .../entities/programming-exercise.model.ts | 25 +++++++----- ...ution-entry-generation-step.component.html | 2 +- ...programming-exercise-detail.component.html | 2 +- .../programming-exercise-detail.component.ts | 24 +++++------ .../programming-exercise-update.component.ts | 28 +++++++------ ...se-custom-aeolus-build-plan.component.html | 9 +++-- ...cise-custom-aeolus-build-plan.component.ts | 40 +++++++++---------- ...-exercise-custom-build-plan.component.html | 7 +++- ...ng-exercise-custom-build-plan.component.ts | 32 +++++++-------- ...amming-exercise-information.component.html | 2 +- ...ogramming-exercise-language.component.html | 14 ++++--- 12 files changed, 103 insertions(+), 84 deletions(-) diff --git a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html index 00d362a32d54..b141e7c88b94 100644 --- a/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html +++ b/src/main/webapp/app/detail-overview-list/detail-overview-list.component.html @@ -268,7 +268,7 @@

{{ section [programmingExercise]="detail.data.exercise" [programmingLanguage]="detail.data.programmingLanguage" [isLocal]="detail.data.isLocal" - [checkoutSolutionRepository]="detail.data.exercise.checkoutSolutionRepository" + [checkoutSolutionRepository]="detail.data.exercise.buildConfig?.checkoutSolutionRepository" /> } diff --git a/src/main/webapp/app/entities/programming-exercise.model.ts b/src/main/webapp/app/entities/programming-exercise.model.ts index 5e36139c11cd..fff850872954 100644 --- a/src/main/webapp/app/entities/programming-exercise.model.ts +++ b/src/main/webapp/app/entities/programming-exercise.model.ts @@ -58,6 +58,18 @@ export class WindFile { actions: BuildAction[]; } +export class ProgrammingExerciseBuildConfig { + public sequentialTestRuns?: boolean; + public buildPlanConfiguration?: string; + public buildScript?: string; + public checkoutSolutionRepository?: boolean; + public checkoutPath?: string; + public timeoutSeconds?: number; + public dockerFlags?: string; + public windFile?: WindFile; + public testwiseCoverageEnabled?: boolean; +} + export enum ProgrammingLanguage { JAVA = 'JAVA', PYTHON = 'PYTHON', @@ -98,25 +110,19 @@ export class ProgrammingExercise extends Exercise { public allowOfflineIde?: boolean; public programmingLanguage?: ProgrammingLanguage; public packageName?: string; - public sequentialTestRuns?: boolean; public showTestNamesToStudents?: boolean; - public checkoutSolutionRepository?: boolean; public auxiliaryRepositories?: AuxiliaryRepository[]; public submissionPolicy?: SubmissionPolicy; public exerciseHints?: ExerciseHint[]; public gitDiffReport?: ProgrammingExerciseGitDiffReport; public buildLogStatistics?: BuildLogStatisticsDTO; + public buildConfig?: ProgrammingExerciseBuildConfig; public releaseTestsWithExampleSolution?: boolean; public buildAndTestStudentSubmissionsAfterDueDate?: dayjs.Dayjs; public testCasesChanged?: boolean; public projectType?: ProjectType; - public windFile?: WindFile; - public buildScript?: string; - public buildPlanConfiguration?: string; - - public testwiseCoverageEnabled?: boolean; // helper attributes @@ -140,10 +146,11 @@ export class ProgrammingExercise extends Exercise { this.allowOfflineIde = true; // default value this.programmingLanguage = ProgrammingLanguage.JAVA; // default value this.noVersionControlAndContinuousIntegrationAvailable = false; // default value - this.checkoutSolutionRepository = false; // default value this.projectType = ProjectType.PLAIN_GRADLE; // default value this.showTestNamesToStudents = false; // default value - this.testwiseCoverageEnabled = false; // default value + this.buildConfig = new ProgrammingExerciseBuildConfig(); + this.buildConfig.testwiseCoverageEnabled = false; // default value + this.buildConfig.checkoutSolutionRepository = false; // default value } } diff --git a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.html b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.html index b1610c41d457..433689205c2b 100644 --- a/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.html +++ b/src/main/webapp/app/exercises/programming/hestia/generation-overview/steps/solution-entry-generation-step/solution-entry-generation-step.component.html @@ -18,7 +18,7 @@ [ngbTooltip]="'artemisApp.codeHint.management.step3.structuralEntriesButton.tooltip' | artemisTranslate" (click)="onGenerateStructuralSolutionEntries()" > - @if (!!exercise?.testwiseCoverageEnabled) { + @if (!!exercise?.buildConfig?.testwiseCoverageEnabled) {