* @throws IllegalStateException if baseProjectSnapshot has not been set
*/
boolean isFirstAnalysis();
+
+ /**
+ * Whether this is an incremental analysis or a full analysis.
+ */
+ boolean isIncrementalAnalysis();
/**
* Return the last analysis of the project.
private final InitializedProperty<Organization> organization = new InitializedProperty<>();
private final InitializedProperty<String> uuid = new InitializedProperty<>();
private final InitializedProperty<Long> analysisDate = new InitializedProperty<>();
+ private final InitializedProperty<Boolean> incrementalAnalysis = new InitializedProperty<>();
private final InitializedProperty<Analysis> baseProjectSnapshot = new InitializedProperty<>();
private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>();
private final InitializedProperty<String> branch = new InitializedProperty<>();
return getBaseAnalysis() == null;
}
+ @Override
+ public MutableAnalysisMetadataHolder setIncrementalAnalysis(boolean isIncrementalAnalysis) {
+ checkState(!incrementalAnalysis.isInitialized(), "Incremental analysis flag has already been set");
+ this.incrementalAnalysis.setProperty(isIncrementalAnalysis);
+ return this;
+ }
+
+ @Override
+ public boolean isIncrementalAnalysis() {
+ checkState(incrementalAnalysis.isInitialized(), "Incremental analysis flag has not been set");
+ return this.incrementalAnalysis.getProperty();
+ }
+
@Override
public MutableAnalysisMetadataHolder setBaseAnalysis(@Nullable Analysis baseAnalysis) {
checkState(!this.baseProjectSnapshot.isInitialized(), "Base project snapshot has already been set");
*/
MutableAnalysisMetadataHolder setAnalysisDate(long date);
+ /**
+ * @throws IllegalStateException if it has already been set
+ */
+ MutableAnalysisMetadataHolder setIncrementalAnalysis(boolean isIncrementalAnalysis);
+
/**
* @throws IllegalStateException if baseAnalysis has already been set
*/
}
}
+ enum Status {
+ UNAVAILABLE, SAME, CHANGED, ADDED;
+ }
+
Type getType();
+ Status getStatus();
+
/**
* Returns the component uuid
*/
@Immutable
public class ComponentImpl implements Component {
private final Type type;
+ private final Status status;
private final String name;
private final String key;
private final String uuid;
private ComponentImpl(Builder builder) {
this.type = builder.type;
+ this.status = builder.status;
this.key = builder.key;
this.name = builder.name;
this.description = builder.description;
public Type getType() {
return type;
}
+
+ @Override
+ public Status getStatus() {
+ return status;
+ }
@Override
public String getUuid() {
private static final String UUID_CANNOT_BE_NULL = "uuid can't be null";
private static final String REPORT_ATTRIBUTES_CANNOT_BE_NULL = "reportAttributes can't be null";
private static final String NAME_CANNOT_BE_NULL = "name can't be null";
-
+ private static final String STATUS_CANNOT_BE_NULL = "status can't be null";
+
private final Type type;
+ private Status status;
private ReportAttributes reportAttributes;
private String uuid;
private String key;
public String getUuid() {
return uuid;
}
+
+ public Builder setStatus(Status status) {
+ this.status = requireNonNull(status, STATUS_CANNOT_BE_NULL);
+ return this;
+ }
public Builder setKey(String s) {
this.key = requireNonNull(s, KEY_CANNOT_BE_NULL);
requireNonNull(uuid, UUID_CANNOT_BE_NULL);
requireNonNull(key, KEY_CANNOT_BE_NULL);
requireNonNull(name, NAME_CANNOT_BE_NULL);
+ requireNonNull(status, STATUS_CANNOT_BE_NULL);
return new ComponentImpl(this);
}
}
return ComponentImpl.builder(convertType(reportComponent.getType()))
.setUuid(uuidSupplier.apply(componentKey))
.setKey(componentKey)
+ .setStatus(convertStatus(reportComponent.getStatus()))
.setDescription(trimToNull(reportComponent.getDescription()))
.setFileAttributes(createFileAttributes(reportComponent))
.addChildren(toArray(buildChildren(reportComponent, latestModuleKey), Component.class));
component.getLines());
}
+ static Component.Status convertStatus(ScannerReport.Component.FileStatus status) {
+ switch(status) {
+ case ADDED:
+ return Component.Status.ADDED;
+ case SAME:
+ return Component.Status.SAME;
+ case CHANGED:
+ return Component.Status.CHANGED;
+ case UNAVAILABLE:
+ return Component.Status.UNAVAILABLE;
+ case UNRECOGNIZED:
+ default:
+ throw new IllegalArgumentException("Unsupported ComponentType value " + status);
+ }
+ }
+
@VisibleForTesting
static Component.Type convertType(ScannerReport.Component.ComponentType type) {
switch (type) {
mutableAnalysisMetadataHolder.setRootComponentRef(reportMetadata.getRootComponentRef());
mutableAnalysisMetadataHolder.setBranch(isNotEmpty(reportMetadata.getBranch()) ? reportMetadata.getBranch() : null);
mutableAnalysisMetadataHolder.setCrossProjectDuplicationEnabled(reportMetadata.getCrossProjectDuplicationActivated());
+ mutableAnalysisMetadataHolder.setIncrementalAnalysis(reportMetadata.getIncremental());
mutableAnalysisMetadataHolder.setQProfilesByLanguage(transformValues(reportMetadata.getQprofilesPerLanguage(), TO_COMPUTE_QPROFILE));
mutableAnalysisMetadataHolder.setOrganization(organization);
}
this.rawProject = rawProject;
String rawProjectKey = rawProject.getKey();
validateBranch();
+ validateNotIncrementalAndFirstAnalysis(rawProjectKey);
validateBatchKey(rawProject);
Optional<ComponentDto> baseProject = loadBaseComponent(rawProjectKey);
}
}
+ private void validateNotIncrementalAndFirstAnalysis(String rawProjectKey) {
+ if (analysisMetadataHolder.isIncrementalAnalysis() && analysisMetadataHolder.isFirstAnalysis()) {
+ validationMessages.add(format("The project \"%s\" hasn't been analysed before and the first analysis can't be incremental."
+ + " Please launch a full analysis of the project.", rawProjectKey));
+ }
+ }
+
private void validateProjectKey(Optional<ComponentDto> baseProject, String rawProjectKey) {
if (baseProject.isPresent() && !baseProject.get().projectUuid().equals(baseProject.get().uuid())) {
// Project key is already used as a module of another project
new AnalysisMetadataHolderImpl().isCrossProjectDuplicationEnabled();
}
-
+
@Test
public void setIsCrossProjectDuplicationEnabled_throws_ISE_when_called_twice() {
AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl();
underTest.setCrossProjectDuplicationEnabled(false);
}
+ @Test
+ public void setIsIncrementalAnalysis_throws_ISE_when_called_twice() {
+ AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl();
+ underTest.setIncrementalAnalysis(true);
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Incremental analysis flag has already been set");
+ underTest.setIncrementalAnalysis(false);
+ }
+
+ @Test
+ public void isIncrementalAnalysis_return_true() {
+ AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl();
+
+ underTest.setIncrementalAnalysis(true);
+
+ assertThat(underTest.isIncrementalAnalysis()).isEqualTo(true);
+ }
+
+ @Test
+ public void isIncrementalAnalysis_return_false() {
+ AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl();
+
+ underTest.setIncrementalAnalysis(false);
+
+ assertThat(underTest.isIncrementalAnalysis()).isEqualTo(false);
+ }
+
+ @Test
+ public void isIncrementalAnalysisEnabled_throws_ISE_when_holder_is_not_initialized() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Incremental analysis flag has not been set");
+
+ new AnalysisMetadataHolderImpl().isIncrementalAnalysis();
+ }
+
+ @Test
+ public void setIsIncrementalAnalys_throws_ISE_when_called_twice() {
+ AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl();
+ underTest.setIncrementalAnalysis(true);
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Incremental analysis flag has already been set");
+ underTest.setIncrementalAnalysis(false);
+ }
+
@Test
public void set_branch() {
AnalysisMetadataHolderImpl underTest = new AnalysisMetadataHolderImpl();
private final InitializedProperty<Long> analysisDate = new InitializedProperty<>();
+ private final InitializedProperty<Boolean> incremental = new InitializedProperty<>();
+
private final InitializedProperty<Analysis> baseAnalysis = new InitializedProperty<>();
private final InitializedProperty<Boolean> crossProjectDuplicationEnabled = new InitializedProperty<>();
checkState(qProfilesPerLanguage.isInitialized(), "QProfile per language has not been set");
return qProfilesPerLanguage.getProperty();
}
+
+ @Override
+ public boolean isIncrementalAnalysis() {
+ checkState(incremental.isInitialized(), "Incremental mode flag has not been set");
+ return incremental.getProperty();
+ }
+
+ @Override
+ public AnalysisMetadataHolderRule setIncrementalAnalysis(boolean isIncrementalAnalysis) {
+ this.incremental.setProperty(isIncrementalAnalysis);
+ return this;
+ }
}
public Map<String, QualityProfile> getQProfilesByLanguage() {
return delegate.getQProfilesByLanguage();
}
+
+ @Override
+ public boolean isIncrementalAnalysis() {
+ return delegate.isIncrementalAnalysis();
+ }
+
+ @Override
+ public MutableAnalysisMetadataHolder setIncrementalAnalysis(boolean isIncrementalAnalysis) {
+ delegate.setIncrementalAnalysis(isIncrementalAnalysis);
+ return this;
+ }
}
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.server.computation.task.projectanalysis.component.Component.Status;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
builder(null);
}
+ @Test
+ public void builder_throws_NPE_if_status_arg_is_Null() {
+ thrown.expect(NullPointerException.class);
+
+ builder(FILE).setStatus(null);
+ }
+
+ @Test
+ public void builder_throws_NPE_if_status_is_Null() {
+ thrown.expect(NullPointerException.class);
+
+ builder(Component.Type.DIRECTORY)
+ .setName("DIR")
+ .setKey(KEY)
+ .setUuid(UUID)
+ .setReportAttributes(ReportAttributes.newBuilder(1).build())
+ .build();
+ }
+
@Test
public void set_key_throws_NPE_if_component_arg_is_Null() {
thrown.expect(NullPointerException.class);
.setName("CHILD_NAME")
.setKey("CHILD_KEY")
.setUuid("CHILD_UUID")
+ .setStatus(Status.UNAVAILABLE)
.setReportAttributes(ReportAttributes.newBuilder(2).build())
.build();
ComponentImpl componentImpl = builder(Component.Type.DIRECTORY)
.setName("DIR")
.setKey(KEY)
.setUuid(UUID)
+ .setStatus(Status.UNAVAILABLE)
.setReportAttributes(ReportAttributes.newBuilder(1).build())
.addChildren(child)
.build();
return builder(type)
.setName("name_" + key)
.setKey(key)
+ .setStatus(Status.UNAVAILABLE)
.setUuid("uuid_" + key)
.setReportAttributes(ReportAttributes.newBuilder(key.hashCode())
.build());
public static final Component DUMB_PROJECT = builder(Type.PROJECT, 1).setKey("PROJECT_KEY").setUuid("PROJECT_UUID").setName("Project Name").setVersion("1.0-SNAPSHOT").build();
private final Type type;
+ private final Status status;
private final String name;
@CheckForNull
private final String description;
private ReportComponent(Builder builder) {
this.type = builder.type;
+ this.status = builder.status;
this.key = builder.key;
this.name = builder.name == null ? String.valueOf(builder.key) : builder.name;
this.description = builder.description;
public Type getType() {
return type;
}
+
+ @Override
+ public Status getStatus() {
+ return status;
+ }
@Override
public String getUuid() {
public static final class Builder {
private final Type type;
private final int ref;
+ private Status status;
private String uuid;
private String key;
private String name;
this.ref = ref;
}
+ public Builder setStatus(Status s) {
+ this.status = Objects.requireNonNull(s);
+ return this;
+ }
+
public Builder setUuid(String s) {
this.uuid = Objects.requireNonNull(s);
return this;
return new ReportComponent(this);
}
}
+
}
public Type getType() {
return type;
}
+
+ @Override
+ public Status getStatus() {
+ return Status.UNAVAILABLE;
+ }
@Override
public String getUuid() {
import org.sonar.db.organization.OrganizationDto;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
+import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus;
import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderImpl;
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder;
import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule;
ScannerReport.Component.Builder builder = ScannerReport.Component.newBuilder()
.setType(componentType)
.setRef(componentRef)
+ .setStatus(FileStatus.UNAVAILABLE)
.setLines(1);
if (key != null) {
builder.setKey(key);
assertThat(analysisMetadataHolder.isCrossProjectDuplicationEnabled()).isEqualTo(false);
}
+
+ @Test
+ public void set_incremental_analysis_to_true() {
+ reportReader.setMetadata(
+ newBatchReportBuilder()
+ .setIncremental(true)
+ .build());
+
+ underTest.execute();
+
+ assertThat(analysisMetadataHolder.isIncrementalAnalysis()).isTrue();
+ }
+
+ @Test
+ public void set_incremental_analysis_to_false() {
+ reportReader.setMetadata(
+ newBatchReportBuilder()
+ .setIncremental(false)
+ .build());
+
+ underTest.execute();
+
+ assertThat(analysisMetadataHolder.isIncrementalAnalysis()).isFalse();
+ }
+
@Test
public void set_cross_project_duplication_to_false_when_nothing_in_the_report() {
@Rule
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule()
.setAnalysisDate(new Date(DEFAULT_ANALYSIS_TIME))
+ .setIncrementalAnalysis(false)
.setBranch(DEFAULT_BRANCH);
DbClient dbClient = dbTester.getDbClient();
underTest.execute();
}
+
+ @Test
+ public void fail_if_incremental_and_first_analysis() {
+ analysisMetadataHolder.setBaseAnalysis(null);
+ //setAnalysisDate(DateUtils.parseDate("2015-01-01"));
+
+ reportReader.putComponent(ScannerReport.Component.newBuilder()
+ .setRef(1)
+ .setType(ComponentType.PROJECT)
+ .setKey(PROJECT_KEY)
+ .addChildRef(2)
+ .build());
+
+ analysisMetadataHolder.setIncrementalAnalysis(true);
+
+ //dbTester.getSession().commit();
+
+ treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
+
+ thrown.expect(MessageException.class);
+ thrown.expectMessage("Validation of project failed:");
+ thrown.expectMessage("hasn't been analysed before and the first analysis can't be incremental. Please launch a full analysis of the project.");
+
+ underTest.execute();
+ }
}