aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-db-dao/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-db-dao/src')
-rw-r--r--server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDaoIT.java109
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java7
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssueReleaseDto.java105
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesDao.java47
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesMapper.java32
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/sca/ScaIssuesReleasesMapper.xml59
-rw-r--r--server/sonar-db-dao/src/schema/schema-sq.ddl14
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaDependencyDtoTest.java2
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaIssueReleaseDtoTest.java38
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaReleaseDtoTest.java2
12 files changed, 417 insertions, 2 deletions
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDaoIT.java
new file mode 100644
index 00000000000..8a4f5d4bec7
--- /dev/null
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/sca/ScaIssuesReleasesDaoIT.java
@@ -0,0 +1,109 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.sca;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ScaIssuesReleasesDaoIT {
+
+ @RegisterExtension
+ private final DbTester db = DbTester.create(System2.INSTANCE);
+
+ private final ScaIssuesReleasesDao scaIssuesReleasesDao = db.getDbClient().scaIssuesReleasesDao();
+
+ private static ScaIssueReleaseDto newScaIssueReleaseDto(String suffix) {
+ return new ScaIssueReleaseDto("uuid" + suffix, "sca-issue-uuid" + suffix, "sca-release-uuid" + suffix, ScaSeverity.INFO, 1L, 2L);
+ }
+
+ @Test
+ void insert_shouldPersistScaIssuesReleases() {
+ ScaIssueReleaseDto issueReleaseDto = newScaIssueReleaseDto("1");
+
+ scaIssuesReleasesDao.insert(db.getSession(), issueReleaseDto);
+
+ List<Map<String, Object>> select = db.select(db.getSession(), "select * from sca_issues_releases");
+ assertThat(select).hasSize(1);
+ Map<String, Object> stringObjectMap = select.get(0);
+ assertThat(stringObjectMap).usingRecursiveComparison().isEqualTo(
+ Map.ofEntries(
+ Map.entry("uuid", issueReleaseDto.uuid()),
+ Map.entry("sca_issue_uuid", issueReleaseDto.scaIssueUuid()),
+ Map.entry("sca_release_uuid", issueReleaseDto.scaReleaseUuid()),
+ Map.entry("severity", issueReleaseDto.severity().name()),
+ Map.entry("severity_sort_key", (long) issueReleaseDto.severitySortKey()),
+ Map.entry("created_at", issueReleaseDto.createdAt()),
+ Map.entry("updated_at", issueReleaseDto.updatedAt())));
+ }
+
+ // Postgresql apparently doesn't support doing anything else in the session
+ // after a statement with an error (constraint violation), while other
+ // databases do. So we use a dedicated session here.
+ private void insertAndCommit(ScaIssueReleaseDto issueReleaseDto) {
+ try (var dbSession = db.getDbClient().openSession(false)) {
+ scaIssuesReleasesDao.insert(dbSession, issueReleaseDto);
+ dbSession.commit(true);
+ }
+ }
+
+ @Test
+ void insert_shouldFailOnDuplicateInsert() {
+ ScaIssueReleaseDto issueReleaseDto = newScaIssueReleaseDto("1");
+ try (var dbSession = db.getDbClient().openSession(false)) {
+ scaIssuesReleasesDao.insert(dbSession, issueReleaseDto);
+ dbSession.commit();
+ }
+
+ ScaIssueReleaseDto issueReleaseDtoDifferentUuid = new ScaIssueReleaseDto("uuid-different",
+ issueReleaseDto.scaIssueUuid(), issueReleaseDto.scaReleaseUuid(), ScaSeverity.INFO,
+ 10L, 11L);
+
+ assertThrows(PersistenceException.class, () -> insertAndCommit(issueReleaseDtoDifferentUuid));
+
+ try (var dbSession = db.getDbClient().openSession(false)) {
+ List<Map<String, Object>> select = db.select(dbSession, "select * from sca_issues_releases");
+ assertThat(select).hasSize(1);
+ Map<String, Object> stringObjectMap = select.get(0);
+ assertThat(stringObjectMap).containsEntry("uuid", issueReleaseDto.uuid());
+ }
+ }
+
+ @Test
+ void deleteByUuid_shouldDelete() {
+ var dbSession = db.getSession();
+ ScaIssueReleaseDto issueReleaseDto = newScaIssueReleaseDto("1");
+ scaIssuesReleasesDao.insert(dbSession, issueReleaseDto);
+ dbSession.commit();
+
+ assertThat(db.countRowsOfTable(dbSession, "sca_issues_releases")).isOne();
+
+ scaIssuesReleasesDao.deleteByUuid(dbSession, issueReleaseDto.uuid());
+
+ assertThat(db.countRowsOfTable(dbSession, "sca_issues_releases")).isZero();
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
index 49397cbcd1d..552520ed4ee 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
@@ -90,6 +90,7 @@ import org.sonar.db.rule.RuleDao;
import org.sonar.db.rule.RuleRepositoryDao;
import org.sonar.db.sca.ScaDependenciesDao;
import org.sonar.db.sca.ScaIssuesDao;
+import org.sonar.db.sca.ScaIssuesReleasesDao;
import org.sonar.db.sca.ScaReleasesDao;
import org.sonar.db.sca.ScaVulnerabilityIssuesDao;
import org.sonar.db.scannercache.ScannerAnalysisCacheDao;
@@ -190,6 +191,7 @@ public class DaoModule extends Module {
SamlMessageIdDao.class,
ScaDependenciesDao.class,
ScaIssuesDao.class,
+ ScaIssuesReleasesDao.class,
ScaReleasesDao.class,
ScaVulnerabilityIssuesDao.class,
ScannerAnalysisCacheDao.class,
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
index e3ea8c2aa7e..120a04adc3c 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
@@ -90,6 +90,7 @@ import org.sonar.db.rule.RuleDao;
import org.sonar.db.rule.RuleRepositoryDao;
import org.sonar.db.sca.ScaDependenciesDao;
import org.sonar.db.sca.ScaIssuesDao;
+import org.sonar.db.sca.ScaIssuesReleasesDao;
import org.sonar.db.sca.ScaReleasesDao;
import org.sonar.db.sca.ScaVulnerabilityIssuesDao;
import org.sonar.db.scannercache.ScannerAnalysisCacheDao;
@@ -207,6 +208,7 @@ public class DbClient {
private final ScaReleasesDao scaReleasesDao;
private final ScaDependenciesDao scaDependenciesDao;
private final ScaIssuesDao scaIssuesDao;
+ private final ScaIssuesReleasesDao scaIssuesReleasesDao;
private final ScaVulnerabilityIssuesDao scaVulnerabilityIssuesDao;
public DbClient(Database database, MyBatis myBatis, DBSessions dbSessions, Dao... daos) {
@@ -307,6 +309,7 @@ public class DbClient {
scaReleasesDao = getDao(map, ScaReleasesDao.class);
scaDependenciesDao = getDao(map, ScaDependenciesDao.class);
scaIssuesDao = getDao(map, ScaIssuesDao.class);
+ scaIssuesReleasesDao = getDao(map, ScaIssuesReleasesDao.class);
scaVulnerabilityIssuesDao = getDao(map, ScaVulnerabilityIssuesDao.class);
}
@@ -684,6 +687,10 @@ public class DbClient {
return scaIssuesDao;
}
+ public ScaIssuesReleasesDao scaIssuesReleasesDao() {
+ return scaIssuesReleasesDao;
+ }
+
public ScaVulnerabilityIssuesDao scaVulnerabilityIssuesDao() {
return scaVulnerabilityIssuesDao;
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
index 4c668866151..2de44b8eb92 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
@@ -154,6 +154,7 @@ import org.sonar.db.rule.RuleRepositoryMapper;
import org.sonar.db.sca.ScaDependenciesMapper;
import org.sonar.db.sca.ScaDependencyDto;
import org.sonar.db.sca.ScaIssuesMapper;
+import org.sonar.db.sca.ScaIssuesReleasesMapper;
import org.sonar.db.sca.ScaReleasesMapper;
import org.sonar.db.sca.ScaVulnerabilityIssuesMapper;
import org.sonar.db.scannercache.ScannerAnalysisCacheMapper;
@@ -347,6 +348,7 @@ public class MyBatis {
SamlMessageIdMapper.class,
ScaDependenciesMapper.class,
ScaIssuesMapper.class,
+ ScaIssuesReleasesMapper.class,
ScaReleasesMapper.class,
ScaVulnerabilityIssuesMapper.class,
ScannerAnalysisCacheMapper.class,
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssueReleaseDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssueReleaseDto.java
new file mode 100644
index 00000000000..98b1616a690
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssueReleaseDto.java
@@ -0,0 +1,105 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.sca;
+
+/**
+ * Represents a many-to-many join between Software Composition Analysis (SCA) issue and a SCA release.
+ *
+ * @param uuid primary key
+ * @param scaIssueUuid the UUID of the SCA issue
+ * @param scaReleaseUuid the UUID of the SCA release
+ * @param severity the severity of the issue
+ * @param createdAt timestamp of creation
+ * @param updatedAt timestamp of most recent update
+ */
+public record ScaIssueReleaseDto(
+ String uuid,
+ String scaIssueUuid,
+ String scaReleaseUuid,
+ ScaSeverity severity,
+ long createdAt,
+ long updatedAt) {
+
+ /**
+ * This constructor makes it a little harder to get the issue and release uuids backward,
+ * if you have the DTOs around to use it.
+ */
+ public ScaIssueReleaseDto(String uuid, ScaIssueDto scaIssueDto, ScaReleaseDto scaReleaseDto, ScaSeverity severity, long createdAt, long updatedAt) {
+ this(uuid, scaIssueDto.uuid(), scaReleaseDto.uuid(), severity, createdAt, updatedAt);
+ }
+
+ public int severitySortKey() {
+ return severity.databaseSortKey();
+ }
+
+ public Builder toBuilder() {
+ return new Builder()
+ .setUuid(this.uuid)
+ .setScaIssueUuid(this.scaIssueUuid)
+ .setScaReleaseUuid(this.scaReleaseUuid)
+ .setSeverity(this.severity)
+ .setCreatedAt(this.createdAt)
+ .setUpdatedAt(this.updatedAt);
+ }
+
+ public static class Builder {
+ private String uuid;
+ private String scaIssueUuid;
+ private String scaReleaseUuid;
+ private ScaSeverity severity;
+ private long createdAt;
+ private long updatedAt;
+
+ public Builder setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ public Builder setScaIssueUuid(String scaIssueUuid) {
+ this.scaIssueUuid = scaIssueUuid;
+ return this;
+ }
+
+ public Builder setScaReleaseUuid(String scaReleaseUuid) {
+ this.scaReleaseUuid = scaReleaseUuid;
+ return this;
+ }
+
+ public Builder setSeverity(ScaSeverity severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ public Builder setCreatedAt(long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public Builder setUpdatedAt(long updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ public ScaIssueReleaseDto build() {
+ return new ScaIssueReleaseDto(
+ uuid, scaIssueUuid, scaReleaseUuid, severity, createdAt, updatedAt);
+ }
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesDao.java
new file mode 100644
index 00000000000..710deb12d2c
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesDao.java
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.sca;
+
+import java.util.List;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+public class ScaIssuesReleasesDao implements Dao {
+
+ private static ScaIssuesReleasesMapper mapper(DbSession session) {
+ return session.getMapper(ScaIssuesReleasesMapper.class);
+ }
+
+ public void insert(DbSession session, ScaIssueReleaseDto scaIssueReleaseDto) {
+ mapper(session).insert(scaIssueReleaseDto);
+ }
+
+ public void update(DbSession session, ScaIssueReleaseDto scaIssueReleaseDto) {
+ mapper(session).update(scaIssueReleaseDto);
+ }
+
+ public void deleteByUuid(DbSession session, String uuid) {
+ mapper(session).deleteByUuid(uuid);
+ }
+
+ public List<ScaIssueReleaseDto> selectByBranchUuid(DbSession dbSession, String branchUuid) {
+ return mapper(dbSession).selectByBranchUuid(branchUuid);
+ }
+}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesMapper.java
new file mode 100644
index 00000000000..58c40fd1435
--- /dev/null
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/sca/ScaIssuesReleasesMapper.java
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.sca;
+
+import java.util.List;
+
+public interface ScaIssuesReleasesMapper {
+ void insert(ScaIssueReleaseDto dto);
+
+ void update(ScaIssueReleaseDto dto);
+
+ void deleteByUuid(String uuid);
+
+ List<ScaIssueReleaseDto> selectByBranchUuid(String branchUuid);
+}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/sca/ScaIssuesReleasesMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/sca/ScaIssuesReleasesMapper.xml
new file mode 100644
index 00000000000..38c7fb400e2
--- /dev/null
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/sca/ScaIssuesReleasesMapper.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
+<mapper namespace="org.sonar.db.sca.ScaIssuesReleasesMapper">
+ <sql id="scaIssuesReleasesColumns">
+ sir.uuid as uuid,
+ sir.sca_issue_uuid as scaIssueUuid,
+ sir.sca_release_uuid as scaReleaseUuid,
+ sir.severity as severity,
+ sir.created_at as createdAt,
+ sir.updated_at as updatedAt
+ </sql>
+
+ <insert id="insert" parameterType="org.sonar.db.sca.ScaIssueReleaseDto" useGeneratedKeys="false">
+ insert into sca_issues_releases (
+ uuid,
+ sca_issue_uuid,
+ sca_release_uuid,
+ severity,
+ severity_sort_key,
+ created_at,
+ updated_at
+ ) values (
+ #{uuid,jdbcType=VARCHAR},
+ #{scaIssueUuid,jdbcType=VARCHAR},
+ #{scaReleaseUuid,jdbcType=VARCHAR},
+ #{severity,jdbcType=VARCHAR},
+ #{severitySortKey,jdbcType=INTEGER},
+ #{createdAt,jdbcType=BIGINT},
+ #{updatedAt,jdbcType=BIGINT}
+ )
+ </insert>
+
+ <delete id="deleteByUuid" parameterType="string">
+ delete from sca_issues_releases
+ where uuid = #{uuid,jdbcType=VARCHAR}
+ </delete>
+
+ <update id="update" parameterType="org.sonar.db.sca.ScaIssueReleaseDto" useGeneratedKeys="false">
+ update sca_issues_releases
+ set
+ sca_issue_uuid = #{scaIssueUuid, jdbcType=VARCHAR},
+ sca_release_uuid = #{scaReleaseUuid, jdbcType=VARCHAR},
+ severity = #{severity, jdbcType=VARCHAR},
+ severity_sort_key = #{severitySortKey, jdbcType=VARCHAR},
+ updated_at = #{updatedAt, jdbcType=BIGINT}
+ where
+ uuid = #{uuid, jdbcType=VARCHAR}
+</update>
+
+
+ <select id="selectByBranchUuid" parameterType="string" resultType="org.sonar.db.sca.ScaIssueReleaseDto">
+ select <include refid="scaIssuesReleasesColumns"/>
+ from sca_issues_releases sir
+ inner join sca_releases sr on sir.sca_release_uuid = sr.uuid
+ inner join components c on sr.component_uuid = c.uuid
+ where c.branch_uuid = #{branchUuid,jdbcType=VARCHAR}
+ order by sir.uuid asc
+ </select>
+</mapper>
diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl
index b101c4fface..fdbc9970573 100644
--- a/server/sonar-db-dao/src/schema/schema-sq.ddl
+++ b/server/sonar-db-dao/src/schema/schema-sq.ddl
@@ -1058,6 +1058,20 @@ CREATE TABLE "SCA_ISSUES"(
ALTER TABLE "SCA_ISSUES" ADD CONSTRAINT "PK_SCA_ISSUES" PRIMARY KEY("UUID");
CREATE UNIQUE NULLS NOT DISTINCT INDEX "SCA_ISSUES_UNIQUE" ON "SCA_ISSUES"("SCA_ISSUE_TYPE" NULLS FIRST, "VULNERABILITY_ID" NULLS FIRST, "PACKAGE_URL" NULLS FIRST, "SPDX_LICENSE_ID" NULLS FIRST);
+CREATE TABLE "SCA_ISSUES_RELEASES"(
+ "UUID" CHARACTER VARYING(40) NOT NULL,
+ "SCA_ISSUE_UUID" CHARACTER VARYING(40) NOT NULL,
+ "SCA_RELEASE_UUID" CHARACTER VARYING(40) NOT NULL,
+ "SEVERITY" CHARACTER VARYING(15) NOT NULL,
+ "SEVERITY_SORT_KEY" INTEGER NOT NULL,
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL
+);
+ALTER TABLE "SCA_ISSUES_RELEASES" ADD CONSTRAINT "PK_SCA_ISSUES_RELEASES" PRIMARY KEY("UUID");
+CREATE INDEX "SCA_ISSUES_RELEASES_SCA_ISSUE" ON "SCA_ISSUES_RELEASES"("SCA_ISSUE_UUID" NULLS FIRST);
+CREATE INDEX "SCA_ISSUES_RELEASES_SCA_RELEAS" ON "SCA_ISSUES_RELEASES"("SCA_RELEASE_UUID" NULLS FIRST);
+CREATE UNIQUE NULLS NOT DISTINCT INDEX "SCA_ISSUES_RELEASES_UNIQUE" ON "SCA_ISSUES_RELEASES"("SCA_ISSUE_UUID" NULLS FIRST, "SCA_RELEASE_UUID" NULLS FIRST);
+
CREATE TABLE "SCA_RELEASES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
"COMPONENT_UUID" CHARACTER VARYING(40) NOT NULL,
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaDependencyDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaDependencyDtoTest.java
index dff74348819..bf899451fcb 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaDependencyDtoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaDependencyDtoTest.java
@@ -37,7 +37,7 @@ class ScaDependencyDtoTest {
List.of(List.of("pkg:npm/fodo@1.0.0")),
1L,
2L);
- assertThat(scaDependencyDto).isEqualTo(scaDependencyDto.toBuilder().build());
+ assertThat(scaDependencyDto.toBuilder().build()).isEqualTo(scaDependencyDto);
}
@Test
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaIssueReleaseDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaIssueReleaseDtoTest.java
new file mode 100644
index 00000000000..1a6a33a955a
--- /dev/null
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaIssueReleaseDtoTest.java
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2025 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.sca;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+class ScaIssueReleaseDtoTest {
+
+ @Test
+ void test_toBuilder_build_shouldRoundTrip() {
+ var scaIssueReleaseDto = new ScaIssueReleaseDto("sca-issue-release-uuid",
+ "sca-issue-uuid",
+ "sca-release-uuid",
+ ScaSeverity.INFO,
+ 1L,
+ 2L);
+ assertThat(scaIssueReleaseDto.toBuilder().build()).isEqualTo(scaIssueReleaseDto);
+ }
+}
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaReleaseDtoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaReleaseDtoTest.java
index 33324eaec0d..3b493e3c2a7 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaReleaseDtoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/sca/ScaReleaseDtoTest.java
@@ -37,6 +37,6 @@ class ScaReleaseDtoTest {
true,
1L,
2L);
- assertThat(scaReleaseDto).isEqualTo(scaReleaseDto.toBuilder().build());
+ assertThat(scaReleaseDto.toBuilder().build()).isEqualTo(scaReleaseDto);
}
}