+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.batch.issue;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.batch.index.ScanPersister;
-
-/**
- * Executed at the end of project scan, when all the modules are completed.
- */
-public class IssuePersister implements ScanPersister {
-
- private static final Logger LOG = LoggerFactory.getLogger(IssuePersister.class);
-
- private final IssueCache issueCache;
- private final ScanIssueStorage storage;
- private AnalysisMode analysisMode;
-
- public IssuePersister(IssueCache issueCache, ScanIssueStorage storage, AnalysisMode analysisMode) {
- this.issueCache = issueCache;
- this.storage = storage;
- this.analysisMode = analysisMode;
- }
-
- @Override
- public void persist() {
- if (analysisMode.isPreview()) {
- LOG.debug("IssuePersister skipped in preview mode");
- return;
- }
- Iterable<DefaultIssue> issues = issueCache.all();
- // storage.save(issues);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.batch.issue;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.batch.ProjectTree;
-import org.sonar.batch.index.BatchResource;
-import org.sonar.batch.index.ResourceCache;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.db.IssueMapper;
-import org.sonar.core.issue.db.IssueStorage;
-import org.sonar.core.issue.db.UpdateConflictResolver;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceQuery;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class ScanIssueStorage extends IssueStorage implements BatchComponent {
-
- private final ResourceCache resourceCache;
- private final ResourceDao resourceDao;
- private final ProjectTree projectTree;
- private final UpdateConflictResolver conflictResolver = new UpdateConflictResolver();
-
- public ScanIssueStorage(MyBatis mybatis, RuleFinder ruleFinder, ResourceCache resourceCache, ResourceDao resourceDao, ProjectTree projectTree) {
- super(mybatis, ruleFinder);
- this.resourceCache = resourceCache;
- this.resourceDao = resourceDao;
- this.projectTree = projectTree;
- }
-
- @Override
- protected void doInsert(DbSession session, long now, DefaultIssue issue) {
- IssueMapper issueMapper = session.getMapper(IssueMapper.class);
- long componentId = componentId(issue);
- long projectId = projectId();
- Rule rule = rule(issue);
- List<String> allTags = new ArrayList<String>();
- allTags.addAll(Arrays.asList(rule.getTags()));
- allTags.addAll(Arrays.asList(rule.getSystemTags()));
- issue.setTags(allTags);
- IssueDto dto = IssueDto.toDtoForBatchInsert(issue, componentId, projectId, rule.getId(), now);
- issueMapper.insert(dto);
- }
-
- @Override
- protected void doUpdate(DbSession session, long now, DefaultIssue issue) {
- IssueMapper issueMapper = session.getMapper(IssueMapper.class);
- IssueDto dto = IssueDto.toDtoForUpdate(issue, projectId(), now);
- if (Issue.STATUS_CLOSED.equals(issue.status()) || issue.selectedAt() == null) {
- // Issue is closed by scan or changed by end-user
- issueMapper.update(dto);
-
- } else {
- int count = issueMapper.updateIfBeforeSelectedDate(dto);
- if (count == 0) {
- // End-user and scan changed the issue at the same time.
- // See https://jira.codehaus.org/browse/SONAR-4309
- conflictResolver.resolve(issue, issueMapper);
- }
- }
- }
-
- @VisibleForTesting
- long componentId(DefaultIssue issue) {
- BatchResource resource = resourceCache.get(issue.componentKey());
- if (resource != null) {
- return resource.resource().getId();
- }
-
- // Load from db when component does not exist in cache (deleted file for example)
- ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(issue.componentKey()));
- if (resourceDto == null) {
- throw new IllegalStateException("Unknown component: " + issue.componentKey());
- }
- return resourceDto.getId();
- }
-
- @VisibleForTesting
- long projectId() {
- return projectTree.getRootProject().getId();
- }
-
-}
import org.sonar.batch.issue.DefaultProjectIssues;
import org.sonar.batch.issue.DeprecatedViolations;
import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.issue.IssuePersister;
-import org.sonar.batch.issue.ScanIssueStorage;
import org.sonar.batch.languages.DefaultLanguagesReferential;
import org.sonar.batch.phases.GraphPersister;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
IssueWorkflow.class,
DeprecatedViolations.class,
IssueCache.class,
- ScanIssueStorage.class,
- IssuePersister.class,
IssueNotifications.class,
DefaultProjectIssues.class,
IssueChangelogDebtCalculator.class,
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.batch.issue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.batch.bootstrap.AnalysisMode;
-import org.sonar.core.persistence.AbstractDaoTestCase;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.mockito.Mockito.*;
-
-public class IssuePersisterTest extends AbstractDaoTestCase {
-
- IssuePersister persister;
- private ScanIssueStorage storage;
- private List<DefaultIssue> issues;
- private AnalysisMode mode;
-
- @Before
- public void prepare() {
- issues = Arrays.asList(new DefaultIssue());
- IssueCache issueCache = mock(IssueCache.class);
- when(issueCache.all()).thenReturn(issues);
- storage = mock(ScanIssueStorage.class);
-
- mode = mock(AnalysisMode.class);
- persister = new IssuePersister(issueCache, storage, mode);
- }
-
- @Test
- public void should_not_persist_issues_anymore() throws Exception {
- persister.persist();
-
- verify(storage, never()).save(issues);
- }
-
- @Test
- public void should_not_persist_issues_in_preview_mode() throws Exception {
- when(mode.isPreview()).thenReturn(true);
-
- persister.persist();
-
- verify(storage, never()).save(issues);
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.batch.issue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.DefaultIssueComment;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.System2;
-import org.sonar.batch.ProjectTree;
-import org.sonar.batch.index.BatchResource;
-import org.sonar.batch.index.ResourceCache;
-import org.sonar.core.persistence.AbstractDaoTestCase;
-import org.sonar.core.resource.ResourceDao;
-
-import java.util.Collection;
-import java.util.Date;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ScanIssueStorageTest extends AbstractDaoTestCase {
-
- @Mock
- ResourceCache resourceCache;
-
- @Mock
- ProjectTree projectTree;
-
- ScanIssueStorage storage;
-
- @Before
- public void setUp() throws Exception {
- storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), resourceCache, new ResourceDao(getMyBatis(), System2.INSTANCE), projectTree);
- }
-
- @Test
- public void should_load_component_id_from_cache() throws Exception {
- when(resourceCache.get("struts:Action.java")).thenReturn(new BatchResource(1, File.create("Action.java").setId(123), new Snapshot(), null));
-
- long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
-
- assertThat(componentId).isEqualTo(123);
- }
-
- @Test
- public void should_load_component_id_from_db() throws Exception {
- setupData("should_load_component_id_from_db");
- when(resourceCache.get("struts:Action.java")).thenReturn(null);
-
- long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
-
- assertThat(componentId).isEqualTo(123);
- }
-
- @Test
- public void should_fail_to_load_component_id_if_unknown_component() throws Exception {
- setupData("should_fail_to_load_component_id_if_unknown_component");
- when(resourceCache.get("struts:Action.java")).thenReturn(null);
-
- try {
- storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("Unknown component: struts:Action.java");
- }
- }
-
- @Test
- public void should_load_project_id() throws Exception {
- when(projectTree.getRootProject()).thenReturn((Project) new Project("struts").setId(100));
-
- long projectId = storage.projectId();
-
- assertThat(projectId).isEqualTo(100);
- }
-
- @Test
- public void should_insert_new_issues() throws Exception {
- setupData("should_insert_new_issues");
-
- Project project = new Project("struts");
- project.setId(10);
- when(projectTree.getRootProject()).thenReturn(project);
-
- DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
- // override generated key
- comment.setKey("FGHIJ");
-
- Date date = DateUtils.parseDate("2013-05-18");
- DefaultIssue issue = new DefaultIssue()
- .setKey("ABCDE")
- .setNew(true)
-
- .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
- .setLine(5000)
- .setDebt(Duration.create(10L))
- .setReporter("emmerik")
- .setResolution("OPEN")
- .setStatus("OPEN")
- .setSeverity("BLOCKER")
- .setAttribute("foo", "bar")
- .addComment(comment)
- .setCreationDate(date)
- .setUpdateDate(date)
- .setCloseDate(date)
-
- .setComponentKey("struts:Action");
-
- storage.save(issue);
-
- checkTables("should_insert_new_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
- }
-
- @Test
- public void should_update_issues() throws Exception {
- setupData("should_update_issues");
-
- IssueChangeContext context = IssueChangeContext.createUser(new Date(), "emmerik");
-
- Project project = new Project("struts");
- project.setId(10);
- when(projectTree.getRootProject()).thenReturn(project);
-
- DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
- // override generated key
- comment.setKey("FGHIJ");
-
- Date date = DateUtils.parseDate("2013-05-18");
- DefaultIssue issue = new DefaultIssue()
- .setKey("ABCDE")
- .setNew(false)
- .setChanged(true)
-
- // updated fields
- .setLine(5000)
- .setDebt(Duration.create(10L))
- .setChecksum("FFFFF")
- .setAuthorLogin("simon")
- .setAssignee("loic")
- .setFieldChange(context, "severity", "INFO", "BLOCKER")
- .setReporter("emmerik")
- .setResolution("FIXED")
- .setStatus("RESOLVED")
- .setSeverity("BLOCKER")
- .setAttribute("foo", "bar")
- .addComment(comment)
- .setCreationDate(date)
- .setUpdateDate(date)
- .setCloseDate(date)
-
- // unmodifiable fields
- .setRuleKey(RuleKey.of("xxx", "unknown"))
- .setComponentKey("not:a:component");
-
- storage.save(issue);
-
- checkTables("should_update_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
- }
-
- @Test
- public void should_resolve_conflicts_on_updates() throws Exception {
- setupData("should_resolve_conflicts_on_updates");
-
- Project project = new Project("struts");
- project.setId(10);
- when(projectTree.getRootProject()).thenReturn(project);
-
- Date date = DateUtils.parseDate("2013-05-18");
- DefaultIssue issue = new DefaultIssue()
- .setKey("ABCDE")
- .setNew(false)
- .setChanged(true)
- .setCreationDate(DateUtils.parseDate("2005-05-12"))
- .setUpdateDate(date)
- .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
- .setComponentKey("struts:Action")
-
- // issue in database has been updated in 2015, after the loading by scan
- .setSelectedAt(1400000000000L)
-
- // fields to be updated
- .setLine(444)
- .setSeverity("BLOCKER")
- .setChecksum("FFFFF")
- .setAttribute("JIRA", "http://jira.com")
-
- // fields overridden by end-user -> do not save
- .setAssignee("looser")
- .setResolution(null)
- .setStatus("REOPEN");
-
- storage.save(issue);
-
- checkTables("should_resolve_conflicts_on_updates", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues");
- }
-
- static class FakeRuleFinder implements RuleFinder {
-
- @Override
- public Rule findById(int ruleId) {
- return null;
- }
-
- @Override
- public Rule findByKey(String repositoryKey, String key) {
- return null;
- }
-
- @Override
- public Rule findByKey(RuleKey key) {
- Rule rule = Rule.create().setRepositoryKey(key.repository()).setKey(key.rule());
- rule.setId(200);
- return rule;
- }
-
- @Override
- public Rule find(RuleQuery query) {
- return null;
- }
-
- @Override
- public Collection<Rule> findAll(RuleQuery query) {
- return null;
- }
- }
-}