From c28353ec8b036b74bb070ca03420bfea29b1ca8d Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Thu, 28 Apr 2022 16:22:34 -0500 Subject: [PATCH] SONAR-16316 DAO to fetch report issues from DB SONAR-16316 Export CSV files with issues SONAR-16316 Create Web API 'api/regulatory_reports/download' SONAR-16316 Export Scanner Context SONAR-16316 Write report zip file SONAR-16316 Integrate pdf report in zip file --- .../src/main/java/org/sonar/db/DaoModule.java | 2 + .../src/main/java/org/sonar/db/DbClient.java | 7 ++ .../src/main/java/org/sonar/db/MyBatis.java | 2 + .../db/newcodeperiod/NewCodePeriodDao.java | 7 ++ .../org/sonar/db/report/IssueFindingDto.java | 108 ++++++++++++++++++ .../sonar/db/report/RegulatoryReportDao.java | 35 ++++++ .../db/report/RegulatoryReportMapper.java | 26 +++++ .../org/sonar/db/report/package-info.java | 24 ++++ .../db/report/RegulatoryReportMapper.xml | 36 ++++++ .../db/report/RegulatoryReportDaoTest.java | 87 ++++++++++++++ .../org/sonar/db/issue/IssueDbTester.java | 5 + .../sonar/server/plugins/PluginJarLoader.java | 3 +- .../platform/monitoring/SettingsSection.java | 14 +-- 13 files changed, 345 insertions(+), 11 deletions(-) create mode 100644 server/sonar-db-dao/src/main/java/org/sonar/db/report/IssueFindingDto.java create mode 100644 server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportDao.java create mode 100644 server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportMapper.java create mode 100644 server/sonar-db-dao/src/main/java/org/sonar/db/report/package-info.java create mode 100644 server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml create mode 100644 server/sonar-db-dao/src/test/java/org/sonar/db/report/RegulatoryReportDaoTest.java 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 c0c487f2f34..01893f01de6 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 @@ -75,6 +75,7 @@ import org.sonar.db.qualityprofile.QProfileEditGroupsDao; import org.sonar.db.qualityprofile.QProfileEditUsersDao; import org.sonar.db.qualityprofile.QualityProfileDao; import org.sonar.db.qualityprofile.QualityProfileExportDao; +import org.sonar.db.report.RegulatoryReportDao; import org.sonar.db.rule.RuleDao; import org.sonar.db.rule.RuleRepositoryDao; import org.sonar.db.scannercache.ScannerAnalysisCacheDao; @@ -152,6 +153,7 @@ public class DaoModule extends Module { QualityGateUserPermissionsDao.class, QualityProfileDao.class, QualityProfileExportDao.class, + RegulatoryReportDao.class, RoleDao.class, RuleDao.class, RuleRepositoryDao.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 d545de23ae5..b883f7623d2 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 @@ -75,6 +75,7 @@ import org.sonar.db.qualityprofile.QProfileEditGroupsDao; import org.sonar.db.qualityprofile.QProfileEditUsersDao; import org.sonar.db.qualityprofile.QualityProfileDao; import org.sonar.db.qualityprofile.QualityProfileExportDao; +import org.sonar.db.report.RegulatoryReportDao; import org.sonar.db.rule.RuleDao; import org.sonar.db.rule.RuleRepositoryDao; import org.sonar.db.scannercache.ScannerAnalysisCacheDao; @@ -122,6 +123,7 @@ public class DbClient { private final PermissionTemplateDao permissionTemplateDao; private final PermissionTemplateCharacteristicDao permissionTemplateCharacteristicDao; private final IssueDao issueDao; + private final RegulatoryReportDao regulatoryReportDao; private final IssueChangeDao issueChangeDao; private final CeActivityDao ceActivityDao; private final CeQueueDao ceQueueDao; @@ -219,6 +221,7 @@ public class DbClient { qualityGateGroupPermissionsDao = getDao(map, QualityGateGroupPermissionsDao.class); projectQgateAssociationDao = getDao(map, ProjectQgateAssociationDao.class); duplicationDao = getDao(map, DuplicationDao.class); + regulatoryReportDao = getDao(map, RegulatoryReportDao.class); notificationQueueDao = getDao(map, NotificationQueueDao.class); metricDao = getDao(map, MetricDao.class); groupDao = getDao(map, GroupDao.class); @@ -290,6 +293,10 @@ public class DbClient { return issueDao; } + public RegulatoryReportDao regulatoryReportDao() { + return regulatoryReportDao; + } + public IssueChangeDao issueChangeDao() { return issueChangeDao; } 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 462ea745804..112752428a3 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 @@ -131,6 +131,7 @@ import org.sonar.db.qualityprofile.QProfileEditGroupsMapper; import org.sonar.db.qualityprofile.QProfileEditUsersMapper; import org.sonar.db.qualityprofile.QualityProfileExportMapper; import org.sonar.db.qualityprofile.QualityProfileMapper; +import org.sonar.db.report.RegulatoryReportMapper; import org.sonar.db.rule.RuleMapper; import org.sonar.db.rule.RuleParamDto; import org.sonar.db.rule.RuleRepositoryMapper; @@ -292,6 +293,7 @@ public class MyBatis { QualityGateUserPermissionsMapper.class, QualityProfileMapper.class, QualityProfileExportMapper.class, + RegulatoryReportMapper.class, RoleMapper.class, RuleMapper.class, RuleRepositoryMapper.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java index c59df0ef221..82b2d02702b 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/newcodeperiod/NewCodePeriodDao.java @@ -90,6 +90,13 @@ public class NewCodePeriodDao implements Dao { return ofNullable(mapper(dbSession).selectByBranch(projectUuid, branchUuid)); } + public NewCodePeriodDto selectBestMatchForBranch(DbSession dbSession, String projectUuid, String branchUuid) { + return selectByBranch(dbSession, projectUuid, branchUuid) + .or(() -> selectByProject(dbSession, projectUuid) + .or(() -> selectGlobal(dbSession))) + .orElse(NewCodePeriodDto.defaultInstance()); + } + public Set selectBranchesReferencing(DbSession dbSession, String projectUuid, String referenceBranchName) { return mapper(dbSession).selectBranchesReferencing(projectUuid, referenceBranchName); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/report/IssueFindingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/report/IssueFindingDto.java new file mode 100644 index 00000000000..b1fdfe9f761 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/report/IssueFindingDto.java @@ -0,0 +1,108 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.report; + +import java.util.Set; +import javax.annotation.CheckForNull; +import org.sonar.api.rules.RuleType; +import org.sonar.db.rule.RuleDto; + +public class IssueFindingDto { + private String kee; + private String message; + private int type; + private String severity; + private boolean isManualSeverity; + private String ruleKey; + private String ruleRepository; + private String ruleName; + private String status; + private String resolution; + private String fileName; + private Integer line; + private String securityStandards; + private boolean isNewCodeReferenceIssue; + private long creationDate; + + public String getStatus() { + return status; + } + + @CheckForNull + public String getRuleName() { + return ruleName; + } + + public String getKey() { + return kee; + } + + public Set getSecurityStandards() { + return RuleDto.deserializeSecurityStandardsString(securityStandards); + } + + public boolean isManualSeverity() { + return isManualSeverity; + } + + @CheckForNull + public String getResolution() { + return resolution; + } + + @CheckForNull + public String getMessage() { + return message; + } + + public RuleType getType() { + return RuleType.valueOf(type); + } + + public String getSeverity() { + return severity; + } + + public String getRuleKey() { + return ruleKey; + } + + public String getRuleRepository() { + return ruleRepository; + } + + @CheckForNull + public String getFileName() { + return fileName; + } + + @CheckForNull + public Integer getLine() { + return line; + } + + public boolean isNewCodeReferenceIssue() { + return isNewCodeReferenceIssue; + } + + public long getCreationDate() { + return creationDate; + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportDao.java new file mode 100644 index 00000000000..8cd4a7c350b --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportDao.java @@ -0,0 +1,35 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.report; + +import org.apache.ibatis.session.ResultHandler; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; + +public class RegulatoryReportDao implements Dao { + public void scrollIssues(DbSession dbSession, String branchUuid, ResultHandler handler) { + mapper(dbSession).scrollIssues(branchUuid, handler); + } + + private static RegulatoryReportMapper mapper(DbSession dbSession) { + return dbSession.getMapper(RegulatoryReportMapper.class); + } + +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportMapper.java new file mode 100644 index 00000000000..1a75e22bdcb --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/report/RegulatoryReportMapper.java @@ -0,0 +1,26 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.report; + +import org.apache.ibatis.session.ResultHandler; + +public interface RegulatoryReportMapper { + void scrollIssues(String branchUuid, ResultHandler handler); +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/report/package-info.java b/server/sonar-db-dao/src/main/java/org/sonar/db/report/package-info.java new file mode 100644 index 00000000000..35263a2e558 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/report/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.db.report; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml new file mode 100644 index 00000000000..84787bdc8ca --- /dev/null +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml @@ -0,0 +1,36 @@ + + + + + + + i.kee as kee, + i.severity as severity, + i.manual_severity as isManualSeverity, + i.message as message, + i.line as line, + i.status as status, + i.resolution as resolution, + p.kee as componentKey, + p.path as fileName, + i.issue_type as type, + r.plugin_name as ruleRepository, + r.plugin_rule_key as ruleKey, + r.security_standards as securityStandards, + r.name as ruleName, + i.issue_creation_date as creationDate, + + + + + + diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/report/RegulatoryReportDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/report/RegulatoryReportDaoTest.java new file mode 100644 index 00000000000..81411f30ae4 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/report/RegulatoryReportDaoTest.java @@ -0,0 +1,87 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 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.report; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.issue.IssueDto; +import org.sonar.db.rule.RuleDto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX; +import static org.sonar.db.component.ComponentTesting.newFileDto; + +public class RegulatoryReportDaoTest { + private static final String PROJECT_UUID = "prj_uuid"; + private static final String PROJECT_KEY = "prj_key"; + private static final String FILE_UUID = "file_uuid"; + private static final String FILE_KEY = "file_key"; + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private final RegulatoryReportDao underTest = db.getDbClient().regulatoryReportDao(); + private ComponentDto project; + private RuleDto rule; + private ComponentDto file; + + @Before + public void prepare() { + rule = db.rules().insertRule(); + project = db.components().insertPrivateProject(t -> t.setProjectUuid(PROJECT_UUID).setUuid(PROJECT_UUID).setDbKey(PROJECT_KEY)); + file = db.components().insertComponent(newFileDto(project).setUuid(FILE_UUID).setDbKey(FILE_KEY)); + } + + @Test + public void scrollIssues_returns_all_non_closed_issues_for_project() { + IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setStatus("OPEN").setResolution(null)); + IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setStatus("CONFIRMED").setResolution(null)); + IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i.setStatus("RESOLVED").setResolution(RESOLUTION_WONT_FIX)); + + // not returned + IssueDto issue4 = db.issues().insertIssue(rule, project, file, i -> i.setStatus("CLOSED").setResolution(null)); + ComponentDto otherProject = db.components().insertPrivateProject(); + ComponentDto otherFile = db.components().insertComponent(newFileDto(otherProject)); + IssueDto issue5 = db.issues().insertIssue(rule, otherProject, otherFile); + + List issues = new ArrayList<>(); + underTest.scrollIssues(db.getSession(), PROJECT_UUID, result -> issues.add(result.getResultObject())); + assertThat(issues).extracting(IssueFindingDto::getKey).containsOnly(issue1.getKey(), issue2.getKey(), issue3.getKey()); + + // check fields + IssueFindingDto issue = issues.stream().filter(i -> i.getKey().equals(issue1.getKey())).findFirst().get(); + assertThat(issue.getFileName()).isEqualTo(file.path()); + assertThat(issue.getRuleName()).isEqualTo(rule.getName()); + assertThat(issue.getRuleKey()).isEqualTo(rule.getRuleKey()); + assertThat(issue.getRuleRepository()).isEqualTo(rule.getRepositoryKey()); + assertThat(issue.getMessage()).isEqualTo(issue1.getMessage()); + assertThat(issue.getLine()).isEqualTo(issue1.getLine()); + assertThat(issue.getSeverity()).isEqualTo(issue1.getSeverity()); + assertThat(issue.getType().getDbConstant()).isEqualTo(issue1.getType()); + assertThat(issue.getSecurityStandards()).isEqualTo(rule.getSecurityStandards()); + assertThat(issue.isManualSeverity()).isEqualTo(issue1.isManualSeverity()); + } +} diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java index 595183d387d..e57b9166489 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java @@ -226,4 +226,9 @@ public class IssueDbTester { db.commit(); } + public void insertNewCodeReferenceIssue(IssueDto issue) { + db.getDbClient().issueDao().insertAsNewCodeOnReferenceBranch(db.getSession(), IssueTesting.newCodeReferenceIssue(issue)); + db.commit(); + } + } diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginJarLoader.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginJarLoader.java index 0f2eb7ccab9..a39998be132 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginJarLoader.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/plugins/PluginJarLoader.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import javax.inject.Inject; import org.apache.commons.io.FileUtils; import org.sonar.api.SonarRuntime; import org.sonar.api.utils.MessageException; @@ -50,8 +51,6 @@ import static org.sonar.server.log.ServerProcessLogging.STARTUP_LOGGER_NAME; import static org.sonar.server.plugins.PluginType.BUNDLED; import static org.sonar.server.plugins.PluginType.EXTERNAL; -import javax.inject.Inject; - public class PluginJarLoader { private static final Logger LOG = Loggers.get(PluginJarLoader.class); diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java index 8c87854b66a..9bf64d642ad 100644 --- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java +++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java @@ -77,7 +77,7 @@ public class SettingsSection implements SystemInfoSection, Global { private void addDefaultNewCodeDefinition(Builder protobuf) { try (DbSession dbSession = dbClient.openSession(false)) { Optional period = dbClient.newCodePeriodDao().selectGlobal(dbSession); - setAttribute(protobuf, "Default New Code Definition", parseDefaultNewCodeDefinition(period)); + setAttribute(protobuf, "Default New Code Definition", parseDefaultNewCodeDefinition(period.orElse(NewCodePeriodDto.defaultInstance()))); } } @@ -95,15 +95,11 @@ public class SettingsSection implements SystemInfoSection, Global { return abbreviate(value, MAX_VALUE_LENGTH); } - private static String parseDefaultNewCodeDefinition(Optional period) { - if (!period.isPresent()) { - return "PREVIOUS_VERSION"; + private static String parseDefaultNewCodeDefinition(NewCodePeriodDto period) { + if (period.getValue() == null) { + return period.getType().name(); } - if (period.get().getValue() == null) { - return period.get().getType().name(); - } - - return period.get().getType().name() + ": " + period.get().getValue(); + return period.getType().name() + ": " + period.getValue(); } } -- 2.39.5