aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2014-09-29 18:04:53 +0200
committerJulien HENRY <julien.henry@sonarsource.com>2014-10-02 17:52:23 +0200
commit327799ec3efa6e9cb6180cd40a7d41cee0c1ce43 (patch)
tree461c6b5ef75775907a985cb0634499a71fc09653 /plugins
parent6122d2708aa9b2e43e6f7be50b54d6d8f7319e9b (diff)
downloadsonarqube-327799ec3efa6e9cb6180cd40a7d41cee0c1ce43.tar.gz
sonarqube-327799ec3efa6e9cb6180cd40a7d41cee0c1ce43.zip
SONAR-5677 Provide JGit implementation
Diffstat (limited to 'plugins')
-rw-r--r--plugins/sonar-git-plugin/pom.xml5
-rw-r--r--plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitPlugin.java17
-rw-r--r--plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitScmProvider.java19
-rw-r--r--plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java64
-rw-r--r--plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitPluginTest.java2
-rw-r--r--plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitScmProviderTest.java32
-rw-r--r--plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java115
-rw-r--r--plugins/sonar-git-plugin/test-repos/dummy-git.zipbin0 -> 51878 bytes
8 files changed, 244 insertions, 10 deletions
diff --git a/plugins/sonar-git-plugin/pom.xml b/plugins/sonar-git-plugin/pom.xml
index ef707db2795..98cac3424e4 100644
--- a/plugins/sonar-git-plugin/pom.xml
+++ b/plugins/sonar-git-plugin/pom.xml
@@ -24,6 +24,11 @@
<artifactId>sonar-plugin-api</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.jgit</groupId>
+ <artifactId>org.eclipse.jgit</artifactId>
+ <version>3.5.0.201409260305-r</version>
+ </dependency>
<!-- unit tests -->
<dependency>
diff --git a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitPlugin.java b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitPlugin.java
index e5c12c42900..958f838a9b0 100644
--- a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitPlugin.java
+++ b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitPlugin.java
@@ -20,16 +20,31 @@
package org.sonar.plugins.scm.git;
import com.google.common.collect.ImmutableList;
+import org.sonar.api.PropertyType;
import org.sonar.api.SonarPlugin;
+import org.sonar.api.config.PropertyDefinition;
import java.util.List;
public final class GitPlugin extends SonarPlugin {
+ static final String GIT_IMPLEMENTATION_PROP_KEY = "sonar.git.implementation";
+ static final String JGIT = "jgit";
+ static final String EXE = "exe";
+
public List getExtensions() {
return ImmutableList.of(
GitScmProvider.class,
- GitBlameCommand.class);
+ GitBlameCommand.class,
+ JGitBlameCommand.class,
+
+ PropertyDefinition.builder(GIT_IMPLEMENTATION_PROP_KEY)
+ .name("Git implementation")
+ .description("Use pure Java implementation by default but you can use command line git executable in case of issue.")
+ .defaultValue(JGIT)
+ .type(PropertyType.SINGLE_SELECT_LIST)
+ .options(EXE, JGIT)
+ .build());
}
}
diff --git a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitScmProvider.java b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitScmProvider.java
index a0dfeb92601..677bb6aa063 100644
--- a/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitScmProvider.java
+++ b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/GitScmProvider.java
@@ -21,15 +21,20 @@ package org.sonar.plugins.scm.git;
import org.sonar.api.batch.scm.BlameCommand;
import org.sonar.api.batch.scm.ScmProvider;
+import org.sonar.api.config.Settings;
import java.io.File;
public class GitScmProvider extends ScmProvider {
- private GitBlameCommand blameCommand;
+ private final GitBlameCommand blameCommand;
+ private final JGitBlameCommand jgitBlameCommand;
+ private final Settings settings;
- public GitScmProvider(GitBlameCommand blameCommand) {
+ public GitScmProvider(Settings settings, GitBlameCommand blameCommand, JGitBlameCommand jgitBlameCommand) {
+ this.settings = settings;
this.blameCommand = blameCommand;
+ this.jgitBlameCommand = jgitBlameCommand;
}
@Override
@@ -44,7 +49,13 @@ public class GitScmProvider extends ScmProvider {
@Override
public BlameCommand blameCommand() {
- return this.blameCommand;
+ String implem = settings.getString(GitPlugin.GIT_IMPLEMENTATION_PROP_KEY);
+ if (GitPlugin.EXE.equals(implem)) {
+ return this.blameCommand;
+ } else if (GitPlugin.JGIT.equals(implem)) {
+ return this.jgitBlameCommand;
+ } else {
+ throw new IllegalArgumentException("Illegal value for " + GitPlugin.GIT_IMPLEMENTATION_PROP_KEY + ": " + implem);
+ }
}
-
}
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
new file mode 100644
index 00000000000..4f0e99af560
--- /dev/null
+++ b/plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java
@@ -0,0 +1,64 @@
+/*
+ * 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.plugins.scm.git;
+
+import org.eclipse.jgit.api.Git;
+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;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
+public class JGitBlameCommand implements BlameCommand, BatchComponent {
+
+ @Override
+ public void blame(FileSystem fs, Iterable<InputFile> files, BlameResult result) {
+ Git git = null;
+ File basedir = fs.baseDir();
+ try {
+ git = Git.open(basedir);
+ for (InputFile inputFile : files) {
+ String filename = inputFile.relativePath();
+ org.eclipse.jgit.blame.BlameResult blameResult = git.blame().setFilePath(filename).call();
+ List<BlameLine> lines = new ArrayList<BlameLine>();
+ for (int i = 0; i < blameResult.getResultContents().size(); i++) {
+ 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()));
+ }
+ result.add(inputFile, lines);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("JGit blame failure!", e);
+ } finally {
+ if (git != null && git.getRepository() != null) {
+ git.getRepository().close();
+ }
+ }
+ }
+
+}
diff --git a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitPluginTest.java b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitPluginTest.java
index d175cdcbe91..d77cf7f242d 100644
--- a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitPluginTest.java
+++ b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitPluginTest.java
@@ -27,6 +27,6 @@ public class GitPluginTest {
@Test
public void getExtensions() {
- assertThat(new GitPlugin().getExtensions()).hasSize(2);
+ assertThat(new GitPlugin().getExtensions()).hasSize(4);
}
}
diff --git a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitScmProviderTest.java b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitScmProviderTest.java
index 9bc5801d055..97450a991fa 100644
--- a/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitScmProviderTest.java
+++ b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/GitScmProviderTest.java
@@ -21,7 +21,10 @@ package org.sonar.plugins.scm.git;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
import java.io.File;
import java.io.IOException;
@@ -32,22 +35,43 @@ public class GitScmProviderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
@Test
public void sanityCheck() {
- assertThat(new GitScmProvider(null).key()).isEqualTo("git");
+ assertThat(new GitScmProvider(null, null, null).key()).isEqualTo("git");
+ }
+
+ @Test
+ public void selectImplem() {
GitBlameCommand blameCommand = new GitBlameCommand();
- assertThat(new GitScmProvider(blameCommand).blameCommand()).isEqualTo(blameCommand);
+ JGitBlameCommand jblameCommand = new JGitBlameCommand();
+ Settings settings = new Settings(new PropertyDefinitions(new GitPlugin().getExtensions()));
+ GitScmProvider gitScmProvider = new GitScmProvider(settings, blameCommand, jblameCommand);
+
+ assertThat(gitScmProvider.blameCommand()).isEqualTo(jblameCommand);
+
+ settings.setProperty(GitPlugin.GIT_IMPLEMENTATION_PROP_KEY, GitPlugin.EXE);
+ assertThat(gitScmProvider.blameCommand()).isEqualTo(blameCommand);
+
+ settings.setProperty(GitPlugin.GIT_IMPLEMENTATION_PROP_KEY, GitPlugin.JGIT);
+ assertThat(gitScmProvider.blameCommand()).isEqualTo(jblameCommand);
+
+ settings.setProperty(GitPlugin.GIT_IMPLEMENTATION_PROP_KEY, "foo");
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Illegal value for " + GitPlugin.GIT_IMPLEMENTATION_PROP_KEY + ": foo");
+ gitScmProvider.blameCommand();
}
@Test
public void testAutodetection() throws IOException {
File baseDirEmpty = temp.newFolder();
- assertThat(new GitScmProvider(null).supports(baseDirEmpty)).isFalse();
+ assertThat(new GitScmProvider(null, null, null).supports(baseDirEmpty)).isFalse();
File gitBaseDir = temp.newFolder();
new File(gitBaseDir, ".git").mkdir();
- assertThat(new GitScmProvider(null).supports(gitBaseDir)).isTrue();
+ assertThat(new GitScmProvider(null, null, null).supports(gitBaseDir)).isTrue();
}
}
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
new file mode 100644
index 00000000000..58aad97d844
--- /dev/null
+++ b/plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java
@@ -0,0 +1,115 @@
+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.Rule;
+import org.junit.Test;
+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.BlameLine;
+import org.sonar.api.utils.DateUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class JGitBlameCommandTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void testBlame() throws IOException {
+ File projectDir = temp.newFolder();
+ javaUnzip(new File("test-repos/dummy-git.zip"), projectDir);
+
+ JGitBlameCommand jGitBlameCommand = new JGitBlameCommand();
+
+ DefaultFileSystem fs = new DefaultFileSystem();
+ fs.setBaseDir(new File(projectDir, "dummy-git"));
+ DefaultInputFile inputFile = new DefaultInputFile("foo", "src/main/java/org/dummy/Dummy.java");
+ fs.add(inputFile);
+
+ BlameResult blameResult = mock(BlameResult.class);
+ jGitBlameCommand.blame(fs, Arrays.<InputFile>asList(inputFile), blameResult);
+
+ Date revisionDate = DateUtils.parseDateTime("2012-07-17T16:12:48+0200");
+ String revision = "6b3aab35a3ea32c1636fee56f996e677653c48ea";
+ String author = "david@gageot.net";
+ verify(blameResult).add(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)));
+
+ }
+
+ private static void javaUnzip(File zip, File toDir) {
+ try {
+ ZipFile zipFile = new ZipFile(zip);
+ try {
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ File to = new File(toDir, entry.getName());
+ if (entry.isDirectory()) {
+ FileUtils.forceMkdir(to);
+ } else {
+ File parent = to.getParentFile();
+ if (parent != null) {
+ FileUtils.forceMkdir(parent);
+ }
+
+ OutputStream fos = new FileOutputStream(to);
+ try {
+ IOUtils.copy(zipFile.getInputStream(entry), fos);
+ } finally {
+ Closeables.closeQuietly(fos);
+ }
+ }
+ }
+ } finally {
+ zipFile.close();
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to unzip " + zip + " to " + toDir, e);
+ }
+ }
+
+}
diff --git a/plugins/sonar-git-plugin/test-repos/dummy-git.zip b/plugins/sonar-git-plugin/test-repos/dummy-git.zip
new file mode 100644
index 00000000000..e019a80dee2
--- /dev/null
+++ b/plugins/sonar-git-plugin/test-repos/dummy-git.zip
Binary files differ