import org.sonar.api.rule.RuleKey;
import org.sonar.batch.scan.LastSnapshots;
import org.sonar.core.issue.db.IssueDto;
-import org.sonar.plugins.core.issue.tracking.HashedSequence;
-import org.sonar.plugins.core.issue.tracking.HashedSequenceComparator;
-import org.sonar.plugins.core.issue.tracking.RollingHashSequence;
-import org.sonar.plugins.core.issue.tracking.RollingHashSequenceComparator;
-import org.sonar.plugins.core.issue.tracking.SourceChecksum;
-import org.sonar.plugins.core.issue.tracking.StringText;
-import org.sonar.plugins.core.issue.tracking.StringTextComparator;
-import org.sonar.plugins.core.issue.tracking.ViolationTrackingBlocksRecognizer;
+import org.sonar.plugins.core.issue.tracking.*;
import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
public class IssueTracking implements BatchExtension {
for (DefaultIssue newIssue : newIssues) {
if (isNotAlreadyMapped(newIssue, result)) {
mapIssue(
- newIssue,
- findLastIssueWithSameLineAndChecksum(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
- result);
+ newIssue,
+ findLastIssueWithSameLineAndChecksum(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
+ result);
}
}
}
for (DefaultIssue newIssue : newIssues) {
if (isNotAlreadyMapped(newIssue, result)) {
mapIssue(
- newIssue,
- findLastIssueWithSameChecksumAndMessage(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
- result);
+ newIssue,
+ findLastIssueWithSameChecksumAndMessage(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
+ result);
}
}
for (DefaultIssue newIssue : newIssues) {
if (isNotAlreadyMapped(newIssue, result)) {
mapIssue(
- newIssue,
- findLastIssueWithSameLineAndMessage(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
- result);
+ newIssue,
+ findLastIssueWithSameLineAndMessage(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
+ result);
}
}
for (DefaultIssue newIssue : newIssues) {
if (isNotAlreadyMapped(newIssue, result)) {
mapIssue(
- newIssue,
- findLastIssueWithSameChecksum(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
- result);
+ newIssue,
+ findLastIssueWithSameChecksum(newIssue, result.unmatchedForRule(newIssue.ruleKey())),
+ result);
}
}
}
private final ResourcePerspectives perspectives;
private final RulesProfile rulesProfile;
private final RuleFinder ruleFinder;
- private FileLinesContextFactory fileLineContextFactory;
public IssueTrackingDecorator(IssueCache issueCache, InitialOpenIssuesStack initialOpenIssues, IssueTracking tracking,
- IssueHandlers handlers, IssueWorkflow workflow,
- IssueUpdater updater,
- Project project,
- ResourcePerspectives perspectives,
- RulesProfile rulesProfile,
- RuleFinder ruleFinder,
- FileLinesContextFactory fileLineContextFactory) {
+ IssueHandlers handlers, IssueWorkflow workflow,
+ IssueUpdater updater,
+ Project project,
+ ResourcePerspectives perspectives,
+ RulesProfile rulesProfile,
+ RuleFinder ruleFinder) {
this.issueCache = issueCache;
this.initialOpenIssues = initialOpenIssues;
this.tracking = tracking;
this.handlers = handlers;
this.workflow = workflow;
this.updater = updater;
- this.fileLineContextFactory = fileLineContextFactory;
this.changeContext = IssueChangeContext.createScan(project.getAnalysisDate());
this.perspectives = perspectives;
this.rulesProfile = rulesProfile;
// all the issues that are not closed in db before starting this module scan, including manual issues
Collection<IssueDto> dbOpenIssues = initialOpenIssues.selectAndRemove(resource.getEffectiveKey());
- setScmAuthorOnNewIssues(resource, issues);
-
IssueTrackingResult trackingResult = tracking.track(resource, dbOpenIssues, issues);
// unmatched = issues that have been resolved + issues on disabled/removed rules + manual issues
}
}
- @VisibleForTesting
- void setScmAuthorOnNewIssues(Resource resource, Collection<DefaultIssue> newIssues) {
- if (ResourceUtils.isFile(resource)) {
- FileLinesContext fileLineContext = fileLineContextFactory.createFor(resource);
- for (DefaultIssue issue : newIssues) {
- Integer line = issue.line();
- if (line != null) {
- // TODO When issue is on line 0 then who is the author?
- String scmAuthorLogin = fileLineContext.getStringValue(CoreMetrics.SCM_AUTHORS_BY_LINE_KEY, line);
- if (scmAuthorLogin != null) {
- issue.setAuthorLogin(scmAuthorLogin);
- }
- }
- }
- }
- }
-
private void mergeMatched(IssueTrackingResult result) {
for (DefaultIssue issue : result.matched()) {
IssueDto ref = result.matching(issue);
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.measures.FileLinesContext;
-import org.sonar.api.measures.FileLinesContextFactory;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.Scopes;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyCollection;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.RETURNS_MOCKS;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
RulesProfile profile = mock(RulesProfile.class);
RuleFinder ruleFinder = mock(RuleFinder.class);
- private FileLinesContextFactory fileLineContextFactory;
@Before
public void init() {
- fileLineContextFactory = mock(FileLinesContextFactory.class);
decorator = new IssueTrackingDecorator(
- issueCache,
- initialOpenIssues,
- tracking,
- handlers,
- workflow,
- updater,
- mock(Project.class),
- perspectives,
- profile,
- ruleFinder,
- fileLineContextFactory);
+ issueCache,
+ initialOpenIssues,
+ tracking,
+ handlers,
+ workflow,
+ updater,
+ mock(Project.class),
+ perspectives,
+ profile,
+ ruleFinder);
}
@Test
}
}));
}
-
- @Test
- public void should_update_scm_author_on_new_issues() {
- Resource resource = mock(Resource.class);
- FileLinesContext context = mock(FileLinesContext.class);
- when(context.getStringValue("authors_by_line", 1)).thenReturn("julien");
- when(fileLineContextFactory.createFor(resource)).thenReturn(context);
-
- DefaultIssue newIssue = mock(DefaultIssue.class);
- when(newIssue.line()).thenReturn(1);
-
- when(resource.getScope()).thenReturn(Scopes.FILE);
- decorator.setScmAuthorOnNewIssues(resource, Arrays.asList(newIssue));
-
- verify(newIssue).setAuthorLogin("julien");
- }
-
- @Test
- public void should_not_update_scm_author_when_resource_is_not_a_file() {
- Resource resource = mock(Resource.class);
-
- DefaultIssue newIssue = mock(DefaultIssue.class);
- when(newIssue.line()).thenReturn(1);
-
- when(resource.getScope()).thenReturn(Scopes.PROJECT);
- decorator.setScmAuthorOnNewIssues(resource, Arrays.asList(newIssue));
-
- verify(newIssue, never()).setAuthorLogin(anyString());
- }
-
- @Test
- public void should_not_update_scm_author_when_issue_is_on_line_0() {
- Resource resource = mock(Resource.class);
- FileLinesContext context = mock(FileLinesContext.class);
- when(context.getStringValue("authors_by_line", 1)).thenReturn("julien");
- when(fileLineContextFactory.createFor(resource)).thenReturn(context);
-
- DefaultIssue newIssue = mock(DefaultIssue.class);
- when(newIssue.line()).thenReturn(null);
-
- when(resource.getScope()).thenReturn(Scopes.FILE);
- decorator.setScmAuthorOnNewIssues(resource, Arrays.asList(newIssue));
-
- verify(newIssue, never()).setAuthorLogin(anyString());
- }
-
- @Test
- public void should_not_update_scm_author_when_unknow_scm_author() {
- Resource resource = mock(Resource.class);
- FileLinesContext context = mock(FileLinesContext.class);
- when(context.getStringValue("authors_by_line", 1)).thenReturn(null);
- when(fileLineContextFactory.createFor(resource)).thenReturn(context);
-
- DefaultIssue newIssue = mock(DefaultIssue.class);
- when(newIssue.line()).thenReturn(1);
-
- when(resource.getScope()).thenReturn(Scopes.FILE);
- decorator.setScmAuthorOnNewIssues(resource, Arrays.asList(newIssue));
-
- verify(newIssue, never()).setAuthorLogin(anyString());
- }
}
lastSnapshots = mock(LastSnapshots.class);
project = mock(Project.class);
-
tracking = new IssueTracking(lastSnapshots, null);
}
IssueTrackingResult result = new IssueTrackingResult();
tracking.mapIssues(
- Arrays.asList(newIssue1, newIssue2, newIssue3),
- Arrays.asList(referenceIssue1),
- source, project, result);
+ Arrays.asList(newIssue1, newIssue2, newIssue3),
+ Arrays.asList(referenceIssue1),
+ source, project, result);
assertThat(result.matching(newIssue1)).isNull();
assertThat(result.matching(newIssue2)).isSameAs(referenceIssue1);
IssueDto referenceIssue1 = newReferenceIssue("Avoid unused local variables such as 'j'.", 6, "squid", "AvoidCycle", "63c11570fc0a76434156be5f8138fa03");
IssueDto referenceIssue2 = newReferenceIssue("Avoid unused private methods such as 'myMethod()'.", 13, "squid", "NullDeref", "ef23288705d1ef1e512448ace287586e");
- IssueDto referenceIssue3 = newReferenceIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, "pmd",
- "UnusedLocalVariable", "ed5cdd046fda82727d6fedd1d8e3a310");
+ IssueDto referenceIssue3 = newReferenceIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, "pmd", "UnusedLocalVariable", "ed5cdd046fda82727d6fedd1d8e3a310");
// New issue
DefaultIssue newIssue1 = newDefaultIssue("Avoid unused local variables such as 'msg'.", 18, RuleKey.of("squid", "AvoidCycle"), "a24254126be2bf1a9b9a8db43f633733");
// Same as referenceIssue2
DefaultIssue newIssue2 = newDefaultIssue("Avoid unused private methods such as 'myMethod()'.", 13, RuleKey.of("squid", "NullDeref"), "ef23288705d1ef1e512448ace287586e");
// Same as referenceIssue3
- DefaultIssue newIssue3 = newDefaultIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9,
- RuleKey.of("pmd", "UnusedLocalVariable"), "ed5cdd046fda82727d6fedd1d8e3a310");
+ DefaultIssue newIssue3 = newDefaultIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, RuleKey.of("pmd", "UnusedLocalVariable"), "ed5cdd046fda82727d6fedd1d8e3a310");
// New issue
- DefaultIssue newIssue4 = newDefaultIssue("Method 'newViolation' is not designed for extension - needs to be abstract, final or empty.", 17,
- RuleKey.of("pmd", "UnusedLocalVariable"), "7d58ac9040c27e4ca2f11a0269e251e2");
+ DefaultIssue newIssue4 = newDefaultIssue("Method 'newViolation' is not designed for extension - needs to be abstract, final or empty.", 17, RuleKey.of("pmd", "UnusedLocalVariable"), "7d58ac9040c27e4ca2f11a0269e251e2");
// Same as referenceIssue1
DefaultIssue newIssue5 = newDefaultIssue("Avoid unused local variables such as 'j'.", 6, RuleKey.of("squid", "AvoidCycle"), "4432a2675ec3e1620daefe38386b51ef");
IssueTrackingResult result = new IssueTrackingResult();
tracking.mapIssues(
- Arrays.asList(newIssue1, newIssue2, newIssue3, newIssue4, newIssue5),
- Arrays.asList(referenceIssue1, referenceIssue2, referenceIssue3),
- source, project, result);
+ Arrays.asList(newIssue1, newIssue2, newIssue3, newIssue4, newIssue5),
+ Arrays.asList(referenceIssue1, referenceIssue2, referenceIssue3),
+ source, project, result);
assertThat(result.matching(newIssue1)).isNull();
assertThat(result.matching(newIssue2)).isSameAs(referenceIssue2);
<% if issue.authorLogin %>
<img src="<%= ApplicationController.root_context -%>/images/sep12.png"/>
- <span><%= message('issue.authorLogin') -%> <%= issue.authorLogin -%></span>
+ <span><%= message('issue.authorLogin') -%> <%= issue.authorLogin -%></span>
<% end %>
</div>