added sonarqube config #41

Merged
kasun merged 27 commits from enhancement/Configure-Sonarqube-server into main 2026-06-27 03:23:58 +02:00
6 changed files with 119 additions and 14 deletions
+61
View File
@@ -0,0 +1,61 @@
name: SonarQube Analysis
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
analyze:
name: Build and Analyze
runs-on: ubuntu-latest
services:
postgres:
image: postgres:18.4
env:
POSTGRES_USER: vaessl
POSTGRES_PASSWORD: vaessl
POSTGRES_DB: vaessl_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout Code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 25
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
java-version: "25"
distribution: "zulu" # Alternative distribution options are available.
- name: Make Gradle Executable
run: chmod +x ./gradlew
working-directory: backend
- name: Build and Analyze
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
DB_URL: jdbc:postgresql://postgres:5432/vaessl_test
DB_TEST_URL: jdbc:postgresql://postgres:5432/vaessl_test
DB_USERNAME: vaessl
DB_PASSWORD: vaessl
PG_DRIVER_CLASS_NAME: org.postgresql.Driver
OPENAI_BASE_URL: https://api.openai.com/v1
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
ALLOWED_ORIGINS: http://localhost:3000
run: ./gradlew build sonar --info
working-directory: backend
+38 -2
View File
@@ -1,7 +1,11 @@
val wiremockVersion = "3.12.0"
plugins {
java
jacoco
id("org.springframework.boot") version "4.1.0"
id("io.spring.dependency-management") version "1.1.7"
id("org.sonarqube") version "7.3.0.8198"
}
group = "com.vaessl"
@@ -13,6 +17,15 @@ java {
}
}
sonar {
properties {
property("sonar.projectKey", "Vaessl")
property("sonar.projectName", "Vaessl")
property("sonar.coverage.jacoco.xmlReportPaths",
"${layout.buildDirectory.get()}/reports/jacoco/test/jacocoTestReport.xml")
}
}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
@@ -25,6 +38,7 @@ repositories {
extra["springAiVersion"] = "2.0.0"
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-session-jdbc")
@@ -32,17 +46,24 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-webmvc")
implementation("org.springframework.ai:spring-ai-starter-model-openai")
compileOnly("org.projectlombok:lombok")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-data-jpa-test")
// testImplementation("org.springframework.boot:spring-boot-starter-security-test")
testImplementation("org.springframework.boot:spring-boot-starter-validation-test")
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
testImplementation("org.wiremock:wiremock-standalone:$wiremockVersion")
testImplementation("org.springframework.boot:spring-boot-starter-session-jdbc-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation("org.wiremock:wiremock-standalone:3.12.0")
testImplementation("org.springframework.boot:spring-boot-starter-session-jdbc-test")}
}
dependencyManagement {
imports {
@@ -56,4 +77,19 @@ tasks.withType<JavaCompile> {
tasks.withType<Test> {
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
testLogging {
events("failed", "standardError")
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
}
}
tasks.jacocoTestReport {
dependsOn(tasks.withType<Test>())
reports {
xml.required = true
}
}
@@ -1,9 +1,9 @@
package com.vaessl.app.connection;
import java.time.Instant;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
@@ -18,8 +18,11 @@ public class ConnectionService {
private final ConnectionRepository cRepository;
public ConnectionService(List<ConnectionProvider> providers, ConnectionRepository cRepository) {
this.providerRegistry = providers.stream()
.collect(Collectors.toMap(ConnectionProvider::getServiceType, p -> p));
Map<ServiceType, ConnectionProvider> registry = new EnumMap<>(ServiceType.class);
for (ConnectionProvider provider : providers) {
registry.put(provider.getServiceType(), provider);
}
this.providerRegistry = registry;
this.cRepository = cRepository;
}
@@ -49,7 +52,8 @@ public class ConnectionService {
return new LoginResult(saved.getId(), response.expiresAt());
}
public ConnectionStatusResponse getConnectionStatus(ServiceType serviceType, Long connectionId) {
public ConnectionStatusResponse getConnectionStatus(ServiceType serviceType,
Long connectionId) {
ConnectionEntity entity = cRepository.findById(connectionId).orElse(null);
if (entity == null)
return null;
@@ -58,7 +62,7 @@ public class ConnectionService {
Instant expiresAt = (provider != null) ? provider.getTokenExpiry(entity) : null;
boolean connected = expiresAt == null || expiresAt.isAfter(Instant.now());
return new ConnectionStatusResponse(serviceType.name(), entity.getAppUrl(), entity.getUsername(),
expiresAt, connected);
return new ConnectionStatusResponse(serviceType.name(), entity.getAppUrl(),
entity.getUsername(), expiresAt, connected);
}
}
@@ -3,7 +3,6 @@ package com.vaessl.app.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ProblemDetail;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -24,7 +23,7 @@ public class GlobalExceptionHandler {
public ProblemDetail handleEmptyCredentialInput(MethodArgumentNotValidException e) {
String defaultMessages = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage).collect(Collectors.joining(", "));
.map(field -> field.getDefaultMessage()).collect(Collectors.joining(", "));
return ProblemDetail.forStatusAndDetail(BAD_REQUEST_EMPTY_FIELDS.getStatus(),
BAD_REQUEST_EMPTY_FIELDS.getMessage() + " [" + defaultMessages + "]");
@@ -14,6 +14,7 @@ public interface SearchProvider extends ServiceProvider {
* Executes a search query against the remote service and returns matching results.
*
* @param request the search request containing the query string, app URL, and user credentials
* @param pageable the Pageable interface
* @return a list of Page<SearchResponse> items matching the query
*/
Page<SearchResponse> getSearchResults(SearchRequest request, Pageable pageable);
@@ -1,8 +1,8 @@
package com.vaessl.app.search;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -16,8 +16,12 @@ public class SearchService {
private final Map<ServiceType, SearchProvider> providerRegistry;
public SearchService(List<SearchProvider> providers) {
this.providerRegistry = Map.copyOf(providers.stream()
.collect(Collectors.toMap(SearchProvider::getServiceType, p -> p)));
Map<ServiceType, SearchProvider> registry = new EnumMap<>(ServiceType.class);
for (SearchProvider provider : providers) {
registry.put(provider.getServiceType(), provider);
}
this.providerRegistry = registry;
}
/**