Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exam mode: Visualize student submissions in exam timeline #6882

Merged
merged 118 commits into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
caa1767
initial user interface
tobias-lippert Jul 1, 2023
12af27e
continue implementation
tobias-lippert Jul 2, 2023
eb425a0
continue implementation
tobias-lippert Jul 2, 2023
bacb5e8
continue implementation
tobias-lippert Jul 3, 2023
0a78175
debug logs
tobias-lippert Jul 5, 2023
ec0ba92
try to make it work for modeling
tobias-lippert Jul 7, 2023
aad9cdd
file upload
tobias-lippert Jul 8, 2023
41a5c3a
continue implementation
tobias-lippert Jul 8, 2023
f90b208
make it work for everything besides programming and start writing tests
tobias-lippert Jul 8, 2023
c477d9f
write server test and start writing client tests
tobias-lippert Jul 9, 2023
4a48b0b
write student exam timeline client tests
tobias-lippert Jul 11, 2023
f97afbc
fix probably flaky tests
tobias-lippert Jul 11, 2023
a65f410
remove unnecessary method
tobias-lippert Jul 11, 2023
97e82c8
add jsdoc
tobias-lippert Jul 11, 2023
3fc5c7f
write more client tests
tobias-lippert Jul 12, 2023
4cc8b41
remove debug logs and unnecessary methods and attributes
tobias-lippert Jul 12, 2023
202021c
remove unused methods on the server side
tobias-lippert Jul 12, 2023
8eaed92
remove more unintended changes
tobias-lippert Jul 12, 2023
b0c550c
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 12, 2023
32856b5
add test case for exam navigation bar
tobias-lippert Jul 12, 2023
6fafa4f
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 13, 2023
f5c4e1f
address code review comments
tobias-lippert Jul 14, 2023
ab694d5
review unused services in test class
tobias-lippert Jul 14, 2023
992eb0a
fix ngSwitchCase and tooltip
tobias-lippert Jul 14, 2023
6490a06
remove hardcoded user name for demo purposes
tobias-lippert Jul 14, 2023
8235f97
fix remaining comments
tobias-lippert Jul 14, 2023
7d565ec
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 21, 2023
5b63f8e
Fix flaky modeling assessment component tests
pal03377 Jul 21, 2023
be64589
Use new ApollonEditor.nextRender promise to fix code and tests
pal03377 Jul 22, 2023
fa2db23
Merge branch 'develop' into fix/flaky-modeling-assessment-tests
pal03377 Jul 22, 2023
915a9f9
Change package to @palsch/apollon to be able to test the PR
pal03377 Jul 22, 2023
39f0335
Install @palsch/apollon for testing
pal03377 Jul 22, 2023
464dd5a
minimize changes to package-lock.json
pal03377 Jul 22, 2023
8e57b5a
update Apollon package again
pal03377 Jul 22, 2023
fe34dc1
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 24, 2023
264fa30
add empty line before method and remove empty line at the end of the …
tobias-lippert Jul 24, 2023
0309c76
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 24, 2023
c9add94
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 25, 2023
6816e12
split up services and avoid jumping between submissions if the same e…
tobias-lippert Jul 27, 2023
4c0e97a
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 27, 2023
cacdd5a
fix test
tobias-lippert Jul 27, 2023
0d750ba
remove unused service
tobias-lippert Jul 28, 2023
a64774b
fix retrieving all submissions
tobias-lippert Jul 31, 2023
680a2f6
Merge branch 'fix/flaky-modeling-assessment-tests' into feature/exam-…
tobias-lippert Jul 31, 2023
a1c3c5e
fix apollon editor state undefined with pauls fix
tobias-lippert Jul 31, 2023
06ad8f8
fix breadcrumb
tobias-lippert Jul 31, 2023
3709d32
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Jul 31, 2023
b26db7a
Merge branch 'develop' into fix/flaky-modeling-assessment-tests
pal03377 Aug 3, 2023
d3b7271
Fix tests again by awaiting in more places
pal03377 Aug 3, 2023
cbb78e4
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Aug 7, 2023
8b46e2d
Merge branch 'develop' into fix/flaky-modeling-assessment-tests
pal03377 Aug 7, 2023
a9e075a
Merge branch 'develop' into fix/flaky-modeling-assessment-tests
pal03377 Aug 10, 2023
22f0a7f
small improvements
tobias-lippert Aug 11, 2023
f360e51
fix to not prevent merge
tobias-lippert Aug 24, 2023
aa940ce
fix to not prevent merge
tobias-lippert Aug 24, 2023
f55faf6
merge
tobias-lippert Aug 24, 2023
2ff4136
add npm dependency changes again
tobias-lippert Aug 24, 2023
ff4afc4
fix test
tobias-lippert Aug 24, 2023
9b4999d
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Aug 25, 2023
7449b84
use DTO for newly introduced endpoint
tobias-lippert Aug 25, 2023
14cae2f
fix test
tobias-lippert Aug 25, 2023
7a6a1eb
show exercise and not exercise group name
tobias-lippert Aug 25, 2023
6010278
Merge branch 'fix/flaky-modeling-assessment-tests' into feature/exam-…
tobias-lippert Aug 26, 2023
b3815d1
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Aug 26, 2023
4f81d09
Merge branch 'develop' into fix/flaky-modeling-assessment-tests
pal03377 Aug 27, 2023
de2ccfc
update palsch/apollon version
pal03377 Aug 27, 2023
abf90d4
Merge branch 'fix/flaky-modeling-assessment-tests' into feature/exam-…
tobias-lippert Aug 28, 2023
fc31ffc
update package-lock.json after merge
tobias-lippert Aug 28, 2023
89de6ba
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Aug 29, 2023
573ca07
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 2, 2023
a49af25
revert unintended route change
tobias-lippert Sep 2, 2023
dfcb85a
remove unused param in event emitter
tobias-lippert Sep 2, 2023
805e528
import fixes in production code after merge
tobias-lippert Sep 3, 2023
01b1254
import fixes in test code after merge
tobias-lippert Sep 3, 2023
9c7667a
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 4, 2023
7968bbb
first part of review comments
tobias-lippert Sep 4, 2023
10d9a2c
second part of review comments
tobias-lippert Sep 5, 2023
01f4a15
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 8, 2023
05529de
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 9, 2023
445547c
fix compile error after merge
tobias-lippert Sep 12, 2023
3176a94
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 12, 2023
ce78ac2
fixes after merge
tobias-lippert Sep 14, 2023
b340b38
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 14, 2023
7abec04
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 15, 2023
e863926
fixes after merge
tobias-lippert Sep 15, 2023
fd301a2
Merge remote-tracking branch 'origin/feature/exam-timeline' into feat…
tobias-lippert Sep 15, 2023
6e2dc48
rename dtos to better reflect their content
tobias-lippert Sep 16, 2023
b51d8f2
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 16, 2023
0c879b1
Exam mode: Show diff and commit info for programming exercises in exa…
tobias-lippert Sep 18, 2023
56dcb8d
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 21, 2023
3dba019
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 27, 2023
facef00
fixes after merge
tobias-lippert Sep 28, 2023
2acd06e
mock less but instead really commit something in the local repository…
tobias-lippert Sep 28, 2023
c7db707
fix other tests
tobias-lippert Sep 28, 2023
4a07347
remove unused code
tobias-lippert Sep 28, 2023
e3b15ac
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Sep 29, 2023
0383561
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 8, 2023
695b7f6
fixes after merge
tobias-lippert Oct 8, 2023
3958062
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 10, 2023
08cb81d
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 11, 2023
086ced7
Merge branch 'develop' into feature/exam-timeline
krusche Oct 14, 2023
ca821af
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 15, 2023
000aad4
Merge remote-tracking branch 'origin/feature/exam-timeline' into feat…
tobias-lippert Oct 15, 2023
22dd3d5
fixes after merge
tobias-lippert Oct 15, 2023
c3fe0cf
fix jest config
tobias-lippert Oct 15, 2023
0a73e28
fix client test and undefined error
tobias-lippert Oct 15, 2023
5b298ce
fix displaying of wrong title
tobias-lippert Oct 15, 2023
e4b2c5a
prevent undefined error
tobias-lippert Oct 15, 2023
4647480
add debug log
tobias-lippert Oct 15, 2023
e871bb3
add correct debug log
tobias-lippert Oct 15, 2023
0dab280
handle empty text submission
tobias-lippert Oct 15, 2023
a056499
remove debug log
tobias-lippert Oct 15, 2023
908e572
move exam timeline button to exam summary
tobias-lippert Oct 15, 2023
8e57cd0
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 15, 2023
7a86fc6
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 17, 2023
419ff5a
Merge branch 'develop' into feature/exam-timeline
tobias-lippert Oct 17, 2023
0d50267
Merge branch 'develop' into feature/exam-timeline
dependabot-test Oct 18, 2023
6a1149e
fix import
dependabot-test Oct 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const esModules = [
'ngx-infinite-scroll',
'internmap',
'@swimlane/ngx-graph',
'ngx-slider-v2'
].join('|');

