diff --git a/config/findbugs-exclude.xml b/config/findbugs-exclude.xml index 2e28ef6..22c62d1 100644 --- a/config/findbugs-exclude.xml +++ b/config/findbugs-exclude.xml @@ -1,9 +1,18 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/config/import-control.xml b/config/import-control.xml index 2142bcb..37fde80 100644 --- a/config/import-control.xml +++ b/config/import-control.xml @@ -4,4 +4,9 @@ "http://www.puppycrawl.com/dtds/import_control_1_1.dtd"> + + + + + diff --git a/pom.xml b/pom.xml index 8a8addc..f23cd83 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,18 @@ 4.12 test + + org.powermock + powermock-api-mockito + 1.6.6 + test + + + org.powermock + powermock-module-junit4 + 1.6.6 + test + org.apache.maven maven-jxr @@ -146,7 +158,8 @@ https://raw.githubusercontent.com/checkstyle/checkstyle/checkstyle-${checkstyle.version}/config/checkstyle_sevntu_checks.xml - project.basedir=${project.basedir} + project.basedir=${project.basedir} + true true 0 @@ -205,7 +218,7 @@ xml html - + @@ -254,6 +267,12 @@ 0 0 + + com.github.checkstyle.regression.git.DiffParser + + 50 + 100 + diff --git a/src/main/java/com/github/checkstyle/regression/git/DiffParser.java b/src/main/java/com/github/checkstyle/regression/git/DiffParser.java new file mode 100644 index 0000000..42872d0 --- /dev/null +++ b/src/main/java/com/github/checkstyle/regression/git/DiffParser.java @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.git; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; + +/** + * Git diff parser. + * @author LuoLiangchen + */ +public class DiffParser { + /** The path of checkstyle repository. */ + private final String repositoryPath; + + /** + * Creates a new {@code DiffParser} instance. + * @param repositoryPath the path of checkstyle repository + */ + public DiffParser(String repositoryPath) { + this.repositoryPath = repositoryPath; + } + + /** + * Parses the diff between a given branch and the master. + * @param branchName the name of the branch to be compared with master + * @return a list of {@code GitChange} to represent the changes + * @throws IOException JGit library exception + * @throws GitAPIException JGit library exception + */ + public List parse(String branchName) throws IOException, GitAPIException { + final File gitDir = new File(repositoryPath, ".git"); + try (Repository repository = new FileRepositoryBuilder().setGitDir(gitDir) + .readEnvironment().findGitDir().build()) { + try (Git git = new Git(repository)) { + final AbstractTreeIterator featureTreeParser = + prepareTreeParser(repository, Constants.R_HEADS + branchName); + final AbstractTreeIterator masterTreeParser = + prepareTreeParser(repository, Constants.R_HEADS + "master"); + return git.diff() + .setOldTree(masterTreeParser) + .setNewTree(featureTreeParser) + .call() + .stream() + .map(GitChange::new) + .collect(Collectors.toList()); + } + } + } + + /** + * Creates a tree parser from a commit, to be used by diff command. + * @param repository the repository to parse diff + * @param ref the name of the ref to the commit; e.g., "refs/heads/master" + * @return the tree parser + * @throws IOException JGit library exception + */ + private static AbstractTreeIterator prepareTreeParser(Repository repository, String ref) + throws IOException { + final Ref head = repository.exactRef(ref); + try (RevWalk walk = new RevWalk(repository)) { + final RevCommit commit = walk.parseCommit(head.getObjectId()); + final RevTree tree = walk.parseTree(commit.getTree().getId()); + final CanonicalTreeParser treeParser = new CanonicalTreeParser(); + try (ObjectReader reader = repository.newObjectReader()) { + treeParser.reset(reader, tree.getId()); + } + walk.dispose(); + return treeParser; + } + } +} diff --git a/src/main/java/com/github/checkstyle/regression/git/GitChange.java b/src/main/java/com/github/checkstyle/regression/git/GitChange.java new file mode 100644 index 0000000..cf2b884 --- /dev/null +++ b/src/main/java/com/github/checkstyle/regression/git/GitChange.java @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.git; + +import org.eclipse.jgit.diff.DiffEntry; + +/** + * Represents git changes of a file. + * @author LuoLiangchen + */ +public class GitChange { + /** The path of the changed file. */ + private final String path; + + /** + * Creates a new {@code GitChange} instance from a {@code DiffEntry}. + * @param diff the {@code DiffEntry} + */ + GitChange(DiffEntry diff) { + path = diff.getNewPath(); + } + + /** + * Gets the path of the changed file. + * @return the path of the changed file + */ + public String getPath() { + return path; + } +} diff --git a/src/main/java/com/github/checkstyle/regression/git/package-info.java b/src/main/java/com/github/checkstyle/regression/git/package-info.java new file mode 100644 index 0000000..ded4015 --- /dev/null +++ b/src/main/java/com/github/checkstyle/regression/git/package-info.java @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +/** + * Contains git related classes. + */ +package com.github.checkstyle.regression.git; diff --git a/src/test/java/com/github/checkstyle/regression/git/DiffParserTest.java b/src/test/java/com/github/checkstyle/regression/git/DiffParserTest.java new file mode 100644 index 0000000..50cfe7a --- /dev/null +++ b/src/test/java/com/github/checkstyle/regression/git/DiffParserTest.java @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.git; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.List; + +import org.eclipse.jgit.lib.Repository; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.github.checkstyle.regression.internal.GitUtils; + +public class DiffParserTest { + private Repository repository; + + @Before + public void setUp() throws Exception { + repository = GitUtils.newRepository(); + final File helloWorld = GitUtils.addAnEmptyFileAndCommit(repository, "HelloWorld"); + GitUtils.createNewBranchAndCheckout(repository, "foo"); + Files.write(helloWorld.toPath(), "hello world!".getBytes(), StandardOpenOption.APPEND); + GitUtils.addAllAndCommit(repository, "append text to HelloWorld"); + } + + @After + public void tearDown() throws Exception { + repository.close(); + } + + @Test + public void testParse() throws Exception { + final DiffParser diffParser = new DiffParser(repository.getDirectory().getParent()); + final List changes = diffParser.parse("foo"); + assertEquals(1, changes.size()); + assertEquals("HelloWorld", changes.iterator().next().getPath()); + } +} diff --git a/src/test/java/com/github/checkstyle/regression/internal/GitUtils.java b/src/test/java/com/github/checkstyle/regression/internal/GitUtils.java new file mode 100644 index 0000000..23750b2 --- /dev/null +++ b/src/test/java/com/github/checkstyle/regression/internal/GitUtils.java @@ -0,0 +1,82 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2017 the original author or authors. +// +// This library 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 2.1 of the License, or (at your option) any later version. +// +// This library 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 library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.checkstyle.regression.internal; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; + +/** + * Contains utility methods for git component test. + * @author LuoLiangchen + */ +public final class GitUtils { + /** Prevents instantiation. */ + private GitUtils() { + } + + public static Repository newRepository() throws IOException { + final File repoDir = File.createTempFile("TestTempRepository", ""); + if (!repoDir.delete()) { + throw new IOException("Could not delete temporary file " + repoDir); + } + final Repository repository = FileRepositoryBuilder.create(new File(repoDir, ".git")); + repository.create(); + return repository; + } + + public static void createNewBranchAndCheckout(Repository repository, String branchName) + throws GitAPIException { + try (Git git = new Git(repository)) { + if (git.branchList().call().stream() + .anyMatch(ref -> ref.getName().equals(Constants.R_HEADS + branchName))) { + git.branchDelete().setBranchNames(branchName).setForce(true).call(); + } + git.branchCreate().setName(branchName).call(); + git.checkout().setName(branchName).call(); + } + } + + public static File addAnEmptyFileAndCommit(Repository repository, String fileName) + throws IOException, GitAPIException { + try (Git git = new Git(repository)) { + final File file = new File(repository.getDirectory().getParent(), fileName); + if (!file.createNewFile()) { + throw new IOException("Could not create file " + file); + } + git.add().addFilepattern(fileName).call(); + git.commit().setMessage("add " + fileName).call(); + return file; + } + } + + public static void addAllAndCommit(Repository repository, String message) + throws GitAPIException { + try (Git git = new Git(repository)) { + git.add().addFilepattern(".").call(); + git.commit().setMessage(message).call(); + } + } +}