From 647e21bbc4e1c831a0764f09f92de73297e6a560 Mon Sep 17 00:00:00 2001
From: "Sven F." <9976560+sven1103@users.noreply.github.com>
Date: Tue, 19 Nov 2024 14:53:33 +0100
Subject: [PATCH 1/6] Improve software quality and configure Sonarcloud (#917)
Further improves the reliability of the software code and also introduces a Sonarcloud property file, to tell Sonarcloud to exclude
certain contents from the evaluation (template content, etc).
---
.github/workflows/sonarcloud.yml | 40 ++++++++++++++++++
pom.xml | 5 +++
.../TIBTerminologyServiceIntegration.java | 2 +
.../application/DeletionService.java | 3 +-
.../measurement/MeasurementService.java | 33 +++++++++------
sonar-project.properties | 3 ++
user-interface/src/main/bundles/dev.bundle | Bin 3289811 -> 3289848 bytes
...ejectedExecutionHandlerImplementation.java | 1 +
.../ExperimentDetailsComponent.java | 7 +--
9 files changed, 77 insertions(+), 17 deletions(-)
create mode 100644 .github/workflows/sonarcloud.yml
create mode 100644 sonar-project.properties
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
new file mode 100644
index 0000000000..48ae4281c6
--- /dev/null
+++ b/.github/workflows/sonarcloud.yml
@@ -0,0 +1,40 @@
+name: SonarCloud Analysis
+
+# Run this workflow on commits to the development branch
+on:
+ push:
+ branches:
+ - development
+
+jobs:
+ sonarcloud:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'zulu'
+ java-version: '17'
+ - name: Load local Maven repository cache
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+
+ # Build the project using Maven
+ - name: Build with Maven
+ run: mvn clean install
+
+ # Run SonarCloud analysis
+ - name: SonarCloud Scan
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Use the token stored in GitHub secrets
+ run: mvn sonar:sonar \
+ -Dsonar.projectKey=qbicsoftware_data-manager-app \
+ -Dsonar.organization=qbicsoftware \
+ -Dsonar.host.url=https://sonarcloud.io
diff --git a/pom.xml b/pom.xml
index 5fa1d3cfb8..b371480f06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -233,6 +233,11 @@
${maven.compiler.target}
+
+ org.sonarsource.scanner.maven
+ sonar-maven-plugin
+ 5.0.0.4389
+
diff --git a/project-management-infrastructure/src/main/java/life/qbic/projectmanagement/infrastructure/ontology/TIBTerminologyServiceIntegration.java b/project-management-infrastructure/src/main/java/life/qbic/projectmanagement/infrastructure/ontology/TIBTerminologyServiceIntegration.java
index 6c693ae0d7..82200d6c3a 100644
--- a/project-management-infrastructure/src/main/java/life/qbic/projectmanagement/infrastructure/ontology/TIBTerminologyServiceIntegration.java
+++ b/project-management-infrastructure/src/main/java/life/qbic/projectmanagement/infrastructure/ontology/TIBTerminologyServiceIntegration.java
@@ -164,6 +164,7 @@ public List query(String searchTerm, int offset, int limit)
} catch (IOException e) {
throw wrapIO(e);
} catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
throw wrapInterrupted(e);
} catch (Exception e) {
throw wrapUnknown(e);
@@ -193,6 +194,7 @@ public List search(String searchTerm, int offset, int limit)
} catch (IOException e) {
throw wrapIO(e);
} catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
throw wrapInterrupted(e);
} catch (Exception e) {
throw wrapUnknown(e);
diff --git a/project-management/src/main/java/life/qbic/projectmanagement/application/DeletionService.java b/project-management/src/main/java/life/qbic/projectmanagement/application/DeletionService.java
index 641a58ca20..11b43edff4 100644
--- a/project-management/src/main/java/life/qbic/projectmanagement/application/DeletionService.java
+++ b/project-management/src/main/java/life/qbic/projectmanagement/application/DeletionService.java
@@ -29,7 +29,7 @@
@Service
public class DeletionService {
- private ApplicationContext context;
+ private final ApplicationContext context;
private final ProjectInformationService projectInformationService;
private final ExperimentInformationService experimentInformationService;
@@ -52,6 +52,7 @@ public DeletionService(ProjectInformationService projectInformationService,
BatchDomainService.class.getSimpleName() + " must not be null");
this.sampleDomainService = requireNonNull(sampleDomainService,
SampleDomainService.class.getSimpleName() + " must not be null");
+ this.context = requireNonNull(context);
}
/**
diff --git a/project-management/src/main/java/life/qbic/projectmanagement/application/measurement/MeasurementService.java b/project-management/src/main/java/life/qbic/projectmanagement/application/measurement/MeasurementService.java
index 966d1d2cab..9fae7177d6 100644
--- a/project-management/src/main/java/life/qbic/projectmanagement/application/measurement/MeasurementService.java
+++ b/project-management/src/main/java/life/qbic/projectmanagement/application/measurement/MeasurementService.java
@@ -44,6 +44,7 @@
import life.qbic.projectmanagement.domain.repository.MeasurementRepository;
import life.qbic.projectmanagement.domain.service.MeasurementDomainService;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -60,6 +61,7 @@
public class MeasurementService {
private static final Logger log = logger(MeasurementService.class);
+ private final ApplicationContext context;
private final MeasurementDomainService measurementDomainService;
private final MeasurementLookupService measurementLookupService;
private final SampleInformationService sampleInformationService;
@@ -75,7 +77,8 @@ public MeasurementService(MeasurementDomainService measurementDomainService,
OrganisationLookupService organisationLookupService,
MeasurementLookupService measurementLookupService,
ProjectInformationService projectInformationService,
- MeasurementRepository measurementRepository) {
+ MeasurementRepository measurementRepository,
+ ApplicationContext context) {
this.measurementDomainService = Objects.requireNonNull(measurementDomainService);
this.sampleInformationService = Objects.requireNonNull(sampleInformationService);
this.speciesLookupService = Objects.requireNonNull(speciesLookupService);
@@ -83,6 +86,7 @@ public MeasurementService(MeasurementDomainService measurementDomainService,
this.measurementLookupService = Objects.requireNonNull(measurementLookupService);
this.projectInformationService = Objects.requireNonNull(projectInformationService);
this.measurementRepository = Objects.requireNonNull(measurementRepository);
+ this.context = Objects.requireNonNull(context);
}
/**
@@ -113,7 +117,8 @@ public long countNGSMeasurements(ExperimentId experimentId) {
@PostAuthorize(
"hasPermission(#projectId, 'life.qbic.projectmanagement.domain.model.project.Project', 'READ') ")
public Collection findProteomicsMeasurements(String filter,
- ExperimentId experimentId, int offset, int limit, List sortOrder, ProjectId projectId) {
+ ExperimentId experimentId, int offset, int limit, List sortOrder,
+ ProjectId projectId) {
var result = sampleInformationService.retrieveSamplesForExperiment(experimentId);
var samplesInExperiment = result.getValue().stream().map(Sample::sampleId).toList();
return measurementLookupService.queryProteomicsMeasurementsBySampleIds(filter,
@@ -145,7 +150,8 @@ public Collection findNGSMeasurements(String filter, ExperimentI
@PostAuthorize(
"hasPermission(#projectId, 'life.qbic.projectmanagement.domain.model.project.Project', 'READ') ")
- public Collection findNGSMeasurements(ExperimentId experimentId, ProjectId projectId) {
+ public Collection findNGSMeasurements(ExperimentId experimentId,
+ ProjectId projectId) {
var result = sampleInformationService.retrieveSamplesForExperiment(experimentId);
var samplesInExperiment = result.getValue().stream().map(Sample::sampleId).toList();
return measurementLookupService.queryAllNGSMeasurement(samplesInExperiment);
@@ -192,7 +198,7 @@ public CompletableFuture>> registerAll(
return CompletableFuture.completedFuture(List.of(Result.fromError(e.reason)));
}
try {
- results = performRegistration(measurementMetadataList, projectId).stream()
+ results = context.getBean(MeasurementService.class).performRegistration(measurementMetadataList, projectId).stream()
.map(Result::fromValue).toList();
} catch (MeasurementRegistrationException e) {
log.error("Failed to register measurement", e);
@@ -202,7 +208,7 @@ public CompletableFuture>> registerAll(
return CompletableFuture.completedFuture(List.of(Result.fromError(ErrorCode.FAILED)));
}
// if the creation worked, we forward the events, otherwise it will be rolled back
- if(results.stream().allMatch(Result::isValue)) {
+ if (results.stream().allMatch(Result::isValue)) {
domainEventsCache.forEach(
domainEvent -> DomainEventDispatcher.instance().dispatch(domainEvent));
}
@@ -529,21 +535,21 @@ public CompletableFuture>> updateAll(
private void handleUpdateEvents(List domainEventsCache,
List> results) {
- if(results.stream().anyMatch(Result::isError)) {
+ if (results.stream().anyMatch(Result::isError)) {
return;
}
Set dispatchedIDs = new HashSet<>();
- for(DomainEvent event : domainEventsCache) {
- if(event instanceof MeasurementUpdatedEvent measurementUpdatedEvent) {
+ for (DomainEvent event : domainEventsCache) {
+ if (event instanceof MeasurementUpdatedEvent measurementUpdatedEvent) {
MeasurementId id = measurementUpdatedEvent.measurementId();
- if(dispatchedIDs.contains(id)) {
+ if (dispatchedIDs.contains(id)) {
continue;
}
DomainEventDispatcher.instance().dispatch(event);
dispatchedIDs.add(id);
}
}
-
+
}
/**
@@ -803,7 +809,7 @@ public Result deletePxPMeasurements(ProjectI
Set selectedMeasurements) {
try {
measurementDomainService.deletePxP(selectedMeasurements);
- if(!selectedMeasurements.isEmpty()) {
+ if (!selectedMeasurements.isEmpty()) {
dispatchProjectChangedOnMeasurementDeleted(projectId);
}
return Result.fromValue(null);
@@ -817,7 +823,7 @@ public Result deleteNGSMeasurements(ProjectI
Set selectedMeasurements) {
try {
measurementDomainService.deleteNGS(selectedMeasurements);
- if(!selectedMeasurements.isEmpty()) {
+ if (!selectedMeasurements.isEmpty()) {
dispatchProjectChangedOnMeasurementDeleted(projectId);
}
return Result.fromValue(null);
@@ -829,7 +835,8 @@ public Result deleteNGSMeasurements(ProjectI
private void dispatchProjectChangedOnMeasurementDeleted(ProjectId projectId) {
ProjectChanged projectChanged = ProjectChanged.create(projectId);
DomainEventDispatcher.instance().dispatch(projectChanged);
-}
+ }
+
public enum DeletionErrorCode {
FAILED, DATA_ATTACHED
}
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000000..1b2e6e2874
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,3 @@
+sonar.projectKey=qbicsoftware_data-manager-app
+sonar.organization=qbicsoftware
+sonar.exclusions=src/test/**,build/**,node_modules/**, **/DataPrivacyAgreement.html, **/LegalNotice.html
diff --git a/user-interface/src/main/bundles/dev.bundle b/user-interface/src/main/bundles/dev.bundle
index 88973dba13db69b7cd465b18c5148d35e44d47d0..2902e0e7ee8f2583cb047c0efc12985efc2e15ff 100644
GIT binary patch
delta 3100043
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