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 30f22461dd96..5387324ec120 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 @@ -109,6 +109,7 @@ import org.sonar.server.notification.email.EmailNotificationChannel; import org.sonar.server.organization.BillingValidationsProxyImpl; import org.sonar.server.organization.DefaultOrganizationProviderImpl; +import org.sonar.server.organization.OrganizationFlagsImpl; import org.sonar.server.permission.GroupPermissionChanger; import org.sonar.server.permission.PermissionTemplateService; import org.sonar.server.permission.PermissionUpdater; @@ -312,7 +313,8 @@ private static void populateLevel3(ComponentContainer container) { UriReader.class, ServerImpl.class, DefaultOrganizationProviderImpl.class, - SynchronousAsyncExecution.class); + SynchronousAsyncExecution.class, + OrganizationFlagsImpl.class); } private static void populateLevel4(ComponentContainer container, Props props) { 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 950cbde71b7e..76da867464e0 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 @@ -65,7 +65,7 @@ public class ComputeEngineContainerImplTest { private ComputeEngineContainerImpl underTest; @Before - public void setUp() throws Exception { + public void setUp() { underTest = new ComputeEngineContainerImpl(); underTest.setComputeEngineStatus(mock(ComputeEngineStatus.class)); } @@ -105,7 +105,7 @@ public void test_real_start() throws IOException { ); assertThat(picoContainer.getParent().getComponentAdapters()).hasSize( CONTAINER_ITSELF - + 6 // level 3 + + 7 // level 3 ); assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize( CONTAINER_ITSELF diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java index 6f016550ace4..0bbbae931730 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutor.java @@ -29,6 +29,7 @@ import org.sonar.api.ce.posttask.Analysis; import org.sonar.api.ce.posttask.Branch; import org.sonar.api.ce.posttask.CeTask; +import org.sonar.api.ce.posttask.Organization; import org.sonar.api.ce.posttask.PostProjectAnalysisTask; import org.sonar.api.ce.posttask.Project; import org.sonar.api.ce.posttask.QualityGate; @@ -116,6 +117,7 @@ private static void executeTask(ProjectAnalysisImpl projectAnalysis, PostProject private ProjectAnalysisImpl createProjectAnalysis(CeTask.Status status) { return new ProjectAnalysisImpl( + createOrganization(), new CeTaskImpl(this.ceTask.getUuid(), status), createProject(this.ceTask), getAnalysis().orElse(null), @@ -125,6 +127,15 @@ private ProjectAnalysisImpl createProjectAnalysis(CeTask.Status status) { createBranch()); } + @CheckForNull + private Organization createOrganization() { + org.sonar.server.computation.task.projectanalysis.analysis.Organization organization = analysisMetadataHolder.getOrganization(); + if (organization.isOrganizationsEnabled()) { + return new OrganizationImpl(organization.getName(), organization.getKey()); + } + return null; + } + private Optional getAnalysis() { Long analysisDate = getAnalysisDate(); @@ -196,6 +207,8 @@ private static Collection convert(Set conditio } private static class ProjectAnalysisImpl implements PostProjectAnalysisTask.ProjectAnalysis { + @Nullable + private final Organization organization; private final CeTask ceTask; private final Project project; private final long date; @@ -207,9 +220,10 @@ private static class ProjectAnalysisImpl implements PostProjectAnalysisTask.Proj @Nullable private final Analysis analysis; - private ProjectAnalysisImpl(CeTask ceTask, Project project, + private ProjectAnalysisImpl(@Nullable Organization organization, CeTask ceTask, Project project, @Nullable Analysis analysis, long date, ScannerContext scannerContext, @Nullable QualityGate qualityGate, @Nullable Branch branch) { + this.organization = organization; this.ceTask = requireNonNull(ceTask, "ceTask can not be null"); this.project = requireNonNull(project, "project can not be null"); this.analysis = analysis; @@ -219,6 +233,11 @@ private ProjectAnalysisImpl(CeTask ceTask, Project project, this.branch = branch; } + @Override + public Optional getOrganization() { + return Optional.ofNullable(organization); + } + @Override public CeTask getCeTask() { return ceTask; @@ -293,4 +312,24 @@ public Date getDate() { return new Date(date); } } + + private static class OrganizationImpl implements Organization { + private final String name; + private final String key; + + private OrganizationImpl(String name, String key) { + this.name = requireNonNull(name, "name can't be null"); + this.key = requireNonNull(key, "key can't be null"); + } + + @Override + public String getName() { + return name; + } + + @Override + public String getKey() { + return key; + } + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java index 484180fabb25..6f7ca22c791a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java @@ -26,6 +26,7 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.Random; import javax.annotation.Nullable; import org.apache.commons.lang.RandomStringUtils; import org.junit.Before; @@ -39,9 +40,11 @@ import org.sonar.api.utils.System2; import org.sonar.ce.queue.CeTask; import org.sonar.db.component.BranchType; +import org.sonar.db.organization.OrganizationDto; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; import org.sonar.server.computation.task.projectanalysis.analysis.Branch; +import org.sonar.server.computation.task.projectanalysis.analysis.Organization; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl; import org.sonar.server.computation.task.projectanalysis.metric.Metric; @@ -79,10 +82,13 @@ public class PostProjectAnalysisTasksExecutorTest { @Rule public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + private String organizationUuid = "org1"; + private String organizationKey = organizationUuid + "_key"; + private String organizationName = organizationUuid + "_name"; private System2 system2 = mock(System2.class); private ArgumentCaptor projectAnalysisArgumentCaptor = ArgumentCaptor.forClass(PostProjectAnalysisTask.ProjectAnalysis.class); private CeTask ceTask = new CeTask.Builder() - .setOrganizationUuid("org1") + .setOrganizationUuid(organizationUuid) .setType("type") .setUuid("uuid") .setComponentKey("component key") @@ -104,6 +110,9 @@ public void setUp() throws Exception { Branch branch = mock(Branch.class); when(branch.getType()).thenReturn(BranchType.LONG); analysisMetadataHolder.setBranch(branch); + analysisMetadataHolder.setOrganization(Organization.from( + new OrganizationDto().setKey(organizationKey).setName(organizationName).setUuid(organizationUuid).setDefaultQualityGateUuid("foo"), + new Random().nextBoolean())); } @Test @@ -123,7 +132,7 @@ public void finished_calls_all_PostProjectAnalysisTask_in_order_of_the_array_and new PostProjectAnalysisTasksExecutor( ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader, system2, new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2}) - .finished(allStepsExecuted); + .finished(allStepsExecuted); inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture()); inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture()); @@ -134,6 +143,34 @@ public void finished_calls_all_PostProjectAnalysisTask_in_order_of_the_array_and assertThat(allValues.get(0)).isSameAs(allValues.get(1)); } + @Test + @UseDataProvider("booleanValues") + public void organization_is_null_when_organization_are_disabled(boolean allStepsExecuted) { + analysisMetadataHolder.setOrganization(Organization.from( + new OrganizationDto().setKey(organizationKey).setName(organizationName).setUuid(organizationUuid).setDefaultQualityGateUuid("foo"), + false)); + underTest.finished(allStepsExecuted); + + verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture()); + + assertThat(projectAnalysisArgumentCaptor.getValue().getOrganization()).isEmpty(); + } + + @Test + @UseDataProvider("booleanValues") + public void organization_is_not_null_when_organization_are_enabled(boolean allStepsExecuted) { + analysisMetadataHolder.setOrganization(Organization.from( + new OrganizationDto().setKey(organizationKey).setName(organizationName).setUuid(organizationUuid).setDefaultQualityGateUuid("foo"), + true)); + underTest.finished(allStepsExecuted); + + verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture()); + + org.sonar.api.ce.posttask.Organization organization = projectAnalysisArgumentCaptor.getValue().getOrganization().get(); + assertThat(organization.getKey()).isEqualTo(organizationKey); + assertThat(organization.getName()).isEqualTo(organizationName); + } + @Test @UseDataProvider("booleanValues") public void CeTask_status_depends_on_finished_method_argument_is_true_or_false(boolean allStepsExecuted) { @@ -325,7 +362,7 @@ public void finished_does_not_fail_if_listener_throws_exception_and_execute_subs new PostProjectAnalysisTasksExecutor( ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader, system2, new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2, postProjectAnalysisTask3}) - .finished(allStepsExecuted); + .finished(allStepsExecuted); inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture()); inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture()); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/Organization.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/Organization.java new file mode 100644 index 000000000000..48d9bf79a131 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/Organization.java @@ -0,0 +1,26 @@ +/* + * 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.api.ce.posttask; + +public interface Organization { + String getName(); + + String getKey(); +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTask.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTask.java index d8c2a07640bf..1e3d05b734aa 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTask.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTask.java @@ -52,6 +52,14 @@ public interface PostProjectAnalysisTask { * @since 5.5 */ interface ProjectAnalysis { + /** + * When organizations are enabled in SonarQube, the organization the project belongs to. + * + * @since 7.0 + * @return a non empty value when organizations are enabled, otherwise empty + */ + Optional getOrganization(); + /** * Details of the Compute Engine task in which the project analysis was run. */ diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java index 3d0e678190a0..1db5724b668a 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java @@ -99,8 +99,12 @@ public class PostProjectAnalysisTaskTester { private static final String CE_TASK_CAN_NOT_BE_NULL = "ceTask cannot be null"; private static final String STATUS_CAN_NOT_BE_NULL = "status cannot be null"; private static final String SCANNER_CONTEXT_CAN_NOT_BE_NULL = "scannerContext cannot be null"; + private static final String KEY_CAN_NOT_BE_NULL = "key cannot be null"; + private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; private final PostProjectAnalysisTask underTest; + @Nullable + private Organization organization; @CheckForNull private CeTask ceTask; @CheckForNull @@ -122,6 +126,13 @@ public static PostProjectAnalysisTaskTester of(PostProjectAnalysisTask underTest return new PostProjectAnalysisTaskTester(underTest); } + /** + * @since 7.0 + */ + public static OrganizationBuilder newOrganizationBuilder() { + return new OrganizationBuilder(); + } + public static CeTaskBuilder newCeTaskBuilder() { return new CeTaskBuilder(); } @@ -146,6 +157,14 @@ public static ScannerContextBuilder newScannerContextBuilder() { return new ScannerContextBuilder(); } + /** + * @since 7.0 + */ + public PostProjectAnalysisTaskTester withOrganization(@Nullable Organization organization) { + this.organization = organization; + return this; + } + public PostProjectAnalysisTaskTester withCeTask(CeTask ceTask) { this.ceTask = requireNonNull(ceTask, CE_TASK_CAN_NOT_BE_NULL); return this; @@ -201,6 +220,7 @@ public PostProjectAnalysisTask.ProjectAnalysis execute() { } PostProjectAnalysisTask.ProjectAnalysis projectAnalysis = new ProjectAnalysisBuilder() + .setOrganization(organization) .setCeTask(ceTask) .setProject(project) .setBranch(branch) @@ -216,6 +236,51 @@ public PostProjectAnalysisTask.ProjectAnalysis execute() { return projectAnalysis; } + public static final class OrganizationBuilder { + @CheckForNull + private String name; + @CheckForNull + private String key; + + private OrganizationBuilder() { + // prevents instantiation + } + + public OrganizationBuilder setName(String name) { + this.name = requireNonNull(name, NAME_CAN_NOT_BE_NULL); + return this; + } + + public OrganizationBuilder setKey(String key) { + this.key = requireNonNull(key, KEY_CAN_NOT_BE_NULL); + return this; + } + + public Organization build() { + requireNonNull(this.name, NAME_CAN_NOT_BE_NULL); + requireNonNull(this.key, KEY_CAN_NOT_BE_NULL); + return new Organization() { + @Override + public String getName() { + return name; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String toString() { + return "Organization{" + + "name='" + name + '\'' + + ", key='" + key + '\'' + + '}'; + } + }; + } + } + public static final class CeTaskBuilder { private static final String ID_CAN_NOT_BE_NULL = "id cannot be null"; @@ -265,8 +330,6 @@ public String toString() { public static final class ProjectBuilder { private static final String UUID_CAN_NOT_BE_NULL = "uuid cannot be null"; - private static final String KEY_CAN_NOT_BE_NULL = "key cannot be null"; - private static final String NAME_CAN_NOT_BE_NULL = "name cannot be null"; private String uuid; private String key; private String name; @@ -350,7 +413,6 @@ public BranchBuilder setIsMain(boolean b) { public Branch build() { return new Branch() { - @Override public boolean isMain() { return isMain; @@ -618,6 +680,7 @@ public ScannerContext build() { } public static final class ProjectAnalysisBuilder { + private Organization organization; private CeTask ceTask; private Project project; private Branch branch; @@ -630,6 +693,11 @@ private ProjectAnalysisBuilder() { // prevents instantiation outside PostProjectAnalysisTaskTester } + public ProjectAnalysisBuilder setOrganization(@Nullable Organization organization) { + this.organization = organization; + return this; + } + public ProjectAnalysisBuilder setCeTask(CeTask ceTask) { this.ceTask = ceTask; return this; @@ -667,6 +735,11 @@ public ProjectAnalysisBuilder setDate(Date date) { public PostProjectAnalysisTask.ProjectAnalysis build() { return new PostProjectAnalysisTask.ProjectAnalysis() { + @Override + public Optional getOrganization() { + return Optional.ofNullable(organization); + } + @Override public CeTask getCeTask() { return ceTask; @@ -711,7 +784,8 @@ public ScannerContext getScannerContext() { @Override public String toString() { return "ProjectAnalysis{" + - "ceTask=" + ceTask + + "organization=" + organization + + ", ceTask=" + ceTask + ", project=" + project + ", date=" + date.getTime() + ", analysisDate=" + date.getTime() + diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTesterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTesterTest.java index baec1f163e73..d8aa08d64667 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTesterTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTesterTest.java @@ -33,6 +33,7 @@ public class PostProjectAnalysisTaskTesterTest { @Rule public ExpectedException expectedException = ExpectedException.none(); + private Organization organization = mock(Organization.class); private CeTask ceTask = mock(CeTask.class); private Project project = mock(Project.class); private long someDateAsLong = 846351351684351L; @@ -101,12 +102,13 @@ public void execute_throws_NPE_if_project_is_null() { @Test public void verify_getters_of_ProjectAnalysis_object_passed_to_PostProjectAnalysisTask() { - underTest.withCeTask(ceTask).withProject(project).withQualityGate(qualityGate).withAnalysisUuid(analysisUuid).at(someDate); + underTest.withOrganization(organization).withCeTask(ceTask).withProject(project).withQualityGate(qualityGate).withAnalysisUuid(analysisUuid).at(someDate); underTest.execute(); PostProjectAnalysisTask.ProjectAnalysis projectAnalysis = captorPostProjectAnalysisTask.projectAnalysis; assertThat(projectAnalysis).isNotNull(); + assertThat(projectAnalysis.getOrganization().get()).isSameAs(organization); assertThat(projectAnalysis.getCeTask()).isSameAs(ceTask); assertThat(projectAnalysis.getProject()).isSameAs(project); assertThat(projectAnalysis.getDate()).isSameAs(someDate); @@ -116,15 +118,16 @@ public void verify_getters_of_ProjectAnalysis_object_passed_to_PostProjectAnalys @Test public void verify_toString_of_ProjectAnalysis_object_passed_to_PostProjectAnalysisTask() { + when(organization.toString()).thenReturn("Organization"); when(ceTask.toString()).thenReturn("CeTask"); when(project.toString()).thenReturn("Project"); when(qualityGate.toString()).thenReturn("QualityGate"); - underTest.withCeTask(ceTask).withProject(project).withQualityGate(qualityGate).at(someDate); + underTest.withOrganization(organization).withCeTask(ceTask).withProject(project).withQualityGate(qualityGate).at(someDate); underTest.execute(); assertThat(captorPostProjectAnalysisTask.projectAnalysis.toString()) - .isEqualTo("ProjectAnalysis{ceTask=CeTask, project=Project, date=846351351684351, analysisDate=846351351684351, qualityGate=QualityGate}"); + .isEqualTo("ProjectAnalysis{organization=Organization, ceTask=CeTask, project=Project, date=846351351684351, analysisDate=846351351684351, qualityGate=QualityGate}"); }