mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-08-26 20:05:58 +02:00
merge
This commit is contained in:
@@ -1,11 +1,34 @@
|
||||
package sonia.scm;
|
||||
|
||||
public class AlreadyExistsException extends Exception {
|
||||
import java.util.List;
|
||||
|
||||
public AlreadyExistsException(String message) {
|
||||
super(message);
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class AlreadyExistsException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "FtR7UznKU1";
|
||||
|
||||
public AlreadyExistsException(ModelObject object) {
|
||||
this(singletonList(new ContextEntry(object.getClass(), object.getId())));
|
||||
}
|
||||
|
||||
public AlreadyExistsException() {
|
||||
public static AlreadyExistsException alreadyExists(ContextEntry.ContextBuilder builder) {
|
||||
return new AlreadyExistsException(builder.build());
|
||||
}
|
||||
|
||||
private AlreadyExistsException(List<ContextEntry> context) {
|
||||
super(context, createMessage(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
|
||||
private static String createMessage(List<ContextEntry> context) {
|
||||
return context.stream()
|
||||
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
|
||||
.collect(joining(" in ", "", " already exists"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,34 @@
|
||||
package sonia.scm;
|
||||
|
||||
public class ConcurrentModificationException extends Exception {
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class ConcurrentModificationException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "2wR7UzpPG1";
|
||||
|
||||
public ConcurrentModificationException(Class type, String id) {
|
||||
this(Collections.singletonList(new ContextEntry(type, id)));
|
||||
}
|
||||
|
||||
public ConcurrentModificationException(String type, String id) {
|
||||
this(Collections.singletonList(new ContextEntry(type, id)));
|
||||
}
|
||||
|
||||
private ConcurrentModificationException(List<ContextEntry> context) {
|
||||
super(context, createMessage(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
|
||||
private static String createMessage(List<ContextEntry> context) {
|
||||
return context.stream()
|
||||
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
|
||||
.collect(joining(" in ", "", " has been modified concurrently"));
|
||||
}
|
||||
}
|
||||
|
||||
84
scm-core/src/main/java/sonia/scm/ContextEntry.java
Normal file
84
scm-core/src/main/java/sonia/scm/ContextEntry.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package sonia.scm;
|
||||
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ContextEntry {
|
||||
private final String type;
|
||||
private final String id;
|
||||
|
||||
ContextEntry(Class type, String id) {
|
||||
this(type.getSimpleName(), id);
|
||||
}
|
||||
|
||||
ContextEntry(String type, String id) {
|
||||
AssertUtil.assertIsNotEmpty(type);
|
||||
AssertUtil.assertIsNotEmpty(id);
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public static class ContextBuilder {
|
||||
private final List<ContextEntry> context = new LinkedList<>();
|
||||
|
||||
public static List<ContextEntry> noContext() {
|
||||
return new ContextBuilder().build();
|
||||
}
|
||||
|
||||
public static List<ContextEntry> only(String type, String id) {
|
||||
return new ContextBuilder().in(type, id).build();
|
||||
}
|
||||
|
||||
public static ContextBuilder entity(Repository repository) {
|
||||
return new ContextBuilder().in(repository.getNamespaceAndName());
|
||||
}
|
||||
|
||||
public static ContextBuilder entity(NamespaceAndName namespaceAndName) {
|
||||
return new ContextBuilder().in(Repository.class, namespaceAndName.logString());
|
||||
}
|
||||
|
||||
public static ContextBuilder entity(Class type, String id) {
|
||||
return new ContextBuilder().in(type, id);
|
||||
}
|
||||
|
||||
public static ContextBuilder entity(String type, String id) {
|
||||
return new ContextBuilder().in(type, id);
|
||||
}
|
||||
|
||||
public ContextBuilder in(Repository repository) {
|
||||
return in(repository.getNamespaceAndName());
|
||||
}
|
||||
|
||||
public ContextBuilder in(NamespaceAndName namespaceAndName) {
|
||||
return this.in(Repository.class, namespaceAndName.logString());
|
||||
}
|
||||
|
||||
public ContextBuilder in(Class type, String id) {
|
||||
context.add(new ContextEntry(type, id));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContextBuilder in(String type, String id) {
|
||||
context.add(new ContextEntry(type, id));
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<ContextEntry> build() {
|
||||
return Collections.unmodifiableList(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
scm-core/src/main/java/sonia/scm/ExceptionWithContext.java
Normal file
26
scm-core/src/main/java/sonia/scm/ExceptionWithContext.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package sonia.scm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
|
||||
public abstract class ExceptionWithContext extends RuntimeException {
|
||||
|
||||
private final List<ContextEntry> context;
|
||||
|
||||
public ExceptionWithContext(List<ContextEntry> context, String message) {
|
||||
super(message);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public ExceptionWithContext(List<ContextEntry> context, String message, Exception cause) {
|
||||
super(message, cause);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public List<ContextEntry> getContext() {
|
||||
return unmodifiableList(context);
|
||||
}
|
||||
|
||||
public abstract String getCode();
|
||||
}
|
||||
@@ -54,25 +54,21 @@ public interface HandlerBase<T extends TypedObject>
|
||||
*
|
||||
* @return The persisted object.
|
||||
*/
|
||||
T create(T object) throws AlreadyExistsException;
|
||||
T create(T object);
|
||||
|
||||
/**
|
||||
* Removes a persistent object.
|
||||
*
|
||||
*
|
||||
* @param object to delete
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void delete(T object) throws NotFoundException;
|
||||
void delete(T object);
|
||||
|
||||
/**
|
||||
* Modifies a persistent object.
|
||||
*
|
||||
*
|
||||
* @param object to modify
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void modify(T object) throws NotFoundException;
|
||||
void modify(T object);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public interface Manager<T extends ModelObject>
|
||||
*
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
void refresh(T object) throws NotFoundException;
|
||||
void refresh(T object);
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class ManagerDecorator<T extends ModelObject> implements Manager<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T create(T object) throws AlreadyExistsException {
|
||||
public T create(T object) {
|
||||
return decorated.create(object);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,38 @@
|
||||
package sonia.scm;
|
||||
|
||||
public class NotFoundException extends RuntimeException {
|
||||
public NotFoundException(String type, String id) {
|
||||
super(type + " with id '" + id + "' not found");
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class NotFoundException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "AGR7UzkhA1";
|
||||
|
||||
public NotFoundException(Class type, String id) {
|
||||
this(Collections.singletonList(new ContextEntry(type, id)));
|
||||
}
|
||||
|
||||
public NotFoundException() {
|
||||
public NotFoundException(String type, String id) {
|
||||
this(Collections.singletonList(new ContextEntry(type, id)));
|
||||
}
|
||||
|
||||
public static NotFoundException notFound(ContextEntry.ContextBuilder contextBuilder) {
|
||||
return new NotFoundException(contextBuilder.build());
|
||||
}
|
||||
|
||||
private NotFoundException(List<ContextEntry> context) {
|
||||
super(context, createMessage(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
|
||||
private static String createMessage(List<ContextEntry> context) {
|
||||
return context.stream()
|
||||
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
|
||||
.collect(joining(" in ", "could not find ", ""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,33 +33,30 @@
|
||||
|
||||
package sonia.scm;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @version 1.6
|
||||
*/
|
||||
public class NotSupportedFeatuerException extends Exception
|
||||
{
|
||||
public class NotSupportedFeatureException extends ExceptionWithContext {
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = 256498734456613496L;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
private static final String CODE = "9SR8G0kmU1";
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public NotSupportedFeatuerException() {}
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public NotSupportedFeatuerException(String message)
|
||||
public NotSupportedFeatureException(String feature)
|
||||
{
|
||||
super(message);
|
||||
super(Collections.emptyList(),createMessage(feature));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
|
||||
private static String createMessage(String feature) {
|
||||
return "feature " + feature + " is not supported by this repository";
|
||||
}
|
||||
}
|
||||
@@ -45,28 +45,12 @@ public final class Filters
|
||||
/** Field description */
|
||||
public static final String PATTERN_ALL = "/*";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_CONFIG = REST_API_PATH + "/config*";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_DEBUG = "/debug.html";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_GROUPS = REST_API_PATH + "/groups*";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_PLUGINS = REST_API_PATH + "/plugins*";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_RESOURCE_REGEX =
|
||||
"^/(?:resources|api|plugins|index)[\\./].*(?:html|\\.css|\\.js|\\.xml|\\.json|\\.txt)";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_RESTAPI = REST_API_PATH + "/*";
|
||||
|
||||
/** Field description */
|
||||
public static final String PATTERN_USERS = REST_API_PATH + "/users*";
|
||||
|
||||
/** authentication priority */
|
||||
public static final int PRIORITY_AUTHENTICATION = 5000;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ package sonia.scm.repository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.NotSupportedFeatuerException;
|
||||
import sonia.scm.NotSupportedFeatureException;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
|
||||
@@ -165,13 +165,12 @@ public abstract class AbstractRepositoryHandler<C extends RepositoryConfig>
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws NotSupportedFeatuerException
|
||||
* @throws NotSupportedFeatureException
|
||||
*/
|
||||
@Override
|
||||
public ImportHandler getImportHandler() throws NotSupportedFeatuerException
|
||||
public ImportHandler getImportHandler() throws NotSupportedFeatureException
|
||||
{
|
||||
throw new NotSupportedFeatuerException(
|
||||
"import handler is not supported by this repository handler");
|
||||
throw new NotSupportedFeatureException("import");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
import sonia.scm.ConfigurationException;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.io.CommandResult;
|
||||
import sonia.scm.io.ExtendedCommand;
|
||||
import sonia.scm.io.FileSystem;
|
||||
@@ -80,13 +81,13 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repository create(Repository repository) throws AlreadyExistsException {
|
||||
public Repository create(Repository repository) {
|
||||
File directory = repositoryLocationResolver.getInitialNativeDirectory(repository);
|
||||
if (directory != null && directory.exists()) {
|
||||
throw new AlreadyExistsException();
|
||||
throw new AlreadyExistsException(repository);
|
||||
}
|
||||
|
||||
checkPath(directory);
|
||||
checkPath(directory, repository);
|
||||
|
||||
try {
|
||||
fileSystem.create(directory);
|
||||
@@ -120,15 +121,20 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
|
||||
@Override
|
||||
public void delete(Repository repository) {
|
||||
File directory = null;
|
||||
try {
|
||||
directory = repositoryLocationResolver.getRepositoryDirectory(repository);
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(repository, "Cannot get the repository directory");
|
||||
}
|
||||
try {
|
||||
File directory = repositoryLocationResolver.getRepositoryDirectory(repository);
|
||||
if (directory.exists()) {
|
||||
fileSystem.destroy(directory);
|
||||
} else {
|
||||
logger.warn("repository {} not found", repository.getNamespaceAndName());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException("could not delete repository directory", e);
|
||||
throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity("directory", directory.toString()).in(repository), "could not delete repository directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +184,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
}
|
||||
|
||||
protected void create(Repository repository, File directory)
|
||||
throws IOException, AlreadyExistsException {
|
||||
throws IOException {
|
||||
ExtendedCommand cmd = buildCreateCommand(repository, directory);
|
||||
CommandResult result = cmd.execute();
|
||||
|
||||
@@ -233,9 +239,9 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
* Check path for existing repositories
|
||||
*
|
||||
* @param directory repository target directory
|
||||
* @throws AlreadyExistsException
|
||||
* @throws RuntimeException when the parent directory already is a repository
|
||||
*/
|
||||
private void checkPath(File directory) throws AlreadyExistsException {
|
||||
private void checkPath(File directory, Repository repository) {
|
||||
if (directory == null) {
|
||||
return;
|
||||
}
|
||||
@@ -246,9 +252,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends RepositoryConfig
|
||||
logger.trace("check {} for existing repository", parent);
|
||||
|
||||
if (isRepository(parent)) {
|
||||
logger.error("parent path {} is a repository", parent);
|
||||
|
||||
throw new AlreadyExistsException();
|
||||
throw new InternalRepositoryException(repository, "parent path" + parent + " is a repository");
|
||||
}
|
||||
|
||||
parent = parent.getParentFile();
|
||||
|
||||
@@ -1,15 +1,34 @@
|
||||
package sonia.scm.repository;
|
||||
|
||||
public class InternalRepositoryException extends RuntimeException {
|
||||
public InternalRepositoryException(Throwable ex) {
|
||||
super(ex);
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.ExceptionWithContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InternalRepositoryException extends ExceptionWithContext {
|
||||
|
||||
public InternalRepositoryException(ContextEntry.ContextBuilder context, String message) {
|
||||
this(context, message, null);
|
||||
}
|
||||
|
||||
public InternalRepositoryException(String msg, Exception ex) {
|
||||
super(msg, ex);
|
||||
public InternalRepositoryException(ContextEntry.ContextBuilder context, String message, Exception cause) {
|
||||
this(context.build(), message, cause);
|
||||
}
|
||||
|
||||
public InternalRepositoryException(String message) {
|
||||
super(message);
|
||||
public InternalRepositoryException(Repository repository, String message) {
|
||||
this(ContextEntry.ContextBuilder.entity(repository), message, null);
|
||||
}
|
||||
|
||||
public InternalRepositoryException(Repository repository, String message, Exception cause) {
|
||||
this(ContextEntry.ContextBuilder.entity(repository), message, cause);
|
||||
}
|
||||
|
||||
public InternalRepositoryException(List<ContextEntry> context, String message, Exception cause) {
|
||||
super(context, message, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,13 @@ public class NamespaceAndName implements Comparable<NamespaceAndName> {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String logString() {
|
||||
return getNamespace() + "/" + getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getNamespace() + "/" + getName();
|
||||
return logString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* 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.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
/**
|
||||
* Signals that the specified path could be found.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class PathNotFoundException extends NotFoundException
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = 4629690181172951809L;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link PathNotFoundException}
|
||||
* with the specified path.
|
||||
*
|
||||
*
|
||||
* @param path path which could not be found
|
||||
*/
|
||||
public PathNotFoundException(String path)
|
||||
{
|
||||
super("path", Util.nonNull(path));
|
||||
this.path = Util.nonNull(path);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the path which could not be found.
|
||||
*
|
||||
*
|
||||
* @return path which could not be found
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private String path;
|
||||
}
|
||||
@@ -37,7 +37,6 @@ import com.github.sdorra.ssp.PermissionObject;
|
||||
import com.github.sdorra.ssp.StaticPermissions;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.Lists;
|
||||
import sonia.scm.BasicPropertiesAware;
|
||||
import sonia.scm.ModelObject;
|
||||
import sonia.scm.util.Util;
|
||||
@@ -50,8 +49,11 @@ import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Source code repository.
|
||||
@@ -79,7 +81,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
||||
private Long lastModified;
|
||||
private String namespace;
|
||||
private String name;
|
||||
private List<Permission> permissions;
|
||||
private final Set<Permission> permissions = new HashSet<>();
|
||||
@XmlElement(name = "public")
|
||||
private boolean publicReadable = false;
|
||||
private boolean archived = false;
|
||||
@@ -127,7 +129,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
||||
this.name = name;
|
||||
this.contact = contact;
|
||||
this.description = description;
|
||||
this.permissions = Lists.newArrayList();
|
||||
|
||||
if (Util.isNotEmpty(permissions)) {
|
||||
this.permissions.addAll(Arrays.asList(permissions));
|
||||
@@ -200,12 +201,8 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
||||
return new NamespaceAndName(getNamespace(), getName());
|
||||
}
|
||||
|
||||
public List<Permission> getPermissions() {
|
||||
if (permissions == null) {
|
||||
permissions = Lists.newArrayList();
|
||||
}
|
||||
|
||||
return permissions;
|
||||
public Collection<Permission> getPermissions() {
|
||||
return Collections.unmodifiableCollection(permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,8 +297,17 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setPermissions(List<Permission> permissions) {
|
||||
this.permissions = permissions;
|
||||
public void setPermissions(Collection<Permission> permissions) {
|
||||
this.permissions.clear();
|
||||
this.permissions.addAll(permissions);
|
||||
}
|
||||
|
||||
public void addPermission(Permission newPermission) {
|
||||
this.permissions.add(newPermission);
|
||||
}
|
||||
|
||||
public void removePermission(Permission permission) {
|
||||
this.permissions.remove(permission);
|
||||
}
|
||||
|
||||
public void setPublicReadable(boolean publicReadable) {
|
||||
|
||||
@@ -36,7 +36,7 @@ package sonia.scm.repository;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.Handler;
|
||||
import sonia.scm.NotSupportedFeatuerException;
|
||||
import sonia.scm.NotSupportedFeatureException;
|
||||
import sonia.scm.plugin.ExtensionPoint;
|
||||
|
||||
/**
|
||||
@@ -70,9 +70,9 @@ public interface RepositoryHandler
|
||||
* @return {@link ImportHandler} for the repository type of this handler
|
||||
* @since 1.12
|
||||
*
|
||||
* @throws NotSupportedFeatuerException
|
||||
* @throws NotSupportedFeatureException
|
||||
*/
|
||||
public ImportHandler getImportHandler() throws NotSupportedFeatuerException;
|
||||
public ImportHandler getImportHandler() throws NotSupportedFeatureException;
|
||||
|
||||
/**
|
||||
* Returns informations about the version of the RepositoryHandler.
|
||||
|
||||
@@ -35,7 +35,6 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
import sonia.scm.TypeManager;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -73,7 +72,7 @@ public interface RepositoryManager
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void importRepository(Repository repository) throws IOException, AlreadyExistsException;
|
||||
public void importRepository(Repository repository) throws IOException;
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
import sonia.scm.ManagerDecorator;
|
||||
import sonia.scm.Type;
|
||||
|
||||
@@ -82,7 +81,7 @@ public class RepositoryManagerDecorator
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void importRepository(Repository repository) throws IOException, AlreadyExistsException {
|
||||
public void importRepository(Repository repository) throws IOException {
|
||||
decorated.importRepository(repository);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* 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.repository;
|
||||
|
||||
import sonia.scm.NotFoundException;
|
||||
|
||||
/**
|
||||
* Signals that the specified {@link Repository} could be found.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.6
|
||||
*/
|
||||
public class RepositoryNotFoundException extends NotFoundException
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = -6583078808900520166L;
|
||||
private static final String TYPE_REPOSITORY = "repository";
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link RepositoryNotFoundException} with null as its
|
||||
* error detail message.
|
||||
*
|
||||
*/
|
||||
public RepositoryNotFoundException(Repository repository) {
|
||||
super(TYPE_REPOSITORY, repository.getName() + "/" + repository.getNamespace());
|
||||
}
|
||||
|
||||
public RepositoryNotFoundException(String repositoryId) {
|
||||
super(TYPE_REPOSITORY, repositoryId);
|
||||
}
|
||||
|
||||
public RepositoryNotFoundException(NamespaceAndName namespaceAndName) {
|
||||
super(TYPE_REPOSITORY, namespaceAndName.toString());
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* 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.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
/**
|
||||
* Signals that the specified revision could be found.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class RevisionNotFoundException extends NotFoundException {
|
||||
|
||||
/** Field description */
|
||||
private static final long serialVersionUID = -5594008535358811998L;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new {@link RevisionNotFoundException}
|
||||
* with the specified revision.
|
||||
*
|
||||
*
|
||||
* @param revision revision which could not be found
|
||||
*/
|
||||
public RevisionNotFoundException(String revision)
|
||||
{
|
||||
super("revision", revision);
|
||||
this.revision = Util.nonNull(revision);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the revision which could not be found.
|
||||
*
|
||||
*
|
||||
* @return revision which could not be found
|
||||
*/
|
||||
public String getRevision()
|
||||
{
|
||||
return revision;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private String revision;
|
||||
}
|
||||
@@ -38,7 +38,6 @@ package sonia.scm.repository.api;
|
||||
import com.google.common.base.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.repository.BrowserResult;
|
||||
@@ -46,7 +45,6 @@ import sonia.scm.repository.FileObject;
|
||||
import sonia.scm.repository.PreProcessorUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryCacheKey;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
import sonia.scm.repository.spi.BrowseCommand;
|
||||
import sonia.scm.repository.spi.BrowseCommandRequest;
|
||||
|
||||
@@ -136,7 +134,7 @@ public final class BrowseCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public BrowserResult getBrowserResult() throws IOException, NotFoundException {
|
||||
public BrowserResult getBrowserResult() throws IOException {
|
||||
BrowserResult result = null;
|
||||
|
||||
if (disableCache)
|
||||
|
||||
@@ -37,9 +37,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.PathNotFoundException;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
import sonia.scm.repository.spi.CatCommand;
|
||||
import sonia.scm.repository.spi.CatCommandRequest;
|
||||
import sonia.scm.util.IOUtil;
|
||||
@@ -107,7 +105,7 @@ public final class CatCommandBuilder
|
||||
* @param outputStream output stream for the content
|
||||
* @param path file path
|
||||
*/
|
||||
public void retriveContent(OutputStream outputStream, String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
|
||||
public void retriveContent(OutputStream outputStream, String path) throws IOException {
|
||||
getCatResult(outputStream, path);
|
||||
}
|
||||
|
||||
@@ -116,7 +114,7 @@ public final class CatCommandBuilder
|
||||
*
|
||||
* @param path file path
|
||||
*/
|
||||
public InputStream getStream(String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
|
||||
public InputStream getStream(String path) throws IOException {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(path),
|
||||
"path is required");
|
||||
|
||||
@@ -139,7 +137,7 @@ public final class CatCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public String getContent(String path) throws IOException, PathNotFoundException, RevisionNotFoundException {
|
||||
public String getContent(String path) throws IOException {
|
||||
String content = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
|
||||
@@ -186,7 +184,7 @@ public final class CatCommandBuilder
|
||||
* @throws IOException
|
||||
*/
|
||||
private void getCatResult(OutputStream outputStream, String path)
|
||||
throws IOException, PathNotFoundException, RevisionNotFoundException {
|
||||
throws IOException {
|
||||
Preconditions.checkNotNull(outputStream, "OutputStream is required");
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(path),
|
||||
"path is required");
|
||||
|
||||
@@ -66,6 +66,10 @@ public enum Command
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
MODIFICATIONS
|
||||
MODIFICATIONS,
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
MERGE
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ package sonia.scm.repository.api;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
import sonia.scm.repository.spi.DiffCommand;
|
||||
import sonia.scm.repository.spi.DiffCommandRequest;
|
||||
import sonia.scm.util.IOUtil;
|
||||
@@ -104,7 +103,7 @@ public final class DiffCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public DiffCommandBuilder retriveContent(OutputStream outputStream) throws IOException, RevisionNotFoundException {
|
||||
public DiffCommandBuilder retrieveContent(OutputStream outputStream) throws IOException {
|
||||
getDiffResult(outputStream);
|
||||
|
||||
return this;
|
||||
@@ -119,7 +118,7 @@ public final class DiffCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public String getContent() throws IOException, RevisionNotFoundException {
|
||||
public String getContent() throws IOException {
|
||||
String content = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
|
||||
@@ -199,7 +198,7 @@ public final class DiffCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void getDiffResult(OutputStream outputStream) throws IOException, RevisionNotFoundException {
|
||||
private void getDiffResult(OutputStream outputStream) throws IOException {
|
||||
Preconditions.checkNotNull(outputStream, "OutputStream is required");
|
||||
Preconditions.checkArgument(request.isValid(),
|
||||
"path and/or revision is required");
|
||||
|
||||
@@ -46,7 +46,6 @@ import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.PreProcessorUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryCacheKey;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
import sonia.scm.repository.spi.LogCommand;
|
||||
import sonia.scm.repository.spi.LogCommandRequest;
|
||||
|
||||
@@ -165,7 +164,7 @@ public final class LogCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public Changeset getChangeset(String id) throws IOException, RevisionNotFoundException {
|
||||
public Changeset getChangeset(String id) throws IOException {
|
||||
Changeset changeset;
|
||||
|
||||
if (disableCache)
|
||||
@@ -224,7 +223,7 @@ public final class LogCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public ChangesetPagingResult getChangesets() throws IOException, RevisionNotFoundException {
|
||||
public ChangesetPagingResult getChangesets() throws IOException {
|
||||
ChangesetPagingResult cpr;
|
||||
|
||||
if (disableCache)
|
||||
@@ -398,6 +397,11 @@ public final class LogCommandBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
public LogCommandBuilder setAncestorChangeset(String ancestorChangeset) {
|
||||
request.setAncestorChangeset(ancestorChangeset);
|
||||
return this;
|
||||
}
|
||||
|
||||
//~--- inner classes --------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import sonia.scm.repository.Person;
|
||||
import sonia.scm.repository.spi.MergeCommand;
|
||||
import sonia.scm.repository.spi.MergeCommandRequest;
|
||||
|
||||
/**
|
||||
* Use this {@link MergeCommandBuilder} to merge two branches of a repository ({@link #executeMerge()}) or to check if
|
||||
* the branches could be merged without conflicts ({@link #dryRun()}). To do so, you have to specify the name of
|
||||
* the target branch ({@link #setTargetBranch(String)}) and the name of the branch that should be merged
|
||||
* ({@link #setBranchToMerge(String)}). Additionally you can specify an author that should be used for the commit
|
||||
* ({@link #setAuthor(Person)}) and a message template ({@link #setMessageTemplate(String)}) if you are not doing a dry
|
||||
* run only. If no author is specified, the logged in user and a default message will be used instead.
|
||||
*
|
||||
* To actually merge <code>feature_branch</code> into <code>integration_branch</code> do this:
|
||||
* <pre><code>
|
||||
* repositoryService.gerMergeCommand()
|
||||
* .setBranchToMerge("feature_branch")
|
||||
* .setTargetBranch("integration_branch")
|
||||
* .executeMerge();
|
||||
* </code></pre>
|
||||
*
|
||||
* If the merge is successful, the result will look like this:
|
||||
* <pre><code>
|
||||
* O <- Merge result (new head of integration_branch)
|
||||
* |\
|
||||
* | \
|
||||
* old integration_branch -> O O <- feature_branch
|
||||
* | |
|
||||
* O O
|
||||
* </code></pre>
|
||||
*
|
||||
* To check whether they can be merged without conflicts beforehand do this:
|
||||
* <pre><code>
|
||||
* repositoryService.gerMergeCommand()
|
||||
* .setBranchToMerge("feature_branch")
|
||||
* .setTargetBranch("integration_branch")
|
||||
* .dryRun()
|
||||
* .isMergeable();
|
||||
* </code></pre>
|
||||
*
|
||||
* Keep in mind that you should <em>always</em> check the result of a merge even though you may have done a dry run
|
||||
* beforehand, because the branches can change between the dry run and the actual merge.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class MergeCommandBuilder {
|
||||
|
||||
private final MergeCommand mergeCommand;
|
||||
private final MergeCommandRequest request = new MergeCommandRequest();
|
||||
|
||||
MergeCommandBuilder(MergeCommand mergeCommand) {
|
||||
this.mergeCommand = mergeCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to set the branch that should be merged into the target branch.
|
||||
*
|
||||
* <b>This is mandatory.</b>
|
||||
*
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public MergeCommandBuilder setBranchToMerge(String branchToMerge) {
|
||||
request.setBranchToMerge(branchToMerge);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to set the target branch the other branch should be merged into.
|
||||
*
|
||||
* <b>This is mandatory.</b>
|
||||
*
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public MergeCommandBuilder setTargetBranch(String targetBranch) {
|
||||
request.setTargetBranch(targetBranch);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to set the author of the merge commit manually. If this is omitted, the currently logged in user will be
|
||||
* used instead.
|
||||
*
|
||||
* This is optional and for {@link #executeMerge()} only.
|
||||
*
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public MergeCommandBuilder setAuthor(Person author) {
|
||||
request.setAuthor(author);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to set a template for the commit message. If no message is set, a default message will be used.
|
||||
*
|
||||
* You can use the placeholder <code>{0}</code> for the branch to be merged and <code>{1}</code> for the target
|
||||
* branch, eg.:
|
||||
*
|
||||
* <pre><code>
|
||||
* ...setMessageTemplate("Merge of {0} into {1}")...
|
||||
* </code></pre>
|
||||
*
|
||||
* This is optional and for {@link #executeMerge()} only.
|
||||
*
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public MergeCommandBuilder setMessageTemplate(String messageTemplate) {
|
||||
request.setMessageTemplate(messageTemplate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to reset the command.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public MergeCommandBuilder reset() {
|
||||
request.reset();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to actually do the merge. If an automatic merge is not possible, {@link MergeCommandResult#isSuccess()}
|
||||
* will return <code>false</code>.
|
||||
*
|
||||
* @return The result of the merge.
|
||||
*/
|
||||
public MergeCommandResult executeMerge() {
|
||||
Preconditions.checkArgument(request.isValid(), "revision to merge and target revision is required");
|
||||
return mergeCommand.merge(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to check whether the given branches can be merged autmatically. If this is possible,
|
||||
* {@link MergeDryRunCommandResult#isMergeable()} will return <code>true</code>.
|
||||
*
|
||||
* @return The result whether the given branches can be merged automatically.
|
||||
*/
|
||||
public MergeDryRunCommandResult dryRun() {
|
||||
Preconditions.checkArgument(request.isValid(), "revision to merge and target revision is required");
|
||||
return mergeCommand.dryRun(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.unmodifiableCollection;
|
||||
|
||||
/**
|
||||
* This class keeps the result of a merge of branches. Use {@link #isSuccess()} to check whether the merge was
|
||||
* sucessfully executed. If the result is <code>false</code> the merge could not be done without conflicts. In this
|
||||
* case you can use {@link #getFilesWithConflict()} to get a list of files with merge conflicts.
|
||||
*/
|
||||
public class MergeCommandResult {
|
||||
private final Collection<String> filesWithConflict;
|
||||
|
||||
private MergeCommandResult(Collection<String> filesWithConflict) {
|
||||
this.filesWithConflict = filesWithConflict;
|
||||
}
|
||||
|
||||
public static MergeCommandResult success() {
|
||||
return new MergeCommandResult(emptyList());
|
||||
}
|
||||
|
||||
public static MergeCommandResult failure(Collection<String> filesWithConflict) {
|
||||
return new MergeCommandResult(new HashSet<>(filesWithConflict));
|
||||
}
|
||||
|
||||
/**
|
||||
* If this returns <code>true</code>, the merge was successfull. If this returns <code>false</code> there were
|
||||
* merge conflicts. In this case you can use {@link #getFilesWithConflict()} to check what files could not be merged.
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return filesWithConflict.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the merge was not successful ({@link #isSuccess()} returns <code>false</code>) this will give you a list of
|
||||
* file paths that could not be merged automatically.
|
||||
*/
|
||||
public Collection<String> getFilesWithConflict() {
|
||||
return unmodifiableCollection(filesWithConflict);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
/**
|
||||
* This class keeps the result of a merge dry run. Use {@link #isMergeable()} to check whether an automatic merge is
|
||||
* possible or not.
|
||||
*/
|
||||
public class MergeDryRunCommandResult {
|
||||
|
||||
private final boolean mergeable;
|
||||
|
||||
public MergeDryRunCommandResult(boolean mergeable) {
|
||||
this.mergeable = mergeable;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will return <code>true</code>, when an automatic merge is possible <em>at the moment</em>; <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isMergeable() {
|
||||
return mergeable;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import sonia.scm.repository.Modifications;
|
||||
import sonia.scm.repository.PreProcessorUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryCacheKey;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
import sonia.scm.repository.spi.ModificationsCommand;
|
||||
import sonia.scm.repository.spi.ModificationsCommandRequest;
|
||||
|
||||
@@ -67,7 +66,7 @@ public final class ModificationsCommandBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Modifications getModifications() throws IOException, RevisionNotFoundException {
|
||||
public Modifications getModifications() throws IOException {
|
||||
Modifications modifications;
|
||||
if (disableCache) {
|
||||
log.info("Get modifications for {} with disabled cache", request);
|
||||
|
||||
@@ -79,6 +79,7 @@ import java.util.stream.Stream;
|
||||
* @apiviz.uses sonia.scm.repository.api.PushCommandBuilder
|
||||
* @apiviz.uses sonia.scm.repository.api.BundleCommandBuilder
|
||||
* @apiviz.uses sonia.scm.repository.api.UnbundleCommandBuilder
|
||||
* @apiviz.uses sonia.scm.repository.api.MergeCommandBuilder
|
||||
* @since 1.17
|
||||
*/
|
||||
@Slf4j
|
||||
@@ -353,6 +354,22 @@ public final class RepositoryService implements Closeable {
|
||||
repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* The merge command executes a merge of two branches. It is possible to do a dry run to check, whether the given
|
||||
* branches can be merged without conflicts.
|
||||
*
|
||||
* @return instance of {@link MergeCommandBuilder}
|
||||
* @throws CommandNotSupportedException if the command is not supported
|
||||
* by the implementation of the repository service provider.
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public MergeCommandBuilder gerMergeCommand() {
|
||||
logger.debug("create unbundle command for repository {}",
|
||||
repository.getNamespaceAndName());
|
||||
|
||||
return new MergeCommandBuilder(provider.getMergeCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the command is supported by the repository service.
|
||||
*
|
||||
|
||||
@@ -45,6 +45,7 @@ import com.google.inject.Singleton;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
@@ -57,7 +58,6 @@ import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryCacheKeyPredicate;
|
||||
import sonia.scm.repository.RepositoryEvent;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryNotFoundException;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.spi.RepositoryServiceProvider;
|
||||
import sonia.scm.repository.spi.RepositoryServiceResolver;
|
||||
@@ -65,6 +65,9 @@ import sonia.scm.security.ScmSecurityException;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.NotFoundException.notFound;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -161,7 +164,7 @@ public final class RepositoryServiceFactory
|
||||
* @return a implementation of RepositoryService
|
||||
* for the given type of repository
|
||||
*
|
||||
* @throws RepositoryNotFoundException if no repository
|
||||
* @throws NotFoundException if no repository
|
||||
* with the given id is available
|
||||
* @throws RepositoryServiceNotFoundException if no repository service
|
||||
* implementation for this kind of repository is available
|
||||
@@ -169,7 +172,7 @@ public final class RepositoryServiceFactory
|
||||
* @throws ScmSecurityException if current user has not read permissions
|
||||
* for that repository
|
||||
*/
|
||||
public RepositoryService create(String repositoryId) throws RepositoryNotFoundException {
|
||||
public RepositoryService create(String repositoryId) {
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(repositoryId),
|
||||
"a non empty repositoryId is required");
|
||||
|
||||
@@ -177,7 +180,7 @@ public final class RepositoryServiceFactory
|
||||
|
||||
if (repository == null)
|
||||
{
|
||||
throw new RepositoryNotFoundException(repositoryId);
|
||||
throw new NotFoundException(Repository.class, repositoryId);
|
||||
}
|
||||
|
||||
return create(repository);
|
||||
@@ -192,7 +195,7 @@ public final class RepositoryServiceFactory
|
||||
* @return a implementation of RepositoryService
|
||||
* for the given type of repository
|
||||
*
|
||||
* @throws RepositoryNotFoundException if no repository
|
||||
* @throws NotFoundException if no repository
|
||||
* with the given id is available
|
||||
* @throws RepositoryServiceNotFoundException if no repository service
|
||||
* implementation for this kind of repository is available
|
||||
@@ -201,7 +204,6 @@ public final class RepositoryServiceFactory
|
||||
* for that repository
|
||||
*/
|
||||
public RepositoryService create(NamespaceAndName namespaceAndName)
|
||||
throws RepositoryNotFoundException
|
||||
{
|
||||
Preconditions.checkArgument(namespaceAndName != null,
|
||||
"a non empty namespace and name is required");
|
||||
@@ -210,7 +212,7 @@ public final class RepositoryServiceFactory
|
||||
|
||||
if (repository == null)
|
||||
{
|
||||
throw new RepositoryNotFoundException(namespaceAndName);
|
||||
throw notFound(entity(namespaceAndName));
|
||||
}
|
||||
|
||||
return create(repository);
|
||||
|
||||
@@ -35,7 +35,6 @@ package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.repository.BrowserResult;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -60,5 +59,5 @@ public interface BrowseCommand
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
BrowserResult getBrowserResult(BrowseCommandRequest request) throws IOException, NotFoundException;
|
||||
BrowserResult getBrowserResult(BrowseCommandRequest request) throws IOException;
|
||||
}
|
||||
|
||||
@@ -33,9 +33,6 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.repository.PathNotFoundException;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -47,7 +44,7 @@ import java.io.OutputStream;
|
||||
*/
|
||||
public interface CatCommand {
|
||||
|
||||
void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, RevisionNotFoundException, PathNotFoundException;
|
||||
void getCatResult(CatCommandRequest request, OutputStream output) throws IOException;
|
||||
|
||||
InputStream getCatResultStream(CatCommandRequest request) throws IOException, RevisionNotFoundException, PathNotFoundException;
|
||||
InputStream getCatResultStream(CatCommandRequest request) throws IOException;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@@ -56,5 +54,5 @@ public interface DiffCommand
|
||||
* @throws IOException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public void getDiffResult(DiffCommandRequest request, OutputStream output) throws IOException, RevisionNotFoundException;
|
||||
public void getDiffResult(DiffCommandRequest request, OutputStream output) throws IOException;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,10 @@ public final class DiffCommandRequest extends FileBaseCommandRequest
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
public void setAncestorChangeset(String ancestorChangeset) {
|
||||
this.ancestorChangeset = ancestorChangeset;
|
||||
}
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the output format of the diff command.
|
||||
@@ -124,8 +127,13 @@ public final class DiffCommandRequest extends FileBaseCommandRequest
|
||||
return format;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
public String getAncestorChangeset() {
|
||||
return ancestorChangeset;
|
||||
}
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** diff format */
|
||||
private DiffFormat format = DiffFormat.NATIVE;
|
||||
|
||||
private String ancestorChangeset;
|
||||
}
|
||||
|
||||
@@ -40,10 +40,12 @@ import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryHookEvent;
|
||||
import sonia.scm.repository.RepositoryHookType;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryNotFoundException;
|
||||
import sonia.scm.repository.api.HookContext;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.NotFoundException.notFound;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
@@ -71,18 +73,18 @@ public final class HookEventFacade
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
public HookEventHandler handle(String id) throws RepositoryNotFoundException {
|
||||
public HookEventHandler handle(String id) {
|
||||
return handle(repositoryManagerProvider.get().get(id));
|
||||
}
|
||||
|
||||
public HookEventHandler handle(NamespaceAndName namespaceAndName) throws RepositoryNotFoundException {
|
||||
public HookEventHandler handle(NamespaceAndName namespaceAndName) {
|
||||
return handle(repositoryManagerProvider.get().get(namespaceAndName));
|
||||
}
|
||||
|
||||
public HookEventHandler handle(Repository repository) throws RepositoryNotFoundException {
|
||||
public HookEventHandler handle(Repository repository) {
|
||||
if (repository == null)
|
||||
{
|
||||
throw new RepositoryNotFoundException(repository);
|
||||
throw notFound(entity(repository));
|
||||
}
|
||||
|
||||
return new HookEventHandler(repositoryManagerProvider.get(),
|
||||
|
||||
@@ -37,7 +37,6 @@ package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -50,7 +49,7 @@ import java.io.IOException;
|
||||
*/
|
||||
public interface LogCommand {
|
||||
|
||||
Changeset getChangeset(String id) throws IOException, RevisionNotFoundException;
|
||||
Changeset getChangeset(String id) throws IOException;
|
||||
|
||||
ChangesetPagingResult getChangesets(LogCommandRequest request) throws IOException, RevisionNotFoundException;
|
||||
ChangesetPagingResult getChangesets(LogCommandRequest request) throws IOException;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,8 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
&& Objects.equal(pagingStart, other.pagingStart)
|
||||
&& Objects.equal(pagingLimit, other.pagingLimit)
|
||||
&& Objects.equal(path, other.path)
|
||||
&& Objects.equal(branch, other.branch);
|
||||
&& Objects.equal(branch, other.branch)
|
||||
&& Objects.equal(ancestorChangeset, other.ancestorChangeset);
|
||||
//J+
|
||||
}
|
||||
|
||||
@@ -98,7 +99,7 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(startChangeset, endChangeset, pagingStart,
|
||||
pagingLimit, path, branch);
|
||||
pagingLimit, path, branch, ancestorChangeset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,6 +115,7 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
pagingLimit = 20;
|
||||
path = null;
|
||||
branch = null;
|
||||
ancestorChangeset = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,6 +135,7 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
.add("pagingLimit", pagingLimit)
|
||||
.add("path", path)
|
||||
.add("branch", branch)
|
||||
.add("ancestorChangeset", ancestorChangeset)
|
||||
.toString();
|
||||
//J+
|
||||
}
|
||||
@@ -205,6 +208,10 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
this.startChangeset = startChangeset;
|
||||
}
|
||||
|
||||
public void setAncestorChangeset(String ancestorChangeset) {
|
||||
this.ancestorChangeset = ancestorChangeset;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -284,6 +291,10 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
return pagingLimit < 0;
|
||||
}
|
||||
|
||||
public String getAncestorChangeset() {
|
||||
return ancestorChangeset;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@@ -303,4 +314,6 @@ public final class LogCommandRequest implements Serializable, Resetable
|
||||
|
||||
/** Field description */
|
||||
private String startChangeset;
|
||||
|
||||
private String ancestorChangeset;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.repository.api.MergeCommandResult;
|
||||
import sonia.scm.repository.api.MergeDryRunCommandResult;
|
||||
|
||||
public interface MergeCommand {
|
||||
MergeCommandResult merge(MergeCommandRequest request);
|
||||
|
||||
MergeDryRunCommandResult dryRun(MergeCommandRequest request);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Strings;
|
||||
import sonia.scm.Validateable;
|
||||
import sonia.scm.repository.Person;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class MergeCommandRequest implements Validateable, Resetable, Serializable, Cloneable {
|
||||
|
||||
private static final long serialVersionUID = -2650236557922431528L;
|
||||
|
||||
private String branchToMerge;
|
||||
private String targetBranch;
|
||||
private Person author;
|
||||
private String messageTemplate;
|
||||
|
||||
public String getBranchToMerge() {
|
||||
return branchToMerge;
|
||||
}
|
||||
|
||||
public void setBranchToMerge(String branchToMerge) {
|
||||
this.branchToMerge = branchToMerge;
|
||||
}
|
||||
|
||||
public String getTargetBranch() {
|
||||
return targetBranch;
|
||||
}
|
||||
|
||||
public void setTargetBranch(String targetBranch) {
|
||||
this.targetBranch = targetBranch;
|
||||
}
|
||||
|
||||
public Person getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Person author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getMessageTemplate() {
|
||||
return messageTemplate;
|
||||
}
|
||||
|
||||
public void setMessageTemplate(String messageTemplate) {
|
||||
this.messageTemplate = messageTemplate;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return !Strings.isNullOrEmpty(getBranchToMerge())
|
||||
&& !Strings.isNullOrEmpty(getTargetBranch());
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.setBranchToMerge(null);
|
||||
this.setTargetBranch(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final MergeCommandRequest other = (MergeCommandRequest) obj;
|
||||
|
||||
return Objects.equal(branchToMerge, other.branchToMerge)
|
||||
&& Objects.equal(targetBranch, other.targetBranch)
|
||||
&& Objects.equal(author, other.author);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(branchToMerge, targetBranch, author);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("branchToMerge", branchToMerge)
|
||||
.add("targetBranch", targetBranch)
|
||||
.add("author", author)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import sonia.scm.repository.Modifications;
|
||||
import sonia.scm.repository.RevisionNotFoundException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -46,8 +45,8 @@ import java.io.IOException;
|
||||
*/
|
||||
public interface ModificationsCommand {
|
||||
|
||||
Modifications getModifications(String revision) throws IOException, RevisionNotFoundException;
|
||||
Modifications getModifications(String revision) throws IOException;
|
||||
|
||||
Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException;
|
||||
Modifications getModifications(ModificationsCommandRequest request) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -251,4 +251,12 @@ public abstract class RepositoryServiceProvider implements Closeable
|
||||
{
|
||||
throw new CommandNotSupportedException(Command.UNBUNDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public MergeCommand getMergeCommand()
|
||||
{
|
||||
throw new CommandNotSupportedException(Command.MERGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
public class ChangePasswordNotAllowedException extends RuntimeException {
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.ExceptionWithContext;
|
||||
|
||||
public class ChangePasswordNotAllowedException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "9BR7qpDAe1";
|
||||
public static final String WRONG_USER_TYPE = "User of type %s are not allowed to change password";
|
||||
|
||||
public ChangePasswordNotAllowedException(String type) {
|
||||
super(String.format(WRONG_USER_TYPE, type));
|
||||
public ChangePasswordNotAllowedException(ContextEntry.ContextBuilder context, String type) {
|
||||
super(context.build(), String.format(WRONG_USER_TYPE, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
package sonia.scm.user;
|
||||
|
||||
public class InvalidPasswordException extends RuntimeException {
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.ExceptionWithContext;
|
||||
|
||||
public InvalidPasswordException() {
|
||||
super("The given Password does not match with the stored one.");
|
||||
public class InvalidPasswordException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "8YR7aawFW1";
|
||||
|
||||
public InvalidPasswordException(ContextEntry.ContextBuilder context) {
|
||||
super(context.build(), "The given old password does not match with the stored one.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class VndMediaType {
|
||||
|
||||
public static final String ME = PREFIX + "me" + SUFFIX;
|
||||
public static final String SOURCE = PREFIX + "source" + SUFFIX;
|
||||
public static final String ERROR_TYPE = PREFIX + "error" + SUFFIX;
|
||||
|
||||
private VndMediaType() {
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ public class AuthenticationFilter extends HttpFilter
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(new SecurityHttpServletRequestWrapper(request, username),
|
||||
chain.doFilter(new PropagatePrincipleServletRequestWrapper(request, username),
|
||||
response);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,37 +38,17 @@ package sonia.scm.web.filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class SecurityHttpServletRequestWrapper extends HttpServletRequestWrapper
|
||||
{
|
||||
public class PropagatePrincipleServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param principal
|
||||
*/
|
||||
public SecurityHttpServletRequestWrapper(HttpServletRequest request,
|
||||
String principal)
|
||||
{
|
||||
private final String principal;
|
||||
|
||||
public PropagatePrincipleServletRequestWrapper(HttpServletRequest request, String principal) {
|
||||
super(request);
|
||||
this.principal = principal;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public String getRemoteUser()
|
||||
{
|
||||
public String getRemoteUser() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final String principal;
|
||||
}
|
||||
@@ -43,7 +43,6 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.group.GroupNames;
|
||||
@@ -132,7 +131,7 @@ public class SyncingRealmHelperTest {
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testStoreGroupCreate() throws AlreadyExistsException {
|
||||
public void testStoreGroupCreate() {
|
||||
Group group = new Group("unit-test", "heartOfGold");
|
||||
|
||||
helper.store(group);
|
||||
@@ -143,7 +142,7 @@ public class SyncingRealmHelperTest {
|
||||
* Tests {@link SyncingRealmHelper#store(Group)}.
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testStoreGroupFailure() throws AlreadyExistsException {
|
||||
public void testStoreGroupFailure() {
|
||||
Group group = new Group("unit-test", "heartOfGold");
|
||||
|
||||
doThrow(AlreadyExistsException.class).when(groupManager).create(group);
|
||||
@@ -169,7 +168,7 @@ public class SyncingRealmHelperTest {
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testStoreUserCreate() throws AlreadyExistsException {
|
||||
public void testStoreUserCreate() {
|
||||
User user = new User("tricia");
|
||||
|
||||
helper.store(user);
|
||||
@@ -180,7 +179,7 @@ public class SyncingRealmHelperTest {
|
||||
* Tests {@link SyncingRealmHelper#store(User)} with a thrown {@link AlreadyExistsException}.
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testStoreUserFailure() throws AlreadyExistsException {
|
||||
public void testStoreUserFailure() {
|
||||
User user = new User("tricia");
|
||||
|
||||
doThrow(AlreadyExistsException.class).when(userManager).create(user);
|
||||
|
||||
Reference in New Issue
Block a user