aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameCommand.java12
-rw-r--r--plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameConsumer.java10
-rw-r--r--plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java27
-rw-r--r--plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitBlameCommandTest.java30
-rw-r--r--plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java147
-rw-r--r--plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameCommand.java18
-rw-r--r--plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameConsumer.java5
-rw-r--r--plugins/sonar-svn-plugin/src/test/java/org/sonar/plugins/scm/svn/SvnBlameCommandTest.java48
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/scm/XooBlameCommand.java24
-rw-r--r--plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/scm/XooBlameCommandTest.java18
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameInput.java46
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java (renamed from sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameResult.java)18
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java6
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java30
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java (renamed from sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameResultTest.java)15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameCommand.java34
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameLine.java49
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/ScmProvider.java5
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/scm/BlameLineTest.java9
19 files changed, 337 insertions, 214 deletions
diff --git a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameCommand.java b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameCommand.java
index 6cd5145457f..0e7c05f6b05 100644
--- a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameCommand.java
+++ b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameCommand.java
@@ -21,8 +21,6 @@ package org.sonar.plugins.scm.git;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.scm.BlameCommand;
@@ -35,8 +33,7 @@ import org.sonar.api.utils.command.StringStreamConsumer;
import java.io.File;
import java.util.List;
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public class GitBlameCommand implements BlameCommand, BatchComponent {
+public class GitBlameCommand extends BlameCommand {
private static final Logger LOG = LoggerFactory.getLogger(GitBlameCommand.class);
private final CommandExecutor commandExecutor;
@@ -50,9 +47,10 @@ public class GitBlameCommand implements BlameCommand, BatchComponent {
}
@Override
- public void blame(FileSystem fs, Iterable<InputFile> files, BlameResult result) {
+ public void blame(BlameInput input, BlameOutput output) {
+ FileSystem fs = input.fileSystem();
LOG.debug("Working directory: " + fs.baseDir().getAbsolutePath());
- for (InputFile inputFile : files) {
+ for (InputFile inputFile : input.filesToBlame()) {
String filename = inputFile.relativePath();
Command cl = createCommandLine(fs.baseDir(), filename);
GitBlameConsumer consumer = new GitBlameConsumer(filename);
@@ -67,7 +65,7 @@ public class GitBlameCommand implements BlameCommand, BatchComponent {
// SONARPLUGINS-3097 Git do not report blame on last empty line
lines.add(lines.get(lines.size() - 1));
}
- result.add(inputFile, lines);
+ output.blameResult(inputFile, lines);
}
}
diff --git a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameConsumer.java b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameConsumer.java
index 350d3dd956f..c8e4eec4f50 100644
--- a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameConsumer.java
+++ b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitBlameConsumer.java
@@ -35,7 +35,6 @@ public class GitBlameConsumer implements StreamConsumer {
private static final String GIT_COMMITTER_PREFIX = "committer";
private static final String GIT_COMMITTER_TIME = GIT_COMMITTER_PREFIX + "-time ";
private static final String GIT_AUTHOR_EMAIL = "author-mail ";
- private static final String GIT_COMMITTER_EMAIL = GIT_COMMITTER_PREFIX + "-mail ";
private static final String OPENING_EMAIL_FIELD = "<";
private static final String CLOSING_EMAIL_FIELD = ">";
@@ -55,7 +54,6 @@ public class GitBlameConsumer implements StreamConsumer {
private String revision = null;
private String author = null;
- private String committer = null;
private Date time = null;
private final String filename;
@@ -93,11 +91,6 @@ public class GitBlameConsumer implements StreamConsumer {
return true;
}
- if (line.startsWith(GIT_COMMITTER_EMAIL)) {
- committer = extractEmail(line);
- return true;
- }
-
if (line.startsWith(GIT_COMMITTER_TIME)) {
String timeStr = line.substring(GIT_COMMITTER_TIME.length());
time = new Date(Long.parseLong(timeStr) * 1000L);
@@ -118,7 +111,7 @@ public class GitBlameConsumer implements StreamConsumer {
}
private void consumeContentLine() {
- BlameLine blameLine = new BlameLine(time, revision, author, committer);
+ BlameLine blameLine = new BlameLine().date(time).revision(revision).author(author);
getLines().add(blameLine);
// keep commitinfo for this sha-1
@@ -142,7 +135,6 @@ public class GitBlameConsumer implements StreamConsumer {
if (oldLine != null) {
// restore the commit info
author = oldLine.author();
- committer = oldLine.committer();
time = oldLine.date();
}
diff --git a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java
index cfc044ad467..9f69f924fdb 100644
--- a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java
+++ b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java
@@ -26,9 +26,6 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.scm.BlameCommand;
import org.sonar.api.batch.scm.BlameLine;
@@ -39,8 +36,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public class JGitBlameCommand implements BlameCommand, BatchComponent {
+public class JGitBlameCommand extends BlameCommand {
private static final Logger LOG = LoggerFactory.getLogger(JGitBlameCommand.class);
@@ -51,9 +47,9 @@ public class JGitBlameCommand implements BlameCommand, BatchComponent {
}
@Override
- public void blame(FileSystem fs, Iterable<InputFile> files, BlameResult result) {
+ public void blame(BlameInput input, BlameOutput output) {
Git git = null;
- File basedir = fs.baseDir();
+ File basedir = input.fileSystem().baseDir();
try {
Repository repo = new RepositoryBuilder()
.findGitDir(basedir)
@@ -61,8 +57,8 @@ public class JGitBlameCommand implements BlameCommand, BatchComponent {
.build();
git = Git.wrap(repo);
File gitBaseDir = repo.getWorkTree();
- for (InputFile inputFile : files) {
- blame(result, git, gitBaseDir, inputFile);
+ for (InputFile inputFile : input.filesToBlame()) {
+ blame(output, git, gitBaseDir, inputFile);
}
} catch (IOException e) {
throw new IllegalStateException("Unable to open Git repository", e);
@@ -75,7 +71,7 @@ public class JGitBlameCommand implements BlameCommand, BatchComponent {
}
}
- private void blame(BlameResult result, Git git, File gitBaseDir, InputFile inputFile) throws GitAPIException {
+ private void blame(BlameOutput output, Git git, File gitBaseDir, InputFile inputFile) throws GitAPIException {
String filename = pathResolver.relativePath(gitBaseDir, inputFile.file());
org.eclipse.jgit.blame.BlameResult blameResult = git.blame()
// Equivalent to -w command line option
@@ -83,22 +79,19 @@ public class JGitBlameCommand implements BlameCommand, BatchComponent {
.setFilePath(filename).call();
List<BlameLine> lines = new ArrayList<BlameLine>();
for (int i = 0; i < blameResult.getResultContents().size(); i++) {
- if (blameResult.getSourceAuthor(i) == null || blameResult.getSourceCommit(i) == null || blameResult.getSourceCommitter(i) == null) {
+ if (blameResult.getSourceAuthor(i) == null || blameResult.getSourceCommit(i) == null) {
LOG.info("Author: " + blameResult.getSourceAuthor(i));
- LOG.info("Committer: " + blameResult.getSourceCommitter(i));
LOG.info("Source commit: " + blameResult.getSourceCommit(i));
throw new IllegalStateException("Unable to blame file " + inputFile.relativePath() + ". No blame info at line " + (i + 1) + ". Is file commited?");
}
- lines.add(new org.sonar.api.batch.scm.BlameLine(blameResult.getSourceAuthor(i).getWhen(),
- blameResult.getSourceCommit(i).getName(),
- blameResult.getSourceAuthor(i).getEmailAddress(),
- blameResult.getSourceCommitter(i).getEmailAddress()));
+ lines.add(new org.sonar.api.batch.scm.BlameLine().date(blameResult.getSourceAuthor(i).getWhen()).revision(blameResult.getSourceCommit(i).getName())
+ .author(blameResult.getSourceAuthor(i).getEmailAddress()));
}
if (lines.size() == inputFile.lines() - 1) {
// SONARPLUGINS-3097 Git do not report blame on last empty line
lines.add(lines.get(lines.size() - 1));
}
- result.add(inputFile, lines);
+ output.blameResult(inputFile, lines);
}
}
diff --git a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitBlameCommandTest.java b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitBlameCommandTest.java
index 574f68dc4da..f5fff20d9da 100644
--- a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitBlameCommandTest.java
+++ b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitBlameCommandTest.java
@@ -30,7 +30,8 @@ import org.mockito.stubbing.Answer;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.scm.BlameCommand.BlameResult;
+import org.sonar.api.batch.scm.BlameCommand.BlameInput;
+import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.command.Command;
@@ -57,12 +58,15 @@ public class GitBlameCommandTest {
private DefaultFileSystem fs;
private File baseDir;
+ private BlameInput input;
@Before
public void prepare() throws IOException {
baseDir = temp.newFolder();
fs = new DefaultFileSystem();
fs.setBaseDir(baseDir);
+ input = mock(BlameInput.class);
+ when(input.fileSystem()).thenReturn(fs);
}
@Test
@@ -72,7 +76,7 @@ public class GitBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -98,11 +102,13 @@ public class GitBlameCommandTest {
return 0;
}
});
-
- new GitBlameCommand(commandExecutor).blame(fs, Arrays.<InputFile>asList(inputFile), result);
- verify(result).add(inputFile,
- Arrays.asList(new BlameLine(DateUtils.parseDateTime("2011-08-05T10:49:31+0200"), "2c68c473da7fc293e12ca50f19380c5118be7ead", "simon.brandhof@gmail.com"),
- new BlameLine(DateUtils.parseDateTime("2011-08-05T10:49:31+0200"), "2c68c473da7fc293e12ca50f19380c5118be7ead", "simon.brandhof@gmail.com")));
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ new GitBlameCommand(commandExecutor).blame(input, result);
+ verify(result).blameResult(
+ inputFile,
+ Arrays.asList(
+ new BlameLine().date(DateUtils.parseDateTime("2011-08-05T10:49:31+0200")).revision("2c68c473da7fc293e12ca50f19380c5118be7ead").author("simon.brandhof@gmail.com"),
+ new BlameLine().date(DateUtils.parseDateTime("2011-08-05T10:49:31+0200")).revision("2c68c473da7fc293e12ca50f19380c5118be7ead").author("simon.brandhof@gmail.com")));
}
@Test
@@ -112,7 +118,7 @@ public class GitBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -141,7 +147,8 @@ public class GitBlameCommandTest {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Unable to blame file src/foo.xoo. No blame info at line 1. Is file commited?");
- new GitBlameCommand(commandExecutor).blame(fs, Arrays.<InputFile>asList(inputFile), result);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ new GitBlameCommand(commandExecutor).blame(input, result);
}
@Test
@@ -151,7 +158,7 @@ public class GitBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -167,7 +174,8 @@ public class GitBlameCommandTest {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("The git blame command [git blame --porcelain src/foo.xoo -w] failed: My error");
- new GitBlameCommand(commandExecutor).blame(fs, Arrays.<InputFile>asList(inputFile), result);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ new GitBlameCommand(commandExecutor).blame(input, result);
}
}
diff --git a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java
index 20b96962f83..7f74bea84a9 100644
--- a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java
+++ b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java
@@ -22,6 +22,7 @@ package org.sonar.plugins.scm.git;
import com.google.common.io.Closeables;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -29,7 +30,8 @@ import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.scm.BlameCommand.BlameResult;
+import org.sonar.api.batch.scm.BlameCommand.BlameInput;
+import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.DateUtils;
@@ -46,6 +48,7 @@ import java.util.zip.ZipFile;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class JGitBlameCommandTest {
@@ -57,6 +60,16 @@ public class JGitBlameCommandTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ private DefaultFileSystem fs;
+ private BlameInput input;
+
+ @Before
+ public void prepare() throws IOException {
+ fs = new DefaultFileSystem();
+ input = mock(BlameInput.class);
+ when(input.fileSystem()).thenReturn(fs);
+ }
+
@Test
public void testBlame() throws IOException {
File projectDir = temp.newFolder();
@@ -64,47 +77,47 @@ public class JGitBlameCommandTest {
JGitBlameCommand jGitBlameCommand = new JGitBlameCommand(new PathResolver());
- DefaultFileSystem fs = new DefaultFileSystem();
File baseDir = new File(projectDir, "dummy-git");
fs.setBaseDir(baseDir);
DefaultInputFile inputFile = new DefaultInputFile("foo", DUMMY_JAVA)
.setFile(new File(baseDir, DUMMY_JAVA));
fs.add(inputFile);
- BlameResult blameResult = mock(BlameResult.class);
- jGitBlameCommand.blame(fs, Arrays.<InputFile>asList(inputFile), blameResult);
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ jGitBlameCommand.blame(input, blameResult);
Date revisionDate = DateUtils.parseDateTime("2012-07-17T16:12:48+0200");
String revision = "6b3aab35a3ea32c1636fee56f996e677653c48ea";
String author = "david@gageot.net";
- verify(blameResult).add(inputFile,
+ verify(blameResult).blameResult(inputFile,
Arrays.asList(
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author)));
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author)));
}
@Test
@@ -114,47 +127,47 @@ public class JGitBlameCommandTest {
JGitBlameCommand jGitBlameCommand = new JGitBlameCommand(new PathResolver());
- DefaultFileSystem fs = new DefaultFileSystem();
File baseDir = new File(projectDir, "dummy-git-nested/dummy-project");
fs.setBaseDir(baseDir);
DefaultInputFile inputFile = new DefaultInputFile("foo", DUMMY_JAVA)
.setFile(new File(baseDir, DUMMY_JAVA));
fs.add(inputFile);
- BlameResult blameResult = mock(BlameResult.class);
- jGitBlameCommand.blame(fs, Arrays.<InputFile>asList(inputFile), blameResult);
+ BlameOutput blameResult = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ jGitBlameCommand.blame(input, blameResult);
Date revisionDate = DateUtils.parseDateTime("2012-07-17T16:12:48+0200");
String revision = "6b3aab35a3ea32c1636fee56f996e677653c48ea";
String author = "david@gageot.net";
- verify(blameResult).add(inputFile,
+ verify(blameResult).blameResult(inputFile,
Arrays.asList(
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author),
- new BlameLine(revisionDate, revision, author)));
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author),
+ new BlameLine().revision(revision).date(revisionDate).author(author)));
}
@Test
@@ -164,7 +177,6 @@ public class JGitBlameCommandTest {
JGitBlameCommand jGitBlameCommand = new JGitBlameCommand(new PathResolver());
- DefaultFileSystem fs = new DefaultFileSystem();
File baseDir = new File(projectDir, "dummy-git");
fs.setBaseDir(baseDir);
String relativePath = DUMMY_JAVA;
@@ -175,11 +187,12 @@ public class JGitBlameCommandTest {
// Emulate a modification
FileUtils.write(new File(baseDir, relativePath), "modification and \n some new line", true);
- BlameResult blameResult = mock(BlameResult.class);
+ BlameOutput blameResult = mock(BlameOutput.class);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Unable to blame file " + relativePath + ". No blame info at line 27. Is file commited?");
- jGitBlameCommand.blame(fs, Arrays.<InputFile>asList(inputFile), blameResult);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ jGitBlameCommand.blame(input, blameResult);
}
@Test
@@ -189,7 +202,6 @@ public class JGitBlameCommandTest {
JGitBlameCommand jGitBlameCommand = new JGitBlameCommand(new PathResolver());
- DefaultFileSystem fs = new DefaultFileSystem();
File baseDir = new File(projectDir, "dummy-git");
fs.setBaseDir(baseDir);
String relativePath = DUMMY_JAVA;
@@ -204,11 +216,12 @@ public class JGitBlameCommandTest {
// Emulate a new file
FileUtils.copyFile(new File(baseDir, relativePath), new File(baseDir, relativePath2));
- BlameResult blameResult = mock(BlameResult.class);
+ BlameOutput blameResult = mock(BlameOutput.class);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Unable to blame file " + relativePath2 + ". No blame info at line 1. Is file commited?");
- jGitBlameCommand.blame(fs, Arrays.<InputFile>asList(inputFile, inputFile2), blameResult);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile, inputFile2));
+ jGitBlameCommand.blame(input, blameResult);
}
private static void javaUnzip(File zip, File toDir) {
diff --git a/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameCommand.java b/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameCommand.java
index 48b65ffee6d..27647c8cad2 100644
--- a/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameCommand.java
+++ b/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameCommand.java
@@ -22,8 +22,6 @@ package org.sonar.plugins.scm.svn;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.scm.BlameCommand;
@@ -44,8 +42,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public class SvnBlameCommand implements BlameCommand, BatchComponent {
+public class SvnBlameCommand extends BlameCommand {
private static final Logger LOG = LoggerFactory.getLogger(SvnBlameCommand.class);
private final CommandExecutor commandExecutor;
@@ -61,12 +58,13 @@ public class SvnBlameCommand implements BlameCommand, BatchComponent {
}
@Override
- public void blame(final FileSystem fs, Iterable<InputFile> files, final BlameResult result) {
+ public void blame(final BlameInput input, final BlameOutput output) {
+ FileSystem fs = input.fileSystem();
LOG.debug("Working directory: " + fs.baseDir().getAbsolutePath());
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
List<Future<Void>> tasks = new ArrayList<Future<Void>>();
- for (InputFile inputFile : files) {
- tasks.add(submitTask(fs, result, executorService, inputFile));
+ for (InputFile inputFile : input.filesToBlame()) {
+ tasks.add(submitTask(fs, output, executorService, inputFile));
}
for (Future<Void> task : tasks) {
@@ -81,7 +79,7 @@ public class SvnBlameCommand implements BlameCommand, BatchComponent {
}
}
- private Future<Void> submitTask(final FileSystem fs, final BlameResult result, ExecutorService executorService, final InputFile inputFile) {
+ private Future<Void> submitTask(final FileSystem fs, final BlameOutput result, ExecutorService executorService, final InputFile inputFile) {
return executorService.submit(new Callable<Void>() {
@Override
public Void call() {
@@ -91,7 +89,7 @@ public class SvnBlameCommand implements BlameCommand, BatchComponent {
});
}
- private void blame(final FileSystem fs, final InputFile inputFile, final BlameResult result) {
+ private void blame(final FileSystem fs, final InputFile inputFile, final BlameOutput output) {
String filename = inputFile.relativePath();
Command cl = createCommandLine(fs.baseDir(), filename);
SvnBlameConsumer consumer = new SvnBlameConsumer(filename);
@@ -111,7 +109,7 @@ public class SvnBlameCommand implements BlameCommand, BatchComponent {
// SONARPLUGINS-3097 SVN do not report blame on last empty line
lines.add(lines.get(lines.size() - 1));
}
- result.add(inputFile, lines);
+ output.blameResult(inputFile, lines);
}
private int execute(Command cl, StreamConsumer consumer, StreamConsumer stderr) {
diff --git a/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameConsumer.java b/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameConsumer.java
index dcf67a50572..8224fab347d 100644
--- a/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameConsumer.java
+++ b/plugins/sonar-svn-plugin/src/main/java/org/sonar/plugins/scm/svn/SvnBlameConsumer.java
@@ -43,6 +43,8 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.utils.command.StreamConsumer;
+import javax.annotation.CheckForNull;
+
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -101,13 +103,14 @@ public class SvnBlameConsumer implements StreamConsumer {
String date = matcher.group(1);
String time = matcher.group(2);
Date dateTime = parseDateTime(date + " " + time);
- lines.add(new BlameLine(dateTime, revision, author));
+ lines.add(new BlameLine().revision(revision).author(author).date(dateTime));
lineNumber = 0;
revision = null;
author = null;
}
}
+ @CheckForNull
protected Date parseDateTime(String dateTimeStr) {
try {
return dateFormat.parse(dateTimeStr);
diff --git a/plugins/sonar-svn-plugin/src/test/java/org/sonar/plugins/scm/svn/SvnBlameCommandTest.java b/plugins/sonar-svn-plugin/src/test/java/org/sonar/plugins/scm/svn/SvnBlameCommandTest.java
index f7bb1fc66dc..b85b71d2fdb 100644
--- a/plugins/sonar-svn-plugin/src/test/java/org/sonar/plugins/scm/svn/SvnBlameCommandTest.java
+++ b/plugins/sonar-svn-plugin/src/test/java/org/sonar/plugins/scm/svn/SvnBlameCommandTest.java
@@ -31,7 +31,8 @@ import org.mockito.stubbing.Answer;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.scm.BlameCommand.BlameResult;
+import org.sonar.api.batch.scm.BlameCommand.BlameInput;
+import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
@@ -48,7 +49,9 @@ import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class SvnBlameCommandTest {
@@ -60,12 +63,15 @@ public class SvnBlameCommandTest {
private DefaultFileSystem fs;
private File baseDir;
+ private BlameInput input;
@Before
public void prepare() throws IOException {
baseDir = temp.newFolder();
fs = new DefaultFileSystem();
fs.setBaseDir(baseDir);
+ input = mock(BlameInput.class);
+ when(input.fileSystem()).thenReturn(fs);
}
@Test
@@ -75,7 +81,7 @@ public class SvnBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -91,12 +97,14 @@ public class SvnBlameCommandTest {
}
});
- new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(fs, Arrays.<InputFile>asList(inputFile), result);
- verify(result).add(inputFile,
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+
+ new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(input, result);
+ verify(result).blameResult(inputFile,
Arrays.asList(
- new BlameLine(DateUtils.parseDateTime("2009-04-18T10:29:59+0000"), "9491", "simon.brandhof"),
- new BlameLine(DateUtils.parseDateTime("2009-04-18T10:29:59+0000"), "9491", "simon.brandhof"),
- new BlameLine(DateUtils.parseDateTime("2009-08-31T22:32:17+0000"), "10558", "david")));
+ new BlameLine().date(DateUtils.parseDateTime("2009-04-18T10:29:59+0000")).revision("9491").author("simon.brandhof"),
+ new BlameLine().date(DateUtils.parseDateTime("2009-04-18T10:29:59+0000")).revision("9491").author("simon.brandhof"),
+ new BlameLine().date(DateUtils.parseDateTime("2009-08-31T22:32:17+0000")).revision("10558").author("david")));
}
@Test
@@ -106,7 +114,7 @@ public class SvnBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -122,12 +130,14 @@ public class SvnBlameCommandTest {
}
});
- new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(fs, Arrays.<InputFile>asList(inputFile), result);
- verify(result).add(inputFile,
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+
+ new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(input, result);
+ verify(result).blameResult(inputFile,
Arrays.asList(
- new BlameLine(DateUtils.parseDateTime("2009-04-18T10:29:59+0000"), "9491", "simon.brandhof"),
- new BlameLine(DateUtils.parseDateTime("2009-04-01T10:29:59+0000"), "1", null),
- new BlameLine(DateUtils.parseDateTime("2009-08-31T22:32:17+0000"), "10558", "david")));
+ new BlameLine().date(DateUtils.parseDateTime("2009-04-18T10:29:59+0000")).revision("9491").author("simon.brandhof"),
+ new BlameLine().date(DateUtils.parseDateTime("2009-04-01T10:29:59+0000")).revision("1"),
+ new BlameLine().date(DateUtils.parseDateTime("2009-08-31T22:32:17+0000")).revision("10558").author("david")));
}
@Test
@@ -137,7 +147,7 @@ public class SvnBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -156,7 +166,8 @@ public class SvnBlameCommandTest {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Unable to blame file src/foo.xoo. No blame info at line 2. Is file commited?");
- new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(fs, Arrays.<InputFile>asList(inputFile), result);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(input, result);
}
@Test
@@ -166,7 +177,7 @@ public class SvnBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath());
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
+ BlameOutput result = mock(BlameOutput.class);
CommandExecutor commandExecutor = mock(CommandExecutor.class);
when(commandExecutor.execute(any(Command.class), any(StreamConsumer.class), any(StreamConsumer.class), anyLong())).thenAnswer(new Answer<Integer>() {
@@ -182,7 +193,8 @@ public class SvnBlameCommandTest {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("The svn blame command [svn blame --xml src/foo.xoo --non-interactive] failed: My error");
- new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(fs, Arrays.<InputFile>asList(inputFile), result);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ new SvnBlameCommand(commandExecutor, mock(SvnConfiguration.class)).blame(input, result);
}
@Test
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/scm/XooBlameCommand.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/scm/XooBlameCommand.java
index 0534d92d8cb..b78deb2812c 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/scm/XooBlameCommand.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/scm/XooBlameCommand.java
@@ -23,9 +23,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.scm.BlameCommand;
import org.sonar.api.batch.scm.BlameLine;
@@ -34,27 +31,25 @@ import org.sonar.api.utils.DateUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public class XooBlameCommand implements BlameCommand, BatchComponent {
+public class XooBlameCommand extends BlameCommand {
private static final String SCM_EXTENSION = ".scm";
@Override
- public void blame(FileSystem fs, Iterable<InputFile> files, BlameResult result) {
- for (InputFile inputFile : files) {
+ public void blame(BlameInput input, BlameOutput result) {
+ for (InputFile inputFile : input.filesToBlame()) {
processFile(inputFile, result);
}
}
@VisibleForTesting
- protected void processFile(InputFile inputFile, BlameResult result) {
+ protected void processFile(InputFile inputFile, BlameOutput result) {
File ioFile = inputFile.file();
File scmDataFile = new java.io.File(ioFile.getParentFile(), ioFile.getName() + SCM_EXTENSION);
if (!scmDataFile.exists()) {
- throw new IllegalStateException("Missing file " + scmDataFile);
+ return;
}
try {
@@ -71,13 +66,16 @@ public class XooBlameCommand implements BlameCommand, BatchComponent {
}
String revision = StringUtils.trimToNull(fields[0]);
String author = StringUtils.trimToNull(fields[1]);
+ BlameLine blameLine = new BlameLine().revision(revision).author(author);
String dateStr = StringUtils.trimToNull(fields[2]);
// Will throw an exception, when date is not in format "yyyy-MM-dd"
- Date date = dateStr != null ? DateUtils.parseDate(dateStr) : null;
- blame.add(new BlameLine(date, revision, author));
+ if (dateStr != null) {
+ blameLine.date(DateUtils.parseDate(dateStr));
+ }
+ blame.add(blameLine);
}
}
- result.add(inputFile, blame);
+ result.blameResult(inputFile, blame);
} catch (IOException e) {
throw new IllegalStateException(e);
}
diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/scm/XooBlameCommandTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/scm/XooBlameCommandTest.java
index bba495dd400..793752bcf0c 100644
--- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/scm/XooBlameCommandTest.java
+++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/scm/XooBlameCommandTest.java
@@ -28,7 +28,8 @@ import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.scm.BlameCommand.BlameResult;
+import org.sonar.api.batch.scm.BlameCommand.BlameInput;
+import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.utils.DateUtils;
import org.sonar.xoo.Xoo;
@@ -39,6 +40,7 @@ import java.util.Arrays;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class XooBlameCommandTest {
@@ -50,11 +52,14 @@ public class XooBlameCommandTest {
private DefaultFileSystem fs;
private File baseDir;
+ private BlameInput input;
@Before
public void prepare() throws IOException {
baseDir = temp.newFolder();
fs = new DefaultFileSystem();
+ input = mock(BlameInput.class);
+ when(input.fileSystem()).thenReturn(fs);
}
@Test
@@ -66,10 +71,11 @@ public class XooBlameCommandTest {
DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath()).setLanguage(Xoo.KEY);
fs.add(inputFile);
- BlameResult result = mock(BlameResult.class);
- new XooBlameCommand().blame(fs, Arrays.<InputFile>asList(inputFile), result);
- verify(result).add(inputFile, Arrays.asList(new BlameLine(DateUtils.parseDate("2014-12-12"), "123", "julien"),
- new BlameLine(DateUtils.parseDate("2014-12-24"), "234", "julien")));
+ BlameOutput result = mock(BlameOutput.class);
+ when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
+ new XooBlameCommand().blame(input, result);
+ verify(result).blameResult(inputFile, Arrays.asList(
+ new BlameLine().revision("123").author("julien").date(DateUtils.parseDate("2014-12-12")),
+ new BlameLine().revision("234").author("julien").date(DateUtils.parseDate("2014-12-24"))));
}
-
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameInput.java b/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameInput.java
new file mode 100644
index 00000000000..f115bf89880
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameInput.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.scm;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.scm.BlameCommand.BlameInput;
+
+class DefaultBlameInput implements BlameInput {
+
+ private FileSystem fs;
+ private Iterable<InputFile> filesToBlame;
+
+ DefaultBlameInput(FileSystem fs, Iterable<InputFile> filesToBlame) {
+ this.fs = fs;
+ this.filesToBlame = filesToBlame;
+ }
+
+ @Override
+ public FileSystem fileSystem() {
+ return fs;
+ }
+
+ @Override
+ public Iterable<InputFile> filesToBlame() {
+ return filesToBlame;
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameResult.java b/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java
index f62e3d00683..de873b135db 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameResult.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java
@@ -21,7 +21,7 @@ package org.sonar.batch.scm;
import com.google.common.base.Preconditions;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.scm.BlameCommand.BlameResult;
+import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.measures.CoreMetrics;
@@ -33,24 +33,29 @@ import javax.annotation.Nullable;
import java.text.Normalizer;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.regex.Pattern;
-class DefaultBlameResult implements BlameResult {
+class DefaultBlameOutput implements BlameOutput {
private static final Pattern NON_ASCII_CHARS = Pattern.compile("[^\\x00-\\x7F]");
private static final Pattern ACCENT_CODES = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
private final SensorContext context;
+ private final Set<InputFile> allFilesToBlame = new HashSet<InputFile>();
- DefaultBlameResult(SensorContext context) {
+ DefaultBlameOutput(SensorContext context, List<InputFile> filesToBlame) {
this.context = context;
+ this.allFilesToBlame.addAll(filesToBlame);
}
@Override
- public void add(InputFile file, List<BlameLine> lines) {
+ public void blameResult(InputFile file, List<BlameLine> lines) {
Preconditions.checkNotNull(file);
Preconditions.checkNotNull(lines);
+ Preconditions.checkArgument(allFilesToBlame.contains(file), "It was not expected to blame file " + file.relativePath());
Preconditions.checkArgument(lines.size() == file.lines(),
"Expected one blame result per line but provider returned " + lines.size() + " blame lines while file " + file.relativePath() + " has " + file.lines() + " lines");
@@ -67,6 +72,7 @@ class DefaultBlameResult implements BlameResult {
lineNumber++;
}
ScmSensor.saveMeasures(context, file, authors.buildData(), dates.buildData(), revisions.buildData());
+ allFilesToBlame.remove(file);
}
private String normalizeString(@Nullable String inputString) {
@@ -90,4 +96,8 @@ class DefaultBlameResult implements BlameResult {
private static PropertiesBuilder<Integer, String> propertiesBuilder(Metric metric) {
return new PropertiesBuilder<Integer, String>(metric);
}
+
+ public Set<InputFile> remainingFiles() {
+ return allFilesToBlame;
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java
index e3de5aa41d1..4480938a7a2 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java
@@ -84,7 +84,11 @@ public final class ScmSensor implements Sensor {
if (!filesToBlame.isEmpty()) {
LOG.info("SCM provider for this project is: " + configuration.provider().key());
TimeProfiler profiler = new TimeProfiler().start("Retrieve SCM blame information");
- configuration.provider().blameCommand().blame(fs, filesToBlame, new DefaultBlameResult(context));
+ DefaultBlameOutput output = new DefaultBlameOutput(context, filesToBlame);
+ configuration.provider().blameCommand().blame(new DefaultBlameInput(fs, filesToBlame), output);
+ if (!output.remainingFiles().isEmpty()) {
+ throw new IllegalStateException("Some files were not blamed");
+ }
profiler.stop();
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java
index 22a3592cd7d..1c3b4209e51 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java
@@ -23,7 +23,9 @@ import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
@@ -42,6 +44,9 @@ public class ScmMediumTest {
@org.junit.Rule
public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
public BatchMediumTester tester = BatchMediumTester.builder()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
@@ -90,6 +95,31 @@ public class ScmMediumTest {
}
@Test
+ public void failIfMissingFile() throws IOException {
+
+ File baseDir = prepareProject();
+ File xooFile = new File(baseDir, "src/sample2.xoo");
+ FileUtils.write(xooFile, "Sample xoo\ncontent\n3\n4\n5");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Some files were not blamed");
+
+ tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .put("sonar.scm.provider", "xoo")
+ .build())
+ .start();
+
+ }
+
+ @Test
public void configureUsingScmURL() throws IOException {
File baseDir = prepareProject();
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameResultTest.java b/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java
index 90d7dc7e1f6..069e3d5f679 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameResultTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scm/DefaultBlameOutputTest.java
@@ -28,7 +28,7 @@ import org.sonar.api.batch.scm.BlameLine;
import java.util.Arrays;
-public class DefaultBlameResultTest {
+public class DefaultBlameOutputTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -40,7 +40,18 @@ public class DefaultBlameResultTest {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Expected one blame result per line but provider returned 1 blame lines while file src/main/java/Foo.java has 10 lines");
- new DefaultBlameResult(null).add(file, Arrays.asList(new BlameLine(null, "1", "guy")));
+ new DefaultBlameOutput(null, Arrays.asList(file)).blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy")));
+ }
+
+ @Test
+ public void shouldFailIfNotExpectedFile() {
+ InputFile file = new DefaultInputFile("foo", "src/main/java/Foo.java").setLines(1);
+
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("It was not expected to blame file src/main/java/Foo.java");
+
+ new DefaultBlameOutput(null, Arrays.<InputFile>asList(new DefaultInputFile("foo", "src/main/java/Foo2.java")))
+ .blameResult(file, Arrays.asList(new BlameLine().revision("1").author("guy")));
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameCommand.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameCommand.java
index e8c74a03e36..b775385eabb 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameCommand.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameCommand.java
@@ -19,33 +19,55 @@
*/
package org.sonar.api.batch.scm;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import java.util.List;
/**
+ * This class should be implemented by SCM providers.
* @since 5.0
*/
-public interface BlameCommand {
+@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
+public abstract class BlameCommand implements BatchComponent {
/**
- * Compute blame of the provided files. Computation can be done in parallel.
+ * Compute blame of the provided files.
+ * Computation can be done in parallel if this is more efficient.
* If there is an error that prevent to blame a file then an exception should be raised. If
* one file is new or contains local modifications then an exception should be raised.
*/
- void blame(FileSystem fs, Iterable<InputFile> files, BlameResult result);
+ public abstract void blame(BlameInput input, BlameOutput output);
/**
* Callback for the provider to report results of blame per file.
*/
- public static interface BlameResult {
+ public static interface BlameInput {
+
+ /**
+ * Filesystem of the current (sub )project.
+ */
+ FileSystem fileSystem();
+
+ /**
+ * List of files that should be blamed.
+ */
+ Iterable<InputFile> filesToBlame();
+
+ }
+
+ /**
+ * Callback for the provider to report results of blame per file.
+ */
+ public static interface BlameOutput {
/**
* Add result of the blame command for a single file. Number of lines should
- * be consistent with {@link InputFile#lines()}.
+ * be consistent with {@link InputFile#lines()}. This method is thread safe.
*/
- void add(InputFile file, List<BlameLine> lines);
+ void blameResult(InputFile file, List<BlameLine> lines);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameLine.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameLine.java
index 7772d706ec2..9aed38d9f32 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameLine.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/BlameLine.java
@@ -37,37 +37,14 @@ public class BlameLine {
private Date date;
private String revision;
private String author;
- private String committer;
- /**
- * @param date of the commit
- * @param revision of the commit
- * @param author will also be used as committer identification
- */
- public BlameLine(@Nullable Date date, String revision, @Nullable String author) {
- this(date, revision, author, author);
+ public String revision() {
+ return revision;
}
- /**
- *
- * @param date of the commit
- * @param revision of the commit
- * @param author the person who wrote the line
- * @param committer the person who committed the change
- */
- public BlameLine(@Nullable Date date, String revision, @Nullable String author, @Nullable String committer) {
- if (date != null) {
- this.date = new Date(date.getTime());
- } else {
- this.date = null;
- }
+ public BlameLine revision(String revision) {
this.revision = revision;
- this.author = author;
- this.committer = committer;
- }
-
- public String revision() {
- return revision;
+ return this;
}
@CheckForNull
@@ -75,9 +52,9 @@ public class BlameLine {
return author;
}
- @CheckForNull
- public String committer() {
- return committer;
+ public BlameLine author(@Nullable String author) {
+ this.author = author;
+ return this;
}
/**
@@ -85,10 +62,12 @@ public class BlameLine {
*/
@CheckForNull
public Date date() {
- if (date != null) {
- return (Date) date.clone();
- }
- return null;
+ return date;
+ }
+
+ public BlameLine date(@Nullable Date date) {
+ this.date = date;
+ return this;
}
// For testing purpose
@@ -109,7 +88,6 @@ public class BlameLine {
.append(date, rhs.date)
.append(revision, rhs.revision)
.append(author, rhs.author)
- .append(committer, rhs.committer)
.isEquals();
}
@@ -119,7 +97,6 @@ public class BlameLine {
append(date)
.append(revision)
.append(author)
- .append(committer)
.toHashCode();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/ScmProvider.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/ScmProvider.java
index a32bec98538..c3f86878293 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/ScmProvider.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/scm/ScmProvider.java
@@ -20,18 +20,21 @@
package org.sonar.api.batch.scm;
import org.sonar.api.BatchExtension;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.InstantiationStrategy;
import java.io.File;
/**
+ * See {@link CoreProperties#LINKS_SOURCES_DEV} to get old Maven URL format.
* @since 5.0
*/
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
public abstract class ScmProvider implements BatchExtension {
/**
- * Unique identifier of the provider. Can be used in SCM URL to define the provider to use.
+ * Unique identifier of the provider. Can be passed to {@link CoreProperties#SCM_PROVIDER_KEY}
+ * Can be used in SCM URL to define the provider to use.
*/
public abstract String key();
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/scm/BlameLineTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/scm/BlameLineTest.java
index 1ff1eee16b2..4a5fb76eb24 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/scm/BlameLineTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/scm/BlameLineTest.java
@@ -30,14 +30,13 @@ public class BlameLineTest {
@Test
public void testBlameLine() {
Date date = new Date();
- BlameLine line1 = new BlameLine(date, "1", "foo");
- BlameLine line1b = new BlameLine(date, "1", "foo");
- BlameLine line2 = new BlameLine(null, "2", "foo2");
+ BlameLine line1 = new BlameLine().date(date).revision("1").author("foo");
+ BlameLine line1b = new BlameLine().date(date).revision("1").author("foo");
+ BlameLine line2 = new BlameLine().date(null).revision("2").author("foo2");
assertThat(line1.author()).isEqualTo("foo");
assertThat(line1.date()).isEqualTo(date);
assertThat(line1.revision()).isEqualTo("1");
- assertThat(line1.committer()).isEqualTo("foo");
assertThat(line1).isEqualTo(line1);
assertThat(line1).isNotEqualTo(null);
@@ -46,7 +45,7 @@ public class BlameLineTest {
assertThat(line1).isNotEqualTo(line2);
assertThat(line1).isNotEqualTo("foo");
- assertThat(line1.toString()).contains("revision=1,author=foo,committer=foo");
+ assertThat(line1.toString()).contains("revision=1,author=foo");
}
}