Skip to content

Commit

Permalink
Merge branch 'develop' into chore/integrated-code-lifecycle/add-build…
Browse files Browse the repository at this point in the history
…-agent-name

# Conflicts:
#	src/test/java/de/tum/cit/aet/artemis/programming/icl/LocalCIResourceIntegrationTest.java
#	src/test/resources/config/application.yml
  • Loading branch information
BBesrour committed Oct 23, 2024
2 parents 6b8e6d4 + c17b2c4 commit 9fc2a97
Show file tree
Hide file tree
Showing 202 changed files with 8,222 additions and 2,774 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ Refer to [Using JHipster in production](http://www.jhipster.tech/production) for
The following command can automate the deployment to a server. The example shows the deployment to the main Artemis test server (which runs a virtual machine):

```shell
./artemis-server-cli deploy [email protected] -w build/libs/Artemis-7.6.1.war
./artemis-server-cli deploy [email protected] -w build/libs/Artemis-7.6.2.war
```

## Architecture
Expand Down
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ plugins {
}

group = "de.tum.cit.aet.artemis"
version = "7.6.1"
version = "7.6.2"
description = "Interactive Learning with Individual Feedback"

java {
Expand Down Expand Up @@ -257,6 +257,7 @@ dependencies {
implementation "de.jplag:rust:${jplag_version}"
implementation "de.jplag:swift:${jplag_version}"
implementation "de.jplag:text:${jplag_version}"
implementation "de.jplag:typescript:${jplag_version}"

// those are transitive dependencies of JPlag Text --> Stanford NLP
// Note: ideally we would exclude them, but for some reason this does not work
Expand Down
4 changes: 4 additions & 0 deletions docs/user/exercises/programming-exercise-features.inc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Instructors can still use those templates to generate programming exercises and
+----------------------+----------+---------+
| C++ | yes | yes |
+----------------------+----------+---------+
| TypeScript | yes | yes |
+----------------------+----------+---------+

- Not all ``templates`` support the same feature set and supported features can also change depending on the continuous integration system setup.
Depending on the feature set, some options might not be available during the creation of the programming exercise.
Expand Down Expand Up @@ -79,6 +81,8 @@ Instructors can still use those templates to generate programming exercises and
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
| C++ | no | no | yes | no | n/a | no | no | L: yes, J: no |
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+
| TypeScript | no | no | yes | no | n/a | no | no | L: yes, J: no |
+----------------------+----------------------+----------------------+---------------------+--------------+------------------------------------------+------------------------------+----------------------------+------------------------+

- *Sequential Test Runs*: ``Artemis`` can generate a build plan which first executes structural and then behavioral tests. This feature can help students to better concentrate on the immediate challenge at hand.
- *Static Code Analysis*: ``Artemis`` can generate a build plan which additionally executes static code analysis tools.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "artemis",
"version": "7.6.1",
"version": "7.6.2",
"description": "Interactive Learning with Individual Feedback",
"private": true,
"license": "MIT",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.tum.cit.aet.artemis.atlas.dto;

import com.fasterxml.jackson.annotation.JsonInclude;

import de.tum.cit.aet.artemis.atlas.domain.competency.RelationType;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record UpdateCourseCompetencyRelationDTO(RelationType newRelationType) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import de.tum.cit.aet.artemis.atlas.service.LearningObjectImportService;
import de.tum.cit.aet.artemis.atlas.service.learningpath.LearningPathService;
import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.core.repository.CourseRepository;
import de.tum.cit.aet.artemis.core.service.AuthorizationCheckService;
import de.tum.cit.aet.artemis.exercise.service.ExerciseService;
import de.tum.cit.aet.artemis.lecture.repository.LectureUnitCompletionRepository;
Expand All @@ -41,9 +42,9 @@ public CompetencyService(CompetencyRepository competencyRepository, Authorizatio
LearningPathService learningPathService, CompetencyProgressService competencyProgressService, LectureUnitService lectureUnitService,
CompetencyProgressRepository competencyProgressRepository, LectureUnitCompletionRepository lectureUnitCompletionRepository,
StandardizedCompetencyRepository standardizedCompetencyRepository, CourseCompetencyRepository courseCompetencyRepository, ExerciseService exerciseService,
LearningObjectImportService learningObjectImportService) {
LearningObjectImportService learningObjectImportService, CourseRepository courseRepository) {
super(competencyProgressRepository, courseCompetencyRepository, competencyRelationRepository, competencyProgressService, exerciseService, lectureUnitService,
learningPathService, authCheckService, standardizedCompetencyRepository, lectureUnitCompletionRepository, learningObjectImportService);
learningPathService, authCheckService, standardizedCompetencyRepository, lectureUnitCompletionRepository, learningObjectImportService, courseRepository);
this.competencyRepository = competencyRepository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import de.tum.cit.aet.artemis.atlas.dto.CompetencyImportOptionsDTO;
import de.tum.cit.aet.artemis.atlas.dto.CompetencyRelationDTO;
import de.tum.cit.aet.artemis.atlas.dto.CompetencyWithTailRelationDTO;
import de.tum.cit.aet.artemis.atlas.dto.UpdateCourseCompetencyRelationDTO;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyProgressRepository;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRelationRepository;
import de.tum.cit.aet.artemis.atlas.repository.CourseCompetencyRepository;
Expand All @@ -39,6 +40,7 @@
import de.tum.cit.aet.artemis.core.dto.pageablesearch.CompetencyPageableSearchDTO;
import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException;
import de.tum.cit.aet.artemis.core.exception.EntityNotFoundException;
import de.tum.cit.aet.artemis.core.repository.CourseRepository;
import de.tum.cit.aet.artemis.core.service.AuthorizationCheckService;
import de.tum.cit.aet.artemis.core.util.PageUtil;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
Expand Down Expand Up @@ -77,11 +79,13 @@ public class CourseCompetencyService {

private final LearningObjectImportService learningObjectImportService;

private final CourseRepository courseRepository;

public CourseCompetencyService(CompetencyProgressRepository competencyProgressRepository, CourseCompetencyRepository courseCompetencyRepository,
CompetencyRelationRepository competencyRelationRepository, CompetencyProgressService competencyProgressService, ExerciseService exerciseService,
LectureUnitService lectureUnitService, LearningPathService learningPathService, AuthorizationCheckService authCheckService,
StandardizedCompetencyRepository standardizedCompetencyRepository, LectureUnitCompletionRepository lectureUnitCompletionRepository,
LearningObjectImportService learningObjectImportService) {
LearningObjectImportService learningObjectImportService, CourseRepository courseRepository) {
this.competencyProgressRepository = competencyProgressRepository;
this.courseCompetencyRepository = courseCompetencyRepository;
this.competencyRelationRepository = competencyRelationRepository;
Expand All @@ -93,6 +97,7 @@ public CourseCompetencyService(CompetencyProgressRepository competencyProgressRe
this.standardizedCompetencyRepository = standardizedCompetencyRepository;
this.lectureUnitCompletionRepository = lectureUnitCompletionRepository;
this.learningObjectImportService = learningObjectImportService;
this.courseRepository = courseRepository;
}

/**
Expand Down Expand Up @@ -123,6 +128,28 @@ public List<CourseCompetency> findCourseCompetenciesWithProgressForUserByCourseI
return findProgressForCompetenciesAndUser(competencies, userId);
}

/**
* Updates the type of a course competency relation.
*
* @param courseId The id of the course for which to fetch the competencies
* @param courseCompetencyRelationId The id of the course competency relation to update
* @param updateCourseCompetencyRelationDTO The DTO containing the new relation type
*
*/
public void updateCourseCompetencyRelation(long courseId, long courseCompetencyRelationId, UpdateCourseCompetencyRelationDTO updateCourseCompetencyRelationDTO) {
var relation = competencyRelationRepository.findByIdElseThrow(courseCompetencyRelationId);
var course = courseRepository.findByIdElseThrow(courseId);
var headCompetency = relation.getHeadCompetency();
var tailCompetency = relation.getTailCompetency();

if (!course.getId().equals(headCompetency.getCourse().getId()) || !course.getId().equals(tailCompetency.getCourse().getId())) {
throw new BadRequestAlertException("The relation does not belong to the course", ENTITY_NAME, "relationWrongCourse");
}

relation.setType(updateCourseCompetencyRelationDTO.newRelationType());
competencyRelationRepository.save(relation);
}

/**
* Search for all course competencies fitting a {@link CompetencyPageableSearchDTO search query}. The result is paged.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import de.tum.cit.aet.artemis.atlas.service.LearningObjectImportService;
import de.tum.cit.aet.artemis.atlas.service.learningpath.LearningPathService;
import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.core.repository.CourseRepository;
import de.tum.cit.aet.artemis.core.service.AuthorizationCheckService;
import de.tum.cit.aet.artemis.exercise.service.ExerciseService;
import de.tum.cit.aet.artemis.lecture.repository.LectureUnitCompletionRepository;
Expand All @@ -41,9 +42,9 @@ public PrerequisiteService(PrerequisiteRepository prerequisiteRepository, Author
LearningPathService learningPathService, CompetencyProgressService competencyProgressService, LectureUnitService lectureUnitService,
CompetencyProgressRepository competencyProgressRepository, LectureUnitCompletionRepository lectureUnitCompletionRepository,
StandardizedCompetencyRepository standardizedCompetencyRepository, CourseCompetencyRepository courseCompetencyRepository, ExerciseService exerciseService,
LearningObjectImportService learningObjectImportService) {
LearningObjectImportService learningObjectImportService, CourseRepository courseRepository) {
super(competencyProgressRepository, courseCompetencyRepository, competencyRelationRepository, competencyProgressService, exerciseService, lectureUnitService,
learningPathService, authCheckService, standardizedCompetencyRepository, lectureUnitCompletionRepository, learningObjectImportService);
learningPathService, authCheckService, standardizedCompetencyRepository, lectureUnitCompletionRepository, learningObjectImportService, courseRepository);
this.prerequisiteRepository = prerequisiteRepository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Set;
import java.util.stream.Collectors;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;

import org.slf4j.Logger;
Expand All @@ -18,6 +19,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
Expand All @@ -32,6 +34,7 @@
import de.tum.cit.aet.artemis.atlas.dto.CompetencyJolPairDTO;
import de.tum.cit.aet.artemis.atlas.dto.CompetencyRelationDTO;
import de.tum.cit.aet.artemis.atlas.dto.CompetencyWithTailRelationDTO;
import de.tum.cit.aet.artemis.atlas.dto.UpdateCourseCompetencyRelationDTO;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyProgressRepository;
import de.tum.cit.aet.artemis.atlas.repository.CompetencyRelationRepository;
import de.tum.cit.aet.artemis.atlas.repository.CourseCompetencyRepository;
Expand Down Expand Up @@ -350,6 +353,23 @@ public ResponseEntity<Void> generateCompetenciesFromCourseDescription(@PathVaria
return ResponseEntity.accepted().build();
}

/**
* PATCH courses/:courseId/course-competencies/relations/:competencyRelationId update a relation type of an existing relation
*
* @param courseId the id of the course to which the competencies belong
* @param competencyRelationId the id of the competency relation to update
* @param updateCourseCompetencyRelationDTO the new relation type
* @return the ResponseEntity with status 200 (OK)
*/
@PatchMapping("courses/{courseId}/course-competencies/relations/{competencyRelationId}")
@EnforceAtLeastInstructorInCourse
public ResponseEntity<Void> updateCompetencyRelation(@PathVariable long courseId, @PathVariable long competencyRelationId,
@RequestBody @Valid UpdateCourseCompetencyRelationDTO updateCourseCompetencyRelationDTO) {
log.info("REST request to update a competency relation: {}", competencyRelationId);
courseCompetencyService.updateCourseCompetencyRelation(courseId, competencyRelationId, updateCourseCompetencyRelationDTO);
return ResponseEntity.noContent().build();
}

/**
* PUT courses/:courseId/course-competencies/:competencyId/jol/:jolValue : Sets the judgement of learning for a competency
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -27,7 +30,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Profile;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.github.dockerjava.api.command.CreateContainerResponse;
Expand Down Expand Up @@ -71,6 +77,8 @@ public class BuildJobExecutionService {
@Value("${artemis.version-control.default-branch:main}")
private String defaultBranch;

private static final Duration TEMP_DIR_RETENTION_PERIOD = Duration.ofMinutes(5);

public BuildJobExecutionService(BuildJobContainerService buildJobContainerService, BuildJobGitService buildJobGitService, BuildAgentDockerService buildAgentDockerService,
BuildLogsMap buildLogsMap) {
this.buildJobContainerService = buildJobContainerService;
Expand All @@ -79,6 +87,38 @@ public BuildJobExecutionService(BuildJobContainerService buildJobContainerServic
this.buildLogsMap = buildLogsMap;
}

/**
* This method is responsible for cleaning up temporary directories that were used for checking out repositories.
* It is triggered when the application is ready and runs asynchronously.
*/
@EventListener(ApplicationReadyEvent.class)
@Async
public void initAsync() {
final ZonedDateTime currentTime = ZonedDateTime.now();
cleanUpTempDirectoriesAsync(currentTime);
}

private void cleanUpTempDirectoriesAsync(ZonedDateTime currentTime) {
log.info("Cleaning up temporary directories in {}", CHECKED_OUT_REPOS_TEMP_DIR);
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Path.of(CHECKED_OUT_REPOS_TEMP_DIR))) {
for (Path path : directoryStream) {
try {
ZonedDateTime lastModifiedTime = ZonedDateTime.ofInstant(Files.getLastModifiedTime(path).toInstant(), currentTime.getZone());
if (Files.isDirectory(path) && lastModifiedTime.isBefore(currentTime.minus(TEMP_DIR_RETENTION_PERIOD))) {
FileUtils.deleteDirectory(path.toFile());
}
}
catch (IOException e) {
log.error("Could not delete temporary directory {}", path, e);
}
}
}
catch (IOException e) {
log.error("Could not delete temporary directories", e);
}
log.info("Clean up of temporary directories in {} completed.", CHECKED_OUT_REPOS_TEMP_DIR);
}

/**
* Orchestrates the execution of a build job in a Docker container. This method handles the preparation and configuration of the container,
* including cloning the necessary repositories, checking out the appropriate branches, and preparing the environment for the build.
Expand Down Expand Up @@ -512,15 +552,16 @@ private void deleteCloneRepo(VcsRepositoryUri repositoryUri, @Nullable String co
}
buildJobGitService.deleteLocalRepository(repository);
}
// Do not throw an exception if deletion fails. If an exception occurs, clean up will happen in the next server start.
catch (EntityNotFoundException e) {
msg = "Error while checking out repository";
buildLogsMap.appendBuildLogEntry(buildJobId, msg);
throw new LocalCIException(msg, e);
log.error("Error while deleting repository with URI {} and Path {}", repositoryUri, repositoryPath, e);
}
catch (IOException e) {
msg = "Error while deleting repository";
buildLogsMap.appendBuildLogEntry(buildJobId, msg);
throw new LocalCIException(msg, e);
log.error("Error while deleting repository with URI {} and Path {}", repositoryUri, repositoryPath, e);
}
}

Expand Down
Loading

0 comments on commit 9fc2a97

Please sign in to comment.