const {
Expand Down
29 changes: 29 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@angular/platform-browser-dynamic": "16.2.7",
"@angular/router": "16.2.7",
"@angular/service-worker": "16.2.7",
"ngx-slider-v2": "16.0.2",
tobias-lippert marked this conversation as resolved.
Show resolved Hide resolved
"@ctrl/ngx-emoji-mart": "9.2.0",
"@danielmoncada/angular-datetime-picker": "16.0.1",
"@fingerprintjs/fingerprintjs": "4.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@
""")
Optional<ProgrammingExercise> findByParticipationId(@Param("participationId") Long participationId);

default ProgrammingExercise findByParticipationIdOrElseThrow(long participationId) throws EntityNotFoundException {

Check warning on line 231 in src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java

View check run for this annotation

Teamscale / teamscale-findings

src/main/java/de/tum/in/www1/artemis/repository/ProgrammingExerciseRepository.java#L231

In this file 35 interface comments are missing. Consider adding explanatory comments or restricting the visibility. View in Teamscale: https://teamscale.io/activity.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3A1697620312000
return findByParticipationId(participationId)
.orElseThrow(() -> new EntityNotFoundException("Programming exercise for participation with id " + participationId + " does not exist"));
}

@Query("""
SELECT pe
FROM ProgrammingExercise pe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,4 +440,8 @@
default Submission findByIdWithResultsElseThrow(long submissionId) {
return findWithEagerResultsAndAssessorById(submissionId).orElseThrow(() -> new EntityNotFoundException("Submission", +submissionId));
}

default Submission findByIdElseThrow(long submissionId) {

Check warning on line 444 in src/main/java/de/tum/in/www1/artemis/repository/SubmissionRepository.java

View check run for this annotation

Teamscale / teamscale-findings

src/main/java/de/tum/in/www1/artemis/repository/SubmissionRepository.java#L444

Interface comment missing https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=FFDEA4D0746EC8D5113072017E994FFD
return findById(submissionId).orElseThrow(() -> new EntityNotFoundException("Submission", submissionId));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.tum.in.www1.artemis.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
Expand Down Expand Up @@ -28,4 +29,6 @@
""")
Optional<SubmissionVersion> findLatestVersion(@Param("submissionId") long submissionId);

List<SubmissionVersion> findSubmissionVersionBySubmissionIdOrderByCreatedDateAsc(long submissionId);

Check warning on line 32 in src/main/java/de/tum/in/www1/artemis/repository/SubmissionVersionRepository.java

View check run for this annotation

Teamscale / teamscale-findings

src/main/java/de/tum/in/www1/artemis/repository/SubmissionVersionRepository.java#L32

Interface comment missing https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=A7515E58E5F8E87F42BD30BD088ABA40

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import de.tum.in.www1.artemis.service.ProfileService;
import de.tum.in.www1.artemis.service.ZipFileService;
import de.tum.in.www1.artemis.service.connectors.localvc.LocalVCRepositoryUrl;
import de.tum.in.www1.artemis.web.rest.dto.CommitInfoDTO;
import de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException;

@Service
Expand Down Expand Up @@ -374,6 +375,40 @@
return getOrCheckoutRepository(repoUrl, localPath, pullOnGet);
}

/**
* Checkout at the given repository at the given commit hash
*
* @param repository the repository to check out the commit in
* @param commitHash the hash of the commit to check out
* @return the repository checked out at the given commit
*/
public Repository checkoutRepositoryAtCommit(Repository repository, String commitHash) {
try (Git git = new Git(repository)) {
git.checkout().setName(commitHash).call();
}
catch (GitAPIException e) {
throw new GitException("Could not checkout commit " + commitHash + " in repository located at " + repository.getLocalPath(), e);
}
return repository;
}

/**
* Get the local repository for a given remote repository URL.
* <p>
* If the local repo does not exist yet, it will be checked out.
* After retrieving the repository, the commit for the given hash will be checked out.
*
* @param vcsRepositoryUrl the url of the remote repository
* @param commitHash the hash of the commit to checkout
* @param pullOnGet pull from the remote on the checked out repository, if it does not need to be cloned
* @return the repository if it could be checked out
* @throws GitAPIException if the repository could not be checked out
*/
public Repository checkoutRepositoryAtCommit(VcsRepositoryUrl vcsRepositoryUrl, String commitHash, boolean pullOnGet) throws GitAPIException {
var repository = getOrCheckoutRepository(vcsRepositoryUrl, pullOnGet);
return checkoutRepositoryAtCommit(repository, commitHash);
}

/**
* Get the local repository for a given remote repository URL. If the local repo does not exist yet, it will be checked out.
*
Expand Down Expand Up @@ -851,6 +886,18 @@
}
}

/**
* Switch back to the HEAD commit of the default branch.
*
* @param repository the repository for which we want to switch to the HEAD commit of the default branch
* @throws GitAPIException if this operation fails
*/
public void switchBackToDefaultBranchHead(Repository repository) throws GitAPIException {
try (Git git = new Git(repository)) {
git.checkout().setName(defaultBranch).call();
}
}

/**
* Get last commit hash from HEAD
*
Expand Down Expand Up @@ -1336,4 +1383,28 @@
public <C extends GitCommand<?>> C authenticate(TransportCommand<C, ?> command) {
return command.setTransportConfigCallback(sshCallback);
}

/**
* Checkout a repository and get the git log for a given repository url.
*
* @param vcsRepositoryUrl the repository url for which the git log should be retrieved
* @return a list of commit info DTOs containing author, timestamp, commit message, and hash
* @throws GitAPIException if an error occurs while retrieving the git log
*/
public List<CommitInfoDTO> getCommitInfos(VcsRepositoryUrl vcsRepositoryUrl) throws GitAPIException {
List<CommitInfoDTO> commitInfos = new ArrayList<>();

try (var repo = getOrCheckoutRepository(vcsRepositoryUrl, true); var git = new Git(repo)) {
var commits = git.log().call();
commits.forEach(commit -> {
var commitInfo = CommitInfoDTO.of(commit);
commitInfos.add(commitInfo);
});
}
return commitInfos;
}

public void clearCachedRepositories() {

Check warning on line 1407 in src/main/java/de/tum/in/www1/artemis/service/connectors/GitService.java

View check run for this annotation

Teamscale / teamscale-findings

src/main/java/de/tum/in/www1/artemis/service/connectors/GitService.java#L1407

In this file 7 interface comments are missing. Consider adding explanatory comments or restricting the visibility. View in Teamscale: Line 62: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=01FA4F90B9B1B82EB761E1B400D578DE Line 119: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=62BD26523B0135C256D4786B7AE00CAC Line 427: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=601CC30058E88EF0B8DBAFF37F7467E5 Line 433: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=24F62C1E39740010C235CE5CD7E21B2C Line 579: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=72D9B0C1FC505108E4104FD72FA90A39 Line 1383: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=A6F3926527DA620EF405C1CE13D3C47F Line 1407: https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=99BBDE967B17AFEB7E6F74FDB5645948
cachedRepositories.clear();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package de.tum.in.www1.artemis.service.hestia;

Check warning on line 1 in src/main/java/de/tum/in/www1/artemis/service/hestia/ProgrammingExerciseGitDiffReportService.java

View check run for this annotation

Teamscale / teamscale-findings

src/main/java/de/tum/in/www1/artemis/service/hestia/ProgrammingExerciseGitDiffReportService.java#L1

Violation of file size threshold (source lines of code) of 300: 331 https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=83C4DAB563059D28BC4C0C2BBD8AC668

import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand All @@ -10,26 +10,29 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.validation.constraints.NotNull;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;

import de.tum.in.www1.artemis.domain.DomainObject;
import de.tum.in.www1.artemis.domain.ProgrammingExercise;
import de.tum.in.www1.artemis.domain.VcsRepositoryUrl;
import de.tum.in.www1.artemis.domain.*;

Check warning on line 24 in src/main/java/de/tum/in/www1/artemis/service/hestia/ProgrammingExerciseGitDiffReportService.java

View check run for this annotation

Teamscale / teamscale-findings

src/main/java/de/tum/in/www1/artemis/service/hestia/ProgrammingExerciseGitDiffReportService.java#L24

Star import of `de.tum.in.www1.artemis.domain.*` should not be used https://teamscale.io/findings.html#details/GitHub-ls1intum-Artemis?t=feature%2Fexam-timeline%3AHEAD&id=9E093CE19835E6BC76EB5651E9B696DB
import de.tum.in.www1.artemis.domain.hestia.ProgrammingExerciseGitDiffEntry;
import de.tum.in.www1.artemis.domain.hestia.ProgrammingExerciseGitDiffReport;
import de.tum.in.www1.artemis.domain.participation.ProgrammingExerciseParticipation;
import de.tum.in.www1.artemis.domain.participation.SolutionProgrammingExerciseParticipation;
import de.tum.in.www1.artemis.domain.participation.TemplateProgrammingExerciseParticipation;
import de.tum.in.www1.artemis.repository.ProgrammingExerciseRepository;
import de.tum.in.www1.artemis.repository.ProgrammingSubmissionRepository;
import de.tum.in.www1.artemis.repository.SolutionProgrammingExerciseParticipationRepository;
import de.tum.in.www1.artemis.repository.TemplateProgrammingExerciseParticipationRepository;
import de.tum.in.www1.artemis.repository.hestia.ProgrammingExerciseGitDiffReportRepository;
import de.tum.in.www1.artemis.service.FileService;
import de.tum.in.www1.artemis.service.connectors.GitService;
import de.tum.in.www1.artemis.web.rest.errors.InternalServerErrorException;

Expand All @@ -53,18 +56,21 @@

private final SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseParticipationRepository;

private final FileService fileService;

private final Pattern gitDiffLinePattern = Pattern.compile("@@ -(?<previousLine>\\d+)(,(?<previousLineCount>\\d+))? \\+(?<newLine>\\d+)(,(?<newLineCount>\\d+))? @@");

public ProgrammingExerciseGitDiffReportService(GitService gitService, ProgrammingExerciseGitDiffReportRepository programmingExerciseGitDiffReportRepository,
ProgrammingSubmissionRepository programmingSubmissionRepository, ProgrammingExerciseRepository programmingExerciseRepository,
TemplateProgrammingExerciseParticipationRepository templateProgrammingExerciseParticipationRepository,
SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseParticipationRepository) {
SolutionProgrammingExerciseParticipationRepository solutionProgrammingExerciseParticipationRepository, FileService fileService) {
this.gitService = gitService;
this.programmingExerciseGitDiffReportRepository = programmingExerciseGitDiffReportRepository;
this.programmingSubmissionRepository = programmingSubmissionRepository;
this.programmingExerciseRepository = programmingExerciseRepository;
this.templateProgrammingExerciseParticipationRepository = templateProgrammingExerciseParticipationRepository;
this.solutionProgrammingExerciseParticipationRepository = solutionProgrammingExerciseParticipationRepository;
this.fileService = fileService;
}

/**
Expand Down Expand Up @@ -160,6 +166,29 @@
}
}

/**
* Creates a new ProgrammingExerciseGitDiffReport for a submission with the template repository.
*
* @param exercise The exercise for which the report should be created
* @param submission The submission for which the report should be created
* @return The report with the changes between the submission and the template
* @throws GitAPIException If an error occurs while accessing the git repository
* @throws IOException If an error occurs while accessing the file system
*/
public ProgrammingExerciseGitDiffReport createReportForSubmissionWithTemplate(ProgrammingExercise exercise, ProgrammingSubmission submission)
throws GitAPIException, IOException {
var templateParticipation = templateProgrammingExerciseParticipationRepository.findByProgrammingExerciseId(exercise.getId()).orElseThrow();
Repository templateRepo = prepareTemplateRepository(templateParticipation);

var repo1 = gitService.checkoutRepositoryAtCommit(((ProgrammingExerciseParticipation) submission.getParticipation()).getVcsRepositoryUrl(), submission.getCommitHash(),
false);
var oldTreeParser = new FileTreeIterator(templateRepo);
var newTreeParser = new FileTreeIterator(repo1);
var report = createReport(templateRepo, oldTreeParser, newTreeParser);
gitService.switchBackToDefaultBranchHead(repo1);
return report;
}

/**
* Calculates git diff between two repositories and returns the cumulative number of diff lines.
*
Expand Down Expand Up @@ -198,18 +227,88 @@
*/
private ProgrammingExerciseGitDiffReport generateReport(TemplateProgrammingExerciseParticipation templateParticipation,
SolutionProgrammingExerciseParticipation solutionParticipation) throws GitAPIException, IOException {
var templateRepo = gitService.getOrCheckoutRepository(templateParticipation.getVcsRepositoryUrl(), true);
Repository templateRepo = prepareTemplateRepository(templateParticipation);
var solutionRepo = gitService.getOrCheckoutRepository(solutionParticipation.getVcsRepositoryUrl(), true);

gitService.resetToOriginHead(templateRepo);
gitService.pullIgnoreConflicts(templateRepo);
gitService.resetToOriginHead(solutionRepo);
gitService.pullIgnoreConflicts(solutionRepo);

var oldTreeParser = new FileTreeIterator(templateRepo);
var newTreeParser = new FileTreeIterator(solutionRepo);

try (ByteArrayOutputStream diffOutputStream = new ByteArrayOutputStream(); Git git = Git.wrap(templateRepo)) {
return createReport(templateRepo, oldTreeParser, newTreeParser);
}

/**
* Prepares the template repository for the git diff calculation by checking it out and resetting it to the origin head.
*
* @param templateParticipation The participation for the template
* @return The checked out template repository
* @throws GitAPIException If an error occurs while accessing the git repository
*/
private Repository prepareTemplateRepository(TemplateProgrammingExerciseParticipation templateParticipation) throws GitAPIException {
var templateRepo = gitService.getOrCheckoutRepository(templateParticipation.getVcsRepositoryUrl(), true);
gitService.resetToOriginHead(templateRepo);
gitService.pullIgnoreConflicts(templateRepo);
return templateRepo;
}

/**
* Creates a new ProgrammingExerciseGitDiffReport containing the git-diff for two submissions.
*
* @param submission1 The first submission (older)
* @param submission2 The second submission (newer)
* @return The report with the changes between the two submissions
* @throws GitAPIException If an error occurs while accessing the git repository
* @throws IOException If an error occurs while accessing the file system
*/
public ProgrammingExerciseGitDiffReport generateReportForSubmissions(ProgrammingSubmission submission1, ProgrammingSubmission submission2) throws GitAPIException, IOException {
var repositoryUrl = ((ProgrammingExerciseParticipation) submission1.getParticipation()).getVcsRepositoryUrl();
var repo1 = gitService.getOrCheckoutRepository(repositoryUrl, true);
var repo1Path = repo1.getLocalPath();
var repo2Path = fileService.getTemporaryUniqueSubfolderPath(repo1Path.getParent(), 5);
FileSystemUtils.copyRecursively(repo1Path, repo2Path);
repo1 = gitService.checkoutRepositoryAtCommit(repo1, submission1.getCommitHash());
var repo2 = gitService.getExistingCheckedOutRepositoryByLocalPath(repo2Path, repositoryUrl);
repo2 = gitService.checkoutRepositoryAtCommit(repo2, submission2.getCommitHash());
return parseFilesAndCreateReport(repo1, repo2);
}

/**
* Parses the files of the given repositories and creates a new ProgrammingExerciseGitDiffReport containing the git-diff.
*
* @param repo1 The first repository
* @param repo2 The second repository
* @return The report with the changes between the two repositories at their checked out state
* @throws IOException If an error occurs while accessing the file system
* @throws GitAPIException If an error occurs while accessing the git repository
*/
@NotNull
private ProgrammingExerciseGitDiffReport parseFilesAndCreateReport(Repository repo1, Repository repo2) throws IOException, GitAPIException {
var oldTreeParser = new FileTreeIterator(repo1);
var newTreeParser = new FileTreeIterator(repo2);

var report = createReport(repo1, oldTreeParser, newTreeParser);
gitService.switchBackToDefaultBranchHead(repo1);
gitService.switchBackToDefaultBranchHead(repo2);
return report;
}

/**
* Creates a new ProgrammingExerciseGitDiffReport containing the git-diff.
* <p>
* It parses all files of the repositories in their directories on the file system and creates a report containing the changes.
* Both repositories have to be checked out at the commit that should be compared and be in different directories
*
* @param repo1 The first repository
* @param oldTreeParser The tree parser for the first repository
* @param newTreeParser The tree parser for the second repository
* @return The report with the changes between the two repositories at their checked out state
* @throws IOException If an error occurs while accessing the file system
* @throws GitAPIException If an error occurs while accessing the git repository
*/
@NotNull
private ProgrammingExerciseGitDiffReport createReport(Repository repo1, FileTreeIterator oldTreeParser, FileTreeIterator newTreeParser) throws IOException, GitAPIException {
try (ByteArrayOutputStream diffOutputStream = new ByteArrayOutputStream(); Git git = Git.wrap(repo1)) {
git.diff().setOldTree(oldTreeParser).setNewTree(newTreeParser).setOutputStream(diffOutputStream).call();
var diff = diffOutputStream.toString();
var programmingExerciseGitDiffEntries = extractDiffEntries(diff, false);
Expand Down
Loading
Loading