Skip to content

Commit

Permalink
Improve software quality and configure Sonarcloud (#917)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
sven1103 authored Nov 19, 2024
1 parent 9466cd4 commit 647e21b
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 17 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.0.0.4389</version>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ public List<OntologyClass> 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);
Expand Down Expand Up @@ -193,6 +194,7 @@ public List<OntologyClass> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
@Service
public class DeletionService {

private ApplicationContext context;
private final ApplicationContext context;

private final ProjectInformationService projectInformationService;
private final ExperimentInformationService experimentInformationService;
Expand All @@ -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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -75,14 +77,16 @@ 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);
this.organisationLookupService = Objects.requireNonNull(organisationLookupService);
this.measurementLookupService = Objects.requireNonNull(measurementLookupService);
this.projectInformationService = Objects.requireNonNull(projectInformationService);
this.measurementRepository = Objects.requireNonNull(measurementRepository);
this.context = Objects.requireNonNull(context);
}

/**
Expand Down Expand Up @@ -113,7 +117,8 @@ public long countNGSMeasurements(ExperimentId experimentId) {
@PostAuthorize(
"hasPermission(#projectId, 'life.qbic.projectmanagement.domain.model.project.Project', 'READ') ")
public Collection<ProteomicsMeasurement> findProteomicsMeasurements(String filter,
ExperimentId experimentId, int offset, int limit, List<SortOrder> sortOrder, ProjectId projectId) {
ExperimentId experimentId, int offset, int limit, List<SortOrder> sortOrder,
ProjectId projectId) {
var result = sampleInformationService.retrieveSamplesForExperiment(experimentId);
var samplesInExperiment = result.getValue().stream().map(Sample::sampleId).toList();
return measurementLookupService.queryProteomicsMeasurementsBySampleIds(filter,
Expand Down Expand Up @@ -145,7 +150,8 @@ public Collection<NGSMeasurement> findNGSMeasurements(String filter, ExperimentI

@PostAuthorize(
"hasPermission(#projectId, 'life.qbic.projectmanagement.domain.model.project.Project', 'READ') ")
public Collection<NGSMeasurement> findNGSMeasurements(ExperimentId experimentId, ProjectId projectId) {
public Collection<NGSMeasurement> findNGSMeasurements(ExperimentId experimentId,
ProjectId projectId) {
var result = sampleInformationService.retrieveSamplesForExperiment(experimentId);
var samplesInExperiment = result.getValue().stream().map(Sample::sampleId).toList();
return measurementLookupService.queryAllNGSMeasurement(samplesInExperiment);
Expand Down Expand Up @@ -192,7 +198,7 @@ public CompletableFuture<List<Result<MeasurementId, ErrorCode>>> 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::<MeasurementId, ErrorCode>fromValue).toList();
} catch (MeasurementRegistrationException e) {
log.error("Failed to register measurement", e);
Expand All @@ -202,7 +208,7 @@ public CompletableFuture<List<Result<MeasurementId, ErrorCode>>> 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));
}
Expand Down Expand Up @@ -529,21 +535,21 @@ public CompletableFuture<List<Result<MeasurementId, ErrorCode>>> updateAll(

private void handleUpdateEvents(List<DomainEvent> domainEventsCache,
List<Result<MeasurementId, ErrorCode>> results) {
if(results.stream().anyMatch(Result::isError)) {
if (results.stream().anyMatch(Result::isError)) {
return;
}
Set<MeasurementId> 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);
}
}

}

/**
Expand Down Expand Up @@ -803,7 +809,7 @@ public Result<Void, MeasurementDeletionException> deletePxPMeasurements(ProjectI
Set<ProteomicsMeasurement> selectedMeasurements) {
try {
measurementDomainService.deletePxP(selectedMeasurements);
if(!selectedMeasurements.isEmpty()) {
if (!selectedMeasurements.isEmpty()) {
dispatchProjectChangedOnMeasurementDeleted(projectId);
}
return Result.fromValue(null);
Expand All @@ -817,7 +823,7 @@ public Result<Void, MeasurementDeletionException> deleteNGSMeasurements(ProjectI
Set<NGSMeasurement> selectedMeasurements) {
try {
measurementDomainService.deleteNGS(selectedMeasurements);
if(!selectedMeasurements.isEmpty()) {
if (!selectedMeasurements.isEmpty()) {
dispatchProjectChangedOnMeasurementDeleted(projectId);
}
return Result.fromValue(null);
Expand All @@ -829,7 +835,8 @@ public Result<Void, MeasurementDeletionException> deleteNGSMeasurements(ProjectI
private void dispatchProjectChangedOnMeasurementDeleted(ProjectId projectId) {
ProjectChanged projectChanged = ProjectChanged.create(projectId);
DomainEventDispatcher.instance().dispatch(projectChanged);
}
}

public enum DeletionErrorCode {
FAILED, DATA_ATTACHED
}
Expand Down
3 changes: 3 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sonar.projectKey=qbicsoftware_data-manager-app
sonar.organization=qbicsoftware
sonar.exclusions=src/test/**,build/**,node_modules/**, **/DataPrivacyAgreement.html, **/LegalNotice.html
Binary file modified user-interface/src/main/bundles/dev.bundle
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
"Thread " + Thread.currentThread().getId() + " rejected, because the queue was full.");
executor.getQueue().put(r);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RejectedExecutionException("Unexpected InterruptedException", e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,11 +603,12 @@ private void addExperimentalVariables(
}

public void setContext(Context context) {
this.context = requireNonNull(context);
if (context.projectId().isEmpty()) {
throw new ApplicationException("no project id in context " + context);
}
ExperimentId experimentId = context.experimentId()
.orElseThrow(() -> new ApplicationException("no experiment id in context " + context));
context.projectId()
.orElseThrow(() -> new ApplicationException("no project id in context " + context));
this.context = context;
reloadExperimentInfo(experimentId);
}

Expand Down

0 comments on commit 647e21b

Please sign in to comment.