diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2017-10-04 12:13:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-04 12:13:07 +0200 |
commit | b8a42fed352a0349caf85393b2e4c60ceb647e72 (patch) | |
tree | 6664d605e88669d2f835e33650ddda9798cfdca5 /sonar-core | |
parent | a816f8904d4a9474308845537a85ff64f71156b7 (diff) | |
download | sonarqube-b8a42fed352a0349caf85393b2e4c60ceb647e72.tar.gz sonarqube-b8a42fed352a0349caf85393b2e4c60ceb647e72.zip |
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
Diffstat (limited to 'sonar-core')
4 files changed, 262 insertions, 199 deletions
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<RAW extends Trackable, BASE extends Trackable> { + + protected void match(Tracking<RAW, BASE> tracking, SearchKeyFactory factory) { + match(tracking, factory, false); + } + + protected void match(Tracking<RAW, BASE> tracking, SearchKeyFactory factory, boolean rejectMultipleMatches) { + + if (tracking.isComplete()) { + return; + } + + Multimap<SearchKey, BASE> 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<BASE> bases = baseSearch.get(rawKey); + if (!bases.isEmpty()) { + Iterator<BASE> 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<RAW extends Trackable, BASE extends Trackable> extends AbstractTracker<RAW, BASE> { + + public Tracking<RAW, BASE> track(Collection<RAW> rawInput, Collection<BASE> baseInput) { + Tracking<RAW, BASE> 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<RAW extends Trackable, BASE extends Trackable> { +public class Tracker<RAW extends Trackable, BASE extends Trackable> extends AbstractTracker<RAW, BASE> { public Tracking<RAW, BASE> track(Input<RAW> rawInput, Input<BASE> baseInput) { - Tracking<RAW, BASE> tracking = new Tracking<>(rawInput, baseInput); + Tracking<RAW, BASE> 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<RAW extends Trackable, BASE extends Trackable> { new BlockRecognizer<RAW, BASE>().match(rawInput, baseInput, tracking); } } - - private void match(Tracking<RAW, BASE> tracking, SearchKeyFactory factory) { - if (tracking.isComplete()) { - return; - } - - Multimap<SearchKey, BASE> 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<BASE> 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<RAW extends Trackable, BASE extends Trackable> { private final Collection<BASE> bases; private final Predicate<RAW> unmatchedRawPredicate = raw -> !rawToBase.containsKey(raw); - private final Predicate<BASE> unmatchedBasePredicate = raw -> !baseToRaw.containsKey(raw); - public Tracking(Input<RAW> rawInput, Input<BASE> baseInput) { - this.raws = rawInput.getIssues(); - this.bases = baseInput.getIssues(); + public Tracking(Collection<RAW> rawInput, Collection<BASE> baseInput) { + this.raws = rawInput; + this.bases = baseInput; } /** |