aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2017-04-25 10:47:37 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2017-04-26 16:34:31 +0200
commit4d9cbe9276073d6b026cbaf8510743aa0b62c4fb (patch)
tree6cad753829d8d037a98dffd1a35aade91968170d /server
parentc3403683032b6077ef3e38caad872c040a22daaf (diff)
downloadsonarqube-4d9cbe9276073d6b026cbaf8510743aa0b62c4fb.tar.gz
sonarqube-4d9cbe9276073d6b026cbaf8510743aa0b62c4fb.zip
SONAR-9126 Allow preventing projects analysis on a organization
Diffstat (limited to 'server')
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java2
-rw-r--r--server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java76
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsExtension.java32
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxy.java30
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java43
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java42
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java59
10 files changed, 301 insertions, 3 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
index d0600dc7e0d..90fe0838bb2 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
@@ -96,6 +96,7 @@ import org.sonar.server.notification.NotificationCenter;
import org.sonar.server.notification.NotificationService;
import org.sonar.server.notification.email.AlertsEmailTemplate;
import org.sonar.server.notification.email.EmailNotificationChannel;
+import org.sonar.server.organization.BillingValidationsProxyImpl;
import org.sonar.server.organization.DefaultOrganizationProviderImpl;
import org.sonar.server.permission.GroupPermissionChanger;
import org.sonar.server.permission.PermissionTemplateService;
@@ -289,6 +290,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
ResourceTypes.class,
DefaultResourceTypes.get(),
Periods.class,
+ BillingValidationsProxyImpl.class,
// quality profile
ActiveRuleIndexer.class,
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
index 89a1da47da4..edf0062e394 100644
--- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
+++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
@@ -88,7 +88,7 @@ public class ComputeEngineContainerImplTest {
assertThat(picoContainer.getComponentAdapters())
.hasSize(
CONTAINER_ITSELF
- + 73 // level 4
+ + 74 // level 4
+ 4 // content of CeConfigurationModule
+ 5 // content of CeQueueModule
+ 3 // content of CeHttpModule
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java
index fd8f7cb451d..c89f97140d1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java
@@ -38,6 +38,9 @@ import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysi
import org.sonar.server.computation.task.projectanalysis.analysis.Organization;
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader;
import org.sonar.server.computation.task.step.ComputationStep;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidations.BillingValidationsException;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.qualityprofile.QualityProfile;
@@ -66,14 +69,16 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep {
private final MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder;
private final DefaultOrganizationProvider defaultOrganizationProvider;
private final DbClient dbClient;
+ private final BillingValidations billingValidations;
public LoadReportAnalysisMetadataHolderStep(CeTask ceTask, BatchReportReader reportReader, MutableAnalysisMetadataHolder mutableAnalysisMetadataHolder,
- DefaultOrganizationProvider defaultOrganizationProvider, DbClient dbClient) {
+ DefaultOrganizationProvider defaultOrganizationProvider, DbClient dbClient, BillingValidationsProxy billingValidations) {
this.ceTask = ceTask;
this.reportReader = reportReader;
this.mutableAnalysisMetadataHolder = mutableAnalysisMetadataHolder;
this.defaultOrganizationProvider = defaultOrganizationProvider;
this.dbClient = dbClient;
+ this.billingValidations = billingValidations;
}
@Override
@@ -84,6 +89,7 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep {
checkProjectKeyConsistency(reportMetadata);
Organization organization = toOrganization(ceTask.getOrganizationUuid());
checkOrganizationKeyConsistency(reportMetadata, organization);
+ checkOrganizationCanExecuteAnalysis(organization);
checkQualityProfilesConsistency(reportMetadata, organization);
mutableAnalysisMetadataHolder.setRootComponentRef(reportMetadata.getRootComponentRef());
@@ -146,6 +152,14 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep {
}
}
+ private void checkOrganizationCanExecuteAnalysis(Organization organization) {
+ try {
+ billingValidations.checkOnProjectAnalysis(new BillingValidations.Organization(organization.getKey(), organization.getUuid()));
+ } catch (BillingValidationsException e) {
+ throw MessageException.of(e.getMessage());
+ }
+ }
+
private String resolveReportOrganizationKey(@Nullable String organizationKey) {
if (reportBelongsToDefaultOrganization(organizationKey)) {
return defaultOrganizationProvider.get().getKey();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
new file mode 100644
index 00000000000..1c524acce1a
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.organization;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Available checks that will be done by the billing plugin.
+ * When the billing plugin is not loaded, no check will be done.
+ * This is not the interface that should be implemented by the plugin, but {@link BillingValidationsExtension}
+ */
+public interface BillingValidations {
+
+ /**
+ * @throws BillingValidationsException when projects analysis on organization is not allowed
+ */
+ void checkOnProjectAnalysis(Organization organization);
+
+ class Organization {
+ private final String key;
+ private final String uuid;
+
+ public Organization(String key, String uuid) {
+ this.key = requireNonNull(key, "Organization key cannot be null");
+ this.uuid = requireNonNull(uuid, "Organization uuid cannot be null");
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+ }
+
+ class BillingValidationsException extends RuntimeException {
+ public BillingValidationsException(String message) {
+ super(message);
+ }
+
+ /**
+ * Does not fill in the stack trace
+ *
+ * @see java.lang.Throwable#fillInStackTrace()
+ */
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return getMessage();
+ }
+
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsExtension.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsExtension.java
new file mode 100644
index 00000000000..0b70671d8c9
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsExtension.java
@@ -0,0 +1,32 @@
+/*
+ * 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.server.organization;
+
+import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.server.ServerSide;
+
+/**
+ * The billing plugin must implement this interface
+ */
+@ServerSide
+@ComputeEngineSide
+public interface BillingValidationsExtension extends BillingValidations {
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxy.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxy.java
new file mode 100644
index 00000000000..f0b52192d2b
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxy.java
@@ -0,0 +1,30 @@
+/*
+ * 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.server.organization;
+
+/**
+ * The goal of this class is to handle the 2 different use case :
+ * - The billing plugin exists, the proxy will redirect method calls to the plugin
+ * - No billing plugin, every methods won't do anything
+ */
+public interface BillingValidationsProxy extends BillingValidations {
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
new file mode 100644
index 00000000000..c091e346b9e
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
@@ -0,0 +1,43 @@
+/*
+ * 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.server.organization;
+
+public class BillingValidationsProxyImpl implements BillingValidationsProxy {
+
+ private final BillingValidationsExtension billingValidationsExtension;
+
+ public BillingValidationsProxyImpl(BillingValidationsExtension billingValidationsExtension) {
+ this.billingValidationsExtension = billingValidationsExtension;
+ }
+
+ // Used when no plugin is providing the extension
+ public BillingValidationsProxyImpl() {
+ this.billingValidationsExtension = null;
+ }
+
+ @Override
+ public void checkOnProjectAnalysis(Organization organization) {
+ if (billingValidationsExtension == null) {
+ return;
+ }
+ billingValidationsExtension.checkOnProjectAnalysis(organization);
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
index a979638fdfd..294a3dbde4c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
@@ -84,6 +84,7 @@ import org.sonar.server.metric.CoreCustomMetrics;
import org.sonar.server.metric.DefaultMetricFinder;
import org.sonar.server.metric.ws.MetricsWsModule;
import org.sonar.server.notification.NotificationModule;
+import org.sonar.server.organization.BillingValidationsProxyImpl;
import org.sonar.server.organization.OrganizationCreationImpl;
import org.sonar.server.organization.OrganizationValidationImpl;
import org.sonar.server.organization.ws.OrganizationsWsModule;
@@ -256,6 +257,7 @@ public class PlatformLevel4 extends PlatformLevel {
OrganizationValidationImpl.class,
OrganizationCreationImpl.class,
OrganizationsWsModule.class,
+ BillingValidationsProxyImpl.class,
// quality profile
DefinedQProfileRepositoryImpl.class,
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java
index 8ae21842cc7..bc0a286f29e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStepTest.java
@@ -23,6 +23,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.mockito.ArgumentCaptor;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.ce.queue.CeTask;
@@ -34,11 +35,17 @@ import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysi
import org.sonar.server.computation.task.projectanalysis.analysis.Organization;
import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule;
import org.sonar.server.computation.task.step.ComputationStep;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidations.BillingValidationsException;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class LoadReportAnalysisMetadataHolderStepTest {
@@ -58,6 +65,7 @@ public class LoadReportAnalysisMetadataHolderStepTest {
private DbClient dbClient = dbTester.getDbClient();
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
+ private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class);
private ComputationStep underTest;
@Before
@@ -308,8 +316,40 @@ public class LoadReportAnalysisMetadataHolderStepTest {
underTest.execute();
}
+ @Test
+ public void execute_fails_with_MessageException_when_organization_is_not_allowed_to_execute_analysis() {
+ OrganizationDto organization = dbTester.organizations().insert();
+ reportReader.setMetadata(newBatchReportBuilder()
+ .setOrganizationKey(organization.getKey())
+ .build());
+ ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid()));
+ doThrow(new BillingValidationsException("This organization cannot execute project analysis")).when(billingValidations)
+ .checkOnProjectAnalysis(any(BillingValidations.Organization.class));
+
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("This organization cannot execute project analysis");
+
+ underTest.execute();
+ }
+
+ @Test
+ public void execute_does_no_fails_when_organization_is_allowed_to_execute_analysis() {
+ OrganizationDto organization = dbTester.organizations().insert();
+ reportReader.setMetadata(newBatchReportBuilder()
+ .setOrganizationKey(organization.getKey())
+ .build());
+ ComputationStep underTest = createStep(createCeTask(PROJECT_KEY, organization.getUuid()));
+
+ underTest.execute();
+
+ ArgumentCaptor<BillingValidations.Organization> argumentCaptor = ArgumentCaptor.forClass(BillingValidations.Organization.class);
+ verify(billingValidations).checkOnProjectAnalysis(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue().getKey()).isEqualTo(organization.getKey());
+ assertThat(argumentCaptor.getValue().getUuid()).isEqualTo(organization.getUuid());
+ }
+
private LoadReportAnalysisMetadataHolderStep createStep(CeTask ceTask) {
- return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, defaultOrganizationProvider, dbClient);
+ return new LoadReportAnalysisMetadataHolderStep(ceTask, reportReader, analysisMetadataHolder, defaultOrganizationProvider, dbClient, billingValidations);
}
private static ScannerReport.Metadata.Builder newBatchReportBuilder() {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java
new file mode 100644
index 00000000000..649a35cc743
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.organization;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.sonar.server.organization.BillingValidations.Organization;
+
+public class BillingValidationsProxyTest {
+
+ private static String ORGANIZATION_KEY = "ORGANIZATION_KEY";
+ private static String ORGANIZATION_UUID = "ORGANIZATION_UUID";
+
+ private BillingValidationsExtension billingValidationsExtension = mock(BillingValidationsExtension.class);
+
+ private BillingValidationsProxyImpl underTest;
+
+ @Test
+ public void checkOnProjectAnalysis_calls_extension_when_available() {
+ underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
+
+ Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+ underTest.checkOnProjectAnalysis(organization);
+
+ verify(billingValidationsExtension).checkOnProjectAnalysis(organization);
+ }
+
+ @Test
+ public void checkOnProjectAnalysis_does_nothing_when_no_extension_available() {
+ underTest = new BillingValidationsProxyImpl();
+
+ Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+ underTest.checkOnProjectAnalysis(organization);
+
+ verifyZeroInteractions(billingValidationsExtension);
+ }
+
+}