mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-06 21:45:43 +01:00
merge with branch 1.x
This commit is contained in:
@@ -160,6 +160,23 @@ public class GitChangesetConverter implements Closeable
|
||||
return createChangeset(commit, branches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param commit
|
||||
* @param branch
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public Changeset createChangeset(RevCommit commit, String branch)
|
||||
throws IOException
|
||||
{
|
||||
return createChangeset(commit, Lists.newArrayList(branch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -35,6 +35,9 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
@@ -42,4 +45,15 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "config")
|
||||
public class GitConfig extends SimpleRepositoryConfig {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class GitConfig extends SimpleRepositoryConfig {
|
||||
|
||||
@XmlElement(name = "gc-expression")
|
||||
private String gcExpression;
|
||||
|
||||
public String getGcExpression()
|
||||
{
|
||||
return gcExpression;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Constants for Git.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.50
|
||||
*/
|
||||
public final class GitConstants {
|
||||
|
||||
/**
|
||||
* Default branch repository property.
|
||||
*/
|
||||
public static final String PROPERTY_DEFAULT_BRANCH = "git.default-branch";
|
||||
|
||||
private GitConstants() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/***
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.eclipse.jgit.api.GarbageCollectCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Executes git gc on every git repository. Statistics of the gc process are logged to the info level. The task is
|
||||
* disabled by default and must be enabled through the global git configuration.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.47
|
||||
*/
|
||||
public class GitGcTask implements Runnable {
|
||||
|
||||
private static final String SP = System.getProperty("line.seperator", "\n");
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitGcTask.class);
|
||||
|
||||
private final RepositoryManager repositoryManager;
|
||||
private final RepositoryDirectoryHandler repositoryHandler;
|
||||
|
||||
@Inject
|
||||
public GitGcTask(RepositoryManager repositoryManager)
|
||||
{
|
||||
this.repositoryManager = repositoryManager;
|
||||
this.repositoryHandler = (RepositoryDirectoryHandler) repositoryManager.getHandler(GitRepositoryHandler.TYPE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
for (Repository repository : repositoryManager.getAll())
|
||||
{
|
||||
handle(repository);
|
||||
}
|
||||
}
|
||||
|
||||
private void handle(Repository repository){
|
||||
if (GitRepositoryHandler.TYPE_NAME.equals(repository.getType()))
|
||||
{
|
||||
if (repository.isValid() && repository.isHealthy())
|
||||
{
|
||||
logger.info("start git gc for repository {}", repository.getName());
|
||||
Stopwatch sw = Stopwatch.createStarted();
|
||||
gc(repository);
|
||||
logger.debug("gc of repository {} has finished after {}", repository.getName(), sw.stop());
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("skip non valid/healthy repository {}", repository.getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace("skip non git repository {}", repository.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void appendProperties(StringBuilder buffer, Properties properties){
|
||||
for (Map.Entry<Object,Object> entry : properties.entrySet()){
|
||||
buffer.append(SP).append(" - ").append(entry.getKey()).append(" = ").append(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String message(Repository repository, Properties statistics, String span){
|
||||
StringBuilder buffer = new StringBuilder("gc statistics for ");
|
||||
buffer.append(repository.getName()).append(" ").append(span).append(" execution:");
|
||||
appendProperties(buffer, statistics);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void statistics(Repository repository, GarbageCollectCommand gcc) throws GitAPIException {
|
||||
Properties properties = gcc.getStatistics();
|
||||
logger.info(message(repository, properties, "before"));
|
||||
}
|
||||
|
||||
private void execute(Repository repository, GarbageCollectCommand gcc) throws GitAPIException {
|
||||
Properties properties = gcc.call();
|
||||
logger.info(message(repository, properties, "after"));
|
||||
}
|
||||
|
||||
private void gc(Repository repository){
|
||||
File file = repositoryHandler.getDirectory(repository);
|
||||
Git git = null;
|
||||
try {
|
||||
git = open(file);
|
||||
GarbageCollectCommand gcc = git.gc();
|
||||
// print statistics before execution, because it looks like
|
||||
// jgit returns the statistics after gc has finished
|
||||
statistics(repository, gcc);
|
||||
execute(repository, gcc);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.warn("failed to open git repository", ex);
|
||||
}
|
||||
catch (GitAPIException ex)
|
||||
{
|
||||
logger.warn("failed running git gc command", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (git != null){
|
||||
git.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the git repository. This method is only visible for testing purposes.
|
||||
*
|
||||
* @param file repository directory
|
||||
*
|
||||
* @return git for repository
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected Git open(File file) throws IOException {
|
||||
return Git.open(file);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ package sonia.scm.repository;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
@@ -49,12 +50,14 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.web.CollectingPackParserListener;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -72,7 +75,7 @@ public class GitHookChangesetCollector
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new instance
|
||||
*
|
||||
*
|
||||
* @param rpack
|
||||
@@ -83,19 +86,19 @@ public class GitHookChangesetCollector
|
||||
{
|
||||
this.rpack = rpack;
|
||||
this.receiveCommands = receiveCommands;
|
||||
this.listener = CollectingPackParserListener.get(rpack);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Collect all new changesets from the received hook.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return new changesets
|
||||
*/
|
||||
public List<Changeset> collectChangesets()
|
||||
{
|
||||
List<Changeset> changesets = Lists.newArrayList();
|
||||
Map<String, Changeset> changesets = Maps.newLinkedHashMap();
|
||||
|
||||
org.eclipse.jgit.lib.Repository repository = rpack.getRepository();
|
||||
|
||||
@@ -110,7 +113,19 @@ public class GitHookChangesetCollector
|
||||
|
||||
for (ReceiveCommand rc : receiveCommands)
|
||||
{
|
||||
if (rc.getType() != ReceiveCommand.Type.DELETE)
|
||||
String ref = rc.getRefName();
|
||||
|
||||
logger.trace("handle receive command, type={}, ref={}, result={}", rc.getType(), ref, rc.getResult());
|
||||
|
||||
if (rc.getType() == ReceiveCommand.Type.DELETE)
|
||||
{
|
||||
logger.debug("skip delete of ref {}", ref);
|
||||
}
|
||||
else if (! GitUtil.isBranch(ref))
|
||||
{
|
||||
logger.debug("skip ref {}, because it is not a branch", ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -124,13 +139,10 @@ public class GitHookChangesetCollector
|
||||
builder.append(rc.getType()).append(", ref=");
|
||||
builder.append(rc.getRefName()).append(", result=");
|
||||
builder.append(rc.getResult());
|
||||
|
||||
logger.error(builder.toString(), ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("skip delete of branch {}", rc.getRefName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -144,35 +156,13 @@ public class GitHookChangesetCollector
|
||||
GitUtil.release(walk);
|
||||
}
|
||||
|
||||
return changesets;
|
||||
return Lists.newArrayList(changesets.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param changesets
|
||||
* @param converter
|
||||
* @param walk
|
||||
* @param rc
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws IncorrectObjectTypeException
|
||||
*/
|
||||
private void collectChangesets(List<Changeset> changesets,
|
||||
private void collectChangesets(Map<String, Changeset> changesets,
|
||||
GitChangesetConverter converter, RevWalk walk, ReceiveCommand rc)
|
||||
throws IncorrectObjectTypeException, IOException
|
||||
{
|
||||
//J-
|
||||
logger.trace("handle receive command, type={}, ref={}, result={}",
|
||||
new Object[] {
|
||||
rc.getType(),
|
||||
rc.getRefName(),
|
||||
rc.getResult()
|
||||
}
|
||||
);
|
||||
//J+
|
||||
|
||||
ObjectId newId = rc.getNewId();
|
||||
|
||||
String branch = GitUtil.getBranch(rc.getRefName());
|
||||
@@ -187,7 +177,7 @@ public class GitHookChangesetCollector
|
||||
|
||||
ObjectId oldId = rc.getOldId();
|
||||
|
||||
if ((oldId != null) &&!oldId.equals(ObjectId.zeroId()))
|
||||
if ((oldId != null) && !oldId.equals(ObjectId.zeroId()))
|
||||
{
|
||||
logger.trace("mark {} as uninteresting for rev walk", oldId.getName());
|
||||
|
||||
@@ -196,19 +186,39 @@ public class GitHookChangesetCollector
|
||||
|
||||
RevCommit commit = walk.next();
|
||||
|
||||
List<String> branches = Lists.newArrayList(branch);
|
||||
|
||||
while (commit != null)
|
||||
{
|
||||
String id = commit.getId().name();
|
||||
Changeset changeset = changesets.get(id);
|
||||
|
||||
// parse commit body to avoid npe
|
||||
walk.parseBody(commit);
|
||||
if (changeset != null)
|
||||
{
|
||||
logger.trace(
|
||||
"commit {} already received durring this push, add branch {} to the commit",
|
||||
commit, branch);
|
||||
changeset.getBranches().add(branch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Changeset changeset = converter.createChangeset(commit, branches);
|
||||
// only append new commits
|
||||
if (listener.isNew(commit))
|
||||
{
|
||||
|
||||
logger.trace("retrive commit {} for hook", changeset.getId());
|
||||
// parse commit body to avoid npe
|
||||
walk.parseBody(commit);
|
||||
|
||||
changesets.add(changeset);
|
||||
changeset = converter.createChangeset(commit, branch);
|
||||
|
||||
logger.trace("retrieve commit {} for hook", changeset.getId());
|
||||
|
||||
changesets.put(id, changeset);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace("commit {} was already received", commit.getId());
|
||||
}
|
||||
}
|
||||
|
||||
commit = walk.next();
|
||||
}
|
||||
@@ -216,9 +226,10 @@ public class GitHookChangesetCollector
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
/** listener to track new objects */
|
||||
private final CollectingPackParserListener listener;
|
||||
|
||||
private final List<ReceiveCommand> receiveCommands;
|
||||
|
||||
/** Field description */
|
||||
private final ReceivePack rpack;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@@ -50,6 +51,11 @@ import sonia.scm.repository.spi.GitRepositoryServiceProvider;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.schedule.Scheduler;
|
||||
import sonia.scm.schedule.Task;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -66,19 +72,27 @@ public class GitRepositoryHandler
|
||||
|
||||
/** Field description */
|
||||
public static final String RESOURCE_VERSION =
|
||||
"/sonia/scm/version/scm-git-plugin";
|
||||
"sonia/scm/version/scm-git-plugin";
|
||||
|
||||
/** Field description */
|
||||
public static final String TYPE_DISPLAYNAME = "Git";
|
||||
|
||||
/** Field description */
|
||||
public static final String TYPE_NAME = "git";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitRepositoryHandler.class);
|
||||
|
||||
/** Field description */
|
||||
public static final Type TYPE = new RepositoryType(TYPE_NAME,
|
||||
TYPE_DISPLAYNAME,
|
||||
GitRepositoryServiceProvider.COMMANDS);
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
private final Scheduler scheduler;
|
||||
|
||||
private Task task;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -87,15 +101,48 @@ public class GitRepositoryHandler
|
||||
*
|
||||
* @param storeFactory
|
||||
* @param fileSystem
|
||||
* @param scheduler
|
||||
*/
|
||||
@Inject
|
||||
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, FileSystem fileSystem)
|
||||
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, FileSystem fileSystem, Scheduler scheduler)
|
||||
{
|
||||
super(storeFactory, fileSystem);
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
super.init(context);
|
||||
scheduleGc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(GitConfig config)
|
||||
{
|
||||
super.setConfig(config);
|
||||
scheduleGc();
|
||||
}
|
||||
|
||||
private void scheduleGc()
|
||||
{
|
||||
synchronized (LOCK){
|
||||
if ( task != null ){
|
||||
logger.debug("cancel existing git gc task");
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
String exp = getConfig().getGcExpression();
|
||||
if (!Strings.isNullOrEmpty(exp))
|
||||
{
|
||||
logger.info("schedule git gc task with expression {}", exp);
|
||||
task = scheduler.schedule(exp, GitGcTask.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.EagerSingleton;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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))
|
||||
{
|
||||
logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId());
|
||||
sendClearRepositoryCacheEvent(repository);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void sendClearRepositoryCacheEvent(Repository repository) {
|
||||
ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository));
|
||||
}
|
||||
|
||||
private boolean isModifyEvent(RepositoryEvent event) {
|
||||
return event.getEventType() == HandlerEventType.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),
|
||||
current.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ package sonia.scm.repository;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
@@ -262,7 +263,7 @@ public final class GitUtil
|
||||
{
|
||||
if (formatter != null)
|
||||
{
|
||||
formatter.release();
|
||||
formatter.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +277,7 @@ public final class GitUtil
|
||||
{
|
||||
if (walk != null)
|
||||
{
|
||||
walk.release();
|
||||
walk.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +291,7 @@ public final class GitUtil
|
||||
{
|
||||
if (walk != null)
|
||||
{
|
||||
walk.release();
|
||||
walk.close();;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +336,20 @@ public final class GitUtil
|
||||
|
||||
return branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the provided reference name is a branch name.
|
||||
*
|
||||
* @param refName reference name
|
||||
*
|
||||
* @return {@code true} if the name is a branch name
|
||||
*
|
||||
* @since 1.50
|
||||
*/
|
||||
public static boolean isBranch(String refName)
|
||||
{
|
||||
return Strings.nullToEmpty(refName).startsWith(PREFIX_HEADS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
@@ -631,6 +646,26 @@ public final class GitUtil
|
||||
return String.format(REMOTE_REF, repository.getId(), branch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the tag or {@code null} if the the ref is not a tag.
|
||||
*
|
||||
* @param refName ref name
|
||||
*
|
||||
* @return name of tag or {@link null}
|
||||
*
|
||||
* @since 1.50
|
||||
*/
|
||||
public static String getTagName(String refName)
|
||||
{
|
||||
String tagName = null;
|
||||
if (refName.startsWith(PREFIX_TAG))
|
||||
{
|
||||
tagName = refName.substring(PREFIX_TAG.length());
|
||||
}
|
||||
|
||||
return tagName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.api;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand.Type;
|
||||
|
||||
import sonia.scm.repository.GitUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Collects created, modified and deleted git branches during a hook.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitHookBranchProvider implements HookBranchProvider
|
||||
{
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitHookBranchProvider.class);
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*
|
||||
*
|
||||
* @param commands received git commands
|
||||
*/
|
||||
public GitHookBranchProvider(List<ReceiveCommand> commands)
|
||||
{
|
||||
Builder<String> createdOrModifiedBuilder = ImmutableList.builder();
|
||||
Builder<String> deletedOrClosedBuilder = ImmutableList.builder();
|
||||
|
||||
for (ReceiveCommand command : commands)
|
||||
{
|
||||
Type type = command.getType();
|
||||
String ref = command.getRefName();
|
||||
String branch = GitUtil.getBranch(ref);
|
||||
|
||||
if (Strings.isNullOrEmpty(branch))
|
||||
{
|
||||
logger.debug("ref {} is not a branch", ref);
|
||||
}
|
||||
else if (isCreateOrUpdate(type))
|
||||
{
|
||||
createdOrModifiedBuilder.add(branch);
|
||||
}
|
||||
else if (command.getType() == Type.DELETE)
|
||||
{
|
||||
deletedOrClosedBuilder.add(branch);
|
||||
}
|
||||
}
|
||||
|
||||
createdOrModified = createdOrModifiedBuilder.build();
|
||||
deletedOrClosed = deletedOrClosedBuilder.build();
|
||||
}
|
||||
|
||||
private boolean isCreateOrUpdate(Type type){
|
||||
return type == Type.CREATE || type == Type.UPDATE || type == Type.UPDATE_NONFASTFORWARD;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public List<String> getCreatedOrModified()
|
||||
{
|
||||
return createdOrModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDeletedOrClosed()
|
||||
{
|
||||
return deletedOrClosed;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
private final List<String> createdOrModified;
|
||||
|
||||
private final List<String> deletedOrClosed;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/***
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.Tag;
|
||||
|
||||
/**
|
||||
* Git provider implementation of {@link HookTagProvider}.
|
||||
*
|
||||
* @since 1.50
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitHookTagProvider implements HookTagProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitHookTagProvider.class);
|
||||
|
||||
private final List<Tag> createdTags;
|
||||
private final List<Tag> deletedTags;
|
||||
|
||||
/**
|
||||
* Constructs new instance.
|
||||
*
|
||||
* @param commands received commands
|
||||
*/
|
||||
public GitHookTagProvider(List<ReceiveCommand> commands) {
|
||||
ImmutableList.Builder<Tag> createdTagBuilder = ImmutableList.builder();
|
||||
ImmutableList.Builder<Tag> deletedTagBuilder = ImmutableList.builder();
|
||||
|
||||
for ( ReceiveCommand rc : commands ){
|
||||
String refName = rc.getRefName();
|
||||
String tag = GitUtil.getTagName(refName);
|
||||
|
||||
if (Strings.isNullOrEmpty(tag)){
|
||||
logger.debug("received ref name {} is not a tag", refName);
|
||||
} else if (rc.getType() == ReceiveCommand.Type.CREATE) {
|
||||
createdTagBuilder.add(new Tag(tag, GitUtil.getId(rc.getNewId())));
|
||||
} else if (rc.getType() == ReceiveCommand.Type.DELETE){
|
||||
deletedTagBuilder.add(new Tag(tag, GitUtil.getId(rc.getOldId())));
|
||||
}
|
||||
}
|
||||
|
||||
createdTags = createdTagBuilder.build();
|
||||
deletedTags = deletedTagBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getCreatedTags() {
|
||||
return createdTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getDeletedTags() {
|
||||
return deletedTags;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,11 +34,18 @@ package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitConstants;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -46,6 +53,11 @@ import java.io.IOException;
|
||||
*/
|
||||
public class AbstractGitCommand
|
||||
{
|
||||
|
||||
/**
|
||||
* the logger for AbstractGitCommand
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractGitCommand.class);
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
@@ -75,6 +87,38 @@ public class AbstractGitCommand
|
||||
{
|
||||
return context.open();
|
||||
}
|
||||
|
||||
protected ObjectId getCommitOrDefault(Repository gitRepository, String requestedCommit) throws IOException {
|
||||
ObjectId commit;
|
||||
if ( Strings.isNullOrEmpty(requestedCommit) ) {
|
||||
commit = getDefaultBranch(gitRepository);
|
||||
} else {
|
||||
commit = gitRepository.resolve(requestedCommit);
|
||||
}
|
||||
return commit;
|
||||
}
|
||||
|
||||
protected ObjectId getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException {
|
||||
ObjectId head;
|
||||
if ( Strings.isNullOrEmpty(requestedBranch) ) {
|
||||
head = getDefaultBranch(gitRepository);
|
||||
} else {
|
||||
head = GitUtil.getBranchId(gitRepository, requestedBranch);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
protected ObjectId getDefaultBranch(Repository gitRepository) throws IOException {
|
||||
ObjectId head;
|
||||
String defaultBranchName = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH);
|
||||
if (!Strings.isNullOrEmpty(defaultBranchName)) {
|
||||
head = GitUtil.getBranchId(gitRepository, defaultBranchName);
|
||||
} else {
|
||||
logger.trace("no default branch configured, use repository head as default");
|
||||
head = GitUtil.getRepositoryHead(gitRepository);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ public abstract class AbstractGitIncomingOutgoingCommand
|
||||
|
||||
GitUtil.fetch(git, handler.getDirectory(remoteRepository), remoteRepository);
|
||||
|
||||
ObjectId localId = GitUtil.getRepositoryHead(git.getRepository());
|
||||
ObjectId localId = getDefaultBranch(git.getRepository());
|
||||
ObjectId remoteId = null;
|
||||
|
||||
Ref remoteBranch = getRemoteBranch(git.getRepository(), localId,
|
||||
|
||||
@@ -124,7 +124,7 @@ public class GitBlameCommand extends AbstractGitCommand implements BlameCommand
|
||||
|
||||
blame.setFilePath(request.getPath());
|
||||
|
||||
ObjectId revId = GitUtil.getRevisionId(gr, request.getRevision());
|
||||
ObjectId revId = getCommitOrDefault(gr, request.getRevision());
|
||||
|
||||
blame.setStartCommit(revId);
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ public class GitBranchesCommand extends AbstractGitCommand
|
||||
|
||||
if (branchName != null)
|
||||
{
|
||||
branch = new Branch(branchName);
|
||||
branch = new Branch(branchName, GitUtil.getId(ref.getObjectId()));
|
||||
}
|
||||
|
||||
return branch;
|
||||
|
||||
@@ -71,7 +71,6 @@ import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
/**
|
||||
@@ -96,8 +95,6 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* @param repository
|
||||
*/
|
||||
@@ -124,18 +121,15 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
public BrowserResult getBrowserResult(BrowseCommandRequest request)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("try to create browse result for {}", request);
|
||||
}
|
||||
logger.debug("try to create browse result for {}", request);
|
||||
|
||||
BrowserResult result = null;
|
||||
BrowserResult result;
|
||||
org.eclipse.jgit.lib.Repository repo = open();
|
||||
ObjectId revId = null;
|
||||
ObjectId revId;
|
||||
|
||||
if (Util.isEmpty(request.getRevision()))
|
||||
{
|
||||
revId = GitUtil.getRepositoryHead(repo);
|
||||
revId = getDefaultBranch(repo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -169,70 +163,6 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param files
|
||||
* @param repo
|
||||
* @param revId
|
||||
* @param path
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
private void appendSubModules(List<FileObject> files,
|
||||
org.eclipse.jgit.lib.Repository repo, ObjectId revId, String path)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
path = Util.nonNull(path);
|
||||
|
||||
Map<String, SubRepository> subRepositories = subrepositoryCache.get(revId);
|
||||
|
||||
if (subRepositories == null)
|
||||
{
|
||||
subRepositories = getSubRepositories(repo, revId);
|
||||
subrepositoryCache.put(revId, subRepositories);
|
||||
}
|
||||
|
||||
if (subRepositories != null)
|
||||
{
|
||||
for (Entry<String, SubRepository> e : subRepositories.entrySet())
|
||||
{
|
||||
String p = e.getKey();
|
||||
|
||||
if (p.startsWith(path))
|
||||
{
|
||||
p = p.substring(path.length());
|
||||
|
||||
if (p.startsWith("/"))
|
||||
{
|
||||
p = p.substring(1);
|
||||
}
|
||||
|
||||
if (p.endsWith("/"))
|
||||
{
|
||||
p = p.substring(0, p.length() - 1);
|
||||
}
|
||||
|
||||
if (!p.contains("/"))
|
||||
{
|
||||
FileObject fo = new FileObject();
|
||||
|
||||
fo.setDirectory(true);
|
||||
fo.setPath(path);
|
||||
fo.setName(p);
|
||||
fo.setSubRepository(e.getValue());
|
||||
files.add(fo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param repo
|
||||
* @param request
|
||||
* @param revId
|
||||
@@ -244,9 +174,9 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
*/
|
||||
private FileObject createFileObject(org.eclipse.jgit.lib.Repository repo,
|
||||
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk)
|
||||
throws IOException
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
FileObject file = null;
|
||||
FileObject file;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -257,26 +187,43 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
file.setName(treeWalk.getNameString());
|
||||
file.setPath(path);
|
||||
|
||||
ObjectLoader loader = repo.open(treeWalk.getObjectId(0));
|
||||
SubRepository sub = null;
|
||||
|
||||
file.setDirectory(loader.getType() == Constants.OBJ_TREE);
|
||||
file.setLength(loader.getSize());
|
||||
|
||||
// don't show message and date for directories to improve performance
|
||||
if (!file.isDirectory() &&!request.isDisableLastCommit())
|
||||
if (!request.isDisableSubRepositoryDetection())
|
||||
{
|
||||
logger.trace("fetch last commit for {} at {}", path, revId.getName());
|
||||
sub = getSubRepository(repo, revId, path);
|
||||
}
|
||||
|
||||
RevCommit commit = getLatestCommit(repo, revId, path);
|
||||
if (sub != null)
|
||||
{
|
||||
logger.trace("{} seems to be a sub repository", path);
|
||||
file.setDirectory(true);
|
||||
file.setSubRepository(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectLoader loader = repo.open(treeWalk.getObjectId(0));
|
||||
|
||||
if (commit != null)
|
||||
file.setDirectory(loader.getType() == Constants.OBJ_TREE);
|
||||
file.setLength(loader.getSize());
|
||||
|
||||
// don't show message and date for directories to improve performance
|
||||
if (!file.isDirectory() &&!request.isDisableLastCommit())
|
||||
{
|
||||
file.setLastModified(GitUtil.getCommitTime(commit));
|
||||
file.setDescription(commit.getShortMessage());
|
||||
}
|
||||
else if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("could not find latest commit for {} on {}", path, revId);
|
||||
logger.trace("fetch last commit for {} at {}", path, revId.getName());
|
||||
|
||||
RevCommit commit = getLatestCommit(repo, revId, path);
|
||||
|
||||
if (commit != null)
|
||||
{
|
||||
file.setLastModified(GitUtil.getCommitTime(commit));
|
||||
file.setDescription(commit.getShortMessage());
|
||||
}
|
||||
else if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("could not find latest commit for {} on {}", path,
|
||||
revId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,11 +333,6 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
|
||||
String path = request.getPath();
|
||||
|
||||
if (!request.isDisableSubRepositoryDetection())
|
||||
{
|
||||
appendSubModules(files, repo, revId, path);
|
||||
}
|
||||
|
||||
if (Util.isEmpty(path))
|
||||
{
|
||||
while (treeWalk.next())
|
||||
@@ -496,6 +438,28 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
return subRepositories;
|
||||
}
|
||||
|
||||
private SubRepository getSubRepository(org.eclipse.jgit.lib.Repository repo,
|
||||
ObjectId revId, String path)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
Map<String, SubRepository> subRepositories = subrepositoryCache.get(revId);
|
||||
|
||||
if (subRepositories == null)
|
||||
{
|
||||
subRepositories = getSubRepositories(repo, revId);
|
||||
subrepositoryCache.put(revId, subRepositories);
|
||||
}
|
||||
|
||||
SubRepository sub = null;
|
||||
|
||||
if (subRepositories != null)
|
||||
{
|
||||
sub = subRepositories.get(path);
|
||||
}
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
|
||||
@@ -34,6 +34,7 @@ package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectLoader;
|
||||
@@ -78,7 +79,6 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
|
||||
*
|
||||
* @param context
|
||||
* @param repository
|
||||
* @param repositoryDirectory
|
||||
*/
|
||||
public GitCatCommand(GitContext context,
|
||||
sonia.scm.repository.Repository repository)
|
||||
@@ -102,17 +102,11 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
|
||||
public void getCatResult(CatCommandRequest request, OutputStream output)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("try to read content for {}", request);
|
||||
}
|
||||
|
||||
org.eclipse.jgit.lib.Repository repo = null;
|
||||
|
||||
repo = open();
|
||||
|
||||
ObjectId revId = GitUtil.getRevisionId(repo, request.getRevision());
|
||||
logger.debug("try to read content for {}", request);
|
||||
|
||||
org.eclipse.jgit.lib.Repository repo = open();
|
||||
|
||||
ObjectId revId = getCommitOrDefault(repo, request.getRevision());
|
||||
getContent(repo, revId, request.getPath(), output);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,6 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
|
||||
*
|
||||
* @param context
|
||||
* @param repository
|
||||
* @param repositoryDirectory
|
||||
*/
|
||||
public GitDiffCommand(GitContext context, Repository repository)
|
||||
{
|
||||
|
||||
@@ -36,7 +36,9 @@ package sonia.scm.repository.spi;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.eclipse.jgit.transport.ReceivePack;
|
||||
|
||||
import sonia.scm.repository.api.GitHookBranchProvider;
|
||||
import sonia.scm.repository.api.GitHookMessageProvider;
|
||||
import sonia.scm.repository.api.HookBranchProvider;
|
||||
import sonia.scm.repository.api.HookFeature;
|
||||
import sonia.scm.repository.api.HookMessageProvider;
|
||||
|
||||
@@ -45,6 +47,8 @@ import sonia.scm.repository.api.HookMessageProvider;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import sonia.scm.repository.api.GitHookTagProvider;
|
||||
import sonia.scm.repository.api.HookTagProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -55,33 +59,28 @@ public class GitHookContextProvider extends HookContextProvider
|
||||
|
||||
/** Field description */
|
||||
private static final Set<HookFeature> SUPPORTED_FEATURES =
|
||||
EnumSet.of(HookFeature.MESSAGE_PROVIDER, HookFeature.CHANGESET_PROVIDER);
|
||||
EnumSet.of(HookFeature.MESSAGE_PROVIDER, HookFeature.CHANGESET_PROVIDER,
|
||||
HookFeature.BRANCH_PROVIDER, HookFeature.TAG_PROVIDER);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new instance
|
||||
*
|
||||
*
|
||||
* @param receivePack
|
||||
* @param receiveCommands
|
||||
* @param receivePack git receive pack
|
||||
* @param receiveCommands received commands
|
||||
*/
|
||||
public GitHookContextProvider(ReceivePack receivePack,
|
||||
List<ReceiveCommand> receiveCommands)
|
||||
{
|
||||
this.receivePack = receivePack;
|
||||
this.receiveCommands = receiveCommands;
|
||||
this.changesetProvider = new GitHookChangesetProvider(receivePack,
|
||||
receiveCommands);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public HookMessageProvider createMessageProvider()
|
||||
{
|
||||
@@ -90,24 +89,23 @@ public class GitHookContextProvider extends HookContextProvider
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public HookBranchProvider getBranchProvider()
|
||||
{
|
||||
return new GitHookBranchProvider(receiveCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookTagProvider getTagProvider() {
|
||||
return new GitHookTagProvider(receiveCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookChangesetProvider getChangesetProvider()
|
||||
{
|
||||
return changesetProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<HookFeature> getSupportedFeatures()
|
||||
{
|
||||
@@ -117,8 +115,11 @@ public class GitHookContextProvider extends HookContextProvider
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private GitHookChangesetProvider changesetProvider;
|
||||
private final GitHookChangesetProvider changesetProvider;
|
||||
|
||||
/** Field description */
|
||||
private ReceivePack receivePack;
|
||||
private final List<ReceiveCommand> receiveCommands;
|
||||
|
||||
/** Field description */
|
||||
private final ReceivePack receivePack;
|
||||
}
|
||||
|
||||
@@ -221,17 +221,8 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
|
||||
AndTreeFilter.create(
|
||||
PathFilter.create(request.getPath()), TreeFilter.ANY_DIFF));
|
||||
}
|
||||
|
||||
ObjectId head = null;
|
||||
|
||||
if (!Strings.isNullOrEmpty(request.getBranch()))
|
||||
{
|
||||
head = GitUtil.getBranchId(gr, request.getBranch());
|
||||
}
|
||||
else
|
||||
{
|
||||
head = GitUtil.getRepositoryHead(gr);
|
||||
}
|
||||
|
||||
ObjectId head = getBranchOrDefault(gr, request.getBranch());
|
||||
|
||||
if (head != null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* 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.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectIdSubclassMap;
|
||||
import org.eclipse.jgit.revwalk.RevObject;
|
||||
import org.eclipse.jgit.transport.BaseReceivePack;
|
||||
import org.eclipse.jgit.transport.BaseReceivePack.PackParserListener;
|
||||
import org.eclipse.jgit.transport.PackParser;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementation of {@link PackParserListener} to collect every object which is
|
||||
* pushed with the reveive pack. The listener is used to find out which object
|
||||
* is new and which was already pushed.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class CollectingPackParserListener implements PackParserListener
|
||||
{
|
||||
|
||||
/**
|
||||
* the logger for CollectingPackParserListener
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(CollectingPackParserListener.class);
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the listener from the receive pack.
|
||||
*
|
||||
*
|
||||
* @param pack receive pack
|
||||
*
|
||||
* @return listener
|
||||
*/
|
||||
public static CollectingPackParserListener get(BaseReceivePack pack)
|
||||
{
|
||||
PackParserListener listener = pack.getPackParserListener();
|
||||
|
||||
if (listener == null)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"receive pack does not contain a listener");
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(
|
||||
listener instanceof CollectingPackParserListener,
|
||||
"listener is not a CollectingPackParserListener");
|
||||
|
||||
return (CollectingPackParserListener) listener;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Applies the listener to the receive pack.
|
||||
*
|
||||
*
|
||||
* @param pack receive pack
|
||||
*/
|
||||
public static void set(BaseReceivePack pack)
|
||||
{
|
||||
logger.trace("apply collecting listener to receive pack");
|
||||
pack.setPackParserListener(new CollectingPackParserListener());
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Collects all new object ids.
|
||||
*
|
||||
*
|
||||
* @param parser pack parser
|
||||
*/
|
||||
@Override
|
||||
public void after(PackParser parser)
|
||||
{
|
||||
logger.trace("retrieve new object ids from pack parser");
|
||||
|
||||
ObjectIdSubclassMap<ObjectId> newObjectIdMap = parser.getNewObjectIds();
|
||||
|
||||
if (newObjectIdMap != null)
|
||||
{
|
||||
newObjectIds = ImmutableSet.copyOf(newObjectIdMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("pack parser returned no newObjectIds");
|
||||
newObjectIds = ImmutableSet.of();
|
||||
}
|
||||
|
||||
if (newObjectIds.isEmpty())
|
||||
{
|
||||
logger.debug("new object ids are empty, we treat every commit as new");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("collected {} new object ids", newObjectIds.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the pack parser to retrieve the new object ids.
|
||||
*
|
||||
*
|
||||
* @param parser pack parser
|
||||
*/
|
||||
@Override
|
||||
public void before(PackParser parser)
|
||||
{
|
||||
logger.trace("prepare pack parser to collect new object ids");
|
||||
parser.setNeedNewObjectIds(true);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the object is a new object. The method will also
|
||||
* return {@code true}, if the pack parser does not return a list with new
|
||||
* object ids.
|
||||
*
|
||||
*
|
||||
* @param object rev object
|
||||
*
|
||||
* @return {@code true} if the object is new
|
||||
*/
|
||||
public boolean isNew(RevObject object)
|
||||
{
|
||||
ensureAfterWasCalled();
|
||||
|
||||
return newObjectIds.isEmpty() || newObjectIds.contains(object.getId());
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Throws an {@link IllegalStateException} if the after method was not called.
|
||||
*/
|
||||
private void ensureAfterWasCalled()
|
||||
{
|
||||
if (newObjectIds == null)
|
||||
{
|
||||
throw new IllegalStateException( "Pack parser seem not to be finished. "
|
||||
+ "The receive pack has not called the after method of the listener.");
|
||||
}
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** set of new object ids */
|
||||
private Set<ObjectId> newObjectIds;
|
||||
}
|
||||
@@ -35,27 +35,18 @@ package sonia.scm.web;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.http.server.GitSmartHttpTools;
|
||||
|
||||
import sonia.scm.ClientMessages;
|
||||
import sonia.scm.Priority;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.filter.Filters;
|
||||
import sonia.scm.filter.WebElement;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.web.filter.AuthenticationFilter;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* Handles git specific basic authentication.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Priority(Filters.PRIORITY_AUTHENTICATION)
|
||||
@@ -64,11 +55,10 @@ public class GitBasicAuthenticationFilter extends AuthenticationFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new instance.
|
||||
*
|
||||
*
|
||||
* @param configuration
|
||||
* @param webTokenGenerators
|
||||
* @param configuration scm-manager main configuration
|
||||
* @param webTokenGenerators web token generators
|
||||
*/
|
||||
@Inject
|
||||
public GitBasicAuthenticationFilter(ScmConfiguration configuration,
|
||||
@@ -76,32 +66,4 @@ public class GitBasicAuthenticationFilter extends AuthenticationFilter
|
||||
{
|
||||
super(configuration, webTokenGenerators);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected void sendFailedAuthenticationError(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException
|
||||
{
|
||||
if (GitUtil.isGitClient(request))
|
||||
{
|
||||
GitSmartHttpTools.sendError(request, response,
|
||||
HttpServletResponse.SC_FORBIDDEN,
|
||||
ClientMessages.get(request).failedAuthentication());
|
||||
}
|
||||
else
|
||||
{
|
||||
super.sendFailedAuthenticationError(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,9 @@ public class GitReceivePackFactory
|
||||
|
||||
rpack.setPreReceiveHook(hook);
|
||||
rpack.setPostReceiveHook(hook);
|
||||
|
||||
// apply collecting listener, to be able to check which commits are new
|
||||
CollectingPackParserListener.set(rpack);
|
||||
|
||||
return rpack;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra <sebastian.sdorra@gmail.com>
|
||||
* @since 1.45
|
||||
*/
|
||||
@Extension
|
||||
public class GitUserAgentProvider implements UserAgentProvider
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent GIT = UserAgent.builder("Git").browser(
|
||||
false).basicAuthenticationCharset(
|
||||
Charsets.UTF_8).build();
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent MSYSGIT = UserAgent.builder("msysGit").browser(
|
||||
false).basicAuthenticationCharset(
|
||||
Charsets.UTF_8).build();
|
||||
|
||||
/** Field description */
|
||||
private static final String PREFIX = "git/";
|
||||
|
||||
/** Field description */
|
||||
private static final String SUFFIX = "msysgit";
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param userAgentString
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public UserAgent parseUserAgent(String userAgentString)
|
||||
{
|
||||
UserAgent ua = null;
|
||||
|
||||
if (userAgentString.startsWith(PREFIX))
|
||||
{
|
||||
if (userAgentString.contains(SUFFIX))
|
||||
{
|
||||
ua = MSYSGIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ua = GIT;
|
||||
}
|
||||
}
|
||||
|
||||
return ua;
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -170,7 +171,11 @@ public class ScmGitServlet extends GitServlet
|
||||
{
|
||||
repositoryViewer.handleRequest(request, response, scmRepository);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (RepositoryException ex)
|
||||
{
|
||||
throw new ServletException("could not create repository view", ex);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new ServletException("could not create repository view", ex);
|
||||
}
|
||||
@@ -184,11 +189,11 @@ public class ScmGitServlet extends GitServlet
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private RepositoryProvider repositoryProvider;
|
||||
private final RepositoryProvider repositoryProvider;
|
||||
|
||||
/** Field description */
|
||||
private RepositoryRequestListenerUtil repositoryRequestListenerUtil;
|
||||
private final RepositoryRequestListenerUtil repositoryRequestListenerUtil;
|
||||
|
||||
/** Field description */
|
||||
private GitRepositoryViewer repositoryViewer;
|
||||
private final GitRepositoryViewer repositoryViewer;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,23 @@ Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, {
|
||||
// labels
|
||||
titleText: 'Git Settings',
|
||||
repositoryDirectoryText: 'Repository directory',
|
||||
gcExpressionText: 'Git GC Cron Expression',
|
||||
disabledText: 'Disabled',
|
||||
|
||||
// helpTexts
|
||||
repositoryDirectoryHelpText: 'Location of the Git repositories.',
|
||||
// TODO i18n
|
||||
gcExpressionHelpText: '<p>Use Quartz Cron Expressions (SECOND MINUTE HOUR DAYOFMONTH MONTH DAYOFWEEK) to run git gc in intervals.</p>\n\
|
||||
<table>\n\
|
||||
<tr><th><b>SECOND</b></th><td>Seconds within the minute (0–59)</td></tr>\n\
|
||||
<tr><th><b>MINUTE</b></th><td>Minutes within the hour (0–59)</td></tr>\n\
|
||||
<tr><th><b>HOUR</b></th><td>The hour of the day (0–23)</td></tr>\n\
|
||||
<tr><th><b>DAYOFMONTH</b></th><td>The day of the month (1–31)</td></tr>\n\
|
||||
<tr><th><b>MONTH</b></th><td>The month (1–12)</td></tr>\n\
|
||||
<tr><th><b>DAYOFWEEK</b></th><td>The day of the week (MON, TUE, WED, THU, FRI, SAT, SUN)</td></tr>\n\
|
||||
</table>\n\
|
||||
<p>E.g.: To run the task on every sunday at two o\'clock in the morning: 0 0 2 ? * SUN</p>\n\
|
||||
<p>For more informations please have a look at <a href="http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/crontrigger.html">Quartz CronTrigger</a></p>',
|
||||
disabledHelpText: 'Enable or disable the Git plugin.\n\
|
||||
Note you have to reload the page, after changing this value.',
|
||||
|
||||
@@ -54,6 +67,12 @@ Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, {
|
||||
fieldLabel: this.repositoryDirectoryText,
|
||||
helpText: this.repositoryDirectoryHelpText,
|
||||
allowBlank : false
|
||||
},{
|
||||
xtype: 'textfield',
|
||||
name: 'gc-expression',
|
||||
fieldLabel: this.gcExpressionText,
|
||||
helpText: this.gcExpressionHelpText,
|
||||
allowBlank : true
|
||||
},{
|
||||
xtype: 'checkbox',
|
||||
name: 'disabled',
|
||||
@@ -71,6 +90,93 @@ Sonia.git.ConfigPanel = Ext.extend(Sonia.config.SimpleConfigForm, {
|
||||
|
||||
Ext.reg("gitConfigPanel", Sonia.git.ConfigPanel);
|
||||
|
||||
// add default branch chooser to settings panel
|
||||
Sonia.git.GitSettingsFormPanel = Ext.extend(Sonia.repository.SettingsFormPanel, {
|
||||
|
||||
defaultBranchText: 'Default Branch',
|
||||
defaultBranchHelpText: 'The default branch which is show first on source or commit view.',
|
||||
|
||||
modifyDefaultConfig: function(config){
|
||||
if (this.item) {
|
||||
var position = -1;
|
||||
for ( var i=0; i<config.items.length; i++ ) {
|
||||
var field = config.items[i];
|
||||
if (field.name === 'public') {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var defaultBranchComboxBox = {
|
||||
fieldLabel: this.defaultBranchText,
|
||||
name: 'defaultBranch',
|
||||
repositoryId: this.item.id,
|
||||
value: this.getDefaultBranch(this.item),
|
||||
useNameAsValue: true,
|
||||
xtype: 'repositoryBranchComboBox',
|
||||
helpText: this.defaultBranchHelpText
|
||||
};
|
||||
|
||||
if (position >= 0) {
|
||||
config.items.splice(position, 0, defaultBranchComboxBox);
|
||||
} else {
|
||||
config.items.push(defaultBranchComboxBox);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultBranch: function(item){
|
||||
if (item.properties) {
|
||||
for ( var i=0; i<item.properties.length; i++ ) {
|
||||
var prop = item.properties[i];
|
||||
if (prop.key === 'git.default-branch') {
|
||||
return prop.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
setDefaultBranch: function(item, defaultBranch){
|
||||
if (!item.properties) {
|
||||
item.properties = [{
|
||||
key: 'git.default-branch',
|
||||
value: defaultBranch
|
||||
}];
|
||||
} else {
|
||||
|
||||
var found = false;
|
||||
for ( var i=0; i<item.properties.length; i++ ) {
|
||||
var prop = item.properties[i];
|
||||
if (prop.key === 'git.default-branch') {
|
||||
prop.value = defaultBranch;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
item.properties.push({
|
||||
key: 'git.default-branch',
|
||||
value: defaultBranch
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
prepareUpdate: function(item) {
|
||||
if (item.defaultBranch) {
|
||||
var defaultBranch = item.defaultBranch;
|
||||
delete item.defaultBranch;
|
||||
this.setDefaultBranch(item, defaultBranch);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Ext.reg("gitSettingsForm", Sonia.git.GitSettingsFormPanel);
|
||||
|
||||
|
||||
// i18n
|
||||
|
||||
if ( i18n && i18n.country === 'de' ){
|
||||
@@ -88,9 +194,21 @@ if ( i18n && i18n.country === 'de' ){
|
||||
Die Seite muss neu geladen werden wenn dieser Wert geändert wird.'
|
||||
|
||||
});
|
||||
|
||||
Ext.override(Sonia.git.GitSettingsFormPanel, {
|
||||
|
||||
// labels
|
||||
defaultBranchText: 'Standard Branch',
|
||||
|
||||
// helpTexts
|
||||
defaultBranchHelpText: 'Der Standard Branch wird für die Source und Commit Ansicht verwendet, \n\
|
||||
wenn kein anderer Branch eingestellt wurde.'
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// register information panel
|
||||
|
||||
initCallbacks.push(function(main){
|
||||
@@ -98,6 +216,9 @@ initCallbacks.push(function(main){
|
||||
checkoutTemplate: 'git clone <a href="{0}" target="_blank">{0}</a>',
|
||||
xtype: 'repositoryExtendedInfoPanel'
|
||||
});
|
||||
main.registerSettingsForm('git', {
|
||||
xtype: 'gitSettingsForm'
|
||||
});
|
||||
});
|
||||
|
||||
// register panel
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/***
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import org.eclipse.jgit.api.GarbageCollectCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.junit.Test;
|
||||
import static org.mockito.Mockito.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GitGcTask}.
|
||||
*
|
||||
* @author Sebastian Sdorra <sebastian.sdorra@triology.de>
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GitGcTaskTest
|
||||
{
|
||||
|
||||
@Mock
|
||||
private RepositoryManager manager;
|
||||
|
||||
@Mock
|
||||
private RepositoryDirectoryHandler handler;
|
||||
|
||||
@Mock
|
||||
private GarbageCollectCommand gcc;
|
||||
|
||||
@Mock
|
||||
private Git git;
|
||||
|
||||
private GitGcTask task;
|
||||
|
||||
/**
|
||||
* Setup mocks for tests.
|
||||
*
|
||||
* @throws GitAPIException
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws GitAPIException
|
||||
{
|
||||
when(git.gc()).thenReturn(gcc);
|
||||
when(gcc.getStatistics()).thenReturn(new Properties());
|
||||
when(gcc.call()).thenReturn(new Properties());
|
||||
when(manager.getHandler(GitRepositoryHandler.TYPE_NAME)).thenReturn(handler);
|
||||
task = new GitGcTask(manager){
|
||||
|
||||
@Override
|
||||
protected Git open(File file) throws IOException
|
||||
{
|
||||
return git;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitGcTask#run()}.
|
||||
*
|
||||
* @throws GitAPIException
|
||||
*/
|
||||
@Test
|
||||
public void testRun() throws GitAPIException
|
||||
{
|
||||
// prepare repositories for task
|
||||
Repository unhealthy = mock(Repository.class);
|
||||
when(unhealthy.getType()).thenReturn("git");
|
||||
when(unhealthy.isHealthy()).thenReturn(Boolean.FALSE);
|
||||
|
||||
Repository invalid = mock(Repository.class);
|
||||
when(unhealthy.getType()).thenReturn("git");
|
||||
when(unhealthy.isValid()).thenReturn(Boolean.FALSE);
|
||||
|
||||
List<Repository> repositories = Lists.newArrayList(
|
||||
RepositoryTestData.create42Puzzle("git"),
|
||||
RepositoryTestData.createHeartOfGold("hg"),
|
||||
unhealthy,
|
||||
invalid
|
||||
);
|
||||
when(manager.getAll()).thenReturn(repositories);
|
||||
|
||||
// run
|
||||
task.run();
|
||||
|
||||
// gc command should only be called once
|
||||
verify(gcc).getStatistics();
|
||||
verify(gcc).call();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,14 +43,22 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import sonia.scm.schedule.Scheduler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
|
||||
{
|
||||
|
||||
@Mock
|
||||
private Scheduler scheduler;
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -90,7 +98,7 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
|
||||
File directory)
|
||||
{
|
||||
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
|
||||
new DefaultFileSystem());
|
||||
new DefaultFileSystem(), scheduler);
|
||||
|
||||
repositoryHandler.init(contextProvider);
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* 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 org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import sonia.scm.HandlerEventType;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GitRepositoryModifyListener}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitRepositoryModifyListenerTest {
|
||||
|
||||
private GitRepositoryModifyTestListener repositoryModifyListener;
|
||||
|
||||
/**
|
||||
* Set up test object.
|
||||
*/
|
||||
@Before
|
||||
public void setUpObjectUnderTest(){
|
||||
repositoryModifyListener = new GitRepositoryModifyTestListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests happy path.
|
||||
*/
|
||||
@Test
|
||||
public void testHandleEvent() {
|
||||
Repository old = RepositoryTestData.createHeartOfGold("git");
|
||||
old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master");
|
||||
Repository current = RepositoryTestData.createHeartOfGold("git");
|
||||
current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop");
|
||||
|
||||
RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old);
|
||||
repositoryModifyListener.handleEvent(event);
|
||||
|
||||
assertNotNull(repositoryModifyListener.repository);
|
||||
assertSame(current, repositoryModifyListener.repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with new default branch.
|
||||
*/
|
||||
@Test
|
||||
public void testWithNewDefaultBranch() {
|
||||
Repository old = RepositoryTestData.createHeartOfGold("git");
|
||||
Repository current = RepositoryTestData.createHeartOfGold("git");
|
||||
current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop");
|
||||
|
||||
RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old);
|
||||
repositoryModifyListener.handleEvent(event);
|
||||
|
||||
assertNotNull(repositoryModifyListener.repository);
|
||||
assertSame(current, repositoryModifyListener.repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with non git repositories.
|
||||
*/
|
||||
@Test
|
||||
public void testNonGitRepository(){
|
||||
Repository old = RepositoryTestData.createHeartOfGold("hg");
|
||||
old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master");
|
||||
Repository current = RepositoryTestData.createHeartOfGold("hg");
|
||||
current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop");
|
||||
|
||||
RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old);
|
||||
repositoryModifyListener.handleEvent(event);
|
||||
|
||||
assertNull(repositoryModifyListener.repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests without default branch.
|
||||
*/
|
||||
@Test
|
||||
public void testWithoutDefaultBranch(){
|
||||
Repository old = RepositoryTestData.createHeartOfGold("git");
|
||||
Repository current = RepositoryTestData.createHeartOfGold("git");
|
||||
|
||||
RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old);
|
||||
repositoryModifyListener.handleEvent(event);
|
||||
|
||||
assertNull(repositoryModifyListener.repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with non modify event.
|
||||
*/
|
||||
@Test
|
||||
public void testNonModifyEvent(){
|
||||
Repository old = RepositoryTestData.createHeartOfGold("git");
|
||||
old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master");
|
||||
Repository current = RepositoryTestData.createHeartOfGold("git");
|
||||
current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "develop");
|
||||
|
||||
RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.CREATE, current, old);
|
||||
repositoryModifyListener.handleEvent(event);
|
||||
|
||||
assertNull(repositoryModifyListener.repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests with non git repositories.
|
||||
*/
|
||||
@Test
|
||||
public void testNoModification(){
|
||||
Repository old = RepositoryTestData.createHeartOfGold("git");
|
||||
old.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master");
|
||||
Repository current = RepositoryTestData.createHeartOfGold("git");
|
||||
current.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "master");
|
||||
|
||||
RepositoryModificationEvent event = new RepositoryModificationEvent(HandlerEventType.MODIFY, current, old);
|
||||
repositoryModifyListener.handleEvent(event);
|
||||
|
||||
assertNull(repositoryModifyListener.repository);
|
||||
}
|
||||
|
||||
private static class GitRepositoryModifyTestListener extends GitRepositoryModifyListener {
|
||||
|
||||
private Repository repository;
|
||||
|
||||
@Override
|
||||
protected void sendClearRepositoryCacheEvent(Repository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -53,16 +53,18 @@ import static org.mockito.Mockito.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Unit tests for {@link GitUtil}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitUtilTest
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
* Tests {@link GitUtil#checkBranchName(org.eclipse.jgit.lib.Repository, java.lang.String)} with invalid name.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@@ -76,8 +78,7 @@ public class GitUtilTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
* Tests {@link GitUtil#checkBranchName(org.eclipse.jgit.lib.Repository, java.lang.String)}.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@@ -92,32 +93,28 @@ public class GitUtilTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws GitAPIException
|
||||
* @throws IOException
|
||||
* Tests {@link GitUtil#getTagName(java.lang.String)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenJava7() throws GitAPIException, IOException
|
||||
{
|
||||
File dir = temp.newFolder();
|
||||
|
||||
Git.init().setDirectory(dir).setBare(true).call();
|
||||
|
||||
org.eclipse.jgit.lib.Repository repo = GitUtil.open(dir);
|
||||
|
||||
assertThat(repo.getFS().getClass().getName(), containsString("Java7"));
|
||||
public void testGetTagName(){
|
||||
assertNull(GitUtil.getTagName("refs/head/master"));
|
||||
assertEquals("1.0.0", GitUtil.getTagName("refs/tags/1.0.0"));
|
||||
assertEquals("super/1.0.0", GitUtil.getTagName("refs/tags/super/1.0.0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitUtil#isBranch(java.lang.String)}.
|
||||
*/
|
||||
@Test
|
||||
public void testIsBranchName(){
|
||||
assertTrue(GitUtil.isBranch("refs/heads/master"));
|
||||
assertTrue(GitUtil.isBranch("refs/heads/feature/super"));
|
||||
assertFalse(GitUtil.isBranch(""));
|
||||
assertFalse(GitUtil.isBranch(null));
|
||||
assertFalse(GitUtil.isBranch("refs/tags/1.0.0"));
|
||||
assertFalse(GitUtil.isBranch("refs/heads"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param directory
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private org.eclipse.jgit.lib.Repository mockRepo(File directory)
|
||||
{
|
||||
org.eclipse.jgit.lib.Repository repo =
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/***
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GitHookBranchProvider}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GitHookBranchProviderTest {
|
||||
|
||||
@Mock
|
||||
private ReceiveCommand command;
|
||||
|
||||
private List<ReceiveCommand> commands;
|
||||
|
||||
/**
|
||||
* Prepare mocks for upcoming test.
|
||||
*/
|
||||
@Before
|
||||
public void setUpMocks(){
|
||||
commands = Lists.newArrayList(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitHookBranchProvider#getCreatedOrModified()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCreatedOrModified(){
|
||||
List<ReceiveCommand.Type> types = Arrays.asList(
|
||||
ReceiveCommand.Type.CREATE, ReceiveCommand.Type.UPDATE, ReceiveCommand.Type.UPDATE_NONFASTFORWARD
|
||||
);
|
||||
for ( ReceiveCommand.Type type : types ){
|
||||
checkCreatedOrModified(type);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCreatedOrModified(ReceiveCommand.Type type){
|
||||
GitHookBranchProvider provider = createGitHookBranchProvider(type, "refs/heads/hello");
|
||||
assertThat(provider.getCreatedOrModified(), Matchers.contains("hello"));
|
||||
assertThat(provider.getDeletedOrClosed(), empty());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link GitHookBranchProvider#getDeletedOrClosed()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetDeletedOrClosed(){
|
||||
GitHookBranchProvider provider = createGitHookBranchProvider(ReceiveCommand.Type.DELETE, "refs/heads/hello");
|
||||
assertThat(provider.getDeletedOrClosed(), Matchers.contains("hello"));
|
||||
assertThat(provider.getCreatedOrModified(), empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitHookBranchProvider} with a tag instead of a branch.
|
||||
*/
|
||||
@Test
|
||||
public void testWithTag(){
|
||||
GitHookBranchProvider provider = createGitHookBranchProvider(ReceiveCommand.Type.CREATE, "refs/tags/1.0.0");
|
||||
assertThat(provider.getCreatedOrModified(), empty());
|
||||
assertThat(provider.getDeletedOrClosed(), empty());
|
||||
}
|
||||
|
||||
private GitHookBranchProvider createGitHookBranchProvider(ReceiveCommand.Type type, String refName){
|
||||
when(command.getType()).thenReturn(type);
|
||||
when(command.getRefName()).thenReturn(refName);
|
||||
return new GitHookBranchProvider(commands);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/***
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.OngoingStubbing;
|
||||
import sonia.scm.repository.Tag;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GitHookTagProvider}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class GitHookTagProviderTest {
|
||||
|
||||
@Mock
|
||||
private ReceiveCommand command;
|
||||
|
||||
private List<ReceiveCommand> commands;
|
||||
|
||||
/**
|
||||
* Set up mocks for upcoming tests.
|
||||
*/
|
||||
@Before
|
||||
public void setUpMocks(){
|
||||
commands = Lists.newArrayList(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitHookTagProvider#getCreatedTags()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCreatedTags() {
|
||||
String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7";
|
||||
GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/tags/1.0.0", revision);
|
||||
|
||||
assertTag("1.0.0", revision, provider.getCreatedTags());
|
||||
assertThat(provider.getDeletedTags(), empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitHookTagProvider#getDeletedTags()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetDeletedTags() {
|
||||
String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7";
|
||||
GitHookTagProvider provider = createProvider(ReceiveCommand.Type.DELETE, "refs/tags/1.0.0", revision);
|
||||
|
||||
assertThat(provider.getCreatedTags(), empty());
|
||||
assertTag("1.0.0", revision, provider.getDeletedTags());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link GitHookTagProvider} with a branch ref instead of a tag.
|
||||
*/
|
||||
@Test
|
||||
public void testWithBranch(){
|
||||
String revision = "b2002b64013e54b78eac251df0672bd5d6a83aa7";
|
||||
GitHookTagProvider provider = createProvider(ReceiveCommand.Type.CREATE, "refs/heads/1.0.0", revision);
|
||||
|
||||
assertThat(provider.getCreatedTags(), empty());
|
||||
assertThat(provider.getDeletedTags(), empty());
|
||||
}
|
||||
|
||||
private void assertTag(String name, String revision, List<Tag> tags){
|
||||
assertNotNull(tags);
|
||||
assertFalse(tags.isEmpty());
|
||||
assertEquals(1, tags.size());
|
||||
Tag tag = tags.get(0);
|
||||
assertEquals(name, tag.getName());
|
||||
assertEquals(revision, tag.getRevision());
|
||||
}
|
||||
|
||||
private GitHookTagProvider createProvider(ReceiveCommand.Type type, String ref, String id){
|
||||
OngoingStubbing<ObjectId> ongoing;
|
||||
if (type == ReceiveCommand.Type.CREATE){
|
||||
ongoing = when(command.getNewId());
|
||||
} else {
|
||||
ongoing = when(command.getOldId());
|
||||
}
|
||||
ongoing.thenReturn(ObjectId.fromString(id));
|
||||
|
||||
when(command.getType()).thenReturn(type);
|
||||
when(command.getRefName()).thenReturn(ref);
|
||||
|
||||
return new GitHookTagProvider(commands);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,14 +45,42 @@ import static org.junit.Assert.*;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
import sonia.scm.repository.GitConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* Unit tests for {@link GitBlameCommand}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitBlameCommandTest extends AbstractGitCommandTestBase
|
||||
{
|
||||
|
||||
/**
|
||||
* Tests blame command with default branch.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Test
|
||||
public void testDefaultBranch() throws IOException, RepositoryException {
|
||||
// without default branch, the repository head should be used
|
||||
BlameCommandRequest request = new BlameCommandRequest();
|
||||
request.setPath("a.txt");
|
||||
|
||||
BlameResult result = createCommand().getBlameResult(request);
|
||||
assertNotNull(result);
|
||||
assertEquals(2, result.getTotal());
|
||||
assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getLine(0).getRevision());
|
||||
assertEquals("fcd0ef1831e4002ac43ea539f4094334c79ea9ec", result.getLine(1).getRevision());
|
||||
|
||||
// set default branch and test again
|
||||
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
|
||||
result = createCommand().getBlameResult(request);
|
||||
assertNotNull(result);
|
||||
assertEquals(1, result.getTotal());
|
||||
assertEquals("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4", result.getLine(0).getRevision());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -48,13 +48,51 @@ import static org.junit.Assert.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import sonia.scm.repository.GitConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* Unit tests for {@link GitBrowseCommand}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitBrowseCommandTest extends AbstractGitCommandTestBase
|
||||
{
|
||||
|
||||
/**
|
||||
* Test browse command with default branch.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Test
|
||||
public void testDefaultBranch() throws IOException, RepositoryException {
|
||||
// without default branch, the repository head should be used
|
||||
BrowserResult result = createCommand().getBrowserResult(new BrowseCommandRequest());
|
||||
assertNotNull(result);
|
||||
|
||||
List<FileObject> foList = result.getFiles();
|
||||
assertNotNull(foList);
|
||||
assertFalse(foList.isEmpty());
|
||||
assertEquals(4, foList.size());
|
||||
|
||||
assertEquals("a.txt", foList.get(0).getName());
|
||||
assertEquals("b.txt", foList.get(1).getName());
|
||||
assertEquals("c", foList.get(2).getName());
|
||||
assertEquals("f.txt", foList.get(3).getName());
|
||||
|
||||
// set default branch and fetch again
|
||||
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
|
||||
result = createCommand().getBrowserResult(new BrowseCommandRequest());
|
||||
assertNotNull(result);
|
||||
|
||||
foList = result.getFiles();
|
||||
assertNotNull(foList);
|
||||
assertFalse(foList.isEmpty());
|
||||
assertEquals(2, foList.size());
|
||||
|
||||
assertEquals("a.txt", foList.get(0).getName());
|
||||
assertEquals("c", foList.get(1).getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
|
||||
@@ -44,14 +44,36 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import sonia.scm.repository.GitConstants;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GitCatCommand}.
|
||||
*
|
||||
* TODO add not found test
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitCatCommandTest extends AbstractGitCommandTestBase
|
||||
{
|
||||
|
||||
/**
|
||||
* Tests cat command with default branch.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Test
|
||||
public void testDefaultBranch() throws IOException, RepositoryException {
|
||||
// without default branch, the repository head should be used
|
||||
CatCommandRequest request = new CatCommandRequest();
|
||||
request.setPath("a.txt");
|
||||
|
||||
assertEquals("a\nline for blame", execute(request));
|
||||
|
||||
// set default branch for repository and check again
|
||||
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
|
||||
assertEquals("a and b", execute(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
|
||||
@@ -49,14 +49,48 @@ import static org.junit.Assert.*;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import sonia.scm.repository.GitConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* Unit tests for {@link GitLogCommand}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitLogCommandTest extends AbstractGitCommandTestBase
|
||||
{
|
||||
|
||||
/**
|
||||
* Tests log command with the usage of a default branch.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws GitAPIException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
@Test
|
||||
public void testGetDefaultBranch() throws IOException, GitAPIException, RepositoryException {
|
||||
// without default branch, the repository head should be used
|
||||
ChangesetPagingResult result = createCommand().getChangesets(new LogCommandRequest());
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(4, result.getTotal());
|
||||
assertEquals("fcd0ef1831e4002ac43ea539f4094334c79ea9ec", result.getChangesets().get(0).getId());
|
||||
assertEquals("86a6645eceefe8b9a247db5eb16e3d89a7e6e6d1", result.getChangesets().get(1).getId());
|
||||
assertEquals("592d797cd36432e591416e8b2b98154f4f163411", result.getChangesets().get(2).getId());
|
||||
assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getChangesets().get(3).getId());
|
||||
|
||||
// set default branch and fetch again
|
||||
repository.setProperty(GitConstants.PROPERTY_DEFAULT_BRANCH, "test-branch");
|
||||
|
||||
result = createCommand().getChangesets(new LogCommandRequest());
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(3, result.getTotal());
|
||||
assertEquals("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4", result.getChangesets().get(0).getId());
|
||||
assertEquals("592d797cd36432e591416e8b2b98154f4f163411", result.getChangesets().get(1).getId());
|
||||
assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", result.getChangesets().get(2).getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -51,7 +51,8 @@ import static org.junit.Assert.assertNotNull;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Unit tests for {@link OutgoingCommand}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* 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.common.base.Strings;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra <sebastian.sdorra@triology.de>
|
||||
*/
|
||||
public class GitUserAgentProviderTest
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testParseUserAgent()
|
||||
{
|
||||
assertEquals(GitUserAgentProvider.GIT, parse("git/1.7.9.5"));
|
||||
assertEquals(GitUserAgentProvider.MSYSGIT, parse("git/1.8.3.msysgit.0"));
|
||||
assertNull(parse("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param v
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private UserAgent parse(String v)
|
||||
{
|
||||
return provider.parseUserAgent(
|
||||
Strings.nullToEmpty(v).toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final GitUserAgentProvider provider = new GitUserAgentProvider();
|
||||
}
|
||||
Reference in New Issue
Block a user