com.xfyre.maven.plugins.changelog.RepositoryProcessor Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2016 git-changelog-maven-plugin contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.xfyre.maven.plugins.changelog;
import com.xfyre.maven.plugins.changelog.model.TagWrapper;
import com.xfyre.maven.plugins.changelog.handlers.CommitHandler;
import com.xfyre.maven.plugins.changelog.model.CommitWrapper;
import org.apache.maven.plugin.logging.Log;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.io.DisabledOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class RepositoryProcessor {
private final Pattern tagPattern;
private final Log log;
private final boolean deduplicateChildCommits;
private final String toRef;
private final String nextRelease;
private final String repositoryUrl;
private final Predicate commitFilter;
private final List commitHandlers = new ArrayList<>();
private final TreeFilter pathFilter;
private final String commitPrefix;
public RepositoryProcessor(boolean deduplicateChildCommits, String toRef, String nextRelease,
String repositoryUrl, String commitPrefix,
Predicate commitFilter, List commitHandlers, String pathFilter,
String releaseTagFilter, Log log) {
this.deduplicateChildCommits = deduplicateChildCommits;
this.toRef = toRef;
this.nextRelease = nextRelease;
this.repositoryUrl = repositoryUrl;
this.commitPrefix = commitPrefix;
this.commitFilter = commitFilter;
if (!isBlank(pathFilter) && !"/".equals(pathFilter)) {
this.pathFilter = PathFilter.create(pathFilter);
} else {
this.pathFilter = PathFilter.ALL;
}
this.commitHandlers.addAll(commitHandlers);
tagPattern = Pattern.compile(releaseTagFilter);
this.log = log;
}
public List process(File repoRoot) throws IOException {
try (Repository repository = new RepositoryBuilder().findGitDir(repoRoot).build()) {
return process(repository);
}
}
public List process(Repository repository) throws IOException {
final List tags = new ArrayList<>();
log.info("Processing git repository " + repository.getDirectory());
final ObjectId head = repository.resolve(toRef);
if (head == null) {
return tags;
}
try (RevWalk walk = new RevWalk(repository)) {
walk.sort(RevSort.TOPO);
final Map tagMapping = extractTags(repository, walk);
TagWrapper currentTag = new TagWrapper(nextRelease);
tags.add(currentTag);
RevCommit commit = walk.parseCommit(head);
while (commit != null) {
currentTag = tagMapping.getOrDefault(commit.getId(), currentTag);
if (tagMapping.containsKey(commit.getId())) {
tags.add(currentTag);
}
final CommitWrapper commitWrapper = processCommit(commit);
if (commitFilter.test(commit) && isInPath(repository, walk, commit)) {
currentTag.getCommits().add(commitWrapper);
}
final RevCommit[] parents = commit.getParents();
if (parents != null && parents.length > 0) {
final RevCommit parent = walk.parseCommit(parents[0]);
try (RevWalk childWalk = new RevWalk(repository)) {
childWalk.markStart(childWalk.parseCommit(commit));
childWalk.markUninteresting(childWalk.parseCommit(parent));
childWalk.next();
for (RevCommit childCommit : childWalk) {
final CommitWrapper childWrapper = processCommit(childCommit);
if (commitFilter.test(childCommit) && isInPath(repository, walk, commit) && !(deduplicateChildCommits && Objects.equals(commitWrapper.getTitle(), childWrapper.getTitle()))) {
commitWrapper.getChildren().add(childWrapper);
}
}
}
commit = parent;
} else {
commit = null;
}
}
}
return tags;
}
private Map extractTags(Repository repository, RevWalk walk) throws IOException {
final Map tagMapping = new HashMap<>();
for (Entry entry : repository.getTags().entrySet()) {
final String name = entry.getKey();
final Matcher matcher = tagPattern.matcher(name);
if (matcher.matches()) {
tagMapping.put(walk.parseCommit(entry.getValue().getObjectId()), new TagWrapper(name));
}
}
return tagMapping;
}
private boolean isInPath(Repository repository, RevWalk walk, RevCommit commit) throws IOException {
if (commit.getParentCount() == 0) {
RevTree tree = commit.getTree();
try (TreeWalk treeWalk = new TreeWalk(repository)) {
treeWalk.addTree(tree);
treeWalk.setRecursive(true);
treeWalk.setFilter(pathFilter);
return treeWalk.next();
}
} else {
DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
df.setRepository(repository);
df.setPathFilter(pathFilter);
RevCommit parent = walk.parseCommit(commit.getParent(0).getId());
List diffs = df.scan(parent.getTree(), commit.getTree());
return !diffs.isEmpty();
}
}
private CommitWrapper processCommit(RevCommit commit) {
final CommitWrapper commitWrapper = new CommitWrapper(commit, repositoryUrl, commitPrefix);
for (CommitHandler listener : commitHandlers) {
listener.handle(commitWrapper);
}
return commitWrapper;
}
}