Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,8 @@ Now you just have to include such a properties file in your project under `/src/
```
git.tags=${git.tags}
git.branch=${git.branch}
git.local.branch.ahead=${git.local.branch.ahead}
git.local.branch.behind=${git.local.branch.behind}
git.dirty=${git.dirty}
git.remote.origin.url=${git.remote.origin.url}
git.commit.id=${git.commit.id}
Expand Down
60 changes: 60 additions & 0 deletions src/main/java/pl/project13/maven/git/AheadBehind.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package pl.project13.maven.git;

import java.util.Objects;

public class AheadBehind {

public static final AheadBehind NO_REMOTE = AheadBehind.of("NO_REMOTE", "NO_REMOTE");

private final String ahead;

private final String behind;

private AheadBehind(String ahead, String behind) {
this.ahead = ahead;
this.behind = behind;
}

public static AheadBehind of(int ahead, int behind) {
return new AheadBehind(String.valueOf(ahead), String.valueOf(behind));
}

public static AheadBehind of(String ahead, String behind) {
return new AheadBehind(ahead, behind);
}

public String ahead() {
return ahead;
}

public String behind() {
return behind;
}

@Override
public int hashCode() {
return Objects.hash(ahead, behind);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AheadBehind other = (AheadBehind) obj;

if (!Objects.equals(ahead, other.ahead)) {
return false;
}
if (!Objects.equals(behind, other.behind)) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
public class GitCommitPropertyConstant {
// these properties will be exposed to maven
public static final String BRANCH = "branch";
public static final String LOCAL_BRANCH_AHEAD = "local.branch.ahead";
public static final String LOCAL_BRANCH_BEHIND = "local.branch.behind";
public static final String DIRTY = "dirty";
// only one of the following two will be exposed, depending on the commitIdGenerationMode
public static final String COMMIT_ID_FLAT = "commit.id";
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/pl/project13/maven/git/GitDataProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ public void loadGitData(@Nonnull String evaluateOnCommit, @Nonnull Properties pr
put(properties,GitCommitPropertyConstant.CLOSEST_TAG_COMMIT_COUNT, getClosestTagCommitCount());

put(properties,GitCommitPropertyConstant.TOTAL_COMMIT_COUNT, getTotalCommitCount());

AheadBehind aheadBehind = getAheadBehind();
put(properties, GitCommitPropertyConstant.LOCAL_BRANCH_AHEAD, aheadBehind.ahead());
put(properties, GitCommitPropertyConstant.LOCAL_BRANCH_BEHIND, aheadBehind.behind());
} finally {
finalCleanUp();
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/pl/project13/maven/git/GitProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ public interface GitProvider {
String getTotalCommitCount() throws GitCommitIdExecutionException;

void finalCleanUp() throws GitCommitIdExecutionException;

AheadBehind getAheadBehind() throws GitCommitIdExecutionException;

}
24 changes: 24 additions & 0 deletions src/main/java/pl/project13/maven/git/JGitProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@

import com.google.common.annotations.VisibleForTesting;

import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.BranchTrackingStatus;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Ref;
Expand Down Expand Up @@ -286,6 +289,27 @@ private Repository getGitRepository() throws GitCommitIdExecutionException {

return repository;
}

@Override
public AheadBehind getAheadBehind() throws GitCommitIdExecutionException {
try {
fetch();
Optional<BranchTrackingStatus> branchTrackingStatus = Optional.ofNullable(BranchTrackingStatus.of(git, getBranchName()));
return branchTrackingStatus.map(bts -> AheadBehind.of(bts.getAheadCount(), bts.getBehindCount()))
.orElse(AheadBehind.NO_REMOTE);
} catch (Exception e) {
throw new GitCommitIdExecutionException("Failed to read ahead behind count: " + e.getMessage(), e);
}
}

private void fetch() {
FetchCommand fetchCommand = Git.wrap(git).fetch();
try {
fetchCommand.setThin(true).call();
} catch (Exception e) {
log.error("Failed to perform fetch", e);
}
}

// SETTERS FOR TESTS ----------------------------------------------------

Expand Down
47 changes: 47 additions & 0 deletions src/main/java/pl/project13/maven/git/NativeGitProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import pl.project13.maven.git.log.LoggerBridge;

import javax.annotation.Nonnull;

import com.google.common.annotations.VisibleForTesting;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -515,4 +518,48 @@ public Optional<RuntimeException> call() {
}
}
}

@Override
public AheadBehind getAheadBehind() throws GitCommitIdExecutionException {
try {
Optional<String> remoteBranch = remoteBranch();
if (!remoteBranch.isPresent()) {
return AheadBehind.NO_REMOTE;
}
fetch(remoteBranch.get());
String localBranchName = getBranchName();
String ahead = runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list --right-only --count " + remoteBranch.get() + "..." + localBranchName);
String behind = runQuietGitCommand(canonical, nativeGitTimeoutInMs, "rev-list --left-only --count " + remoteBranch.get() + "..." + localBranchName);
return AheadBehind.of(ahead, behind);
} catch (Exception e) {
throw new GitCommitIdExecutionException("Failed to read ahead behind count: " + e.getMessage(), e);
}
}

private Optional<String> remoteBranch() {
try {
String remoteRef = runQuietGitCommand(canonical, nativeGitTimeoutInMs, "symbolic-ref -q " + evaluateOnCommit);
if(remoteRef == null || remoteRef.isEmpty()) {
log.debug("Could not find ref for: " + evaluateOnCommit);;
return Optional.empty();
}
String remoteBranch = runQuietGitCommand(canonical, nativeGitTimeoutInMs, "for-each-ref --format=%(upstream:short) " + remoteRef);
return Optional.ofNullable(remoteBranch.isEmpty() ? null : remoteBranch);
} catch (Exception e) {
return Optional.empty();
}
}

private void fetch(String remoteBranch) {
try {
runQuietGitCommand(canonical, nativeGitTimeoutInMs, "fetch " + remoteBranch.replaceFirst("/", " "));
} catch (Exception e) {
log.error("Failed to execute fetch", e);
}
}

@VisibleForTesting
public void setEvaluateOnCommit(String evaluateOnCommit) {
this.evaluateOnCommit = evaluateOnCommit;
}
}
137 changes: 137 additions & 0 deletions src/test/java/pl/project13/maven/git/AheadBehindTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package pl.project13.maven.git;

import static org.junit.Assert.assertThat;

import java.io.File;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.StoredConfig;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public abstract class AheadBehindTest<T extends GitProvider> {

@Rule
public TemporaryFolder remoteRepository = new TemporaryFolder();

@Rule
public TemporaryFolder localRepository = new TemporaryFolder();

@Rule
public TemporaryFolder secondLocalRepository = new TemporaryFolder();

protected Git localRepositoryGit;

protected Git secondLocalRepositoryGit;

protected T gitProvider;

@Before
public void setup() throws Exception {

createRemoteRepository();

setupLocalRepository();

createAndPushInitialCommit();

setupSecondLocalRepository();

gitProvider = gitProvider();

extraSetup();
}

protected abstract T gitProvider();

protected void extraSetup() {
// Override in subclass to perform extra stuff in setup
}

@Test
public void shouldNotBeAheadOrBehind() throws Exception {

AheadBehind aheadBehind = gitProvider.getAheadBehind();
assertThat(aheadBehind.ahead(), CoreMatchers.is("0"));
assertThat(aheadBehind.behind(), CoreMatchers.is("0"));
}

@Test
public void shouldBe1Ahead() throws Exception {

createLocalCommit();

AheadBehind aheadBehind = gitProvider.getAheadBehind();
assertThat(aheadBehind.ahead(), CoreMatchers.is("1"));
assertThat(aheadBehind.behind(), CoreMatchers.is("0"));
}

@Test
public void shouldBe1Behind() throws Exception {

createCommitInSecondRepoAndPush();

AheadBehind aheadBehind = gitProvider.getAheadBehind();
assertThat(aheadBehind.ahead(), CoreMatchers.is("0"));
assertThat(aheadBehind.behind(), CoreMatchers.is("1"));
}

@Test
public void shouldBe1AheadAnd1Behind() throws Exception {

createLocalCommit();
createCommitInSecondRepoAndPush();

AheadBehind aheadBehind = gitProvider.getAheadBehind();
assertThat(aheadBehind.ahead(), CoreMatchers.is("1"));
assertThat(aheadBehind.behind(), CoreMatchers.is("1"));
}

protected void createLocalCommit() throws Exception {
File newFile = localRepository.newFile();
localRepositoryGit.add().addFilepattern(newFile.getName()).call();
localRepositoryGit.commit().setMessage("ahead").call();
}

protected void createCommitInSecondRepoAndPush() throws Exception {
secondLocalRepositoryGit.pull().call();

File newFile = secondLocalRepository.newFile();
secondLocalRepositoryGit.add().addFilepattern(newFile.getName()).call();
secondLocalRepositoryGit.commit().setMessage("behind").call();

secondLocalRepositoryGit.push().call();
}

protected void createRemoteRepository() throws Exception {
Git.init().setBare(true).setDirectory(remoteRepository.getRoot()).call();
}

protected void setupLocalRepository() throws Exception {
localRepositoryGit = Git.cloneRepository().setURI(remoteRepository.getRoot().toURI().toString())
.setDirectory(localRepository.getRoot()).setBranch("master").call();

StoredConfig config = localRepositoryGit.getRepository().getConfig();
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, "master", "remote", "origin");
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, "master", "merge", "refs/heads/master");
config.save();
}

