if (rule.isExternal()) {
getScmChangeDate(component, issue).ifPresent(changeDate -> updateDate(issue, changeDate));
} else {
- ActiveRule activeRule = toJavaUtilOptional(activeRulesHolder.get(issue.getRuleKey()))
- .orElseThrow(illegalStateException("The rule %s raised an issue, but is not one of the active rules.", issue.getRuleKey()));
+ // Rule can't be inactive (see contract of IssueVisitor)
+ ActiveRule activeRule = activeRulesHolder.get(issue.getRuleKey()).get();
if (firstAnalysis || activeRuleIsNew(activeRule, lastAnalysisOptional.get())
|| ruleImplementationChanged(activeRule.getRuleKey(), activeRule.getPluginKey(), lastAnalysisOptional.get())) {
getScmChangeDate(component, issue).ifPresent(changeDate -> updateDate(issue, changeDate));
issueUpdater.setCreationDate(issue, scmDate, changeContext);
}
- private static <T> Optional<T> toJavaUtilOptional(com.google.common.base.Optional<T> scmInfo) {
- return scmInfo.transform(Optional::of).or(Optional::empty);
- }
-
private static Supplier<? extends IllegalStateException> illegalStateException(String str, Object... args) {
return () -> new IllegalStateException(String.format(str, args));
}
* This method is called for each issue of a component when tracking is done and issue is initialized.
* That means that the following fields are set: resolution, status, line, creation date, uuid
* and all the fields merged from base issues.
+ * <br/>
+ * The related rule is active in the Quality profile. Issues on inactive rules
+ * are ignored.
*/
public void onIssue(Component component, DefaultIssue issue) {
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder;
import org.sonar.server.computation.task.projectanalysis.issue.commonrule.CommonRuleEngine;
import org.sonar.server.computation.task.projectanalysis.issue.filter.IssueFilter;
+import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolder;
import org.sonar.server.computation.task.projectanalysis.source.SourceLinesHashRepository;
import org.sonar.server.rule.CommonRuleKeys;
private final IssueFilter issueFilter;
private final SourceLinesHashRepository sourceLinesHash;
private final RuleRepository ruleRepository;
+ private final ActiveRulesHolder activeRulesHolder;
public TrackerRawInputFactory(TreeRootHolder treeRootHolder, BatchReportReader reportReader,
- SourceLinesHashRepository sourceLinesHash, CommonRuleEngine commonRuleEngine, IssueFilter issueFilter, RuleRepository ruleRepository) {
+ SourceLinesHashRepository sourceLinesHash, CommonRuleEngine commonRuleEngine, IssueFilter issueFilter, RuleRepository ruleRepository,
+ ActiveRulesHolder activeRulesHolder) {
this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
this.sourceLinesHash = sourceLinesHash;
this.commonRuleEngine = commonRuleEngine;
this.issueFilter = issueFilter;
this.ruleRepository = ruleRepository;
+ this.activeRulesHolder = activeRulesHolder;
}
public Input<DefaultIssue> create(Component component) {
// as late as possible
while (reportIssues.hasNext()) {
ScannerReport.Issue reportIssue = reportIssues.next();
+ if (isOnInactiveRule(reportIssue)) {
+ continue;
+ }
if (!isIssueOnUnsupportedCommonRule(reportIssue)) {
Loggers.get(getClass()).debug("Ignored issue from analysis report on rule {}:{}", reportIssue.getRuleRepository(), reportIssue.getRuleKey());
continue;
return result;
}
+ private boolean isOnInactiveRule(ScannerReport.Issue reportIssue) {
+ RuleKey ruleKey = RuleKey.of(reportIssue.getRuleRepository(), reportIssue.getRuleKey());
+ return !activeRulesHolder.get(ruleKey).isPresent();
+ }
+
private boolean isIssueOnUnsupportedCommonRule(ScannerReport.Issue issue) {
// issues on batch common rules are ignored. This feature
// is natively supported by compute engine since 5.2.
import org.sonar.server.computation.task.projectanalysis.filemove.MovedFilesRepository;
import org.sonar.server.computation.task.projectanalysis.issue.commonrule.CommonRuleEngineImpl;
import org.sonar.server.computation.task.projectanalysis.issue.filter.IssueFilter;
+import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolder;
import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
import org.sonar.server.computation.task.projectanalysis.source.SourceLinesHashRepository;
+import org.sonar.server.computation.task.projectanalysis.qualityprofile.AlwaysActiveRulesHolderImpl;
import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepositoryRule;
import static com.google.common.collect.Lists.newArrayList;
public class IntegrateIssuesVisitorTest {
- static final String FILE_UUID = "FILE_UUID";
- static final String FILE_UUID_ON_BRANCH = "FILE_UUID_BRANCH";
- static final String FILE_KEY = "FILE_KEY";
- static final int FILE_REF = 2;
+ private static final String FILE_UUID = "FILE_UUID";
+ private static final String FILE_UUID_ON_BRANCH = "FILE_UUID_BRANCH";
+ private static final String FILE_KEY = "FILE_KEY";
+ private static final int FILE_REF = 2;
- static final Component FILE = builder(Component.Type.FILE, FILE_REF)
+ private static final Component FILE = builder(Component.Type.FILE, FILE_REF)
.setKey(FILE_KEY)
.setUuid(FILE_UUID)
.build();
- static final String PROJECT_KEY = "PROJECT_KEY";
- static final String PROJECT_UUID = "PROJECT_UUID";
- static final String PROJECT_UUID_ON_BRANCH = "PROJECT_UUID_BRANCH";
- static final int PROJECT_REF = 1;
- static final Component PROJECT = builder(Component.Type.PROJECT, PROJECT_REF)
+ private static final String PROJECT_KEY = "PROJECT_KEY";
+ private static final String PROJECT_UUID = "PROJECT_UUID";
+ private static final String PROJECT_UUID_ON_BRANCH = "PROJECT_UUID_BRANCH";
+ private static final int PROJECT_REF = 1;
+ private static final Component PROJECT = builder(Component.Type.PROJECT, PROJECT_REF)
.setKey(PROJECT_KEY)
.setUuid(PROJECT_UUID)
.addChildren(FILE)
private MergeBranchComponentUuids mergeBranchComponentUuids = mock(MergeBranchComponentUuids.class);
private SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
- ArgumentCaptor<DefaultIssue> defaultIssueCaptor;
+ private ArgumentCaptor<DefaultIssue> defaultIssueCaptor;
- ComponentIssuesLoader issuesLoader = new ComponentIssuesLoader(dbTester.getDbClient(), ruleRepositoryRule, activeRulesHolderRule);
- IssueTrackingDelegator trackingDelegator;
- TrackerExecution tracker;
- ShortBranchTrackerExecution shortBranchTracker;
- MergeBranchTrackerExecution mergeBranchTracker;
- IssueCache issueCache;
+ private ComponentIssuesLoader issuesLoader = new ComponentIssuesLoader(dbTester.getDbClient(), ruleRepositoryRule, activeRulesHolderRule);
+ private IssueTrackingDelegator trackingDelegator;
+ private TrackerExecution tracker;
+ private ShortBranchTrackerExecution shortBranchTracker;
+ private MergeBranchTrackerExecution mergeBranchTracker;
+ private ActiveRulesHolder activeRulesHolder = new AlwaysActiveRulesHolderImpl();
+ private IssueCache issueCache;
- TypeAwareVisitor underTest;
+ private TypeAwareVisitor underTest;
@Before
public void setUp() throws Exception {
defaultIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
when(movedFilesRepository.getOriginalFile(any(Component.class))).thenReturn(Optional.absent());
- TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(), issueFilter, ruleRepository);
+ TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(), issueFilter, ruleRepository, activeRulesHolder);
TrackerBaseInputFactory baseInputFactory = new TrackerBaseInputFactory(issuesLoader, dbTester.getDbClient(), movedFilesRepository);
TrackerMergeBranchInputFactory mergeInputFactory = new TrackerMergeBranchInputFactory(issuesLoader, mergeBranchComponentsUuids, dbTester.getDbClient());
tracker = new TrackerExecution(baseInputFactory, rawInputFactory, new Tracker<>());
import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.server.computation.task.projectanalysis.issue.commonrule.CommonRuleEngine;
import org.sonar.server.computation.task.projectanalysis.issue.filter.IssueFilter;
+import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRule;
+import org.sonar.server.computation.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
import org.sonar.server.computation.task.projectanalysis.source.SourceLinesHashRepository;
import org.sonar.server.rule.CommonRuleKeys;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT);
-
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
-
+ @Rule
+ public ActiveRulesHolderRule activeRulesHolder = new ActiveRulesHolderRule();
@Rule
public RuleRepositoryRule ruleRepository = new RuleRepositoryRule();
- SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
- CommonRuleEngine commonRuleEngine = mock(CommonRuleEngine.class);
- IssueFilter issueFilter = mock(IssueFilter.class);
- TrackerRawInputFactory underTest = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, commonRuleEngine, issueFilter, ruleRepository);
+ private SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
+ private CommonRuleEngine commonRuleEngine = mock(CommonRuleEngine.class);
+ private IssueFilter issueFilter = mock(IssueFilter.class);
+ private TrackerRawInputFactory underTest = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash,
+ commonRuleEngine, issueFilter, ruleRepository, activeRulesHolder);
@Test
public void load_source_hash_sequences() {
@Test
public void load_issues_from_report() {
- when(issueFilter.accept(any(DefaultIssue.class), eq(FILE))).thenReturn(true);
+ RuleKey ruleKey = RuleKey.of("java", "S001");
+ markRuleAsActive(ruleKey);
+ when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
+
when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
.setTextRange(TextRange.newBuilder().setStartLine(2).build())
.setMsg("the message")
- .setRuleRepository("java")
- .setRuleKey("S001")
+ .setRuleRepository(ruleKey.repository())
+ .setRuleKey(ruleKey.rule())
.setSeverity(Constants.Severity.BLOCKER)
.setGap(3.14)
.build();
- reportReader.putIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
+ reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
Input<DefaultIssue> input = underTest.create(FILE);
Collection<DefaultIssue> issues = input.getIssues();
DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
// fields set by analysis report
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("java", "S001"));
+ assertThat(issue.ruleKey()).isEqualTo(ruleKey);
assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
assertThat(issue.line()).isEqualTo(2);
assertThat(issue.effortToFix()).isEqualTo(3.14);
// fields set by compute engine
assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
assertThat(issue.tags()).isEmpty();
- assertInitializedIssue(issue);
+ assertInitializedExternalIssue(issue);
}
@Test
// fields set by compute engine
assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
assertThat(issue.tags()).isEmpty();
- assertInitializedIssue(issue);
+ assertInitializedExternalIssue(issue);
}
@Test
- public void ignore_issue_from_report() {
- when(issueFilter.accept(any(DefaultIssue.class), eq(FILE))).thenReturn(false);
+ public void excludes_issues_on_inactive_rules() {
+ RuleKey ruleKey = RuleKey.of("java", "S001");
+ when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
+
when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
.setTextRange(TextRange.newBuilder().setStartLine(2).build())
.setMsg("the message")
- .setRuleRepository("java")
- .setRuleKey("S001")
+ .setRuleRepository(ruleKey.repository())
+ .setRuleKey(ruleKey.rule())
.setSeverity(Constants.Severity.BLOCKER)
.setGap(3.14)
.build();
- reportReader.putIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
+ reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
Input<DefaultIssue> input = underTest.create(FILE);
Collection<DefaultIssue> issues = input.getIssues();
}
@Test
- public void ignore_report_issues_on_common_rules() {
+ public void filter_excludes_issues_from_report() {
+ RuleKey ruleKey = RuleKey.of("java", "S001");
+ markRuleAsActive(ruleKey);
+ when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
+ .setTextRange(TextRange.newBuilder().setStartLine(2).build())
.setMsg("the message")
- .setRuleRepository(CommonRuleKeys.commonRepositoryForLang("java"))
- .setRuleKey("S001")
+ .setRuleRepository(ruleKey.repository())
+ .setRuleKey(ruleKey.rule())
+ .setSeverity(Constants.Severity.BLOCKER)
+ .setGap(3.14)
+ .build();
+ reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
+ Input<DefaultIssue> input = underTest.create(FILE);
+
+ Collection<DefaultIssue> issues = input.getIssues();
+ assertThat(issues).isEmpty();
+ }
+
+ @Test
+ public void exclude_issues_on_common_rules() {
+ RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "S001");
+ markRuleAsActive(ruleKey);
+ when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
+ ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
+ .setMsg("the message")
+ .setRuleRepository(ruleKey.repository())
+ .setRuleKey(ruleKey.rule())
.setSeverity(Constants.Severity.BLOCKER)
.build();
- reportReader.putIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
+ reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
Input<DefaultIssue> input = underTest.create(FILE);
@Test
public void load_issues_of_compute_engine_common_rules() {
- when(issueFilter.accept(any(DefaultIssue.class), eq(FILE))).thenReturn(true);
+ RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage");
+ markRuleAsActive(ruleKey);
+ when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
DefaultIssue ceIssue = new DefaultIssue()
- .setRuleKey(RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage"))
+ .setRuleKey(ruleKey)
.setMessage("not enough coverage")
.setGap(10.0);
- when(commonRuleEngine.process(FILE)).thenReturn(asList(ceIssue));
+ when(commonRuleEngine.process(FILE)).thenReturn(singletonList(ceIssue));
Input<DefaultIssue> input = underTest.create(FILE);
}
@Test
- public void ignore_issue_from_common_rule() {
- when(issueFilter.accept(any(DefaultIssue.class), eq(FILE))).thenReturn(false);
+ public void filter_exclude_issues_on_common_rule() {
+ RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage");
+ markRuleAsActive(ruleKey);
+ when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
DefaultIssue ceIssue = new DefaultIssue()
- .setRuleKey(RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "InsufficientCoverage"))
+ .setRuleKey(ruleKey)
.setMessage("not enough coverage")
.setGap(10.0);
- when(commonRuleEngine.process(FILE)).thenReturn(asList(ceIssue));
+ when(commonRuleEngine.process(FILE)).thenReturn(singletonList(ceIssue));
Input<DefaultIssue> input = underTest.create(FILE);
assertThat(issue.status()).isEqualTo(Issue.STATUS_OPEN);
assertThat(issue.key()).isNull();
assertThat(issue.authorLogin()).isNull();
+ assertThat(issue.effort()).isNull();
+ assertThat(issue.effortInMinutes()).isNull();
+ assertThat(issue.debt()).isNull();
+ }
+
+ private void assertInitializedExternalIssue(DefaultIssue issue) {
+ assertThat(issue.projectKey()).isEqualTo(PROJECT.getPublicKey());
+ assertThat(issue.componentKey()).isEqualTo(FILE.getPublicKey());
+ assertThat(issue.componentUuid()).isEqualTo(FILE.getUuid());
+ assertThat(issue.resolution()).isNull();
+ assertThat(issue.status()).isEqualTo(Issue.STATUS_OPEN);
+ assertThat(issue.key()).isNull();
+ assertThat(issue.authorLogin()).isNull();
+ }
+
+ private void markRuleAsActive(RuleKey ruleKey) {
+ activeRulesHolder.put(new ActiveRule(ruleKey, Severity.CRITICAL, emptyMap(), 1_000L, null));
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.server.computation.task.projectanalysis.qualityprofile;
+
+import com.google.common.base.Optional;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+
+import static java.util.Collections.emptyMap;
+
+public class AlwaysActiveRulesHolderImpl implements ActiveRulesHolder {
+ @Override
+ public Optional<ActiveRule> get(RuleKey ruleKey) {
+ return Optional.of(new ActiveRule(ruleKey, Severity.MAJOR, emptyMap(), 1_000L, null));
+ }
+
+}
include 'tests:plugins:backdating-plugin-v2'
include 'tests:plugins:base-auth-plugin'
include 'tests:plugins:batch-plugin'
+include 'tests:plugins:blue-green-plugin-v1'
+include 'tests:plugins:blue-green-plugin-v2'
include 'tests:plugins:extension-lifecycle-plugin'
include 'tests:plugins:fake-billing-plugin'
include 'tests:plugins:fake-governance-plugin'
':tests:plugins:backdating-customplugin',
':tests:plugins:base-auth-plugin',
':tests:plugins:batch-plugin',
+ ':tests:plugins:blue-green-plugin-v1',
+ ':tests:plugins:blue-green-plugin-v2',
':tests:plugins:extension-lifecycle-plugin',
':tests:plugins:fake-billing-plugin',
':tests:plugins:fake-governance-plugin',
--- /dev/null
+sonarqube {
+ skipProject = true
+}
+
+dependencies {
+ compileOnly 'com.google.code.findbugs:jsr305'
+ compileOnly project(path: ':sonar-plugin-api', configuration: 'shadow')
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Plugin-Key': 'bluegreen',
+ 'Plugin-Version': '1.0',
+ 'Plugin-Class': 'org.sonarqube.qa.bluegreen.BlueGreenPlugin',
+ 'Plugin-ChildFirstClassLoader': 'false',
+ 'Sonar-Version': version,
+ 'SonarLint-Supported': 'false',
+ 'Plugin-Name': 'BlueGreen',
+ 'Plugin-License': 'GNU LGPL 3'
+ )
+ }
+ into('META-INF/lib') {
+ from configurations.compile
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.Plugin;
+
+public class BlueGreenPlugin implements Plugin {
+
+ @Override
+ public void define(Context context) {
+ context.addExtensions(
+ BuiltInProfilesV1.class,
+ PageDefinitionV1.class,
+ RulesDefinitionV1.class,
+ RuleSensorV1.class);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
+
+public class BuiltInProfilesV1 implements BuiltInQualityProfilesDefinition {
+ @Override
+ public void define(Context context) {
+ NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile("Blue Profile", "xoo");
+ profile.activateRule(RulesDefinitionV1.REPOSITORY_KEY, "a").overrideSeverity("BLOCKER");
+ profile.activateRule(RulesDefinitionV1.REPOSITORY_KEY, "b").overrideSeverity("CRITICAL");
+ profile.done();
+ }
+}
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.web.page.Context;
+import org.sonar.api.web.page.Page;
+import org.sonar.api.web.page.PageDefinition;
+
+public class PageDefinitionV1 implements PageDefinition {
+ @Override
+ public void define(Context context) {
+ context
+ .addPage(Page.builder("bluegreen/global_page").setName("Blue Green Page").build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
+
+import static org.sonarqube.qa.bluegreen.RulesDefinitionV1.REPOSITORY_KEY;
+
+public class RuleSensorV1 implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.createIssuesForRuleRepositories(REPOSITORY_KEY)
+ .onlyOnLanguage("xoo")
+ .name("BlueGreen V1");
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ for (InputFile inputFile : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguage("xoo"))) {
+ saveIssue(context, inputFile, "a");
+ saveIssue(context, inputFile, "b");
+ }
+ }
+
+ private void saveIssue(SensorContext context, InputFile inputFile, String ruleKey) {
+ NewIssue newIssue = context.newIssue();
+ newIssue.at(newIssue.newLocation().on(inputFile).at(inputFile.selectLine(1)))
+ .forRule(RuleKey.of(REPOSITORY_KEY, ruleKey))
+ .save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.server.rule.RulesDefinition;
+
+public class RulesDefinitionV1 implements RulesDefinition {
+
+ public static final String REPOSITORY_KEY = "bluegreen";
+
+ @Override
+ public void define(Context context) {
+ NewRepository repo = context.createRepository(REPOSITORY_KEY, "xoo").setName("BlueGreen");
+ repo.createRule("a").setName("Rule A").setHtmlDescription("Rule A");
+ repo.createRule("b").setName("Rule B").setHtmlDescription("Rule B");
+ repo.done();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+window.registerExtension('bluegreen/global_page', function (options) {
+ options.el.textContent = 'BLUE';
+ return function () {};
+});
--- /dev/null
+sonarqube {
+ skipProject = true
+}
+
+dependencies {
+ compileOnly 'com.google.code.findbugs:jsr305'
+ compileOnly project(path: ':sonar-plugin-api', configuration: 'shadow')
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Plugin-Key': 'bluegreen',
+ 'Plugin-Version': '2.0',
+ 'Plugin-Class': 'org.sonarqube.qa.bluegreen.BlueGreenPlugin',
+ 'Plugin-ChildFirstClassLoader': 'false',
+ 'Sonar-Version': version,
+ 'SonarLint-Supported': 'false',
+ 'Plugin-Name': 'BlueGreen',
+ 'Plugin-License': 'GNU LGPL 3'
+ )
+ }
+ into('META-INF/lib') {
+ from configurations.compile
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.Plugin;
+
+public class BlueGreenPlugin implements Plugin {
+
+ @Override
+ public void define(Context context) {
+ context.addExtensions(
+ BuiltInProfilesV2.class,
+ PageDefinitionV2.class,
+ RulesDefinitionV2.class,
+ RuleSensorV2.class);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
+
+public class BuiltInProfilesV2 implements BuiltInQualityProfilesDefinition {
+ @Override
+ public void define(Context context) {
+ NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile("Green Profile", "xoo");
+ profile.activateRule(RulesDefinitionV2.REPOSITORY_KEY, "b").overrideSeverity("MINOR");
+ profile.activateRule(RulesDefinitionV2.REPOSITORY_KEY, "c").overrideSeverity("INFO");
+ profile.done();
+ }
+}
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.web.page.Context;
+import org.sonar.api.web.page.Page;
+import org.sonar.api.web.page.PageDefinition;
+
+public class PageDefinitionV2 implements PageDefinition {
+ @Override
+ public void define(Context context) {
+ context
+ .addPage(Page.builder("bluegreen/global_page").setName("Blue Green Page").build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
+
+import static org.sonarqube.qa.bluegreen.RulesDefinitionV2.REPOSITORY_KEY;
+
+public class RuleSensorV2 implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.createIssuesForRuleRepositories(REPOSITORY_KEY)
+ .onlyOnLanguage("xoo")
+ .name("BlueGreen V2");
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ for (InputFile inputFile : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguage("xoo"))) {
+ saveIssue(context, inputFile, "b");
+ saveIssue(context, inputFile, "c");
+ }
+ }
+
+ private void saveIssue(SensorContext context, InputFile inputFile, String ruleKey) {
+ NewIssue newIssue = context.newIssue();
+ newIssue.at(newIssue.newLocation().on(inputFile).at(inputFile.selectLine(1)))
+ .forRule(RuleKey.of(REPOSITORY_KEY, ruleKey))
+ .save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.server.rule.RulesDefinition;
+
+public class RulesDefinitionV2 implements RulesDefinition {
+
+ public static final String REPOSITORY_KEY = "bluegreen";
+
+ @Override
+ public void define(Context context) {
+ NewRepository repo = context.createRepository(REPOSITORY_KEY, "xoo").setName("BlueGreen");
+ repo.createRule("b").setName("Rule B").setHtmlDescription("Rule B");
+ repo.createRule("c").setName("Rule C").setHtmlDescription("Rule C");
+ repo.done();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.
+ */
+window.registerExtension('bluegreen/global_page', function (options) {
+ options.el.textContent = 'GREEN';
+ return function () {};
+});
--- /dev/null
+sonarqube {
+ skipProject = true
+}
+
+dependencies {
+ compile 'com.google.guava:guava'
+ compile 'commons-io:commons-io'
+ compile 'commons-lang:commons-lang'
+ compileOnly 'com.google.code.findbugs:jsr305'
+ compileOnly project(path: ':sonar-plugin-api', configuration: 'shadow')
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Plugin-Key': 'bluegreen',
+ 'Plugin-Version': version,
+ 'Plugin-Class': 'org.sonarqube.qa.bluegreen',
+ 'Plugin-ChildFirstClassLoader': 'false',
+ 'Sonar-Version': version,
+ 'SonarLint-Supported': 'false',
+ 'Plugin-Name': 'Foo',
+ 'Plugin-License': 'GNU LGPL 3'
+ )
+ }
+ into('META-INF/lib') {
+ from configurations.compile
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import java.util.Optional;
+import org.sonar.api.Plugin;
+
+public class BlueGreenPlugin implements Plugin {
+
+ @Override
+ public void define(Context context) {
+ Optional<String> version = context.getBootConfiguration().get("bluegreenplugin.version");
+ if (version.isPresent()) {
+ if (version.get().equals("1")) {
+ context.addExtension(RulesDefinitionV1.class);
+
+ } else if (version.get().equals("2")) {
+ context.addExtension(RulesDefinitionV2.class);
+
+ }
+ }
+ }
+
+}
--- /dev/null
+package org.sonarqube.qa.bluegreen;
+
+public class BuiltInProfileV1 {
+}
--- /dev/null
+package org.sonarqube.qa.bluegreen;
+
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
+
+public class BuiltInProfilesV2 implements BuiltInQualityProfilesDefinition {
+ @Override
+ public void define(Context context) {
+ NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile("Profile One", "xoo");
+ profile.setDefault(true);
+ profile.activateRule(RulesDefinitionV1.REPOSITORY_KEY, "a").overrideSeverity("BLOCKER");
+ profile.activateRule(RulesDefinitionV1.REPOSITORY_KEY, "b").overrideSeverity("CRITICAL");
+ profile.done();
+ }
+}
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.plugins.backdating.rule.BackRulesDefinition;
+
+public class RuleSensorV1 implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.createIssuesForRuleRepositories(BackRulesDefinition.BACK_REPOSITORY)
+ .onlyOnLanguage("xoo")
+ .name("Back V1");
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ for (InputFile inputFile : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguage("xoo"))) {
+ int lineNb = 0;
+ try {
+ BufferedReader reader = new BufferedReader(new StringReader(inputFile.contents()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ lineNb++;
+ if (line.contains("BACKV1")) {
+ NewIssue newIssue = context.newIssue();
+ newIssue.at(newIssue.newLocation().on(inputFile).at(inputFile.selectLine(lineNb)))
+ .forRule(RuleKey.of(BackRulesDefinition.BACK_REPOSITORY, BackRulesDefinition.RULE_KEY))
+ .save();
+ }
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.rule.RuleKey;
+
+import static org.sonarqube.qa.bluegreen.RulesDefinitionV1.REPOSITORY_KEY;
+
+public class RuleSensorV2 implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.createIssuesForRuleRepositories(REPOSITORY_KEY)
+ .onlyOnLanguage("xoo")
+ .name("BlueGreen V1");
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ for (InputFile inputFile : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguage("xoo"))) {
+ saveIssue(context, inputFile, "a");
+ saveIssue(context, inputFile, "b");
+ }
+ }
+
+ private void saveIssue(SensorContext context, InputFile inputFile, String ruleKey) {
+ NewIssue newIssue = context.newIssue();
+ newIssue.at(newIssue.newLocation().on(inputFile).at(inputFile.selectLine(1)))
+ .forRule(RuleKey.of(REPOSITORY_KEY, ruleKey))
+ .save();
+ }
+
+}
--- /dev/null
+package org.sonarqube.qa.bluegreen;
+
+public class RulesDefinitionV1 {
+}
--- /dev/null
+package org.sonarqube.qa.bluegreen;
+
+import org.sonar.api.server.rule.RulesDefinition;
+
+public class RulesDefinitionV2 implements RulesDefinition {
+
+ @Override
+ public void define(Context context) {
+ NewRepository repo = context.createRepository("bluegreen", "xoo").setName("BlueGreen");
+ repo.createRule("a").setName("Rule A").setHtmlDescription("Rule A");
+ repo.createRule("b").setName("Rule B").setHtmlDescription("Rule B");
+ repo.done();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.qa.bluegreen;
+
+import javax.annotation.ParametersAreNonnullByDefault;
import org.sonarqube.tests.qualityProfile.ActiveRuleEsResilienceTest;
import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest;
import org.sonarqube.tests.rule.RuleEsResilienceTest;
+import org.sonarqube.tests.serverSystem.BlueGreenTest;
import org.sonarqube.tests.serverSystem.RestartTest;
import org.sonarqube.tests.serverSystem.ServerSystemRestartingOrchestrator;
import org.sonarqube.tests.serverSystem.SystemStateTest;
@Deprecated
@RunWith(Suite.class)
@Suite.SuiteClasses({
+ BlueGreenTest.class,
ServerSystemRestartingOrchestrator.class,
RestartTest.class,
SettingsTestRestartingOrchestrator.class,
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonarqube.tests.serverSystem;
+
+import com.google.common.util.concurrent.Uninterruptibles;
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.build.SonarScanner;
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+import org.sonarqube.qa.util.Tester;
+import org.sonarqube.qa.util.pageobjects.Navigation;
+import org.sonarqube.ws.Ce;
+import org.sonarqube.ws.Projects;
+import org.sonarqube.ws.client.ce.ActivityStatusRequest;
+import org.sonarqube.ws.client.qualityprofiles.AddProjectRequest;
+import util.XooProjectBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static util.ItUtils.newOrchestratorBuilder;
+import static util.ItUtils.pluginArtifact;
+import static util.ItUtils.xooPlugin;
+
+public class BlueGreenTest {
+
+ @Rule
+ public TestRule safeguard = new DisableOnDebug(Timeout.seconds(600));
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private Orchestrator orchestrator;
+ private Tester tester;
+
+ @After
+ public void tearDown() {
+ if (tester != null) {
+ tester.after();
+ }
+ if (orchestrator != null) {
+ orchestrator.stop();
+ }
+ }
+
+ @Test
+ public void test_change_of_version_at_runtime() throws Exception {
+ orchestrator = newOrchestratorBuilder()
+ .addPlugin(pluginArtifact("blue-green-plugin-v1"))
+ .addPlugin(xooPlugin())
+ .build();
+ tester = new Tester(orchestrator).disableOrganizations();
+ orchestrator.start();
+ tester.before();
+
+ // pause compute engine so that analysis is kept pending
+ tester.wsClient().ce().pause();
+ Projects.CreateWsResponse.Project project = tester.projects().provision();
+ associateProjectToProfile(project, "Blue Profile");
+ analyze(project);
+ assertThat(loadCeActivity().getPending()).isEqualTo(1);
+
+ // open browser
+ Navigation browser = tester.openBrowser();
+
+
+ // upgrade plugin
+ File pluginV2 = pluginArtifact("blue-green-plugin-v2").getFile();
+ FileUtils.copyFileToDirectory(pluginV2, new File(orchestrator.getServer().getHome(), "extensions/downloads"));
+ orchestrator.restartServer();
+
+ // analysis task is still pending
+ Ce.ActivityStatusWsResponse ceActivity = loadCeActivity();
+ assertThat(ceActivity.getInProgress()).isEqualTo(0);
+ assertThat(ceActivity.getPending()).isEqualTo(1);
+
+ resumeAndWaitForCeQueueEmpty();
+
+ // TODO check issues and measures
+ }
+
+ private void analyze(Projects.CreateWsResponse.Project project) throws IOException {
+ File projectDir = new XooProjectBuilder(project.getKey())
+ .setFilesPerModule(1)
+ .build(temp.newFolder());
+ orchestrator.executeBuild(SonarScanner.create(projectDir), false);
+ }
+
+ private void associateProjectToProfile(Projects.CreateWsResponse.Project project, String xooProfileName) {
+ tester.wsClient().qualityprofiles().addProject(new AddProjectRequest()
+ .setProject(project.getKey())
+ .setLanguage("xoo")
+ .setQualityProfile(xooProfileName));
+ }
+
+ private void resumeAndWaitForCeQueueEmpty() {
+ tester.wsClient().ce().resume();
+ while (true) {
+ Ce.ActivityStatusWsResponse activity = loadCeActivity();
+ if (activity.getPending() + activity.getInProgress() == 0) {
+ return;
+ }
+ Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ private Ce.ActivityStatusWsResponse loadCeActivity() {
+ return tester.wsClient().ce().activityStatus(new ActivityStatusRequest());
+ }
+}
for (int i = 0; i < filesPerModule; i++) {
File sourceFile = new File(sourceDir, "File" + i + ".xoo");
FileUtils.write(sourceFile, "content of " + sourceFile.getName());
+
+ File measuresFile = new File(sourceFile + ".measures");
+ FileUtils.write(measuresFile, "ncloc:10\n" +
+ "comment_lines:3\n");
}
Properties props = new Properties();
props.setProperty("sonar.projectKey", key);