From b8a42fed352a0349caf85393b2e4c60ceb647e72 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Wed, 4 Oct 2017 12:13:07 +0200 Subject: SONAR-9887 Reuse information from issues in short living branches targeting current branch * Add ShortBranchComponentsWithIssues * Load only required component fields from dto * Keep only uuid and branch from analysisMetadataHolder * No need for branch in ShortBranchComponentsWithIssues * Add IssueDao.selectResolvedOrConfirmedByComponentUuid * Add ResolvedShortBranchIssuesFactory * Add components to ProjectAnalysisTaskContainerPopulator * issue info from short branches * Do not open db session for nothing * Get issues for all uuids at once * Select only fields required for issue tracking * Improvements * Add ShortBranchIssue with only the fields needed for issue tracking * fix test * Add missed license * minor improvements * Fix IssueStatusCopierTest and move ShortBranchIssue class * Clean up ShortBranchIssueDto and its query * Fix mapping of dto class * Verify that required fields are correctly mapped * fixes * Fix issues loader * Do not use "key" as field name in db operations * Should find issues to merge only in short branches * Strip branch from component key --- .../sonar/core/issue/tracking/AbstractTracker.java | 216 +++++++++++++++++++++ .../sonar/core/issue/tracking/SimpleTracker.java | 41 ++++ .../org/sonar/core/issue/tracking/Tracker.java | 197 +------------------ .../org/sonar/core/issue/tracking/Tracking.java | 7 +- 4 files changed, 262 insertions(+), 199 deletions(-) create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/tracking/AbstractTracker.java create mode 100644 sonar-core/src/main/java/org/sonar/core/issue/tracking/SimpleTracker.java (limited to 'sonar-core') diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/AbstractTracker.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/AbstractTracker.java new file mode 100644 index 00000000000..bdf7dd75d5d --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/tracking/AbstractTracker.java @@ -0,0 +1,216 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.core.issue.tracking; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.Iterator; +import java.util.Objects; +import javax.annotation.Nonnull; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.rule.RuleKey; + +public class AbstractTracker { + + protected void match(Tracking tracking, SearchKeyFactory factory) { + match(tracking, factory, false); + } + + protected void match(Tracking tracking, SearchKeyFactory factory, boolean rejectMultipleMatches) { + + if (tracking.isComplete()) { + return; + } + + Multimap baseSearch = ArrayListMultimap.create(); + for (BASE base : tracking.getUnmatchedBases()) { + baseSearch.put(factory.create(base), base); + } + + for (RAW raw : tracking.getUnmatchedRaws()) { + SearchKey rawKey = factory.create(raw); + Collection bases = baseSearch.get(rawKey); + if (!bases.isEmpty()) { + Iterator it = bases.iterator(); + BASE match = it.next(); + if (rejectMultipleMatches && it.hasNext()) { + continue; + } + // TODO taking the first one. Could be improved if there are more than 2 issues on the same line. + // Message could be checked to take the best one. + tracking.match(raw, match); + baseSearch.remove(rawKey, match); + } + } + } + + private interface SearchKey { + } + + private interface SearchKeyFactory { + SearchKey create(Trackable trackable); + } + + private static class LineAndLineHashKey implements SearchKey { + private final RuleKey ruleKey; + private final String lineHash; + private final Integer line; + + LineAndLineHashKey(Trackable trackable) { + this.ruleKey = trackable.getRuleKey(); + this.line = trackable.getLine(); + this.lineHash = StringUtils.defaultString(trackable.getLineHash(), ""); + } + + @Override + public boolean equals(@Nonnull Object o) { + if (this == o) { + return true; + } + LineAndLineHashKey that = (LineAndLineHashKey) o; + // start with most discriminant field + return Objects.equals(line, that.line) + && lineHash.equals(that.lineHash) + && ruleKey.equals(that.ruleKey); + } + + @Override + public int hashCode() { + return Objects.hash(ruleKey, lineHash, line != null ? line : 0); + } + } + + protected enum LineAndLineHashKeyFactory implements SearchKeyFactory { + INSTANCE; + @Override + public SearchKey create(Trackable t) { + return new LineAndLineHashKey(t); + } + } + + private static class LineHashAndMessageKey implements SearchKey { + private final RuleKey ruleKey; + private final String message; + private final String lineHash; + + LineHashAndMessageKey(Trackable trackable) { + this.ruleKey = trackable.getRuleKey(); + this.message = trackable.getMessage(); + this.lineHash = StringUtils.defaultString(trackable.getLineHash(), ""); + } + + @Override + public boolean equals(@Nonnull Object o) { + if (this == o) { + return true; + } + LineHashAndMessageKey that = (LineHashAndMessageKey) o; + // start with most discriminant field + return lineHash.equals(that.lineHash) + && message.equals(that.message) + && ruleKey.equals(that.ruleKey); + } + + @Override + public int hashCode() { + return Objects.hash(ruleKey, message, lineHash); + } + } + + protected enum LineHashAndMessageKeyFactory implements SearchKeyFactory { + INSTANCE; + @Override + public SearchKey create(Trackable t) { + return new LineHashAndMessageKey(t); + } + } + + private static class LineAndMessageKey implements SearchKey { + private final RuleKey ruleKey; + private final String message; + private final Integer line; + + LineAndMessageKey(Trackable trackable) { + this.ruleKey = trackable.getRuleKey(); + this.message = trackable.getMessage(); + this.line = trackable.getLine(); + } + + @Override + public boolean equals(@Nonnull Object o) { + if (this == o) { + return true; + } + LineAndMessageKey that = (LineAndMessageKey) o; + // start with most discriminant field + return Objects.equals(line, that.line) + && message.equals(that.message) + && ruleKey.equals(that.ruleKey); + } + + @Override + public int hashCode() { + return Objects.hash(ruleKey, message, line != null ? line : 0); + } + } + + protected enum LineAndMessageKeyFactory implements SearchKeyFactory { + INSTANCE; + @Override + public SearchKey create(Trackable t) { + return new LineAndMessageKey(t); + } + } + + private static class LineHashKey implements SearchKey { + private final RuleKey ruleKey; + private final String lineHash; + + LineHashKey(Trackable trackable) { + this.ruleKey = trackable.getRuleKey(); + this.lineHash = StringUtils.defaultString(trackable.getLineHash(), ""); + } + + @Override + public boolean equals(@Nonnull Object o) { + if (this == o) { + return true; + } + LineHashKey that = (LineHashKey) o; + // start with most discriminant field + return lineHash.equals(that.lineHash) + && ruleKey.equals(that.ruleKey); + } + + @Override + public int hashCode() { + return Objects.hash(ruleKey, lineHash); + } + } + + protected enum LineHashKeyFactory implements SearchKeyFactory { + INSTANCE; + @Override + public SearchKey create(Trackable t) { + return new LineHashKey(t); + } + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/SimpleTracker.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/SimpleTracker.java new file mode 100644 index 00000000000..4ae1833c8f4 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/issue/tracking/SimpleTracker.java @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.core.issue.tracking; + +import java.util.Collection; + +/** + * A simplified version of {@link Tracker}, which doesn't use line hash sequences nor block hash sequences and + * only has two steps instead of 5 steps. + */ +public class SimpleTracker extends AbstractTracker { + + public Tracking track(Collection rawInput, Collection baseInput) { + Tracking tracking = new Tracking<>(rawInput, baseInput); + + // 1. match issues with same rule, same line and same line hash, but not necessarily with same message + match(tracking, LineAndLineHashKeyFactory.INSTANCE, true); + + // 2. match issues with same rule, same message and same line hash + match(tracking, LineHashAndMessageKeyFactory.INSTANCE, true); + + return tracking; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java index c13481a63f5..2039219ff89 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracker.java @@ -19,22 +19,15 @@ */ package org.sonar.core.issue.tracking; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; -import java.util.Collection; -import java.util.Objects; -import javax.annotation.Nonnull; -import org.apache.commons.lang.StringUtils; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.InstantiationStrategy; -import org.sonar.api.rule.RuleKey; @InstantiationStrategy(InstantiationStrategy.PER_BATCH) @ScannerSide -public class Tracker { +public class Tracker extends AbstractTracker { public Tracking track(Input rawInput, Input baseInput) { - Tracking tracking = new Tracking<>(rawInput, baseInput); + Tracking tracking = new Tracking<>(rawInput.getIssues(), baseInput.getIssues()); // 1. match issues with same rule, same line and same line hash, but not necessarily with same message match(tracking, LineAndLineHashKeyFactory.INSTANCE); @@ -60,190 +53,4 @@ public class Tracker { new BlockRecognizer().match(rawInput, baseInput, tracking); } } - - private void match(Tracking tracking, SearchKeyFactory factory) { - if (tracking.isComplete()) { - return; - } - - Multimap baseSearch = ArrayListMultimap.create(); - for (BASE base : tracking.getUnmatchedBases()) { - baseSearch.put(factory.create(base), base); - } - - for (RAW raw : tracking.getUnmatchedRaws()) { - SearchKey rawKey = factory.create(raw); - Collection bases = baseSearch.get(rawKey); - if (!bases.isEmpty()) { - // TODO taking the first one. Could be improved if there are more than 2 issues on the same line. - // Message could be checked to take the best one. - BASE match = bases.iterator().next(); - tracking.match(raw, match); - baseSearch.remove(rawKey, match); - } - } - } - - private interface SearchKey { - } - - private interface SearchKeyFactory { - SearchKey create(Trackable trackable); - } - - private static class LineAndLineHashKey implements SearchKey { - private final RuleKey ruleKey; - private final String lineHash; - private final Integer line; - - LineAndLineHashKey(Trackable trackable) { - this.ruleKey = trackable.getRuleKey(); - this.line = trackable.getLine(); - this.lineHash = StringUtils.defaultString(trackable.getLineHash(), ""); - } - - @Override - public boolean equals(@Nonnull Object o) { - if (this == o) { - return true; - } - LineAndLineHashKey that = (LineAndLineHashKey) o; - // start with most discriminant field - return Objects.equals(line, that.line) - && lineHash.equals(that.lineHash) - && ruleKey.equals(that.ruleKey); - } - - @Override - public int hashCode() { - int result = ruleKey.hashCode(); - result = 31 * result + lineHash.hashCode(); - result = 31 * result + (line != null ? line.hashCode() : 0); - return result; - } - } - - private enum LineAndLineHashKeyFactory implements SearchKeyFactory { - INSTANCE; - @Override - public SearchKey create(Trackable t) { - return new LineAndLineHashKey(t); - } - } - - private static class LineHashAndMessageKey implements SearchKey { - private final RuleKey ruleKey; - private final String message; - private final String lineHash; - - LineHashAndMessageKey(Trackable trackable) { - this.ruleKey = trackable.getRuleKey(); - this.message = trackable.getMessage(); - this.lineHash = StringUtils.defaultString(trackable.getLineHash(), ""); - } - - @Override - public boolean equals(@Nonnull Object o) { - if (this == o) { - return true; - } - LineHashAndMessageKey that = (LineHashAndMessageKey) o; - // start with most discriminant field - return lineHash.equals(that.lineHash) - && message.equals(that.message) - && ruleKey.equals(that.ruleKey); - } - - @Override - public int hashCode() { - int result = ruleKey.hashCode(); - result = 31 * result + message.hashCode(); - result = 31 * result + lineHash.hashCode(); - return result; - } - } - - private enum LineHashAndMessageKeyFactory implements SearchKeyFactory { - INSTANCE; - @Override - public SearchKey create(Trackable t) { - return new LineHashAndMessageKey(t); - } - } - - private static class LineAndMessageKey implements SearchKey { - private final RuleKey ruleKey; - private final String message; - private final Integer line; - - LineAndMessageKey(Trackable trackable) { - this.ruleKey = trackable.getRuleKey(); - this.message = trackable.getMessage(); - this.line = trackable.getLine(); - } - - @Override - public boolean equals(@Nonnull Object o) { - if (this == o) { - return true; - } - LineAndMessageKey that = (LineAndMessageKey) o; - // start with most discriminant field - return Objects.equals(line, that.line) - && message.equals(that.message) - && ruleKey.equals(that.ruleKey); - } - - @Override - public int hashCode() { - int result = ruleKey.hashCode(); - result = 31 * result + message.hashCode(); - result = 31 * result + (line != null ? line.hashCode() : 0); - return result; - } - } - - private enum LineAndMessageKeyFactory implements SearchKeyFactory { - INSTANCE; - @Override - public SearchKey create(Trackable t) { - return new LineAndMessageKey(t); - } - } - - private static class LineHashKey implements SearchKey { - private final RuleKey ruleKey; - private final String lineHash; - - LineHashKey(Trackable trackable) { - this.ruleKey = trackable.getRuleKey(); - this.lineHash = StringUtils.defaultString(trackable.getLineHash(), ""); - } - - @Override - public boolean equals(@Nonnull Object o) { - if (this == o) { - return true; - } - LineHashKey that = (LineHashKey) o; - // start with most discriminant field - return lineHash.equals(that.lineHash) - && ruleKey.equals(that.ruleKey); - } - - @Override - public int hashCode() { - int result = ruleKey.hashCode(); - result = 31 * result + lineHash.hashCode(); - return result; - } - } - - private enum LineHashKeyFactory implements SearchKeyFactory { - INSTANCE; - @Override - public SearchKey create(Trackable t) { - return new LineHashKey(t); - } - } } diff --git a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java index 844061e380e..99ba9c7b379 100644 --- a/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java +++ b/sonar-core/src/main/java/org/sonar/core/issue/tracking/Tracking.java @@ -39,12 +39,11 @@ public class Tracking { private final Collection bases; private final Predicate unmatchedRawPredicate = raw -> !rawToBase.containsKey(raw); - private final Predicate unmatchedBasePredicate = raw -> !baseToRaw.containsKey(raw); - public Tracking(Input rawInput, Input baseInput) { - this.raws = rawInput.getIssues(); - this.bases = baseInput.getIssues(); + public Tracking(Collection rawInput, Collection baseInput) { + this.raws = rawInput; + this.bases = baseInput; } /** -- cgit v1.2.3