From 327799ec3efa6e9cb6180cd40a7d41cee0c1ce43 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Mon, 29 Sep 2014 18:04:53 +0200 Subject: [PATCH] SONAR-5677 Provide JGit implementation --- plugins/sonar-git-plugin/pom.xml | 5 + .../org/sonar/plugins/scm/git/GitPlugin.java | 17 ++- .../sonar/plugins/scm/git/GitScmProvider.java | 19 ++- .../plugins/scm/git/JGitBlameCommand.java | 64 ++++++++++ .../sonar/plugins/scm/git/GitPluginTest.java | 2 +- .../plugins/scm/git/GitScmProviderTest.java | 32 ++++- .../plugins/scm/git/JGitBlameCommandTest.java | 115 ++++++++++++++++++ .../sonar-git-plugin/test-repos/dummy-git.zip | Bin 0 -> 51878 bytes 8 files changed, 244 insertions(+), 10 deletions(-) create mode 100644 plugins/sonar-git-plugin/src/main/java/org/sonar/plugins/scm/git/JGitBlameCommand.java create mode 100644 plugins/sonar-git-plugin/src/test/java/org/sonar/plugins/scm/git/JGitBlameCommandTest.java create mode 100644 plugins/sonar-git-plugin/test-repos/dummy-git.zip 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 @@ sonar-plugin-api provided + + org.eclipse.jgit + org.eclipse.jgit + 3.5.0.201409260305-r + 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 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 lines = new ArrayList(); + 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.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 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 0000000000000000000000000000000000000000..e019a80dee2eda254083a3516e862b28c59fefe7 GIT binary patch literal 51878 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 literal 0 HcmV?d00001 -- 2.39.5