Repository: vackosar/gitflow-incremental-builder
Pull request #185 (2020-06-21 22:05:26)

allow enable/disable by branch name regex


Patch:
diff --git a/README.md b/README.md
index 6d53c15..b2009df 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ This extension is **not limited to Git Flow setups!** The [extensive configurati
 - [Configuration](#configuration)
   - [gib.help](#gibhelp)
   - [gib.enabled](#gibenabled)
+  - [gib.disabledIfBranchRegex](#gibdisabledIfBranchRegex)
   - [gib.disableBranchComparison](#gibdisablebranchcomparison)
   - [gib.referenceBranch](#gibreferencebranch)
   - [gib.fetchReferenceBranch](#gibfetchreferencebranch)
@@ -270,6 +271,7 @@ Maven pom properties configuration with default values is below:
 <properties>
     <gib.help>false</gib.help>                                                            <!-- or <gib.h>... -->
     <gib.enabled>true</gib.enabled>                                                       <!-- or <gib.e>... -->
+    <gib.disabledIfBranchRegex>.*</gib.disabledIfBranchRegex>                             <!-- or <gib.dibr>... -->
     <gib.disableBranchComparison>false</gib.disableBranchComparison>                      <!-- or <gib.dbc>... -->
     <gib.referenceBranch>refs/remotes/origin/develop</gib.referenceBranch>                <!-- or <gib.rb>... -->
     <gib.fetchReferenceBranch>false</gib.fetchReferenceBranch>                            <!-- or <gib.frb>... -->
@@ -316,6 +318,10 @@ Since: 3.9.0
 
 Can be used to disable this extension temporarily or permanently (e.g. to avoid clashes with IDE building strategy).
 
+### gib.disabledIfBranchRegex
+
+Can be used to disable this extension only on certain branches (e.g. `master|develop`)
+
 ### gib.disableBranchComparison
 
 Disables the comparison between `baseBranch` and `referenceBranch`. This property should be enabled if _only_ uncommitted and/or untracked files shall be detected to only build projects that have been changed since the last commit in the current branch (see `gib.uncommited` and `gib.untracked`).
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java
index 64c93b5..215710b 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/Configuration.java
@@ -1,12 +1,12 @@
 package com.vackosar.gitflowincrementalbuild.boundary;
 
 import com.vackosar.gitflowincrementalbuild.control.Property;
-
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
 
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toList;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -27,12 +27,13 @@ import java.util.stream.Collector;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toList;
 
 public class Configuration {
 
+    public final Optional<Predicate<String>> disableIfBranchRegex;
+
     public final boolean disableBranchComparison;
     public final String referenceBranch;
     public final boolean fetchReferenceBranch;
@@ -62,6 +63,13 @@ public class Configuration {
         Properties projectProperties = getProjectProperties(session);
         checkProperties(projectProperties);
 
+        if (Property.Constants.NEVER_MATCH_REGEX.equals(Property.disableIfBranchRegex.getValue(projectProperties))) {
+            disableIfBranchRegex = Optional.empty();
+        } else {
+            Pattern regex = compilePattern(Property.disableIfBranchRegex, projectProperties);
+            disableIfBranchRegex = Optional.of(regex.asPredicate());
+        }
+
         // change detection config
 
         disableBranchComparison = Boolean.valueOf(Property.disableBranchComparison.getValue(projectProperties));
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java
index 066d1f9..ce1a296 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipant.java
@@ -1,10 +1,12 @@
 package com.vackosar.gitflowincrementalbuild.boundary;
 
 import com.vackosar.gitflowincrementalbuild.control.Property;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
 import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
 import org.apache.maven.AbstractMavenLifecycleParticipant;
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.MavenSession;
+import org.eclipse.jgit.api.Git;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -12,6 +14,8 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.IOException;
+
 @Singleton
 @Named
 public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant {
@@ -35,6 +39,14 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
 
     @Override
     public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
+        try {
+            applyPlugin(session);
+        } finally {
+            GitFactory.destroy();
+        }
+    }
+
+    private void applyPlugin(MavenSession session) throws MavenExecutionException {
 
         if (Configuration.isHelpRequested(session)) {
             logHelp();
@@ -53,8 +65,13 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
             return;
         }
 
-        logger.info("gitflow-incremental-builder {} starting...", implVersion);
         try {
+            if (isDisabledForBranch(session)) {
+                logger.info("gitflow-incremental-builder is disabled for this branch.");
+                return;
+            }
+
+            logger.info("gitflow-incremental-builder {} starting...", implVersion);
             unchangedProjectsRemover.act();
         } catch (Exception e) {
             boolean isSkipExecException = e instanceof SkipExecutionException;
@@ -68,6 +85,17 @@ public class MavenLifecycleParticipant extends AbstractMavenLifecycleParticipant
         logger.info("gitflow-incremental-builder exiting...");
     }
 
+    private boolean isDisabledForBranch(MavenSession session) throws IOException {
+        Configuration configuration = configProvider.get();
+        if (!configuration.disableIfBranchRegex.isPresent()) {
+            return false;
+        }
+        
+        Git git = GitFactory.getOrCreateThreadLocalGit(session, configuration);
+        String branchName = git.getRepository().getBranch();
+        return configuration.disableIfBranchRegex.get().test(branchName);
+    }
+
     private void logHelp() {
         logger.info("gitflow-incremental-builder {} help:\n{}\nFor more help see: {}/tree/version/{}#configuration\n",
                 implVersion,
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java b/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java
index 77ae561..4ca7d5b 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/control/DifferentFiles.java
@@ -2,9 +2,8 @@ package com.vackosar.gitflowincrementalbuild.control;
 
 import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
 import com.vackosar.gitflowincrementalbuild.control.jgit.AgentProxyAwareJschConfigSessionFactory;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
 import com.vackosar.gitflowincrementalbuild.control.jgit.HttpDelegatingCredentialsProvider;
-import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
-
 import org.apache.maven.execution.MavenSession;
 import org.eclipse.jgit.api.FetchCommand;
 import org.eclipse.jgit.api.Git;
@@ -14,7 +13,6 @@ import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
-import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.SshTransport;
 import org.eclipse.jgit.treewalk.TreeWalk;
@@ -26,15 +24,12 @@ import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -59,9 +54,9 @@ public class DifferentFiles {
         Set<Path> paths = new HashSet<>();
 
         Configuration configuration = configProvider.get();
-        Git git = setupGit(configuration);
         Worker worker = null;
         try {
+            Git git = GitFactory.getOrCreateThreadLocalGit(mavenSession, configuration);
             worker = new Worker(git, configuration);
 
             worker.fetch();
@@ -76,8 +71,6 @@ public class DifferentFiles {
             if (worker != null) {
                 worker.credentialsProvider.resetAll();
             }
-            git.getRepository().close();
-            git.close();
         }
         return paths;
     }
@@ -92,34 +85,6 @@ public class DifferentFiles {
         additionalNativeGitEnvironment.put(key, value);
     }
 
-    private Git setupGit(Configuration configuration) throws IOException {
-        final FileRepositoryBuilder builder = new FileRepositoryBuilder();
-        File pomDir = mavenSession.getCurrentProject().getBasedir().toPath().toFile();
-        builder.findGitDir(pomDir);
-        if (builder.getGitDir() == null) {
-            String gitDirNotFoundMessage = "Git repository root directory not found ascending from current working directory:'" + pomDir + "'.";
-            logger.warn(gitDirNotFoundMessage + " Next step is determined by failOnMissingGitDir property.");
-            if (configuration.failOnMissingGitDir) {
-                throw new IllegalArgumentException(gitDirNotFoundMessage);
-            } else {
-                throw new SkipExecutionException(gitDirNotFoundMessage);
-            }
-        }
-        if (isWorktree(builder)) {
-            throw new SkipExecutionException(UNSUPPORTED_WORKTREE + builder.getGitDir());
-        }
-        return Git.wrap(builder.build());
-    }
-
-    private boolean isWorktree(FileRepositoryBuilder builder) {
-        return Optional.ofNullable(builder.getGitDir().toPath().getParent())
-                .filter(parent -> parent.getFileName().toString().equals("worktrees"))
-                .map(Path::getParent)
-                .filter(Objects::nonNull)
-                .map(parentParent -> parentParent.getFileName().toString().equals(".git"))
-                .orElse(false);
-    }
-
     private class Worker {
 
         private final Git git;
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java b/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java
index 2ef6a1b..7cc0a7a 100644
--- a/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/control/Property.java
@@ -1,5 +1,8 @@
 package com.vackosar.gitflowincrementalbuild.control;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -7,12 +10,10 @@ import java.util.Properties;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 public enum Property {
     help("false", "h", true),
     enabled("true", "e", true),
+    disableIfBranchRegex(Constants.NEVER_MATCH_REGEX, "dibr"),
 
     disableBranchComparison("false", "dbc", true),
     referenceBranch("refs/remotes/origin/develop", "rb"),
@@ -133,8 +134,8 @@ public enum Property {
         return builder.toString();
     }
 
-    private static class Constants {
-        private static final String ALWAYS_MATCH_REGEX = ".*";
-        private static final String NEVER_MATCH_REGEX = "(?!x)x";
+    public static interface Constants {
+        public static final String ALWAYS_MATCH_REGEX = ".*";
+        public static final String NEVER_MATCH_REGEX = "(?!x)x";
     }
 }
diff --git a/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitFactory.java b/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitFactory.java
new file mode 100644
index 0000000..d184504
--- /dev/null
+++ b/src/main/java/com/vackosar/gitflowincrementalbuild/control/jgit/GitFactory.java
@@ -0,0 +1,80 @@
+package com.vackosar.gitflowincrementalbuild.control.jgit;
+
+import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
+import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
+import org.apache.maven.execution.MavenSession;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+
+public class GitFactory {
+
+    private static final Logger logger = LoggerFactory.getLogger(GitFactory.class);
+
+    private static final String UNSUPPORTED_WORKTREE = "JGit unsupported separate worktree checkout detected from current git dir path: ";
+
+    private static final ThreadLocal<Git> threadLocal = new ThreadLocal<>();
+    
+    public static Git getOrCreateThreadLocalGit(MavenSession mavenSession, Configuration configuration) throws IOException {
+        if (threadLocal.get() != null) {
+            return threadLocal.get();
+        }
+        Git git = setupGit(mavenSession, configuration);
+        threadLocal.set(git);
+        return git;
+    }
+    
+    public static void bind(Git git) {
+        destroy();
+        threadLocal.set(git);
+    }
+
+    public static void destroy() {
+        Git git = threadLocal.get();
+        threadLocal.remove();
+        if (git != null) {
+            git.close();
+            git.getRepository().close();
+        }
+    }
+
+    private static Git setupGit(MavenSession mavenSession, Configuration configuration) throws IOException {
+        final FileRepositoryBuilder builder = new FileRepositoryBuilder();
+        File pomDir = mavenSession.getCurrentProject().getBasedir().toPath().toFile();
+        builder.findGitDir(pomDir);
+        if (builder.getGitDir() == null) {
+            String gitDirNotFoundMessage = "Git repository root directory not found ascending from current working directory:'"
+                    + pomDir + "'.";
+            logger.warn(gitDirNotFoundMessage + " Next step is determined by failOnMissingGitDir property.");
+            if (configuration.failOnMissingGitDir) {
+                throw new IllegalArgumentException(gitDirNotFoundMessage);
+            } else {
+                throw new SkipExecutionException(gitDirNotFoundMessage);
+            }
+        }
+        if (isWorktree(builder)) {
+            throw new SkipExecutionException(UNSUPPORTED_WORKTREE + builder.getGitDir());
+        }
+        return Git.wrap(builder.build());
+    }
+
+    private static boolean isWorktree(FileRepositoryBuilder builder) {
+        return Optional.ofNullable(builder.getGitDir().toPath().getParent())
+                .filter(parent -> parent.getFileName().toString().equals("worktrees"))
+                .map(Path::getParent)
+                .filter(Objects::nonNull)
+                .map(parentParent -> parentParent.getFileName().toString().equals(".git"))
+                .orElse(false);
+    }
+
+    private GitFactory() {
+        throw new AssertionError();
+    }
+}
\ No newline at end of file


Test patch:
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java
index 043f4c8..95cba17 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/BaseRepoTest.java
@@ -1,16 +1,17 @@
 package com.vackosar.gitflowincrementalbuild;
 
 import com.vackosar.gitflowincrementalbuild.control.Property;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
 import com.vackosar.gitflowincrementalbuild.mocks.LocalRepoMock;
 import com.vackosar.gitflowincrementalbuild.mocks.MavenSessionMock;
 import com.vackosar.gitflowincrementalbuild.mocks.server.TestServerType;
-
 import org.apache.commons.lang3.SystemUtils;
 import org.apache.maven.execution.MavenSession;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.TestInfo;
 import org.junit.jupiter.api.io.TempDir;
+
 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -75,6 +76,7 @@ public abstract class BaseRepoTest {
 
     @AfterEach
     protected void after() throws Exception {
+        GitFactory.destroy();
         if (localRepoMock != null) {
             localRepoMock.close();
         }
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java
index 602a280..0fc9de2 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/boundary/MavenLifecycleParticipantTest.java
@@ -2,13 +2,16 @@ package com.vackosar.gitflowincrementalbuild.boundary;
 
 import com.vackosar.gitflowincrementalbuild.LoggerSpyUtil;
 import com.vackosar.gitflowincrementalbuild.control.Property;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
 import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
-
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.project.MavenProject;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -19,12 +22,14 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.powermock.reflect.Whitebox;
 import org.slf4j.Logger;
 
+import java.io.IOException;
 import java.util.Properties;
 
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -62,6 +67,11 @@ public class MavenLifecycleParticipantTest {
 
         Whitebox.setInternalState(underTest, new Configuration.Provider(mavenSessionMock));
     }
+    
+    @AfterEach
+    void after() {
+        GitFactory.destroy();
+    }
 
     @Test
     public void defaultlyEnabled() throws Exception {
@@ -154,6 +164,38 @@ public class MavenLifecycleParticipantTest {
         verifyNoInteractions(unchangedProjectsRemoverMock);
     }
 
+    @Test
+    public void enabledForBranch() throws Throwable {
+        projectProperties.setProperty(Property.disableIfBranchRegex.fullName(), "master|develop|(release/.+)|(hotfix/.+)");
+
+        mockCurrentBranch("feature/cool-stuff");
+
+        underTest.afterProjectsRead(mavenSessionMock);
+
+        verify(unchangedProjectsRemoverMock).act();
+    }
+
+    @Test
+    public void disabledForBranch() throws Throwable {
+        projectProperties.setProperty(Property.disableIfBranchRegex.fullName(), "master|develop|(release/.+)|(hotfix/.+)");
+
+        mockCurrentBranch("develop");
+
+        underTest.afterProjectsRead(mavenSessionMock);
+
+        verify(loggerSpy).info("gitflow-incremental-builder is disabled for this branch.");
+        verifyNoInteractions(unchangedProjectsRemoverMock);
+    }
+
+    private void mockCurrentBranch(String branchName) throws IOException {
+        Git git = mock(Git.class);
+        Repository repository = mock(Repository.class);
+        doReturn(repository).when(git).getRepository();
+        doReturn(branchName).when(repository).getBranch();
+        
+        GitFactory.bind(git);
+    }
+
     private void verifyHelpLogged(boolean logged) {
         verify(loggerSpy, logged ? Mockito.times(1) : Mockito.never())
                 .info(contains("help:"), eq(TEST_IMPL_VERSION), anyString(), anyString(), anyString());
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java
index 4a37f74..2cab3fd 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/control/BaseDifferentFilesTest.java
@@ -1,13 +1,10 @@
 package com.vackosar.gitflowincrementalbuild.control;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Set;
-
+import com.vackosar.gitflowincrementalbuild.BaseRepoTest;
+import com.vackosar.gitflowincrementalbuild.LoggerSpyUtil;
+import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.mocks.server.TestServerType;
 import org.apache.maven.execution.MavenSession;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ResetCommand;
@@ -18,10 +15,13 @@ import org.junit.jupiter.api.TestInfo;
 import org.powermock.reflect.Whitebox;
 import org.slf4j.Logger;
 
-import com.vackosar.gitflowincrementalbuild.BaseRepoTest;
-import com.vackosar.gitflowincrementalbuild.LoggerSpyUtil;
-import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
-import com.vackosar.gitflowincrementalbuild.mocks.server.TestServerType;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 public abstract class BaseDifferentFilesTest extends BaseRepoTest {
 
@@ -50,6 +50,7 @@ public abstract class BaseDifferentFilesTest extends BaseRepoTest {
     @Override
     @AfterEach
     protected void after() throws Exception {
+        GitFactory.destroy();
         FS.DETECTED.setUserHome(jGitUserHomeBackup);
         super.after();
     }
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/control/PropertyTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/control/PropertyTest.java
index ae6577e..e10f675 100644
--- a/src/test/java/com/vackosar/gitflowincrementalbuild/control/PropertyTest.java
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/control/PropertyTest.java
@@ -3,18 +3,17 @@ package com.vackosar.gitflowincrementalbuild.control;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.fail;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.stream.Collectors;
-
+import com.vackosar.gitflowincrementalbuild.SystemPropertiesResetExtension;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.vackosar.gitflowincrementalbuild.SystemPropertiesResetExtension;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
 
 @ExtendWith(SystemPropertiesResetExtension.class)
 public class PropertyTest {
diff --git a/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitFactoryTest.java b/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitFactoryTest.java
new file mode 100644
index 0000000..9f453e5
--- /dev/null
+++ b/src/test/java/com/vackosar/gitflowincrementalbuild/jgit/GitFactoryTest.java
@@ -0,0 +1,78 @@
+package com.vackosar.gitflowincrementalbuild.jgit;
+
+import com.google.common.io.Files;
+import com.vackosar.gitflowincrementalbuild.boundary.Configuration;
+import com.vackosar.gitflowincrementalbuild.control.jgit.GitFactory;
+import com.vackosar.gitflowincrementalbuild.entity.SkipExecutionException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+public class GitFactoryTest {
+
+    private MavenSession mavenSessionMock = mock(MavenSession.class);
+    private Configuration configuration = mock(Configuration.class);
+
+    private void initSimple() throws IOException {
+        MavenProject mavenProject = new MavenProject();
+        File pomXmlInCwd = new File("pom.xml").getCanonicalFile();
+        File pomXmlInParent = new File("..", "pom.xml").getCanonicalFile();
+        mavenProject.setFile(pomXmlInParent);
+        if (pomXmlInCwd.exists()) {
+            mavenProject.setFile(pomXmlInCwd);
+        }
+        doReturn(mavenProject).when(mavenSessionMock).getCurrentProject();
+    }
+
+    @BeforeEach
+    @AfterEach
+    public void tearDown() {
+        GitFactory.destroy();
+    }
+
+    @Test
+    public void test_simple() throws IOException {
+        initSimple();
+        assertNotNull(GitFactory.getOrCreateThreadLocalGit(mavenSessionMock, configuration));
+        
+        verify(mavenSessionMock).getCurrentProject();
+    }
+    
+    @Test
+    public void test_bind() throws IOException {
+        Git git = mock(Git.class);
+        Repository repository = mock(Repository.class);
+        doReturn(repository).when(git).getRepository();
+        
+        GitFactory.bind(git);
+        assertNotNull(GitFactory.getOrCreateThreadLocalGit(mavenSessionMock, configuration));
+        
+        verifyNoInteractions(mavenSessionMock, configuration);
+    }
+
+    @Test
+    public void test_no_git_dir() {
+
+        MavenProject mavenProject = new MavenProject();
+        File tempDir = Files.createTempDir();
+        File pom = new File(tempDir, "pom.xml");
+        mavenProject.setFile(pom);
+        doReturn(mavenProject).when(mavenSessionMock).getCurrentProject();
+
+        assertThrows(SkipExecutionException.class, () -> GitFactory.getOrCreateThreadLocalGit(mavenSessionMock, configuration));
+    }
+}
\ No newline at end of file