Skip to content

Commit

Permalink
Merge branch 'develop' into feature/communication/reference-faq-in-me…
Browse files Browse the repository at this point in the history
…ssages
  • Loading branch information
cremertim authored Nov 29, 2024
2 parents ad125a4 + 5f2e030 commit 8ed8c14
Show file tree
Hide file tree
Showing 175 changed files with 5,542 additions and 653 deletions.
8 changes: 4 additions & 4 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ Prerequisites:
- [ ] Test 2

### Test Coverage
<!-- Please add the test coverages for all changed files here. You can see this when executing the tests locally (see build.gradle and package.json) or when looking into the corresponding Bamboo build plan. -->
<!-- The line coverage must be above 90% for changes files and you must use extensive and useful assertions for server tests and expect statements for client tests. -->
<!-- Note: Use the table below and confirm in the last column that you have implemented extensive assertions for server tests and expect statements for client tests. -->
<!-- You can use `supporting_script/generate_code_cov_table/generate_code_cov_table.py` to automatically generate one from the corresponding Bamboo build plan artefacts. -->
<!-- Please add the test coverages for all changed files modified in this PR here. You can use `supporting_script/generate_code_cov_table/generate_code_cov_table.py` to automatically generate the coverage table from the corresponding artefacts of your branch (follow the ReadMe for setup details). -->
<!-- Alternatively you can execute the tests locally (see build.gradle and package.json) or look into the corresponding artefacts. -->
<!-- The line coverage must be above 90% for changes files, and you must use extensive and useful assertions for server tests and expect statements for client tests. -->
<!-- Note: Confirm in the last column that you have implemented extensive assertions for server tests and expect statements for client tests. -->
<!-- Remove rows with only trivial changes from the table. -->
<!--
| Class/File | Line Coverage | Confirmation (assert/expect) |
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/de/tum/cit/aet/artemis/assessment/domain/Result.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,12 @@ public class Result extends DomainObject implements Comparable<Result> {
@JsonView(QuizView.Before.class)
private List<Feedback> feedbacks = new ArrayList<>();

/**
* @deprecated: Will be removed for 8.0, please use submission.participation instead
*/
@ManyToOne
@JsonView(QuizView.Before.class)
@Deprecated(since = "7.7", forRemoval = true)
private Participation participation;

@ManyToOne(fetch = FetchType.LAZY)
Expand Down Expand Up @@ -385,15 +389,31 @@ private boolean feedbackTextHasChanged(String existingText, String newText) {
return !Objects.equals(existingText, newText);
}

/**
* @deprecated: Will be removed for 8.0, please use submission.participation instead
* @return the participation
*/
@Deprecated(since = "7.7", forRemoval = true)
public Participation getParticipation() {
return participation;
}

/**
* @deprecated: Will be removed for 8.0, please use submission.participation instead
* @param participation the participation to set
* @return the result
*/
@Deprecated(since = "7.7", forRemoval = true)
public Result participation(Participation participation) {
this.participation = participation;
return this;
}

/**
* @deprecated: Will be removed for 8.0, please use submission.participation instead
* @param participation the participation to set
*/
@Deprecated(since = "7.7", forRemoval = true)
public void setParticipation(Participation participation) {
this.participation = participation;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ public BuildJobQueueItem(BuildJobQueueItem queueItem, ResultDTO submissionResult
this(queueItem.id(), queueItem.name(), queueItem.buildAgent(), queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), queueItem.retryCount(),
queueItem.priority(), queueItem.status(), queueItem.repositoryInfo(), queueItem.jobTimingInfo(), queueItem.buildConfig(), submissionResult);
}

public BuildJobQueueItem(BuildJobQueueItem queueItem, BuildAgentDTO buildAgent, int newRetryCount) {
this(queueItem.id(), queueItem.name(), buildAgent, queueItem.participationId(), queueItem.courseId(), queueItem.exerciseId(), newRetryCount, queueItem.priority(), null,
queueItem.repositoryInfo(), new JobTimingInfo(queueItem.jobTimingInfo.submissionDate(), ZonedDateTime.now(), null), queueItem.buildConfig(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -378,18 +378,18 @@ private BuildResult parseTestResults(TarArchiveInputStream testResultsTarInputSt
}

// Read the contents of the tar entry as a string.
String xmlString = readTarEntryContent(testResultsTarInputStream);
String fileString = readTarEntryContent(testResultsTarInputStream);
// Get the file name of the tar entry.
String fileName = getFileName(tarEntry);

try {
// Check if the file is a static code analysis report file
if (StaticCodeAnalysisTool.getToolByFilePattern(fileName).isPresent()) {
processStaticCodeAnalysisReportFile(fileName, xmlString, staticCodeAnalysisReports, buildJobId);
processStaticCodeAnalysisReportFile(fileName, fileString, staticCodeAnalysisReports, buildJobId);
}
else {
// ugly workaround because in swift result files \n\t breaks the parsing
var testResultFileString = xmlString.replace("\n\t", "");
var testResultFileString = fileString.replace("\n\t", "");
if (!testResultFileString.isBlank()) {
processTestResultFile(testResultFileString, failedTests, successfulTests);
}
Expand Down Expand Up @@ -418,7 +418,7 @@ private boolean isValidTestResultFile(TarArchiveEntry tarArchiveEntry) {
String result = (lastIndexOfSlash != -1 && lastIndexOfSlash + 1 < name.length()) ? name.substring(lastIndexOfSlash + 1) : name;

// Java test result files are named "TEST-*.xml", Python test result files are named "*results.xml".
return !tarArchiveEntry.isDirectory() && result.endsWith(".xml") && !result.equals("pom.xml");
return !tarArchiveEntry.isDirectory() && (result.endsWith(".xml") && !result.equals("pom.xml") || result.endsWith(".sarif"));
}

/**
Expand All @@ -444,12 +444,12 @@ private String getFileName(TarArchiveEntry tarEntry) {
* Processes a static code analysis report file and adds the report to the corresponding list.
*
* @param fileName the file name of the static code analysis report file
* @param xmlString the content of the static code analysis report file
* @param reportContent the content of the static code analysis report file
* @param staticCodeAnalysisReports the list of static code analysis reports
*/
private void processStaticCodeAnalysisReportFile(String fileName, String xmlString, List<StaticCodeAnalysisReportDTO> staticCodeAnalysisReports, String buildJobId) {
private void processStaticCodeAnalysisReportFile(String fileName, String reportContent, List<StaticCodeAnalysisReportDTO> staticCodeAnalysisReports, String buildJobId) {
try {
staticCodeAnalysisReports.add(ReportParser.getReport(xmlString, fileName));
staticCodeAnalysisReports.add(ReportParser.getReport(reportContent, fileName));
}
catch (UnsupportedToolException e) {
String msg = "Failed to parse static code analysis report for " + fileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,26 @@ private void checkAvailabilityAndProcessNextBuild() {
processBuild(buildJob);
}
catch (RejectedExecutionException e) {
log.error("Couldn't add build job to threadpool: {}\n Concurrent Build Jobs Count: {} Active tasks in pool: {}, Concurrent Build Jobs Size: {}", buildJob,
// TODO: we should log this centrally and not on the local node
log.error("Couldn't add build job to thread pool: {}\n Concurrent Build Jobs Count: {} Active tasks in pool: {}, Concurrent Build Jobs Size: {}", buildJob,
localProcessingJobs.get(), localCIBuildExecutorService.getActiveCount(), localCIBuildExecutorService.getMaximumPoolSize(), e);

// Add the build job back to the queue
if (buildJob != null) {
processingJobs.remove(buildJob.id());

buildJob = new BuildJobQueueItem(buildJob, new BuildAgentDTO("", "", ""));
log.info("Adding build job back to the queue: {}", buildJob);
queue.add(buildJob);
// At most try out the build job 5 times when they get rejected
if (buildJob.retryCount() >= 5) {
// TODO: we should log this centrally and not on the local node
log.error("Build job was rejected 5 times. Not adding build job back to the queue: {}", buildJob);
}
else {
// NOTE: we increase the retry count here, because the build job was not processed successfully
// TODO: we should try to run this job on a different build agent to avoid getting the same error again
buildJob = new BuildJobQueueItem(buildJob, new BuildAgentDTO("", "", ""), buildJob.retryCount() + 1);
log.info("Adding build job {} back to the queue with retry count {}", buildJob, buildJob.retryCount());
queue.add(buildJob);
}
localProcessingJobs.decrementAndGet();
}

Expand Down Expand Up @@ -360,7 +370,9 @@ private BuildAgentInformation getUpdatedLocalBuildAgentInformation(BuildJobQueue
}

private List<BuildJobQueueItem> getProcessingJobsOfNode(String memberAddress) {
return processingJobs.values().stream().filter(job -> Objects.equals(job.buildAgent().memberAddress(), memberAddress)).toList();
// NOTE: we should not use streams with IMap, because it can be unstable, when many items are added at the same time and there is a slow network condition
List<BuildJobQueueItem> processingJobsList = new ArrayList<>(processingJobs.values());
return processingJobsList.stream().filter(job -> Objects.equals(job.buildAgent().memberAddress(), memberAddress)).toList();
}

private void removeOfflineNodes() {
Expand Down Expand Up @@ -549,7 +561,8 @@ private void resumeBuildAgent() {
private boolean nodeIsAvailable() {
log.debug("Currently processing jobs on this node: {}, active threads in Pool: {}, maximum pool size of thread executor : {}", localProcessingJobs.get(),
localCIBuildExecutorService.getActiveCount(), localCIBuildExecutorService.getMaximumPoolSize());
return localProcessingJobs.get() < localCIBuildExecutorService.getMaximumPoolSize();
return localProcessingJobs.get() < localCIBuildExecutorService.getMaximumPoolSize()
&& localCIBuildExecutorService.getActiveCount() < localCIBuildExecutorService.getMaximumPoolSize() && localCIBuildExecutorService.getQueue().isEmpty();
}

public class QueuedBuildJobItemListener implements ItemListener<BuildJobQueueItem> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.SQLRestriction;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import de.tum.cit.aet.artemis.communication.domain.conversation.Conversation;
import de.tum.cit.aet.artemis.core.domain.Course;

/**
Expand All @@ -35,10 +39,20 @@ public class AnswerPost extends Posting {
@OneToMany(mappedBy = "answerPost", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER)
private Set<Reaction> reactions = new HashSet<>();

/***
* The value 1 represents an answer post, given by the enum {{@link PostingType}}
*/
@OneToMany(mappedBy = "postId", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY)
@SQLRestriction("post_type = 1")
private Set<SavedPost> savedPosts = new HashSet<>();

@ManyToOne
@JsonIncludeProperties({ "id", "exercise", "lecture", "course", "courseWideContext", "conversation", "author" })
private Post post;

@Transient
private boolean isSaved = false;

@JsonProperty("resolvesPost")
public Boolean doesResolvePost() {
return resolvesPost;
Expand Down Expand Up @@ -76,6 +90,25 @@ public void setPost(Post post) {
this.post = post;
}

@JsonIgnore
public Set<SavedPost> getSavedPosts() {
return savedPosts;
}

@JsonProperty("isSaved")
public boolean getIsSaved() {
return isSaved;
}

public void setIsSaved(boolean isSaved) {
this.isSaved = isSaved;
}

@JsonIgnore
public Conversation getConversation() {
return getPost().getConversation();
}

/**
* Helper method to extract the course an AnswerPost belongs to, which is found in different locations based on the parent Post's context
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import jakarta.validation.constraints.Size;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.SQLRestriction;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import de.tum.cit.aet.artemis.communication.domain.conversation.Conversation;
import de.tum.cit.aet.artemis.core.domain.Course;
Expand Down Expand Up @@ -54,6 +57,13 @@ public class Post extends Posting {
@OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER)
private Set<AnswerPost> answers = new HashSet<>();

/***
* The value 0 represents a post, given by the enum {{@link PostingType}}
*/
@OneToMany(mappedBy = "postId", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.LAZY)
@SQLRestriction("post_type = 0")
private Set<SavedPost> savedPosts = new HashSet<>();

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "post_tag", joinColumns = @JoinColumn(name = "post_id"))
@Column(name = "text")
Expand Down Expand Up @@ -96,6 +106,9 @@ public class Post extends Posting {
@Column(name = "vote_count")
private int voteCount;

@Transient
private boolean isSaved = false;

public Post() {
}

Expand Down Expand Up @@ -222,6 +235,20 @@ public void setVoteCount(Integer voteCount) {
this.voteCount = voteCount != null ? voteCount : 0;
}

@JsonIgnore
public Set<SavedPost> getSavedPosts() {
return savedPosts;
}

@JsonProperty("isSaved")
public boolean getIsSaved() {
return isSaved;
}

public void setIsSaved(boolean isSaved) {
this.isSaved = isSaved;
}

/**
* Helper method to extract the course a Post belongs to, which is found in different locations based on the Post's context
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import de.tum.cit.aet.artemis.communication.domain.conversation.Conversation;
import de.tum.cit.aet.artemis.core.domain.Course;
import de.tum.cit.aet.artemis.core.domain.DomainObject;
import de.tum.cit.aet.artemis.core.domain.User;
Expand Down Expand Up @@ -118,4 +119,6 @@ public void setAuthorRole(UserRole authorRole) {

@Transient
public abstract Course getCoursePostingBelongsTo();

public abstract Conversation getConversation();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package de.tum.cit.aet.artemis.communication.domain;

import java.util.Arrays;

public enum PostingType {

POST((short) 0), ANSWER((short) 1);

private final short databaseKey;

PostingType(short databaseKey) {
this.databaseKey = databaseKey;
}

public short getDatabaseKey() {
return databaseKey;
}

public static PostingType fromDatabaseKey(short databaseKey) {
return Arrays.stream(PostingType.values()).filter(type -> type.getDatabaseKey() == databaseKey).findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unknown database key: " + databaseKey));
}
}
Loading

0 comments on commit 8ed8c14

Please sign in to comment.