Skip to content

Commit

Permalink
SONAR-6620 current project can actually have no QualityGate at all
Browse files Browse the repository at this point in the history
in which case, no QualityGate measure must be created nor any measure have its QualityGateStatus be updated
  • Loading branch information
sns-seb committed Jun 19, 2015
1 parent dae42b8 commit 0c18ea4
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 56 deletions.
Expand Up @@ -30,7 +30,14 @@ public interface MutableQualityGateHolder extends QualityGateHolder {
* @param qualityGate a {@link Component}, can not be {@code null} * @param qualityGate a {@link Component}, can not be {@code null}
* *
* @throws NullPointerException if {@code qualityGate} is {@code null} * @throws NullPointerException if {@code qualityGate} is {@code null}
* @throws IllegalStateException if the quality gate has already been set * @throws IllegalStateException if the holder has already been initialized
*/ */
void setQualityGate(QualityGate qualityGate); void setQualityGate(QualityGate qualityGate);

/**
* Sets that there is no quality gate for the project of the currently processed {@link ReportQueue.Item}.
*
* @throws IllegalStateException if the holder has already been initialized
*/
void setNoQualityGate();
} }
Expand Up @@ -19,13 +19,14 @@
*/ */
package org.sonar.server.computation.qualitygate; package org.sonar.server.computation.qualitygate;


import com.google.common.base.Optional;
import org.sonar.server.computation.ReportQueue; import org.sonar.server.computation.ReportQueue;


public interface QualityGateHolder { public interface QualityGateHolder {
/** /**
* The QualityGate for the project of the current {@link ReportQueue.Item}. * The QualityGate for the project of the current {@link ReportQueue.Item} if there is any.
* *
* @throws IllegalStateException if the holder is empty (ie. there is no quality gate yet) * @throws IllegalStateException if the holder has not been initialized (ie. we don't know yet what is the QualityGate)
*/ */
QualityGate getQualityGate(); Optional<QualityGate> getQualityGate();
} }
Expand Up @@ -19,29 +19,44 @@
*/ */
package org.sonar.server.computation.qualitygate; package org.sonar.server.computation.qualitygate;


import java.util.Objects; import com.google.common.base.Optional;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;


import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;

public class QualityGateHolderImpl implements MutableQualityGateHolder { public class QualityGateHolderImpl implements MutableQualityGateHolder {
private boolean initialized = false;
@CheckForNull @CheckForNull
private QualityGate qualityGate; private Optional<QualityGate> qualityGate;


@Override @Override
public void setQualityGate(QualityGate qualityGate) { public void setQualityGate(QualityGate qualityGate) {
// fail fast // fail fast
Objects.requireNonNull(qualityGate); requireNonNull(qualityGate);
checkNotInitialized();

this.initialized = true;
this.qualityGate = of(qualityGate);
}

@Override
public void setNoQualityGate() {
checkNotInitialized();

this.initialized = true;
this.qualityGate = absent();
}


if (this.qualityGate != null) { private void checkNotInitialized() {
throw new IllegalStateException("QualityGate can be set only once"); checkState(!initialized, "QualityGateHolder can be initialized only once");
}
this.qualityGate = qualityGate;
} }


@Override @Override
public QualityGate getQualityGate() { public Optional<QualityGate> getQualityGate() {
if (qualityGate == null) { checkState(initialized, "QualityGate has not been set yet");
throw new IllegalStateException("QualityGate has not been set yet");
}
return qualityGate; return qualityGate;
} }
} }
Expand Up @@ -19,7 +19,7 @@
*/ */
package org.sonar.server.computation.step; package org.sonar.server.computation.step;


