public class CharsetDetector { | public class CharsetDetector { | ||||
private static final int BYTES_TO_DECODE = 4192; | private static final int BYTES_TO_DECODE = 4192; | ||||
private Path filePath; | |||||
private final Path filePath; | |||||
private BufferedInputStream stream; | private BufferedInputStream stream; | ||||
private Charset detectedCharset; | private Charset detectedCharset; | ||||
private Charset userEncoding; | private Charset userEncoding; |
import org.sonar.api.batch.fs.internal.DefaultInputFile; | import org.sonar.api.batch.fs.internal.DefaultInputFile; | ||||
import org.sonar.api.batch.scm.BlameCommand.BlameOutput; | import org.sonar.api.batch.scm.BlameCommand.BlameOutput; | ||||
import org.sonar.api.batch.scm.BlameLine; | import org.sonar.api.batch.scm.BlameLine; | ||||
import org.sonar.api.notifications.AnalysisWarnings; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.scanner.protocol.output.ScannerReport; | import org.sonar.scanner.protocol.output.ScannerReport; | ||||
private static final Logger LOG = Loggers.get(DefaultBlameOutput.class); | private static final Logger LOG = Loggers.get(DefaultBlameOutput.class); | ||||
private final ScannerReportWriter writer; | private final ScannerReportWriter writer; | ||||
private AnalysisWarnings analysisWarnings; | |||||
private final Set<InputFile> allFilesToBlame = new LinkedHashSet<>(); | private final Set<InputFile> allFilesToBlame = new LinkedHashSet<>(); | ||||
private ProgressReport progressReport; | private ProgressReport progressReport; | ||||
private int count; | private int count; | ||||
private int total; | private int total; | ||||
DefaultBlameOutput(ScannerReportWriter writer, List<InputFile> filesToBlame) { | |||||
DefaultBlameOutput(ScannerReportWriter writer, AnalysisWarnings analysisWarnings, List<InputFile> filesToBlame) { | |||||
this.writer = writer; | this.writer = writer; | ||||
this.analysisWarnings = analysisWarnings; | |||||
this.allFilesToBlame.addAll(filesToBlame); | this.allFilesToBlame.addAll(filesToBlame); | ||||
count = 0; | count = 0; | ||||
total = filesToBlame.size(); | total = filesToBlame.size(); | ||||
LOG.warn(" * " + f); | LOG.warn(" * " + f); | ||||
} | } | ||||
LOG.warn("This may lead to missing/broken features in SonarQube"); | LOG.warn("This may lead to missing/broken features in SonarQube"); | ||||
analysisWarnings.addUnique(String.format("Missing blame information for %d %s. This may lead to some features not working correctly. Please check the analysis logs.", | |||||
allFilesToBlame.size(), | |||||
allFilesToBlame.size() > 1 ? "files" : "file")); | |||||
} | } | ||||
} | } | ||||
import org.sonar.api.batch.fs.InputFile.Status; | import org.sonar.api.batch.fs.InputFile.Status; | ||||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | import org.sonar.api.batch.fs.internal.DefaultInputFile; | ||||
import org.sonar.api.batch.scm.ScmProvider; | import org.sonar.api.batch.scm.ScmProvider; | ||||
import org.sonar.api.notifications.AnalysisWarnings; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.scanner.protocol.output.ScannerReport; | import org.sonar.scanner.protocol.output.ScannerReport; | ||||
private final InputComponentStore componentStore; | private final InputComponentStore componentStore; | ||||
private final FileSystem fs; | private final FileSystem fs; | ||||
private final ScannerReportWriter writer; | private final ScannerReportWriter writer; | ||||
private AnalysisWarnings analysisWarnings; | |||||
private final BranchConfiguration branchConfiguration; | private final BranchConfiguration branchConfiguration; | ||||
public ScmPublisher(ScmConfiguration configuration, ProjectRepositoriesSupplier projectRepositoriesSupplier, | public ScmPublisher(ScmConfiguration configuration, ProjectRepositoriesSupplier projectRepositoriesSupplier, | ||||
InputComponentStore componentStore, FileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) { | |||||
InputComponentStore componentStore, FileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration, AnalysisWarnings analysisWarnings) { | |||||
this.configuration = configuration; | this.configuration = configuration; | ||||
this.projectRepositoriesSupplier = projectRepositoriesSupplier; | this.projectRepositoriesSupplier = projectRepositoriesSupplier; | ||||
this.componentStore = componentStore; | this.componentStore = componentStore; | ||||
this.fs = fs; | this.fs = fs; | ||||
this.branchConfiguration = branchConfiguration; | this.branchConfiguration = branchConfiguration; | ||||
this.writer = reportPublisher.getWriter(); | this.writer = reportPublisher.getWriter(); | ||||
this.analysisWarnings = analysisWarnings; | |||||
} | } | ||||
public void publish() { | public void publish() { | ||||
if (!filesToBlame.isEmpty()) { | if (!filesToBlame.isEmpty()) { | ||||
String key = provider.key(); | String key = provider.key(); | ||||
LOG.info("SCM Publisher SCM provider for this project is: " + key); | LOG.info("SCM Publisher SCM provider for this project is: " + key); | ||||
DefaultBlameOutput output = new DefaultBlameOutput(writer, filesToBlame); | |||||
DefaultBlameOutput output = new DefaultBlameOutput(writer, analysisWarnings, filesToBlame); | |||||
try { | try { | ||||
provider.blameCommand().blame(new DefaultBlameInput(fs, filesToBlame), output); | provider.blameCommand().blame(new DefaultBlameInput(fs, filesToBlame), output); | ||||
} catch (Exception e) { | } catch (Exception e) { |
package org.sonar.scanner.scm; | package org.sonar.scanner.scm; | ||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.Collections; | |||||
import java.util.Date; | import java.util.Date; | ||||
import org.junit.Rule; | import org.junit.Rule; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.sonar.api.batch.fs.InputFile; | import org.sonar.api.batch.fs.InputFile; | ||||
import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | ||||
import org.sonar.api.batch.scm.BlameLine; | import org.sonar.api.batch.scm.BlameLine; | ||||
import org.sonar.api.utils.System2; | |||||
import org.sonar.scanner.notifications.DefaultAnalysisWarnings; | |||||
import static java.util.Collections.emptyList; | |||||
import static java.util.Collections.singletonList; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.verify; | |||||
public class DefaultBlameOutputTest { | public class DefaultBlameOutputTest { | ||||
@Rule | @Rule | ||||
public ExpectedException thrown = ExpectedException.none(); | public ExpectedException thrown = ExpectedException.none(); | ||||
private System2 system2 = mock(System2.class); | |||||
private DefaultAnalysisWarnings analysisWarnings = new DefaultAnalysisWarnings(system2); | |||||
@Test | @Test | ||||
public void shouldNotFailIfNotSameNumberOfLines() { | public void shouldNotFailIfNotSameNumberOfLines() { | ||||
InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(10).build(); | InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(10).build(); | ||||
new DefaultBlameOutput(null, Arrays.asList(file)).blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy"))); | |||||
new DefaultBlameOutput(null, analysisWarnings, singletonList(file)).blameResult(file, singletonList(new BlameLine().revision("1").author("guy"))); | |||||
} | |||||
@Test | |||||
public void addWarningIfFilesMissing() { | |||||
InputFile file = new TestInputFileBuilder("foo", "src/main/java/Foo.java").setLines(10).build(); | |||||
new DefaultBlameOutput(null, analysisWarnings, singletonList(file)).finish(true); | |||||
assertThat(analysisWarnings.warnings()).extracting(DefaultAnalysisWarnings.Message::getText) | |||||
.containsOnly("Missing blame information for 1 file. This may lead to some features not working correctly. Please check the analysis logs."); | |||||
} | } | ||||
@Test | @Test | ||||
thrown.expect(IllegalArgumentException.class); | thrown.expect(IllegalArgumentException.class); | ||||
thrown.expectMessage("It was not expected to blame file " + file); | thrown.expectMessage("It was not expected to blame file " + file); | ||||
new DefaultBlameOutput(null, Arrays.<InputFile>asList(new TestInputFileBuilder("foo", "src/main/java/Foo2.java").build())) | |||||
.blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy"))); | |||||
new DefaultBlameOutput(null, analysisWarnings, singletonList(new TestInputFileBuilder("foo", "src/main/java/Foo2.java").build())) | |||||
.blameResult(file, singletonList(new BlameLine().revision("1").author("guy"))); | |||||
} | } | ||||
@Test | @Test | ||||
thrown.expect(IllegalArgumentException.class); | thrown.expect(IllegalArgumentException.class); | ||||
thrown.expectMessage("Blame date is null for file " + file + " at line 1"); | thrown.expectMessage("Blame date is null for file " + file + " at line 1"); | ||||
new DefaultBlameOutput(null, Arrays.<InputFile>asList(file)) | |||||
.blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy"))); | |||||
new DefaultBlameOutput(null, analysisWarnings, singletonList(file)) | |||||
.blameResult(file, singletonList(new BlameLine().revision("1").author("guy"))); | |||||
} | } | ||||
@Test | @Test | ||||
thrown.expect(IllegalArgumentException.class); | thrown.expect(IllegalArgumentException.class); | ||||
thrown.expectMessage("Blame revision is blank for file " + file + " at line 1"); | thrown.expectMessage("Blame revision is blank for file " + file + " at line 1"); | ||||
new DefaultBlameOutput(null, Arrays.<InputFile>asList(file)) | |||||
.blameResult(file, Arrays.asList(new BlameLine().date(new Date()).author("guy"))); | |||||
new DefaultBlameOutput(null, analysisWarnings, singletonList(file)) | |||||
.blameResult(file, singletonList(new BlameLine().date(new Date()).author("guy"))); | |||||
} | } | ||||
} | } |