protected void setupSecondLocalRepository() throws Exception {
secondLocalRepositoryGit = Git.cloneRepository().setURI(remoteRepository.getRoot().toURI().toString())
.setDirectory(secondLocalRepository.getRoot()).setBranch("master").call();
}

protected void createAndPushInitialCommit() throws Exception {
File newFile = localRepository.newFile();
localRepositoryGit.add().addFilepattern(newFile.getName()).call();
localRepositoryGit.commit().setMessage("initial").call();

localRepositoryGit.push().call();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package pl.project13.maven.git;

import java.nio.file.Paths;

public class JgitProviderAheadBehindTest extends AheadBehindTest<JGitProvider> {

@Override
public void extraSetup() {
gitProvider.setRepository(localRepositoryGit.getRepository());
}

@Override
protected JGitProvider gitProvider() {
return new JGitProvider(Paths.get(localRepository.getRoot().getAbsolutePath(), ".git").toFile(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ public class NativeAndJGitProviderTest extends GitIntegrationTest {
"git.commit.message.short",
"git.commit.time",
"git.total.commit.count",
"git.remote.origin.url"
"git.remote.origin.url",
"git.branch.ahead",
"git.branch.behind"
};

public static final String DEFAULT_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ssZ";
Expand Down Expand Up @@ -87,7 +89,7 @@ public void testCompareSubrepoInChild() throws Exception {
}

@Test
public void testCompareISO8601Time() throws Exception {
public void testCompareIso8601Time() throws Exception {
// Test on all available basic repos to ensure that the output is identical.
for (AvailableGitTestRepo testRepo : AvailableGitTestRepo.values()) {
if (testRepo != AvailableGitTestRepo.GIT_COMMIT_ID) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package pl.project13.maven.git;

public class NativeProviderAheadBehindTest extends AheadBehindTest<NativeGitProvider> {

@Override
protected NativeGitProvider gitProvider() {
return new NativeGitProvider(localRepository.getRoot(), 1000l, null);
}

@Override
protected void extraSetup() {
gitProvider.setEvaluateOnCommit("HEAD");
}
}