import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nonnull;
this.fileHash = fileHash;
}
- public static Optional<DbScmInfo> create(List<DbFileSources.Line> lines, String fileHash) {
+ public static Optional<DbScmInfo> create(List<DbFileSources.Line> lines, int lineCount, String fileHash) {
LineToChangeset lineToChangeset = new LineToChangeset();
- Changeset[] lineChanges = new Changeset[lines.size()];
+ Changeset[] lineChanges = new Changeset[lineCount];
boolean lineAdded = false;
*/
private static class LineToChangeset implements Function<DbFileSources.Line, Changeset> {
private final Changeset.Builder builder = Changeset.newChangesetBuilder();
- private final HashMap<Changeset, Changeset> cache = new HashMap<>();
+ private final Map<Changeset, Changeset> cache = new HashMap<>();
@Override
@Nullable
*/
package org.sonar.ce.task.projectanalysis.scm;
-import static com.google.common.base.Preconditions.checkState;
+import javax.annotation.concurrent.Immutable;
-public class GeneratedScmInfo implements ScmInfo {
- private final ScmInfoImpl delegate;
+import static com.google.common.base.Preconditions.checkState;
- public GeneratedScmInfo(Changeset[] lineChangeset) {
- delegate = new ScmInfoImpl(lineChangeset);
+@Immutable
+public class GeneratedScmInfo {
+ private GeneratedScmInfo() {
+ // static only
}
public static ScmInfo create(long analysisDate, int lines) {
for (int i = 0; i < lines; i++) {
lineChangeset[i] = changeset;
}
- return new GeneratedScmInfo(lineChangeset);
+ return new ScmInfoImpl(lineChangeset);
}
public static ScmInfo create(long analysisDate, int[] matches, ScmInfo dbScmInfo) {
for (int i = 0; i < matches.length; i++) {
if (matches[i] > 0) {
- changesets[i] = dbChangesets[matches[i]];
+ changesets[i] = dbChangesets[matches[i] - 1];
} else {
changesets[i] = changeset;
}
}
- return new GeneratedScmInfo(changesets);
- }
-
- @Override
- public Changeset getLatestChangeset() {
- return delegate.getLatestChangeset();
- }
-
- @Override
- public Changeset getChangesetForLine(int lineNumber) {
- return delegate.getChangesetForLine(lineNumber);
- }
-
- @Override
- public boolean hasChangesetForLine(int lineNumber) {
- return delegate.hasChangesetForLine(lineNumber);
- }
-
- @Override
- public Changeset[] getAllChangesets() {
- return delegate.getAllChangesets();
+ return new ScmInfoImpl(changesets);
}
}
import java.util.HashMap;
import java.util.Map;
-import java.util.function.Function;
+import java.util.function.IntFunction;
import javax.annotation.concurrent.Immutable;
import org.sonar.scanner.protocol.output.ScannerReport;
* ScmInfo implementation based on the changeset information from the Report
*/
@Immutable
-class ReportScmInfo implements ScmInfo {
- private final ScmInfo delegate;
+class ReportScmInfo {
- ReportScmInfo(ScannerReport.Changesets changesets) {
- requireNonNull(changesets);
- this.delegate = convertToScmInfo(changesets);
+ ReportScmInfo() {
+ // static only
}
- private static ScmInfo convertToScmInfo(ScannerReport.Changesets changesets) {
+ public static ScmInfo create(ScannerReport.Changesets changesets) {
+ requireNonNull(changesets);
Changeset[] lineChangesets = new Changeset[changesets.getChangesetIndexByLineCount()];
LineIndexToChangeset lineIndexToChangeset = new LineIndexToChangeset(changesets);
return new ScmInfoImpl(lineChangesets);
}
- @Override
- public Changeset getLatestChangeset() {
- return this.delegate.getLatestChangeset();
- }
-
- @Override
- public Changeset getChangesetForLine(int lineNumber) {
- return this.delegate.getChangesetForLine(lineNumber);
- }
-
- @Override
- public boolean hasChangesetForLine(int lineNumber) {
- return delegate.hasChangesetForLine(lineNumber);
- }
-
- @Override
- public Changeset[] getAllChangesets() {
- return this.delegate.getAllChangesets();
- }
-
- private static class LineIndexToChangeset implements Function<Integer, Changeset> {
+ private static class LineIndexToChangeset implements IntFunction<Changeset> {
private final ScannerReport.Changesets changesets;
private final Map<Integer, Changeset> changesetCache;
private final Changeset.Builder builder = Changeset.newChangesetBuilder();
- public LineIndexToChangeset(ScannerReport.Changesets changesets) {
+ private LineIndexToChangeset(ScannerReport.Changesets changesets) {
this.changesets = changesets;
this.changesetCache = new HashMap<>(changesets.getChangesetCount());
}
@Override
- public Changeset apply(Integer lineNumber) {
+ public Changeset apply(int lineNumber) {
int changesetIndex = changesets.getChangesetIndexByLine(lineNumber);
return changesetCache.computeIfAbsent(changesetIndex, idx -> convert(changesets.getChangeset(changesetIndex), lineNumber));
}
private Changeset convert(ScannerReport.Changesets.Changeset changeset, int line) {
- checkState(isNotEmpty(changeset.getRevision()), "Changeset on line %s must have a revision", line);
- checkState(changeset.getDate() != 0, "Changeset on line %s must have a date", line);
+ checkState(isNotEmpty(changeset.getRevision()), "Changeset on line %s must have a revision", line + 1);
+ checkState(changeset.getDate() != 0, "Changeset on line %s must have a date", line + 1);
return builder
.setRevision(changeset.getRevision().intern())
.setAuthor(isNotEmpty(changeset.getAuthor()) ? changeset.getAuthor().intern() : null)
*/
package org.sonar.ce.task.projectanalysis.scm;
-import java.util.Map;
-
/**
* Represents changeset information for a file. If SCM information is present, it will be the author, revision and date fetched from SCM
* for every line. Otherwise, it's a date that corresponds the the analysis date in which the line was modified.
if (dto == null) {
return Optional.empty();
}
- return DbScmInfo.create(dto.getSourceData().getLinesList(), dto.getSrcHash());
+ return DbScmInfo.create(dto.getSourceData().getLinesList(), dto.getLineCount(), dto.getSrcHash());
}
}
import java.util.Arrays;
import java.util.Comparator;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.utils.Preconditions;
}
private static Changeset computeLatestChangeset(Changeset[] lineChangesets) {
- return Arrays.stream(lineChangesets).max(Comparator.comparingLong(Changeset::getDate))
+ return Arrays.stream(lineChangesets).filter(Objects::nonNull).max(Comparator.comparingLong(Changeset::getDate))
.orElseThrow(() -> new IllegalStateException("Expecting at least one Changeset to be present"));
}
@Override
public Changeset getChangesetForLine(int lineNumber) {
+ if (lineNumber < 1 || lineNumber > lineChangesets.length) {
+ throw new IllegalArgumentException("There's no changeset on line " + lineNumber);
+
+ }
Changeset changeset = lineChangesets[lineNumber - 1];
if (changeset != null) {
return changeset;
public String toString() {
return "ScmInfoImpl{" +
"latestChangeset=" + latestChangeset +
- ", lineChangesets=" + lineChangesets +
- '}';
+ ", lineChangesets={" + IntStream.range(0, lineChangesets.length).mapToObj(i -> i + 1 + "=" + lineChangesets[i]).collect(Collectors.joining(", "))
+ + "}}";
}
}
private static Optional<ScmInfo> getScmInfoFromReport(Component file, ScannerReport.Changesets changesets) {
LOGGER.trace("Reading SCM info from report for file '{}'", file.getDbKey());
- return Optional.of(new ReportScmInfo(changesets));
+ return Optional.of(ReportScmInfo.create(changesets));
}
private Optional<ScmInfo> generateScmInfoForAllFile(Component file) {
*/
package org.sonar.ce.task.projectanalysis.source;
-import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.Component;
public interface SourceLinesDiff {
public ExpectedException thrown = ExpectedException.none();
@Test
- public void create_scm_info_with_some_changesets() throws Exception {
- ScmInfo scmInfo = DbScmInfo.create(newFakeData(10).build().getLinesList(), "hash").get();
+ public void create_scm_info_with_some_changesets() {
+ ScmInfo scmInfo = DbScmInfo.create(newFakeData(10).build().getLinesList(), 10, "hash").get();
assertThat(scmInfo.getAllChangesets()).hasSize(10);
}
addLine(fileDataBuilder, 4, "john", 123456789L, "rev-1");
fileDataBuilder.build();
- ScmInfo scmInfo = DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get();
+ ScmInfo scmInfo = DbScmInfo.create(fileDataBuilder.getLinesList(), 4, "hash").get();
assertThat(scmInfo.getAllChangesets()).hasSize(4);
}
@Test
- public void return_same_changeset_objects_for_lines_with_same_fields() throws Exception {
+ public void return_same_changeset_objects_for_lines_with_same_fields() {
DbFileSources.Data.Builder fileDataBuilder = DbFileSources.Data.newBuilder();
fileDataBuilder.addLinesBuilder().setScmRevision("rev").setScmDate(65L).setLine(1);
fileDataBuilder.addLinesBuilder().setScmRevision("rev2").setScmDate(6541L).setLine(2);
fileDataBuilder.addLinesBuilder().setScmRevision("rev1").setScmDate(6541L).setLine(3);
fileDataBuilder.addLinesBuilder().setScmRevision("rev").setScmDate(65L).setLine(4);
- ScmInfo scmInfo = DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get();
+ ScmInfo scmInfo = DbScmInfo.create(fileDataBuilder.getLinesList(), 4, "hash").get();
assertThat(scmInfo.getAllChangesets()).hasSize(4);
addLine(fileDataBuilder, 3, "john", 123456789L, "rev-1");
fileDataBuilder.build();
- ScmInfo scmInfo = DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get();
+ ScmInfo scmInfo = DbScmInfo.create(fileDataBuilder.getLinesList(), 3, "hash").get();
Changeset latestChangeset = scmInfo.getLatestChangeset();
assertThat(latestChangeset.getAuthor()).isEqualTo("henry");
DbFileSources.Data.Builder fileDataBuilder = DbFileSources.Data.newBuilder();
fileDataBuilder.addLinesBuilder().setLine(1);
- assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), "hash")).isNotPresent();
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 1, "hash")).isNotPresent();
}
@Test
- public void should_support_some_lines_not_having_scm_info() throws Exception {
+ public void should_support_some_lines_not_having_scm_info() {
DbFileSources.Data.Builder fileDataBuilder = DbFileSources.Data.newBuilder();
fileDataBuilder.addLinesBuilder().setScmRevision("rev").setScmDate(543L).setLine(1);
fileDataBuilder.addLinesBuilder().setLine(2);
fileDataBuilder.build();
- assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get().getAllChangesets()).hasSize(1);
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().getAllChangesets()).hasSize(2);
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().hasChangesetForLine(1)).isTrue();
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().hasChangesetForLine(2)).isFalse();
}
@Test
- public void filter_out_entries_without_date() throws Exception {
+ public void filter_out_entries_without_date() {
DbFileSources.Data.Builder fileDataBuilder = DbFileSources.Data.newBuilder();
fileDataBuilder.addLinesBuilder().setScmRevision("rev").setScmDate(555L).setLine(1);
fileDataBuilder.addLinesBuilder().setScmRevision("rev-1").setLine(2);
fileDataBuilder.build();
- assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get().getAllChangesets()).hasSize(1);
- assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get().getChangesetForLine(1).getRevision()).isEqualTo("rev");
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().getAllChangesets()).hasSize(2);
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().getChangesetForLine(1).getRevision()).isEqualTo("rev");
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().hasChangesetForLine(2)).isFalse();
+
}
@Test
- public void should_support_having_no_author() throws Exception {
+ public void should_support_having_no_author() {
DbFileSources.Data.Builder fileDataBuilder = DbFileSources.Data.newBuilder();
// gets filtered out
fileDataBuilder.addLinesBuilder().setScmAuthor("John").setLine(1);
fileDataBuilder.addLinesBuilder().setScmRevision("rev").setScmDate(555L).setLine(2);
fileDataBuilder.build();
- assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get().getAllChangesets()).hasSize(1);
- assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), "hash").get().getChangesetForLine(2).getAuthor()).isNull();
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().getAllChangesets()).hasSize(2);
+ assertThat(DbScmInfo.create(fileDataBuilder.getLinesList(), 2, "hash").get().getChangesetForLine(2).getAuthor()).isNull();
}
private static void addLine(DbFileSources.Data.Builder dataBuilder, Integer line, String author, Long date, String revision) {
@Test
public void create_scm_info_with_some_changesets() {
- ScmInfo scmInfo = new ReportScmInfo(ScannerReport.Changesets.newBuilder()
+ ScmInfo scmInfo = ReportScmInfo.create(ScannerReport.Changesets.newBuilder()
.setComponentRef(FILE_REF)
.addChangeset(ScannerReport.Changesets.Changeset.newBuilder()
.setAuthor("john")
@Test
public void return_changeset_for_a_given_line() {
- ScmInfo scmInfo = new ReportScmInfo(ScannerReport.Changesets.newBuilder()
+ ScmInfo scmInfo = ReportScmInfo.create(ScannerReport.Changesets.newBuilder()
.setComponentRef(FILE_REF)
.addChangeset(ScannerReport.Changesets.Changeset.newBuilder()
.setAuthor("john")
@Test
public void return_latest_changeset() {
- ScmInfo scmInfo = new ReportScmInfo(ScannerReport.Changesets.newBuilder()
+ ScmInfo scmInfo = ReportScmInfo.create(ScannerReport.Changesets.newBuilder()
.setComponentRef(FILE_REF)
.addChangeset(ScannerReport.Changesets.Changeset.newBuilder()
.setAuthor("john")
public void fail_with_ISE_when_no_changeset() {
thrown.expect(IllegalStateException.class);
- new ReportScmInfo(ScannerReport.Changesets.newBuilder().build());
+ ReportScmInfo.create(ScannerReport.Changesets.newBuilder().build());
}
@Test
public void fail_with_NPE_when_report_is_null() {
thrown.expect(NullPointerException.class);
- new ReportScmInfo(null);
+ ReportScmInfo.create(null);
}
@Test
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Changeset on line 1 must have a revision");
- new ReportScmInfo(ScannerReport.Changesets.newBuilder()
+ ReportScmInfo.create(ScannerReport.Changesets.newBuilder()
.setComponentRef(FILE_REF)
.addChangeset(ScannerReport.Changesets.Changeset.newBuilder()
.setAuthor("john")
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Changeset on line 1 must have a date");
- new ReportScmInfo(ScannerReport.Changesets.newBuilder()
+ ReportScmInfo.create(ScannerReport.Changesets.newBuilder()
.setComponentRef(FILE_REF)
.addChangeset(ScannerReport.Changesets.Changeset.newBuilder()
.setAuthor("john")
package org.sonar.ce.task.projectanalysis.scm;
import com.google.common.collect.ImmutableList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
analysisMetadataHolder.setBaseAnalysis(null);
analysisMetadataHolder.setBranch(branch);
-
assertThat(underTest.getScmInfo(FILE)).isEmpty();
assertThat(logTester.logs(TRACE)).isEmpty();
}
builder.setScmRevision(revision);
}
dbTester.getDbClient().fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
+ .setLineHashes(Collections.singletonList("lineHash"))
.setFileUuid(fileUuid)
.setProjectUuid("PROJECT_UUID")
.setSourceData(fileDataBuilder.build())
*/
package org.sonar.ce.task.projectanalysis.scm;
-import com.google.common.collect.ImmutableMap;
-import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
public class ScmInfoImplTest {
public void get_all_changesets() {
ScmInfo scmInfo = createScmInfoWithTwoChangestOnFourLines();
- assertThat(scmInfo.getAllChangesets()).containsOnly(entry(1, CHANGESET_1), entry(2, CHANGESET_2), entry(3, CHANGESET_1), entry(4, CHANGESET_1));
+ assertThat(scmInfo.getAllChangesets()).contains(CHANGESET_1, CHANGESET_2, CHANGESET_1, CHANGESET_1);
}
@Test
@Test
public void fail_with_ISE_on_empty_changeset() {
thrown.expect(IllegalStateException.class);
- thrown.expectMessage("A ScmInfo must have at least one Changeset and does not support any null one");
+ thrown.expectMessage("ScmInfo cannot be empty");
- new ScmInfoImpl(Collections.emptyMap());
+ new ScmInfoImpl(new Changeset[0]);
}
@Test
.setRevision("rev-2")
.build();
- ScmInfo scmInfo = new ScmInfoImpl(ImmutableMap.of(1, changeset1, 2, changeset2, 3, changeset1, 4, changeset1));
- return scmInfo;
+ return new ScmInfoImpl(new Changeset[] {changeset1, changeset2, changeset1, changeset1});
}
}
.setScmAuthor("author1")
.setScmDate(10L)
.build();
- DbScmInfo scmInfo = DbScmInfo.create(Collections.singleton(line1), hash).get();
+ DbScmInfo scmInfo = DbScmInfo.create(Collections.singletonList(line1), 1, hash).get();
when(dbLoader.getScmInfo(FILE)).thenReturn(Optional.of(scmInfo));
return scmInfo;
}
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import org.junit.rules.ExternalResource;
import org.sonar.ce.task.projectanalysis.component.Component;
}
public ScmInfoRepositoryRule setScmInfo(int fileRef, Changeset... changesetList) {
- Map<Integer, Changeset> changeset = IntStream.rangeClosed(1, changesetList.length).boxed().collect(Collectors.toMap(x -> x, x -> changesetList[x - 1]));
- scmInfoByFileRef.put(fileRef, new ScmInfoImpl(changeset));
+ scmInfoByFileRef.put(fileRef, new ScmInfoImpl(changesetList));
return this;
}
public ScmInfoRepositoryRule setScmInfo(int fileRef, Map<Integer, Changeset> changesets) {
- scmInfoByFileRef.put(fileRef, new ScmInfoImpl(changesets));
+ scmInfoByFileRef.put(fileRef, new ScmInfoImpl(changesets.values().stream().toArray(Changeset[]::new)));
return this;
}
}
*/
package org.sonar.ce.task.projectanalysis.source.linereader;
-import com.google.common.collect.ImmutableMap;
-import java.util.Collections;
-import java.util.Map;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.scm.Changeset;
import org.sonar.ce.task.projectanalysis.scm.ScmInfo;
@Test
public void set_scm() {
- ScmInfo scmInfo = new ScmInfoImpl(Collections.singletonMap(1,
+ ScmInfo scmInfo = new ScmInfoImpl(new Changeset[] {
Changeset.newChangesetBuilder()
.setAuthor("john")
.setDate(123_456_789L)
.setRevision("rev-1")
- .build()));
+ .build()});
ScmLineReader lineScm = new ScmLineReader(scmInfo);
@Test
public void set_scm_with_minim_fields() {
- ScmInfo scmInfo = new ScmInfoImpl(Collections.singletonMap(1,
+ ScmInfo scmInfo = new ScmInfoImpl(new Changeset[] {
Changeset.newChangesetBuilder()
.setDate(123456789L)
- .build()));
+ .build()});
ScmLineReader lineScm = new ScmLineReader(scmInfo);
readLineAndAssertLatestChanges(lineScm, 8, changeset2, changeset1);
}
- private static Map<Integer, Changeset> setup8LinesChangeset(Changeset changeset0, Changeset changeset1, Changeset changeset2) {
- return ImmutableMap.<Integer, Changeset>builder()
- .put(1, changeset0)
- .put(2, changeset1)
- .put(3, changeset1)
- .put(4, changeset2)
- .put(5, changeset0)
- .put(6, changeset1)
- .put(7, changeset0)
- .put(8, changeset0).build();
+ private static Changeset[] setup8LinesChangeset(Changeset changeset0, Changeset changeset1, Changeset changeset2) {
+ return new Changeset[] {
+ changeset0,
+ changeset1,
+ changeset1,
+ changeset2,
+ changeset0,
+ changeset1,
+ changeset0,
+ changeset0};
}
private void readLineAndAssertLatestChanges(ScmLineReader lineScm, int line, Changeset expectedChangeset, Changeset expectedChangesetWithRevision) {