import java.util.Collections; import com.google.common.base.Optional;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.sonar.api.config.Settings; import org.sonar.api.config.Settings;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
Expand All @@ -29,7 +29,6 @@
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.ProjectSettingsRepository; import org.sonar.server.computation.component.ProjectSettingsRepository;
import org.sonar.server.computation.component.TreeRootHolder; import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.computation.qualitygate.Condition;
import org.sonar.server.computation.qualitygate.MutableQualityGateHolder; import org.sonar.server.computation.qualitygate.MutableQualityGateHolder;
import org.sonar.server.computation.qualitygate.QualityGate; import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateService; import org.sonar.server.computation.qualitygate.QualityGateService;
Expand All @@ -45,7 +44,6 @@ public class QualityGateLoadingStep implements ComputationStep {
private static final Logger LOGGER = Loggers.get(QualityGateLoadingStep.class); private static final Logger LOGGER = Loggers.get(QualityGateLoadingStep.class);


private static final String PROPERTY_QUALITY_GATE = "sonar.qualitygate"; private static final String PROPERTY_QUALITY_GATE = "sonar.qualitygate";
private static final QualityGate DEFAULT_QUALITY_GATE = new QualityGate("default Quality Gate", Collections.<Condition>emptyList());


private final TreeRootHolder treeRootHolder; private final TreeRootHolder treeRootHolder;
private final ProjectSettingsRepository projectSettingsRepository; private final ProjectSettingsRepository projectSettingsRepository;
Expand Down Expand Up @@ -77,16 +75,23 @@ private void executeForProject(Component project) {


if (qualityGateSetting == null || StringUtils.isBlank(qualityGateSetting)) { if (qualityGateSetting == null || StringUtils.isBlank(qualityGateSetting)) {
LOGGER.debug("No quality gate is configured for project " + projectKey); LOGGER.debug("No quality gate is configured for project " + projectKey);
qualityGateHolder.setQualityGate(DEFAULT_QUALITY_GATE); qualityGateHolder.setNoQualityGate();
return; return;
} }


try { try {
long qualityGateId = Long.parseLong(qualityGateSetting.trim()); long qualityGateId = Long.parseLong(qualityGateSetting);
qualityGateHolder.setQualityGate(qualityGateService.findById(qualityGateId).or(DEFAULT_QUALITY_GATE)); Optional<QualityGate> qualityGate = qualityGateService.findById(qualityGateId);
if (qualityGate.isPresent()) {
qualityGateHolder.setQualityGate(qualityGate.get());
}
else {
qualityGateHolder.setNoQualityGate();
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
LOGGER.error(String.format("Unsupported value in property %s, using empty Quality Gate", PROPERTY_QUALITY_GATE)); throw new IllegalStateException(
qualityGateHolder.setQualityGate(DEFAULT_QUALITY_GATE); String.format("Unsupported value (%s) in property %s", qualityGateSetting, PROPERTY_QUALITY_GATE),
e);
} }
} }


Expand Down
Expand Up @@ -40,6 +40,7 @@
import org.sonar.server.computation.qualitygate.ConditionEvaluator; import org.sonar.server.computation.qualitygate.ConditionEvaluator;
import org.sonar.server.computation.qualitygate.EvaluationResult; import org.sonar.server.computation.qualitygate.EvaluationResult;
import org.sonar.server.computation.qualitygate.EvaluationResultTextConverter; import org.sonar.server.computation.qualitygate.EvaluationResultTextConverter;
import org.sonar.server.computation.qualitygate.QualityGate;
import org.sonar.server.computation.qualitygate.QualityGateHolder; import org.sonar.server.computation.qualitygate.QualityGateHolder;


import static org.sonar.server.computation.component.Component.Type.PROJECT; import static org.sonar.server.computation.component.Component.Type.PROJECT;
Expand Down Expand Up @@ -85,9 +86,12 @@ public void visitProject(Component project) {
private void executeForProject(Component project) { private void executeForProject(Component project) {
QualityGateDetailsDataBuilder builder = new QualityGateDetailsDataBuilder(); QualityGateDetailsDataBuilder builder = new QualityGateDetailsDataBuilder();


updateMeasures(project, qualityGateHolder.getQualityGate().getConditions(), builder); Optional<QualityGate> qualityGate = qualityGateHolder.getQualityGate();
if (qualityGate.isPresent()) {
updateMeasures(project, qualityGate.get().getConditions(), builder);


addProjectMeasure(project, builder); addProjectMeasure(project, builder);
}
} }


private void updateMeasures(Component project, Set<Condition> conditions, QualityGateDetailsDataBuilder builder) { private void updateMeasures(Component project, Set<Condition> conditions, QualityGateDetailsDataBuilder builder) {
Expand Down
Expand Up @@ -19,27 +19,25 @@
*/ */
package org.sonar.server.computation.qualitygate; package org.sonar.server.computation.qualitygate;


import java.util.Objects; import com.google.common.base.Optional;
import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;


public class MutableQualityGateHolderRule extends ExternalResource implements MutableQualityGateHolder { public class MutableQualityGateHolderRule extends ExternalResource implements MutableQualityGateHolder {
private QualityGate qualityGate; private MutableQualityGateHolder delegate = new QualityGateHolderImpl();


@Override @Override
public void setQualityGate(QualityGate qualityGate) { public void setQualityGate(QualityGate qualityGate) {
Objects.requireNonNull(qualityGate); delegate.setQualityGate(qualityGate);
if (this.qualityGate != null) {
throw new IllegalStateException("QualityGate can not be set more than once");
}
this.qualityGate = qualityGate;
} }


@Override @Override
public QualityGate getQualityGate() { public void setNoQualityGate() {
if (this.qualityGate == null) { delegate.setNoQualityGate();
throw new IllegalStateException("QualityGate has not been set"); }
}
return qualityGate; @Override
public Optional<QualityGate> getQualityGate() {
return delegate.getQualityGate();
} }


@Override @Override
Expand All @@ -48,6 +46,6 @@ protected void after() {
} }


public void reset() { public void reset() {
this.qualityGate = null; this.delegate = new QualityGateHolderImpl();
} }
} }
Expand Up @@ -23,6 +23,7 @@
import org.junit.Test; import org.junit.Test;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat;


public class QualityGateHolderImplTest { public class QualityGateHolderImplTest {


Expand Down Expand Up @@ -52,7 +53,16 @@ public void getQualityGate_returns_QualityGate_set_by_setQualityGate() {


holder.setQualityGate(QUALITY_GATE); holder.setQualityGate(QUALITY_GATE);


assertThat(holder.getQualityGate()).isSameAs(QUALITY_GATE); assertThat(holder.getQualityGate().get()).isSameAs(QUALITY_GATE);
}

@Test
public void getQualityGate_returns_absent_if_holder_initialized_with_setNoQualityGate() {
QualityGateHolderImpl holder = new QualityGateHolderImpl();

holder.setNoQualityGate();

assertThat(holder.getQualityGate()).isAbsent();
} }


} }
Expand Up @@ -23,6 +23,7 @@
import java.util.Collections; import java.util.Collections;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings; import org.sonar.api.config.Settings;
import org.sonar.server.computation.batch.TreeRootHolderRule; import org.sonar.server.computation.batch.TreeRootHolderRule;
import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.Component;
Expand All @@ -34,15 +35,18 @@
import org.sonar.server.computation.qualitygate.QualityGateService; import org.sonar.server.computation.qualitygate.QualityGateService;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;


public class QualityGateLoadingStepTest { public class QualityGateLoadingStepTest {
private static final String PROJECT_KEY = "project key"; private static final String PROJECT_KEY = "project key";
public static final DumbComponent PROJECT_ALONE = DumbComponent.builder(Component.Type.PROJECT, 1).setKey(PROJECT_KEY).build(); private static final DumbComponent PROJECT_ALONE = DumbComponent.builder(Component.Type.PROJECT, 1).setKey(PROJECT_KEY).build();


@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule @Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
@Rule @Rule
Expand All @@ -60,7 +64,7 @@ public void execute_sets_default_QualityGate_when_project_has_no_settings() {


underTest.execute(); underTest.execute();


verifyDefaultQualityGateHasBeenSet(); verifyNoQualityGate();


// verify only project is processed // verify only project is processed
verify(projectSettingsRepository).getProjectSettings(PROJECT_KEY); verify(projectSettingsRepository).getProjectSettings(PROJECT_KEY);
Expand All @@ -69,20 +73,13 @@ public void execute_sets_default_QualityGate_when_project_has_no_settings() {


@Test @Test
public void execute_sets_default_QualityGate_when_property_value_is_not_a_long() { public void execute_sets_default_QualityGate_when_property_value_is_not_a_long() {
verify_execute_sets_default_QualityGate_when_property_value_is_not_a_long(""); expectedException.expect(IllegalStateException.class);
verify_execute_sets_default_QualityGate_when_property_value_is_not_a_long(" "); expectedException.expectMessage(String.format("Unsupported value (%s) in property sonar.qualitygate", "10 sds"));
verify_execute_sets_default_QualityGate_when_property_value_is_not_a_long(" 10 sds ");
}


private void verify_execute_sets_default_QualityGate_when_property_value_is_not_a_long(String value) {
treeRootHolder.setRoot(PROJECT_ALONE); treeRootHolder.setRoot(PROJECT_ALONE);
when(projectSettingsRepository.getProjectSettings(PROJECT_KEY)).thenReturn(new Settings().setProperty("sonar.qualitygate", value)); when(projectSettingsRepository.getProjectSettings(PROJECT_KEY)).thenReturn(new Settings().setProperty("sonar.qualitygate", "10 sds"));


underTest.execute(); underTest.execute();

verifyDefaultQualityGateHasBeenSet();

mutableQualityGateHolder.reset();
} }


@Test @Test
Expand All @@ -93,7 +90,7 @@ public void execute_sets_default_QualityGate_if_it_can_not_be_found_by_service()


underTest.execute(); underTest.execute();


verifyDefaultQualityGateHasBeenSet(); verifyNoQualityGate();
} }


@Test @Test
Expand All @@ -106,12 +103,11 @@ public void execute_sets_QualityGate_if_it_can_be_found_by_service() {


underTest.execute(); underTest.execute();


assertThat(mutableQualityGateHolder.getQualityGate()).isSameAs(qualityGate); assertThat(mutableQualityGateHolder.getQualityGate().get()).isSameAs(qualityGate);
} }


private void verifyDefaultQualityGateHasBeenSet() { private void verifyNoQualityGate() {
assertThat(mutableQualityGateHolder.getQualityGate().getName()).isEqualTo("default Quality Gate"); assertThat(mutableQualityGateHolder.getQualityGate()).isAbsent();
assertThat(mutableQualityGateHolder.getQualityGate().getConditions()).isEmpty();
} }


} }
Expand Up @@ -112,6 +112,15 @@ public void no_measure_if_tree_has_no_project() {
verifyNoMoreInteractions(measureRepository); verifyNoMoreInteractions(measureRepository);
} }


@Test
public void no_measure_if_there_is_no_qualitygate() {
qualityGateHolder.setNoQualityGate();

underTest.execute();

verifyNoMoreInteractions(measureRepository);
}

@Test @Test
public void new_measures_are_created_even_if_there_is_no_rawMeasure_for_metric_of_condition() { public void new_measures_are_created_even_if_there_is_no_rawMeasure_for_metric_of_condition() {
Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null); Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null);
Expand Down

0 comments on commit 0c18ea4

Please sign in to comment.