aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gradle.properties2
-rw-r--r--server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java15
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java7
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java6
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml5
-rw-r--r--server/sonar-db-dao/src/schema/schema-sq.ddl11
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphsIT.java55
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphsIT.java53
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleasesIT.java53
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphsIT.java56
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphsIT.java59
-rw-r--r--server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRenameIT.java63
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202502/CreateUniqueIndexOnArchitectureGraphs.java29
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphs.java54
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphs.java54
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleases.java54
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphs.java61
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DbVersion202503.java6
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphs.java33
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRename.java33
-rw-r--r--server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java27
-rw-r--r--server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java14
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sca/CliService.java14
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/sca/CliServiceTest.java18
24 files changed, 735 insertions, 47 deletions
diff --git a/gradle.properties b/gradle.properties
index 6580826a45e..3346946ca26 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,4 +15,4 @@ elasticSearchServerVersion=8.16.3
projectType=application
artifactoryUrl=https://repox.jfrog.io/repox
jre_release_name=jdk-17.0.13+11
-webappVersion=2025.3.0.16221
+webappVersion=2025.3.0.16376
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java
index a7bf75927ec..b781c2ad344 100644
--- a/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java
+++ b/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java
@@ -2002,6 +2002,14 @@ oldCreationDate));
assertThat(db.countRowsOfTable(dbSession, "sca_issues_releases")).isEqualTo(2);
+ var issueReleaseChangeBase = Map.of("created_at", 0L, "updated_at", 0L);
+ db.executeInsert("sca_issue_rels_changes", merge(issueReleaseChangeBase, Map.of("uuid", "issue-release-change-uuid1",
+ "sca_issues_releases_uuid", "issue-release-uuid1")));
+ db.executeInsert("sca_issue_rels_changes", merge(issueReleaseChangeBase, Map.of("uuid", "issue-release-change-uuid2",
+ "sca_issues_releases_uuid", "issue-release-uuid2")));
+
+ assertThat(db.countRowsOfTable(dbSession, "sca_issue_rels_changes")).isEqualTo(2);
+
var analysisBase = Map.of(
"created_at", 0L,
"updated_at", 0L,
@@ -2031,6 +2039,7 @@ oldCreationDate));
assertThat(db.countRowsOfTable(dbSession, "sca_releases")).isEqualTo(1);
assertThat(db.countRowsOfTable(dbSession, "sca_dependencies")).isEqualTo(1);
assertThat(db.countRowsOfTable(dbSession, "sca_issues_releases")).isEqualTo(1);
+ assertThat(db.countRowsOfTable(dbSession, "sca_issue_rels_changes")).isEqualTo(1);
assertThat(db.countRowsOfTable(dbSession, "sca_analyses")).isEqualTo(1);
}
@@ -2064,9 +2073,9 @@ oldCreationDate));
BranchDto branch1 = db.components().insertProjectBranch(project);
BranchDto branch2 = db.components().insertProjectBranch(project);
- db.executeInsert("architecture_graphs", Map.of("uuid", "12345", "branch_uuid", branch1.getUuid(), "source", "xoo", "type", "file_graph", "graph_data", "{}"));
- db.executeInsert("architecture_graphs", Map.of("uuid", "123456", "branch_uuid", branch1.getUuid(), "source", "xoo", "type", "class_graph", "graph_data", "{}"));
- db.executeInsert("architecture_graphs", Map.of("uuid", "1234567", "branch_uuid", branch2.getUuid(), "source", "xoo", "type", "file_graph", "graph_data", "{}"));
+ db.executeInsert("architecture_graphs", Map.of("uuid", "12345", "branch_uuid", branch1.getUuid(), "ecosystem", "xoo", "type", "file_graph", "graph_data", "{}"));
+ db.executeInsert("architecture_graphs", Map.of("uuid", "123456", "branch_uuid", branch1.getUuid(), "ecosystem", "xoo", "type", "class_graph", "graph_data", "{}"));
+ db.executeInsert("architecture_graphs", Map.of("uuid", "1234567", "branch_uuid", branch2.getUuid(), "ecosystem", "xoo", "type", "file_graph", "graph_data", "{}"));
assertThat(db.countRowsOfTable(dbSession, "architecture_graphs")).isEqualTo(3);
underTest.deleteBranch(dbSession, branch1.getUuid());
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
index d818e2361cf..fca991f9f28 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java
@@ -543,6 +543,13 @@ class PurgeCommands {
session.commit();
profiler.stop();
+ // this must be done before deleting sca_issues_releases or we won't
+ // be able to find the rows
+ profiler.start("deleteScaIssuesReleasesChanges (sca_issue_rels_changes)");
+ purgeMapper.deleteScaIssuesReleasesChangesByComponentUuid(componentUuid);
+ session.commit();
+ profiler.stop();
+
profiler.start("deleteScaIssuesReleases (sca_issues_releases)");
purgeMapper.deleteScaIssuesReleasesByComponentUuid(componentUuid);
session.commit();
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
index 2502ac8e5d8..ab4b369aef6 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
@@ -201,9 +201,11 @@ public interface PurgeMapper {
void deleteScaIssuesReleasesByComponentUuid(@Param("componentUuid") String componentUuid);
- void deleteScaReleasesByComponentUuid(@Param("componentUuid") String componentUuid);
+ void deleteScaIssuesReleasesChangesByComponentUuid(@Param("componentUuid") String componentUuid);
- void deleteArchitectureGraphsByBranchUuid(@Param("branchUuid") String branchUuid);
+ void deleteScaReleasesByComponentUuid(@Param("componentUuid") String componentUuid);
void deleteScaLicenseProfileProjectsByProjectUuid(@Param("projectUuid") String projectUuid);
+
+ void deleteArchitectureGraphsByBranchUuid(@Param("branchUuid") String branchUuid);
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
index 9b0b865fc36..bc5c066d6b4 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
@@ -683,6 +683,11 @@
<delete id="deleteScaIssuesReleasesByComponentUuid">
delete from sca_issues_releases where sca_release_uuid in (select uuid from sca_releases where component_uuid = #{componentUuid,jdbcType=VARCHAR})
</delete>
+ <delete id="deleteScaIssuesReleasesChangesByComponentUuid">
+ delete from sca_issue_rels_changes where sca_issues_releases_uuid in
+ (select sca_issues_releases.uuid from sca_issues_releases join sca_releases on sca_releases.uuid = sca_issues_releases.sca_release_uuid
+ where sca_releases.component_uuid = #{componentUuid,jdbcType=VARCHAR})
+ </delete>
<delete id="deleteScaReleasesByComponentUuid">
delete from sca_releases where component_uuid = #{componentUuid,jdbcType=VARCHAR}
</delete>
diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl
index 1f942ae9125..44464c73e4d 100644
--- a/server/sonar-db-dao/src/schema/schema-sq.ddl
+++ b/server/sonar-db-dao/src/schema/schema-sq.ddl
@@ -121,12 +121,14 @@ CREATE INDEX "IDX_APP_PROJ_PROJECT_UUID" ON "APP_PROJECTS"("PROJECT_UUID" NULLS
CREATE TABLE "ARCHITECTURE_GRAPHS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
"BRANCH_UUID" CHARACTER VARYING(40) NOT NULL,
- "SOURCE" CHARACTER VARYING(255) NOT NULL,
+ "ECOSYSTEM" CHARACTER VARYING(255) NOT NULL,
"TYPE" CHARACTER VARYING(255) NOT NULL,
- "GRAPH_DATA" CHARACTER LARGE OBJECT NOT NULL
+ "GRAPH_DATA" CHARACTER LARGE OBJECT NOT NULL,
+ "ANALYSIS_UUID" CHARACTER VARYING(40),
+ "PERSPECTIVE_KEY" CHARACTER VARYING(255)
);
ALTER TABLE "ARCHITECTURE_GRAPHS" ADD CONSTRAINT "PK_ARCHITECTURE_GRAPHS" PRIMARY KEY("UUID");
-CREATE UNIQUE NULLS NOT DISTINCT INDEX "UQ_IDX_AG_BRANCH_TYPE_SOURCE" ON "ARCHITECTURE_GRAPHS"("BRANCH_UUID" NULLS FIRST, "TYPE" NULLS FIRST, "SOURCE" NULLS FIRST);
+CREATE UNIQUE NULLS NOT DISTINCT INDEX "UQ_IDX_AG_BRCH_TP_SRC_PSPCTV" ON "ARCHITECTURE_GRAPHS"("BRANCH_UUID" NULLS FIRST, "TYPE" NULLS FIRST, "ECOSYSTEM" NULLS FIRST, "PERSPECTIVE_KEY" NULLS FIRST);
CREATE TABLE "AUDITS"(
"UUID" CHARACTER VARYING(40) NOT NULL,
@@ -1113,7 +1115,8 @@ CREATE TABLE "SCA_ISSUES_RELEASES"(
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL,
"STATUS" CHARACTER VARYING(40) NOT NULL,
- "ASSIGNEE_UUID" CHARACTER VARYING(40)
+ "ASSIGNEE_UUID" CHARACTER VARYING(40),
+ "PREVIOUS_MANUAL_STATUS" CHARACTER VARYING(40)
);
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);
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphsIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphsIT.java
new file mode 100644
index 00000000000..167b797de15
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphsIT.java
@@ -0,0 +1,55 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static java.sql.Types.VARCHAR;
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+
+class AddAnalysisUuidOnArchitectureGraphsIT {
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String COLUMN_NAME = "analysis_uuid";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(AddAnalysisUuidOnArchitectureGraphs.class);
+ private final DdlChange underTest = new AddAnalysisUuidOnArchitectureGraphs(db.database());
+
+ @Test
+ void execute_shouldAddColumn() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, VARCHAR, VarcharColumnDef.UUID_SIZE, true);
+ }
+
+ @Test
+ void execute_shouldBeReentrant() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, VARCHAR, VarcharColumnDef.UUID_SIZE, true);
+ }
+}
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphsIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphsIT.java
new file mode 100644
index 00000000000..22f757cd152
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphsIT.java
@@ -0,0 +1,53 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static java.sql.Types.VARCHAR;
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+class AddPerspectiveKeyOnArchitectureGraphsIT {
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String COLUMN_NAME = "perspective_key";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(AddPerspectiveKeyOnArchitectureGraphs.class);
+ private final DdlChange underTest = new AddPerspectiveKeyOnArchitectureGraphs(db.database());
+
+ @Test
+ void execute_shouldAddColumn() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, VARCHAR, 255, true);
+ }
+
+ @Test
+ void execute_shouldBeReentrant() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, VARCHAR, 255, true);
+ }
+}
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleasesIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleasesIT.java
new file mode 100644
index 00000000000..cf293d4c9bd
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleasesIT.java
@@ -0,0 +1,53 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static java.sql.Types.VARCHAR;
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+class AddPreviousManualStatusToScaIssuesReleasesIT {
+ private static final String TABLE_NAME = "sca_issues_releases";
+ private static final String COLUMN_NAME = "previous_manual_status";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(AddPreviousManualStatusToScaIssuesReleases.class);
+ private final DdlChange underTest = new AddPreviousManualStatusToScaIssuesReleases(db.database());
+
+ @Test
+ void execute_shouldAddColumn() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, VARCHAR, 40, true);
+ }
+
+ @Test
+ void execute_shouldBeReentrant() throws SQLException {
+ db.assertColumnDoesNotExist(TABLE_NAME, COLUMN_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertColumnDefinition(TABLE_NAME, COLUMN_NAME, VARCHAR, 40, true);
+ }
+}
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphsIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphsIT.java
new file mode 100644
index 00000000000..8cd566df9ce
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphsIT.java
@@ -0,0 +1,56 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+class CreateUniqueIndexOnArchitectureGraphsIT {
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String INDEX_NAME = "uq_idx_ag_brch_tp_src_pspctv";
+ private static final String COLUMN_NAME_BRANCH_UUID = "branch_uuid";
+ private static final String COLUMN_NAME_TYPE = "type";
+ private static final String COLUMN_NAME_ECOSYSTEM = "ecosystem";
+ private static final String COLUMN_NAME_PERSPECTIVE_KEY = "perspective_key";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(CreateUniqueIndexOnArchitectureGraphs.class);
+ private final DdlChange underTest = new CreateUniqueIndexOnArchitectureGraphs(db.database());
+
+ @Test
+ void execute_shouldCreateIndex() throws SQLException {
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+ underTest.execute();
+ db.assertUniqueIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME_BRANCH_UUID, COLUMN_NAME_TYPE, COLUMN_NAME_ECOSYSTEM, COLUMN_NAME_PERSPECTIVE_KEY);
+ }
+
+ @Test
+ void execute_shouldBeReentrant() throws SQLException {
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+ underTest.execute();
+ underTest.execute();
+ db.assertUniqueIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME_BRANCH_UUID, COLUMN_NAME_TYPE, COLUMN_NAME_ECOSYSTEM, COLUMN_NAME_PERSPECTIVE_KEY);
+ }
+}
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphsIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphsIT.java
new file mode 100644
index 00000000000..646be1f2f7c
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphsIT.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+class DropIndexOnArchitectureGraphsIT {
+
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String COLUMN_NAME_BRANCH_UUID = "branch_uuid";
+ private static final String COLUMN_NAME_TYPE = "type";
+ private static final String COLUMN_NAME_SOURCE = "source";
+ private static final String INDEX_NAME = "uq_idx_ag_branch_type_source";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(DropIndexOnArchitectureGraphs.class);
+ private final DropIndexOnArchitectureGraphs underTest = new DropIndexOnArchitectureGraphs(db.database());
+
+ @Test
+ void index_is_dropped() throws SQLException {
+ db.assertUniqueIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME_BRANCH_UUID, COLUMN_NAME_TYPE, COLUMN_NAME_SOURCE);
+
+ underTest.execute();
+
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+ }
+
+ @Test
+ void migration_is_reentrant() throws SQLException {
+ db.assertUniqueIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME_BRANCH_UUID, COLUMN_NAME_TYPE, COLUMN_NAME_SOURCE);
+
+ underTest.execute();
+ underTest.execute();
+
+ db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME);
+ }
+}
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRenameIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRenameIT.java
new file mode 100644
index 00000000000..81c377724e9
--- /dev/null
+++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRenameIT.java
@@ -0,0 +1,63 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.sonar.db.MigrationDbTester;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static java.sql.Types.VARCHAR;
+import static org.sonar.db.MigrationDbTester.createForMigrationStep;
+
+class UpdateArchitectureGraphsSourceColumnRenameIT {
+
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String OLD_COLUMN = "source";
+ private static final String NEW_COLUMN = "ecosystem";
+
+ @RegisterExtension
+ public final MigrationDbTester db = createForMigrationStep(UpdateArchitectureGraphsSourceColumnRename.class);
+ private final DdlChange underTest = new UpdateArchitectureGraphsSourceColumnRename(db.database());
+
+ @Test
+ void execute_shouldUpdateColumn() throws SQLException {
+ db.assertColumnDefinition(TABLE_NAME, OLD_COLUMN, VARCHAR, null, null);
+ db.assertColumnDoesNotExist(TABLE_NAME, NEW_COLUMN);
+
+ underTest.execute();
+
+ db.assertColumnDoesNotExist(TABLE_NAME, OLD_COLUMN);
+ db.assertColumnDefinition(TABLE_NAME, NEW_COLUMN, VARCHAR, null, null);
+ }
+
+ @Test
+ void execute_shouldBeReentrant() throws SQLException {
+ db.assertColumnDefinition(TABLE_NAME, OLD_COLUMN, VARCHAR, null, null);
+ db.assertColumnDoesNotExist(TABLE_NAME, NEW_COLUMN);
+
+ underTest.execute();
+ underTest.execute();
+
+ db.assertColumnDoesNotExist(TABLE_NAME, OLD_COLUMN);
+ db.assertColumnDefinition(TABLE_NAME, NEW_COLUMN, VARCHAR, null, null);
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202502/CreateUniqueIndexOnArchitectureGraphs.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202502/CreateUniqueIndexOnArchitectureGraphs.java
index 802396d18b1..2664ff7c0e9 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202502/CreateUniqueIndexOnArchitectureGraphs.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202502/CreateUniqueIndexOnArchitectureGraphs.java
@@ -46,15 +46,26 @@ public class CreateUniqueIndexOnArchitectureGraphs extends DdlChange {
}
private void createIndex(Context context, Connection connection) {
- if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
- context.execute(new CreateIndexBuilder(getDialect())
- .setTable(TABLE_NAME)
- .setName(INDEX_NAME)
- .setUnique(true)
- .addColumn(COLUMN_NAME_BRANCH_UUID, false)
- .addColumn(COLUMN_NAME_TYPE, false)
- .addColumn(COLUMN_NAME_SOURCE, false)
- .build());
+ if(!DatabaseUtils.tableColumnExists(connection, TABLE_NAME, COLUMN_NAME_BRANCH_UUID)) {
+ return;
}
+ if(!DatabaseUtils.tableColumnExists(connection, TABLE_NAME, COLUMN_NAME_TYPE)) {
+ return;
+ }
+ if(!DatabaseUtils.tableColumnExists(connection, TABLE_NAME, COLUMN_NAME_SOURCE)) {
+ return;
+ }
+ if (DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
+ return;
+ }
+
+ context.execute(new CreateIndexBuilder(getDialect())
+ .setTable(TABLE_NAME)
+ .setName(INDEX_NAME)
+ .setUnique(true)
+ .addColumn(COLUMN_NAME_BRANCH_UUID, false)
+ .addColumn(COLUMN_NAME_TYPE, false)
+ .addColumn(COLUMN_NAME_SOURCE, false)
+ .build());
}
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphs.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphs.java
new file mode 100644
index 00000000000..1110d46c570
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddAnalysisUuidOnArchitectureGraphs.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.db.DatabaseUtils.tableColumnExists;
+
+public class AddAnalysisUuidOnArchitectureGraphs extends DdlChange {
+ static final String TABLE_NAME = "architecture_graphs";
+ static final String COLUMN_NAME = "analysis_uuid";
+
+ public AddAnalysisUuidOnArchitectureGraphs(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(DdlChange.Context context) throws SQLException {
+ try (var connection = getDatabase().getDataSource().getConnection()) {
+ if (!tableColumnExists(connection, TABLE_NAME, COLUMN_NAME)) {
+ var columnDef = VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName(COLUMN_NAME)
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .setIsNullable(true)
+ .build();
+
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(columnDef)
+ .build());
+ }
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphs.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphs.java
new file mode 100644
index 00000000000..994e05650a0
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPerspectiveKeyOnArchitectureGraphs.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.db.DatabaseUtils.tableColumnExists;
+
+public class AddPerspectiveKeyOnArchitectureGraphs extends DdlChange {
+ static final String TABLE_NAME = "architecture_graphs";
+ static final String COLUMN_NAME = "perspective_key";
+
+ public AddPerspectiveKeyOnArchitectureGraphs(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (var connection = getDatabase().getDataSource().getConnection()) {
+ if (!tableColumnExists(connection, TABLE_NAME, COLUMN_NAME)) {
+ var columnDef = VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName(COLUMN_NAME)
+ .setLimit(255)
+ .setIsNullable(true)
+ .build();
+
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(columnDef)
+ .build());
+ }
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleases.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleases.java
new file mode 100644
index 00000000000..fb5514c42e9
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/AddPreviousManualStatusToScaIssuesReleases.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.db.DatabaseUtils.tableColumnExists;
+
+public class AddPreviousManualStatusToScaIssuesReleases extends DdlChange {
+ static final String TABLE_NAME = "sca_issues_releases";
+ static final String COLUMN_NAME = "previous_manual_status";
+
+ public AddPreviousManualStatusToScaIssuesReleases(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (var connection = getDatabase().getDataSource().getConnection()) {
+ if (!tableColumnExists(connection, TABLE_NAME, COLUMN_NAME)) {
+ var columnDef = VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName(COLUMN_NAME)
+ .setLimit(40)
+ .setIsNullable(true)
+ .build();
+
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME)
+ .addColumn(columnDef)
+ .build());
+ }
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphs.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphs.java
new file mode 100644
index 00000000000..1be744195c9
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/CreateUniqueIndexOnArchitectureGraphs.java
@@ -0,0 +1,61 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class CreateUniqueIndexOnArchitectureGraphs extends DdlChange {
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String INDEX_NAME = "uq_idx_ag_brch_tp_src_pspctv";
+ private static final String COLUMN_NAME_BRANCH_UUID = "branch_uuid";
+ private static final String COLUMN_NAME_TYPE = "type";
+ private static final String COLUMN_NAME_ECOSYSTEM = "ecosystem";
+ private static final String COLUMN_NAME_PERSPECTIVE_KEY = "perspective_key";
+
+ public CreateUniqueIndexOnArchitectureGraphs(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
+ createIndex(context, connection);
+ }
+ }
+
+ private void createIndex(Context context, Connection connection) {
+ if (!DatabaseUtils.indexExistsIgnoreCase(TABLE_NAME, INDEX_NAME, connection)) {
+ context.execute(new CreateIndexBuilder(getDialect())
+ .setTable(TABLE_NAME)
+ .setName(INDEX_NAME)
+ .setUnique(true)
+ .addColumn(COLUMN_NAME_BRANCH_UUID, false)
+ .addColumn(COLUMN_NAME_TYPE, false)
+ .addColumn(COLUMN_NAME_ECOSYSTEM, false)
+ .addColumn(COLUMN_NAME_PERSPECTIVE_KEY, true) // nullable
+ .build());
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DbVersion202503.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DbVersion202503.java
index d5be336bce6..ef284c6614f 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DbVersion202503.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DbVersion202503.java
@@ -68,6 +68,12 @@ public class DbVersion202503 implements DbVersion {
.add(2025_03_029, "Create unique index on SCA releases table", CreateUniqueIndexOnScaReleases.class)
.add(2025_03_030, "Create SCA analyses table", CreateScaAnalysesTable.class)
.add(2025_03_031, "Create unique index on SCA analyses table", CreateUniqueIndexOnScaAnalyses.class)
+ .add(2025_03_032, "Add 'analysis_uuid' column to 'architecture_graphs' table", AddAnalysisUuidOnArchitectureGraphs.class)
+ .add(2025_03_033, "Add 'perspective_key' column to 'architecture_graphs' table", AddPerspectiveKeyOnArchitectureGraphs.class)
+ .add(2025_03_034, "Drop unique index on 'architecture_graphs' table", DropIndexOnArchitectureGraphs.class)
+ .add(2025_03_035, "Rename column 'source' to 'ecosystem' on 'architecture_graphs' table", UpdateArchitectureGraphsSourceColumnRename.class)
+ .add(2025_03_036, "Create unique index on 'architecture_graphs' table", CreateUniqueIndexOnArchitectureGraphs.class)
+ .add(2025_03_037, "Add previous_manual_status to SCA issues releases", AddPreviousManualStatusToScaIssuesReleases.class)
;
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphs.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphs.java
new file mode 100644
index 00000000000..d48236d6d76
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/DropIndexOnArchitectureGraphs.java
@@ -0,0 +1,33 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DropIndexChange;
+
+public class DropIndexOnArchitectureGraphs extends DropIndexChange {
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String INDEX_NAME = "uq_idx_ag_branch_type_source";
+
+ public DropIndexOnArchitectureGraphs(Database db) {
+ super(db, INDEX_NAME, TABLE_NAME);
+ }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRename.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRename.java
new file mode 100644
index 00000000000..0a19b0046f9
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v202503/UpdateArchitectureGraphsSourceColumnRename.java
@@ -0,0 +1,33 @@
+/*
+ * 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.server.platform.db.migration.version.v202503;
+
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.RenameVarcharColumnChange;
+
+public class UpdateArchitectureGraphsSourceColumnRename extends RenameVarcharColumnChange {
+ private static final String TABLE_NAME = "architecture_graphs";
+ private static final String OLD_COLUMN_NAME = "source";
+ private static final String NEW_COLUMN_NAME = "ecosystem";
+
+ public UpdateArchitectureGraphsSourceColumnRename(Database db) {
+ super(db, TABLE_NAME, OLD_COLUMN_NAME, NEW_COLUMN_NAME);
+ }
+}
diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
index 72b3bd272f0..9df2bb74034 100644
--- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
+++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
@@ -543,9 +543,8 @@ public class IssueIndex {
addImpactFilters(query, filters);
addComponentRelatedFilters(query, filters);
addDatesFilter(filters, query);
- addCreatedAfterByProjectsFilter(filters, query);
+ addNewCodeByProjectsFilter(filters, query);
addNewCodeReferenceFilter(filters, query);
- addNewCodeReferenceFilterByProjectsFilter(filters, query);
return filters;
}
@@ -873,29 +872,19 @@ public class IssueIndex {
}
}
- private static void addNewCodeReferenceFilterByProjectsFilter(AllFilters allFilters, IssueQuery query) {
- Collection<String> newCodeOnReferenceByProjectUuids = query.newCodeOnReferenceByProjectUuids();
- BoolQueryBuilder boolQueryBuilder = boolQuery();
-
- if (!newCodeOnReferenceByProjectUuids.isEmpty()) {
-
- newCodeOnReferenceByProjectUuids.forEach(projectOrProjectBranchUuid -> boolQueryBuilder.should(boolQuery()
- .filter(termQuery(FIELD_ISSUE_BRANCH_UUID, projectOrProjectBranchUuid))
- .filter(termQuery(FIELD_ISSUE_NEW_CODE_REFERENCE, true))));
-
- allFilters.addFilter("__is_new_code_reference_by_project_uuids",
- new SimpleFieldFilterScope("newCodeReferenceByProjectUuids"), boolQueryBuilder);
- }
- }
-
- private static void addCreatedAfterByProjectsFilter(AllFilters allFilters, IssueQuery query) {
+ private static void addNewCodeByProjectsFilter(AllFilters allFilters, IssueQuery query) {
Map<String, PeriodStart> createdAfterByProjectUuids = query.createdAfterByProjectUuids();
BoolQueryBuilder boolQueryBuilder = boolQuery();
createdAfterByProjectUuids.forEach((projectOrProjectBranchUuid, createdAfterDate) -> boolQueryBuilder.should(boolQuery()
.filter(termQuery(FIELD_ISSUE_BRANCH_UUID, projectOrProjectBranchUuid))
.filter(rangeQuery(FIELD_ISSUE_FUNC_CREATED_AT).from(createdAfterDate.date().getTime(), createdAfterDate.inclusive()))));
- allFilters.addFilter("__created_after_by_project_uuids", new SimpleFieldFilterScope("createdAfterByProjectUuids"), boolQueryBuilder);
+ Collection<String> newCodeOnReferenceByProjectUuids = query.newCodeOnReferenceByProjectUuids();
+ newCodeOnReferenceByProjectUuids.forEach(projectOrProjectBranchUuid -> boolQueryBuilder.should(boolQuery()
+ .filter(termQuery(FIELD_ISSUE_BRANCH_UUID, projectOrProjectBranchUuid))
+ .filter(termQuery(FIELD_ISSUE_NEW_CODE_REFERENCE, true))));
+
+ allFilters.addFilter("__new_code_by_project_uuids", new SimpleFieldFilterScope("newCodeByProjectUuids"), boolQueryBuilder);
}
private void validateCreationDateBounds(@Nullable Date createdBefore, @Nullable Date createdAfter) {
diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java
index 23daad4fed0..e0fa9ca61cc 100644
--- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java
+++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java
@@ -456,7 +456,7 @@ class IssueIndexFiltersTest extends IssueIndexTestCommon {
}
@Test
- void filter_by_new_code_reference_branches() {
+ void filter_by_new_reference_branches() {
ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
IssueDoc project1Issue1 = newDocForProject(project1).setIsNewCodeReference(true);
IssueDoc project1Issue2 = newDocForProject(project1).setIsNewCodeReference(false);
@@ -474,14 +474,20 @@ class IssueIndexFiltersTest extends IssueIndexTestCommon {
IssueDoc project2Branch1Issue1 = newDoc(project2Branch1, project2.uuid()).setIsNewCodeReference(false);
IssueDoc project2Branch1Issue2 = newDoc(project2Branch1, project2.uuid()).setIsNewCodeReference(true);
+ ComponentDto project3 = db.components().insertPrivateProject().getMainBranchComponent();
+ ComponentDto project3Branch1 = db.components().insertProjectBranch(project2);
+ IssueDoc project3Issue1 = newDoc(project3Branch1, project3.uuid()).setFuncCreationDate(new Date(1000L));
+ IssueDoc project3Issue2 = newDoc(project3Branch1, project3.uuid()).setFuncCreationDate(new Date(2000L));
+
indexIssues(project1Issue1, project1Issue2, project2Issue1, project2Issue2,
- project1Branch1Issue1, project1Branch1Issue2, project2Branch1Issue1, project2Branch1Issue2);
+ project1Branch1Issue1, project1Branch1Issue2, project2Branch1Issue1, project2Branch1Issue2, project3Issue1, project3Issue2);
// Search for issues of project 1 branch 1 and project 2 branch 1 that are new code on a branch using reference for new code
assertThatSearchReturnsOnly(IssueQuery.builder()
.mainBranch(false)
- .newCodeOnReferenceByProjectUuids(Set.of(project1Branch1.uuid(), project2Branch1.uuid())),
- project1Branch1Issue2.key(), project2Branch1Issue2.key());
+ .newCodeOnReferenceByProjectUuids(Set.of(project1Branch1.uuid(), project2Branch1.uuid()))
+ .createdAfterByProjectUuids(Map.of(project3Branch1.uuid(), new IssueQuery.PeriodStart(new Date(1500), false))),
+ project1Branch1Issue2.key(), project2Branch1Issue2.key(), project3Issue2.key());
}
@Test
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sca/CliService.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sca/CliService.java
index 6fe099a7209..530798c4395 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sca/CliService.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sca/CliService.java
@@ -37,12 +37,14 @@ import org.apache.commons.csv.CSVPrinter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
+import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.System2;
import org.sonar.core.util.ProcessWrapperFactory;
import org.sonar.scanner.config.DefaultConfiguration;
import org.sonar.scanner.repository.TelemetryCache;
+import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
import org.sonar.scanner.scm.ScmConfiguration;
import org.sonar.scm.git.JGitUtils;
@@ -62,13 +64,16 @@ public class CliService {
private final System2 system2;
private final Server server;
private final ScmConfiguration scmConfiguration;
+ private final ProjectExclusionFilters projectExclusionFilters;
- public CliService(ProcessWrapperFactory processWrapperFactory, TelemetryCache telemetryCache, System2 system2, Server server, ScmConfiguration scmConfiguration) {
+ public CliService(ProcessWrapperFactory processWrapperFactory, TelemetryCache telemetryCache, System2 system2, Server server, ScmConfiguration scmConfiguration,
+ ProjectExclusionFilters projectExclusionFilters) {
this.processWrapperFactory = processWrapperFactory;
this.telemetryCache = telemetryCache;
this.system2 = system2;
this.server = server;
this.scmConfiguration = scmConfiguration;
+ this.projectExclusionFilters = projectExclusionFilters;
}
public File generateManifestsZip(DefaultInputModule module, File cliExecutable, DefaultConfiguration configuration) throws IOException, IllegalStateException {
@@ -123,7 +128,7 @@ public class CliService {
}
private @Nullable String getExcludeFlag(DefaultInputModule module, DefaultConfiguration configuration) throws IOException {
- List<String> configExcludedPaths = getConfigExcludedPaths(configuration);
+ List<String> configExcludedPaths = getConfigExcludedPaths(configuration, projectExclusionFilters);
List<String> scmIgnoredPaths = getScmIgnoredPaths(module);
ArrayList<String> mergedExclusionPaths = new ArrayList<>();
@@ -143,11 +148,12 @@ public class CliService {
return toCsvString(mergedExclusionPaths);
}
- private static List<String> getConfigExcludedPaths(DefaultConfiguration configuration) {
+ private static List<String> getConfigExcludedPaths(DefaultConfiguration configuration, ProjectExclusionFilters projectExclusionFilters) {
+ String[] sonarExclusions = projectExclusionFilters.getExclusionsConfig(InputFile.Type.MAIN);
String[] scaExclusions = configuration.getStringArray(SCA_EXCLUSIONS_KEY);
String[] scaExclusionsLegacy = configuration.getStringArray(LEGACY_SCA_EXCLUSIONS_KEY);
- return Stream.of(scaExclusions, scaExclusionsLegacy)
+ return Stream.of(sonarExclusions, scaExclusions, scaExclusionsLegacy)
.flatMap(Arrays::stream)
.distinct()
.toList();
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sca/CliServiceTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sca/CliServiceTest.java
index a6b10a95efa..7926860b731 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sca/CliServiceTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sca/CliServiceTest.java
@@ -36,6 +36,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.MockedStatic;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.platform.Server;
@@ -44,6 +45,7 @@ import org.sonar.api.utils.System2;
import org.sonar.core.util.ProcessWrapperFactory;
import org.sonar.scanner.config.DefaultConfiguration;
import org.sonar.scanner.repository.TelemetryCache;
+import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
import org.sonar.scanner.scm.ScmConfiguration;
import org.sonar.scm.git.GitScmProvider;
import org.sonar.scm.git.JGitUtils;
@@ -69,6 +71,7 @@ class CliServiceTest {
ProcessWrapperFactory processWrapperFactory = mock(ProcessWrapperFactory.class, CALLS_REAL_METHODS);
private MockedStatic<JGitUtils> jGitUtilsMock;
DefaultConfiguration configuration = mock(DefaultConfiguration.class);
+ ProjectExclusionFilters projectExclusionFilters = mock(ProjectExclusionFilters.class);
private CliService underTest;
@@ -86,11 +89,12 @@ class CliServiceTest {
jGitUtilsMock.when(() -> JGitUtils.getAllIgnoredPaths(any(Path.class))).thenReturn(List.of("ignored.txt"));
when(server.getVersion()).thenReturn("1.0.0");
logTester.setLevel(INFO);
+ when(projectExclusionFilters.getExclusionsConfig(InputFile.Type.MAIN)).thenReturn(new String[0]);
when(configuration.getStringArray(CliService.SCA_EXCLUSIONS_KEY)).thenReturn(new String[0]);
when(configuration.getStringArray(CliService.LEGACY_SCA_EXCLUSIONS_KEY)).thenReturn(new String[0]);
when(configuration.getBoolean("sonar.sca.debug")).thenReturn(Optional.of(true));
- underTest = new CliService(processWrapperFactory, telemetryCache, System2.INSTANCE, server, scmConfiguration);
+ underTest = new CliService(processWrapperFactory, telemetryCache, System2.INSTANCE, server, scmConfiguration, projectExclusionFilters);
}
@AfterEach
@@ -297,6 +301,18 @@ class CliServiceTest {
}
@Test
+ void generateZip_withExcludedManifestsAndSonarExcludesContainingDupes_mergesAndDedupes() throws Exception {
+ when(projectExclusionFilters.getExclusionsConfig(InputFile.Type.MAIN)).thenReturn(new String[] {"**/test1/**", "**/test4/**"});
+ when(configuration.getStringArray(CliService.SCA_EXCLUSIONS_KEY)).thenReturn(new String[] {"**/test1/**", "**/test2/**", "**/test1/**"});
+ when(configuration.getStringArray(CliService.LEGACY_SCA_EXCLUSIONS_KEY)).thenReturn(new String[] {"**/test1/**", "**/test3/**"});
+
+ underTest.generateManifestsZip(rootInputModule, scriptDir(), configuration);
+
+ String capturedArgs = logTester.logs().stream().filter(log -> log.contains("Arguments Passed In:")).findFirst().get();
+ assertThat(capturedArgs).contains("--exclude **/test1/**,**/test4/**,**/test2/**,**/test3/**,ignored.txt,.scannerwork/**");
+ }
+
+ @Test
void generateZip_withScmIgnoresContainingBadCharacters_handlesTheBadCharacters() throws Exception {
jGitUtilsMock.when(() -> JGitUtils.getAllIgnoredPaths(any(Path.class)))
.thenReturn(List.of("**/test/**", "**/path with spaces/**", "**/path,with,commas/**", "**/path'with'quotes/**", "**/path\"with\"double\"quotes/**"));