From 24e2885524769bbf784b70d02e8229f94ceb3589 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 14 Oct 2018 19:11:56 +0200 Subject: [PATCH 1/3] #998 git: set repository head to default branch --- .../sonia/scm/repository/GitHeadHandler.java | 53 ++++++++ .../sonia/scm/repository/GitHeadModifier.java | 7 ++ .../sonia/scm/repository/GitHeadResolver.java | 7 ++ .../GitRepositoryModifyListener.java | 51 +++++--- .../scm/repository/GitHeadHandlerTest.java | 60 +++++++++ .../GitRepositoryModifyListenerTest.java | 116 ++++++++++++------ 6 files changed, 239 insertions(+), 55 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java new file mode 100644 index 0000000000..23e6156297 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java @@ -0,0 +1,53 @@ +package sonia.scm.repository; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.io.Files; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.File; +import java.io.IOException; + +@Singleton +public class GitHeadHandler implements GitHeadResolver, GitHeadModifier { + + private final GitRepositoryHandler repositoryHandler; + + @Inject + public GitHeadHandler(GitRepositoryHandler repositoryHandler) { + this.repositoryHandler = repositoryHandler; + } + + @Override + public String resolve(Repository repository) { + File headFile = findHeadFile(repository); + try { + String line = Files.readFirstLine(headFile, Charsets.UTF_8); + // TODO handle invalid head file + int index = line.indexOf(GitUtil.REF_HEAD_PREFIX); + return line.substring(index + GitUtil.REF_HEAD_PREFIX.length()); + } catch (IOException e) { + // TODO + throw Throwables.propagate(e); + } + } + + @Override + public void modify(Repository repository, String head) { + File headFile = findHeadFile(repository); + try { + String line = "ref: " + GitUtil.REF_HEAD_PREFIX + head + "\n"; + Files.write(line, headFile, Charsets.UTF_8); + } catch (IOException e) { + // TODO + throw Throwables.propagate(e); + } + } + + private File findHeadFile(Repository repository) { + // TODO handle non bare repositories + File directory = repositoryHandler.getDirectory(repository); + return new File(directory, "HEAD"); + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java new file mode 100644 index 0000000000..f6597e3958 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java @@ -0,0 +1,7 @@ +package sonia.scm.repository; + +public interface GitHeadModifier { + + void modify(Repository repository, String head); + +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java new file mode 100644 index 0000000000..c9f3dce609 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java @@ -0,0 +1,7 @@ +package sonia.scm.repository; + +public interface GitHeadResolver { + + String resolve(Repository repository); + +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java index 4309257350..64f93d45de 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java @@ -32,6 +32,7 @@ package sonia.scm.repository; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; +import com.google.common.base.Strings; import com.google.common.eventbus.Subscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,58 +41,74 @@ import sonia.scm.HandlerEvent; import sonia.scm.event.ScmEventBus; import sonia.scm.plugin.ext.Extension; +import javax.inject.Inject; + /** * Repository listener which handles git related repository events. - * + * * @author Sebastian Sdorra * @since 1.50 */ @Extension @EagerSingleton public class GitRepositoryModifyListener { - + /** * the logger for GitRepositoryModifyListener */ private static final Logger logger = LoggerFactory.getLogger(GitRepositoryModifyListener.class); - + + private final GitHeadResolver headResolver; + private final GitHeadModifier headModifier; + + @Inject + public GitRepositoryModifyListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { + this.headResolver = headResolver; + this.headModifier = headModifier; + } + /** * Receives {@link RepositoryModificationEvent} and fires a {@link ClearRepositoryCacheEvent} if * the default branch of a git repository was modified. - * + * * @param event repository modification event */ @Subscribe public void handleEvent(RepositoryModificationEvent event){ Repository repository = event.getItem(); - - if ( isModifyEvent(event) && - isGitRepository(event.getItem()) && - hasDefaultBranchChanged(event.getItemBeforeModification(), repository)) + + if ( isModifyEvent(event) && isGitRepository(event.getItem()) ) { - logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId()); - sendClearRepositoryCacheEvent(repository); + if (hasDefaultBranchChanged(event.getItemBeforeModification(), repository)) { + logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId()); + sendClearRepositoryCacheEvent(repository); + } + + String defaultBranch = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH); + if (defaultBranch != null && ! defaultBranch.equals(headResolver.resolve(repository))) { + headModifier.modify(repository, defaultBranch); + } } } - + @VisibleForTesting protected void sendClearRepositoryCacheEvent(Repository repository) { - ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); + ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository)); } - + private boolean isModifyEvent(RepositoryEvent event) { return event.getEventType() == HandlerEvent.MODIFY; } - + private boolean isGitRepository(Repository repository) { return GitRepositoryHandler.TYPE_NAME.equals(repository.getType()); } - + private boolean hasDefaultBranchChanged(Repository old, Repository current) { return !Objects.equal( - old.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH), + old.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH), current.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH) ); } - + } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java new file mode 100644 index 0000000000..e3ae85baa2 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java @@ -0,0 +1,60 @@ +package sonia.scm.repository; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class GitHeadHandlerTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock + private GitRepositoryHandler repositoryHandler; + + @InjectMocks + private GitHeadHandler headHandler; + + @Test + public void testResolve() throws IOException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + create(repository, "master"); + + String head = headHandler.resolve(repository); + assertEquals("master", head); + } + + @Test + public void testModify() throws IOException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + File file = create(repository, "master"); + + headHandler.modify(repository, "develop"); + + assertEquals("ref: refs/heads/develop", Files.readFirstLine(file, Charsets.UTF_8)); + } + + private File create(Repository repository, String head) throws IOException { + File directory = temporaryFolder.newFolder(); + File headFile = new File(directory, "HEAD"); + Files.write(String.format("ref: refs/heads/%s\n", head), headFile, Charsets.UTF_8); + + when(repositoryHandler.getDirectory(repository)).thenReturn(directory); + + return headFile; + } + +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java index 9f6768aeac..008000daef 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java @@ -1,10 +1,10 @@ /** * Copyright (c) 2014, Sebastian Sdorra * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, @@ -13,7 +13,7 @@ * 3. Neither the name of SCM-Manager; nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -24,34 +24,42 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * http://bitbucket.org/sdorra/scm-manager - * + * */ package sonia.scm.repository; import org.junit.Test; import static org.junit.Assert.*; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.HandlerEvent; /** * Unit tests for {@link GitRepositoryModifyListener}. - * + * * @author Sebastian Sdorra */ +@RunWith(MockitoJUnitRunner.class) public class GitRepositoryModifyListenerTest { + @Mock + private GitHeadResolver headResolver; + + @Mock + private GitHeadModifier headModifier; + + @InjectMocks private GitRepositoryModifyTestListener repositoryModifyListener; - - /** - * Set up test object. - */ - @Before - public void setUpObjectUnderTest(){ - repositoryModifyListener = new GitRepositoryModifyTestListener(); - } /** * Tests happy path. @@ -62,14 +70,14 @@ public class GitRepositoryModifyListenerTest { old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNotNull(repositoryModifyListener.repository); assertSame(current, repositoryModifyListener.repository); } - + /** * Tests with new default branch. */ @@ -78,14 +86,14 @@ public class GitRepositoryModifyListenerTest { Repository old = RepositoryTestData.createHeartOfGold("git"); Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNotNull(repositoryModifyListener.repository); assertSame(current, repositoryModifyListener.repository); } - + /** * Tests with non git repositories. */ @@ -95,13 +103,13 @@ public class GitRepositoryModifyListenerTest { old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); Repository current = RepositoryTestData.createHeartOfGold("hg"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + /** * Tests without default branch. */ @@ -109,13 +117,13 @@ public class GitRepositoryModifyListenerTest { public void testWithoutDefaultBranch(){ Repository old = RepositoryTestData.createHeartOfGold("git"); Repository current = RepositoryTestData.createHeartOfGold("git"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + /** * Tests with non modify event. */ @@ -125,13 +133,13 @@ public class GitRepositoryModifyListenerTest { old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master"); Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.CREATE); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + /** * Tests with non git repositories. */ @@ -144,20 +152,52 @@ public class GitRepositoryModifyListenerTest { RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - + assertNull(repositoryModifyListener.repository); } - + + @Test + public void testModifyRepositoryHead() { + Repository old = RepositoryTestData.createHeartOfGold("git"); + Repository current = RepositoryTestData.createHeartOfGold("git"); + current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); + + when(headResolver.resolve(current)).thenReturn("master"); + + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); + repositoryModifyListener.handleEvent(event); + + verify(headModifier).modify(current, "develop"); + } + + @Test + public void testWithEqualHeads() { + Repository old = RepositoryTestData.createHeartOfGold("git"); + Repository current = RepositoryTestData.createHeartOfGold("git"); + current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); + + when(headResolver.resolve(current)).thenReturn("develop"); + + RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); + repositoryModifyListener.handleEvent(event); + + verify(headModifier, never()).modify(current, "develop"); + } + private static class GitRepositoryModifyTestListener extends GitRepositoryModifyListener { - + private Repository repository; - + + public GitRepositoryModifyTestListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { + super(headResolver, headModifier); + } + @Override protected void sendClearRepositoryCacheEvent(Repository repository) { this.repository = repository; - } - - } - + } -} \ No newline at end of file + } + + +} From 6fb99b70cd419d7b4836e5e1437b90c0b5fbe141 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Mon, 15 Oct 2018 21:32:03 +0200 Subject: [PATCH 2/3] #998 simplify api and use jgit to link new head --- .../sonia/scm/repository/GitHeadHandler.java | 53 ---------- .../sonia/scm/repository/GitHeadModifier.java | 98 ++++++++++++++++- .../sonia/scm/repository/GitHeadResolver.java | 7 -- .../GitRepositoryModifyListener.java | 9 +- .../scm/repository/GitHeadHandlerTest.java | 60 ----------- .../scm/repository/GitHeadModifierTest.java | 100 ++++++++++++++++++ .../GitRepositoryModifyListenerTest.java | 24 +---- 7 files changed, 202 insertions(+), 149 deletions(-) delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java delete mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java deleted file mode 100644 index 23e6156297..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package sonia.scm.repository; - -import com.google.common.base.Charsets; -import com.google.common.base.Throwables; -import com.google.common.io.Files; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.io.File; -import java.io.IOException; - -@Singleton -public class GitHeadHandler implements GitHeadResolver, GitHeadModifier { - - private final GitRepositoryHandler repositoryHandler; - - @Inject - public GitHeadHandler(GitRepositoryHandler repositoryHandler) { - this.repositoryHandler = repositoryHandler; - } - - @Override - public String resolve(Repository repository) { - File headFile = findHeadFile(repository); - try { - String line = Files.readFirstLine(headFile, Charsets.UTF_8); - // TODO handle invalid head file - int index = line.indexOf(GitUtil.REF_HEAD_PREFIX); - return line.substring(index + GitUtil.REF_HEAD_PREFIX.length()); - } catch (IOException e) { - // TODO - throw Throwables.propagate(e); - } - } - - @Override - public void modify(Repository repository, String head) { - File headFile = findHeadFile(repository); - try { - String line = "ref: " + GitUtil.REF_HEAD_PREFIX + head + "\n"; - Files.write(line, headFile, Charsets.UTF_8); - } catch (IOException e) { - // TODO - throw Throwables.propagate(e); - } - } - - private File findHeadFile(Repository repository) { - // TODO handle non bare repositories - File directory = repositoryHandler.getDirectory(repository); - return new File(directory, "HEAD"); - } -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java index f6597e3958..d6613ad6da 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadModifier.java @@ -1,7 +1,101 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ package sonia.scm.repository; -public interface GitHeadModifier { +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - void modify(Repository repository, String head); +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.Objects; +/** + * The GitHeadModifier is able to modify the head of a git repository. + * + * @author Sebastian Sdorra + * @since 1.61 + */ +public class GitHeadModifier { + + private static final Logger LOG = LoggerFactory.getLogger(GitHeadModifier.class); + + private final GitRepositoryHandler repositoryHandler; + + @Inject + public GitHeadModifier(GitRepositoryHandler repositoryHandler) { + this.repositoryHandler = repositoryHandler; + } + + /** + * Ensures that the repositories head points to the given branch. The method will return {@code false} if the + * repositories head points already to the given branch. + * + * @param repository repository to modify + * @param newHead branch which should be the new head of the repository + * + * @return {@code true} if the head has changed + */ + public boolean ensure(Repository repository, String newHead) { + try (org.eclipse.jgit.lib.Repository gitRepository = open(repository)) { + String currentHead = resolve(gitRepository); + if (!Objects.equals(currentHead, newHead)) { + return modify(gitRepository, newHead); + } + } catch (IOException ex) { + LOG.warn("failed to change head of repository", ex); + } + return false; + } + + private String resolve(org.eclipse.jgit.lib.Repository gitRepository) throws IOException { + Ref ref = gitRepository.getRefDatabase().getRef(Constants.HEAD); + if ( ref.isSymbolic() ) { + ref = ref.getTarget(); + } + return GitUtil.getBranch(ref); + } + + private boolean modify(org.eclipse.jgit.lib.Repository gitRepository, String newHead) throws IOException { + RefUpdate refUpdate = gitRepository.getRefDatabase().newUpdate(Constants.HEAD, true); + refUpdate.setForceUpdate(true); + RefUpdate.Result result = refUpdate.link(Constants.R_HEADS + newHead); + return result == RefUpdate.Result.FORCED; + } + + private org.eclipse.jgit.lib.Repository open(Repository repository) throws IOException { + File directory = repositoryHandler.getDirectory(repository); + return GitUtil.open(directory); + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java deleted file mode 100644 index c9f3dce609..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitHeadResolver.java +++ /dev/null @@ -1,7 +0,0 @@ -package sonia.scm.repository; - -public interface GitHeadResolver { - - String resolve(Repository repository); - -} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java index 64f93d45de..c0ab21af9d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitRepositoryModifyListener.java @@ -32,7 +32,6 @@ package sonia.scm.repository; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; -import com.google.common.base.Strings; import com.google.common.eventbus.Subscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,12 +57,10 @@ public class GitRepositoryModifyListener { */ private static final Logger logger = LoggerFactory.getLogger(GitRepositoryModifyListener.class); - private final GitHeadResolver headResolver; private final GitHeadModifier headModifier; @Inject - public GitRepositoryModifyListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { - this.headResolver = headResolver; + public GitRepositoryModifyListener(GitHeadModifier headModifier) { this.headModifier = headModifier; } @@ -85,8 +82,8 @@ public class GitRepositoryModifyListener { } String defaultBranch = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH); - if (defaultBranch != null && ! defaultBranch.equals(headResolver.resolve(repository))) { - headModifier.modify(repository, defaultBranch); + if (defaultBranch != null) { + headModifier.ensure(repository, defaultBranch); } } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java deleted file mode 100644 index e3ae85baa2..0000000000 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadHandlerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package sonia.scm.repository; - -import com.google.common.base.Charsets; -import com.google.common.io.Files; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.io.File; -import java.io.IOException; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class GitHeadHandlerTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Mock - private GitRepositoryHandler repositoryHandler; - - @InjectMocks - private GitHeadHandler headHandler; - - @Test - public void testResolve() throws IOException { - Repository repository = RepositoryTestData.createHeartOfGold("git"); - create(repository, "master"); - - String head = headHandler.resolve(repository); - assertEquals("master", head); - } - - @Test - public void testModify() throws IOException { - Repository repository = RepositoryTestData.createHeartOfGold("git"); - File file = create(repository, "master"); - - headHandler.modify(repository, "develop"); - - assertEquals("ref: refs/heads/develop", Files.readFirstLine(file, Charsets.UTF_8)); - } - - private File create(Repository repository, String head) throws IOException { - File directory = temporaryFolder.newFolder(); - File headFile = new File(directory, "HEAD"); - Files.write(String.format("ref: refs/heads/%s\n", head), headFile, Charsets.UTF_8); - - when(repositoryHandler.getDirectory(repository)).thenReturn(directory); - - return headFile; - } - -} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java new file mode 100644 index 0000000000..7a205d2584 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitHeadModifierTest.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ +package sonia.scm.repository; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class GitHeadModifierTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock + private GitRepositoryHandler repositoryHandler; + + @InjectMocks + private GitHeadModifier modifier; + + @Test + public void testEnsure() throws IOException, GitAPIException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + File headFile = create(repository, "master"); + + boolean result = modifier.ensure(repository, "develop"); + + assertEquals("ref: refs/heads/develop", Files.readFirstLine(headFile, Charsets.UTF_8)); + assertTrue(result); + } + + @Test + public void testEnsureWithSameBranch() throws IOException, GitAPIException { + Repository repository = RepositoryTestData.createHeartOfGold("git"); + create(repository, "develop"); + + boolean result = modifier.ensure(repository, "develop"); + + assertFalse(result); + } + + private File create(Repository repository, String head) throws IOException, GitAPIException { + File directory = temporaryFolder.newFolder(); + + Git.init() + .setBare(true) + .setDirectory(directory) + .call(); + + File headFile = new File(directory, "HEAD"); + Files.write(String.format("ref: refs/heads/%s\n", head), headFile, Charsets.UTF_8); + + when(repositoryHandler.getDirectory(repository)).thenReturn(directory); + + return headFile; + } + +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java index 008000daef..5f0f0aca29 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/GitRepositoryModifyListenerTest.java @@ -52,9 +52,6 @@ import sonia.scm.HandlerEvent; @RunWith(MockitoJUnitRunner.class) public class GitRepositoryModifyListenerTest { - @Mock - private GitHeadResolver headResolver; - @Mock private GitHeadModifier headModifier; @@ -162,34 +159,19 @@ public class GitRepositoryModifyListenerTest { Repository current = RepositoryTestData.createHeartOfGold("git"); current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - when(headResolver.resolve(current)).thenReturn("master"); - RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); repositoryModifyListener.handleEvent(event); - verify(headModifier).modify(current, "develop"); + verify(headModifier).ensure(current, "develop"); } - @Test - public void testWithEqualHeads() { - Repository old = RepositoryTestData.createHeartOfGold("git"); - Repository current = RepositoryTestData.createHeartOfGold("git"); - current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop"); - - when(headResolver.resolve(current)).thenReturn("develop"); - - RepositoryModificationEvent event = new RepositoryModificationEvent(current, old, HandlerEvent.MODIFY); - repositoryModifyListener.handleEvent(event); - - verify(headModifier, never()).modify(current, "develop"); - } private static class GitRepositoryModifyTestListener extends GitRepositoryModifyListener { private Repository repository; - public GitRepositoryModifyTestListener(GitHeadResolver headResolver, GitHeadModifier headModifier) { - super(headResolver, headModifier); + public GitRepositoryModifyTestListener(GitHeadModifier headModifier) { + super(headModifier); } @Override From c188e2cd96419471e0d7d37bb6cc25be369187e2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 19 Oct 2018 18:55:14 +0200 Subject: [PATCH 3/3] close branch issue-998