From 42952518f5ebef195a905b43a24e1ccb6ac5b57f Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sun, 19 May 2013 12:18:45 +0200 Subject: [PATCH] fix missing git hooks on push --- .../jgit/transport/ScmTransportProtocol.java | 257 ++++++++++++++++++ .../scm/repository/spi/GitPushCommand.java | 10 +- .../sonia/scm/web/GitContextListener.java | 111 ++++++++ .../java/sonia/scm/web/GitServletModule.java | 3 + .../repository/spi/GitPushCommandTest.java | 45 +++ 5 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/org/eclipse/jgit/transport/ScmTransportProtocol.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitContextListener.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/org/eclipse/jgit/transport/ScmTransportProtocol.java b/scm-plugins/scm-git-plugin/src/main/java/org/eclipse/jgit/transport/ScmTransportProtocol.java new file mode 100644 index 0000000000..3f33de9d9c --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/org/eclipse/jgit/transport/ScmTransportProtocol.java @@ -0,0 +1,257 @@ +/** + * Copyright (c) 2010, 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 org.eclipse.jgit.transport; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.Provider; + +import org.eclipse.jgit.errors.NoRemoteRepositoryException; +import org.eclipse.jgit.errors.NotSupportedException; +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.RepositoryCache; + +import sonia.scm.repository.GitRepositoryHandler; +import sonia.scm.repository.RepositoryManager; +import sonia.scm.web.GitReceiveHook; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +import java.util.Set; + +/** + * + * @author Sebastian Sdorra + */ +public class ScmTransportProtocol extends TransportProtocol +{ + + /** Field description */ + private static final String NAME = "scm"; + + /** Field description */ + private static final Set SCHEMES = ImmutableSet.of("scm"); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + */ + public ScmTransportProtocol() {} + + /** + * Constructs ... + * + * + * @param repositoryManager + * @param handler + * + * @param repositoryManagerProvider + * @param repositoryHandlerProvider + */ + @Inject + public ScmTransportProtocol( + Provider repositoryManagerProvider, + Provider repositoryHandlerProvider) + { + this.repositoryManagerProvider = repositoryManagerProvider; + this.repositoryHandlerProvider = repositoryHandlerProvider; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param uri + * @param local + * @param remoteName + * + * @return + */ + @Override + public boolean canHandle(URIish uri, Repository local, String remoteName) + { + if ((uri.getPath() == null) || (uri.getPort() > 0) + || (uri.getUser() != null) || (uri.getPass() != null) + || (uri.getHost() != null) + || ((uri.getScheme() != null) &&!getSchemes().contains(uri.getScheme()))) + { + return false; + } + + return true; + } + + /** + * Method description + * + * + * @param uri + * @param local + * @param remoteName + * + * @return + * + * @throws NotSupportedException + * @throws TransportException + */ + @Override + public Transport open(URIish uri, Repository local, String remoteName) + throws NotSupportedException, TransportException + { + File localDirectory = local.getDirectory(); + File path = local.getFS().resolve(localDirectory, uri.getPath()); + File gitDir = RepositoryCache.FileKey.resolve(path, local.getFS()); + + if (gitDir == null) + { + throw new NoRemoteRepositoryException(uri, JGitText.get().notFound); + } + + //J- + return new TransportLocalWithHooks( + repositoryManagerProvider.get(), + repositoryHandlerProvider.get(), + local, uri, gitDir + ); + //J+ + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @return + */ + @Override + public String getName() + { + return NAME; + } + + /** + * Method description + * + * + * @return + */ + @Override + public Set getSchemes() + { + return SCHEMES; + } + + //~--- inner classes -------------------------------------------------------- + + /** + * Class description + * + * + * @version Enter version here..., 13/05/19 + * @author Enter your name here... + */ + private static class TransportLocalWithHooks extends TransportLocal + { + + /** + * Constructs ... + * + * + * @param repositoryManager + * @param handler + * @param local + * @param uri + * @param gitDir + */ + public TransportLocalWithHooks(RepositoryManager repositoryManager, + GitRepositoryHandler handler, Repository local, URIish uri, File gitDir) + { + super(local, uri, gitDir); + this.repositoryManager = repositoryManager; + this.handler = handler; + } + + //~--- methods ------------------------------------------------------------ + + /** + * Method description + * + * + * @param dst + * + * @return + */ + @Override + ReceivePack createReceivePack(Repository dst) + { + ReceivePack pack = new ReceivePack(dst); + + if ((repositoryManager != null) && (handler != null)) + { + GitReceiveHook hook = new GitReceiveHook(repositoryManager, handler); + + pack.setPreReceiveHook(hook); + pack.setPostReceiveHook(hook); + } + + return pack; + } + + //~--- fields ------------------------------------------------------------- + + /** Field description */ + private GitRepositoryHandler handler; + + /** Field description */ + private RepositoryManager repositoryManager; + } + + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private Provider repositoryHandlerProvider; + + /** Field description */ + private Provider repositoryManagerProvider; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java index 387ba50a76..5d4c401fec 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPushCommand.java @@ -52,6 +52,11 @@ import java.io.IOException; public class GitPushCommand extends AbstractGitCommand implements PushCommand { + /** Field description */ + private static final String SCHEME = "scm://"; + + //~--- constructors --------------------------------------------------------- + /** * Constructs ... * @@ -85,14 +90,11 @@ public class GitPushCommand extends AbstractGitCommand implements PushCommand throws IOException, RepositoryException { PushResponse response = null; - - // TODO call hooks, but how? - File remoteRepository = handler.getDirectory(request.getRemoteRepository()); org.eclipse.jgit.api.PushCommand push = Git.wrap(open()).push(); push.setPushAll().setPushTags(); - push.setRemote(remoteRepository.getAbsolutePath()); + push.setRemote(SCHEME.concat(remoteRepository.getAbsolutePath())); try { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitContextListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitContextListener.java new file mode 100644 index 0000000000..af8527fedf --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitContextListener.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2010, 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.web; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.inject.Inject; + +import org.eclipse.jgit.transport.ScmTransportProtocol; +import org.eclipse.jgit.transport.Transport; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.plugin.ext.Extension; + +//~--- JDK imports ------------------------------------------------------------ + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * + * @author Sebastian Sdorra + */ +@Extension +public class GitContextListener implements ServletContextListener +{ + + /** + * the logger for GitContextListener + */ + private static final Logger logger = + LoggerFactory.getLogger(GitContextListener.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param transportProtocol + */ + @Inject + public GitContextListener(ScmTransportProtocol transportProtocol) + { + this.transportProtocol = transportProtocol; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param sce + */ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + + // do nothing + } + + /** + * Method description + * + * + * @param sce + */ + @Override + public void contextInitialized(ServletContextEvent sce) + { + logger.debug("register scm transport protocol"); + Transport.register(transportProtocol); + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private ScmTransportProtocol transportProtocol; +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java index f059f9d8fd..fd7300817b 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitServletModule.java @@ -37,6 +37,8 @@ package sonia.scm.web; import com.google.inject.servlet.ServletModule; +import org.eclipse.jgit.transport.ScmTransportProtocol; + import sonia.scm.plugin.ext.Extension; import sonia.scm.web.filter.BasicAuthenticationFilter; @@ -63,6 +65,7 @@ public class GitServletModule extends ServletModule bind(GitRepositoryViewer.class); bind(GitRepositoryResolver.class); bind(GitReceivePackFactory.class); + bind(ScmTransportProtocol.class); // serlvelts and filters filter(PATTERN_GIT).through(BasicAuthenticationFilter.class); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java index cee2894f97..a8eb82c6b6 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java @@ -33,12 +33,19 @@ package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- +import com.google.inject.Provider; + import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.ScmTransportProtocol; +import org.eclipse.jgit.transport.Transport; +import org.junit.Before; import org.junit.Test; +import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.RepositoryException; +import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.PushResponse; import static org.junit.Assert.*; @@ -91,6 +98,39 @@ public class GitPushCommandTest extends AbstractRemoteCommandTestBase assertEquals(o1, commits.next()); } + //~--- set methods ---------------------------------------------------------- + + /** + * Method description + * + */ + @Before + public void setUpProtocol() + { + + // store reference to handle weak references + proto = new ScmTransportProtocol(new Provider() + { + + @Override + public RepositoryManager get() + { + return null; + } + }, new Provider() + { + + @Override + public GitRepositoryHandler get() + { + return null; + } + }); + Transport.register(proto); + } + + //~--- methods -------------------------------------------------------------- + /** * Method description * @@ -102,4 +142,9 @@ public class GitPushCommandTest extends AbstractRemoteCommandTestBase return new GitPushCommand(handler, new GitContext(outgoingDirectory), outgoingRepository); } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private ScmTransportProtocol proto; }