merge with 2.0.0-m3
22
Jenkinsfile
vendored
@@ -7,12 +7,15 @@ import com.cloudogu.ces.cesbuildlib.*
|
|||||||
node('docker') {
|
node('docker') {
|
||||||
|
|
||||||
// Change this as when we go back to default - necessary for proper SonarQube analysis
|
// Change this as when we go back to default - necessary for proper SonarQube analysis
|
||||||
mainBranch = "2.0.0-m3"
|
mainBranch = '2.0.0-m3'
|
||||||
|
|
||||||
properties([
|
properties([
|
||||||
// Keep only the last 10 build to preserve space
|
// Keep only the last 10 build to preserve space
|
||||||
buildDiscarder(logRotator(numToKeepStr: '10')),
|
buildDiscarder(logRotator(numToKeepStr: '10')),
|
||||||
disableConcurrentBuilds()
|
disableConcurrentBuilds(),
|
||||||
|
parameters([
|
||||||
|
string(name: 'dockerTag', trim: true, defaultValue: 'latest', description: 'Extra Docker Tag for cloudogu/scm-manager image')
|
||||||
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
timeout(activity: true, time: 30, unit: 'MINUTES') {
|
timeout(activity: true, time: 30, unit: 'MINUTES') {
|
||||||
@@ -51,9 +54,9 @@ node('docker') {
|
|||||||
|
|
||||||
if (isMainBranch()) {
|
if (isMainBranch()) {
|
||||||
|
|
||||||
// stage('Lifecycle') {
|
stage('Lifecycle') {
|
||||||
// nexusPolicyEvaluation iqApplication: selectedApplication('scm'), iqScanPatterns: [[scanPattern: 'scm-server/target/scm-server-app.zip']], iqStage: 'build'
|
nexusPolicyEvaluation iqApplication: selectedApplication('scm'), iqScanPatterns: [[scanPattern: 'scm-server/target/scm-server-app.zip']], iqStage: 'build'
|
||||||
// }
|
}
|
||||||
|
|
||||||
stage('Archive') {
|
stage('Archive') {
|
||||||
archiveArtifacts 'scm-webapp/target/scm-webapp.war'
|
archiveArtifacts 'scm-webapp/target/scm-webapp.war'
|
||||||
@@ -66,6 +69,13 @@ node('docker') {
|
|||||||
docker.withRegistry('', 'hub.docker.com-cesmarvin') {
|
docker.withRegistry('', 'hub.docker.com-cesmarvin') {
|
||||||
image.push(dockerImageTag)
|
image.push(dockerImageTag)
|
||||||
image.push('latest')
|
image.push('latest')
|
||||||
|
if (!'latest'.equals(params.dockerTag)) {
|
||||||
|
image.push(params.dockerTag)
|
||||||
|
|
||||||
|
def newDockerTag = "2.0.0-${commitHash.substring(0,7)}-dev-${params.dockerTag}"
|
||||||
|
currentBuild.description = newDockerTag
|
||||||
|
image.push(newDockerTag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +102,7 @@ String mainBranch
|
|||||||
|
|
||||||
Maven setupMavenBuild() {
|
Maven setupMavenBuild() {
|
||||||
// Keep this version number in sync with .mvn/maven-wrapper.properties
|
// Keep this version number in sync with .mvn/maven-wrapper.properties
|
||||||
Maven mvn = new MavenInDocker(this, "3.5.2-jdk-8")
|
Maven mvn = new MavenInDocker(this, '3.5.2-jdk-8')
|
||||||
|
|
||||||
if (isMainBranch()) {
|
if (isMainBranch()) {
|
||||||
// Release starts javadoc, which takes very long, so do only for certain branches
|
// Release starts javadoc, which takes very long, so do only for certain branches
|
||||||
|
|||||||
@@ -29,46 +29,28 @@
|
|||||||
<!ELEMENT scm-version (#PCDATA)>
|
<!ELEMENT scm-version (#PCDATA)>
|
||||||
|
|
||||||
<!--- contains informations of the plugin for the plugin backend -->
|
<!--- contains informations of the plugin for the plugin backend -->
|
||||||
<!ELEMENT information (author|artifactId|category|tags|description|groupId|name|screenshots|url|version|wiki)*>
|
<!ELEMENT information (author|category|description|name|version|displayName|avatarUrl)*>
|
||||||
|
|
||||||
<!--- plugin author -->
|
<!--- plugin author -->
|
||||||
<!ELEMENT author (#PCDATA)>
|
<!ELEMENT author (#PCDATA)>
|
||||||
|
|
||||||
<!--- maven artifact id -->
|
|
||||||
<!ELEMENT artifactId (#PCDATA)>
|
|
||||||
|
|
||||||
<!--- category of the plugin -->
|
<!--- category of the plugin -->
|
||||||
<!ELEMENT category (#PCDATA)>
|
<!ELEMENT category (#PCDATA)>
|
||||||
|
|
||||||
<!--- tags of the plugin -->
|
|
||||||
<!ELEMENT tags (tag)*>
|
|
||||||
|
|
||||||
<!--- single tag -->
|
|
||||||
<!ELEMENT tag (#PCDATA)>
|
|
||||||
|
|
||||||
<!--- description of the plugin -->
|
<!--- description of the plugin -->
|
||||||
<!ELEMENT description (#PCDATA)>
|
<!ELEMENT description (#PCDATA)>
|
||||||
|
|
||||||
<!--- maven groupId id -->
|
|
||||||
<!ELEMENT groupId (#PCDATA)>
|
|
||||||
|
|
||||||
<!--- name of the plugin or the name of the os condition -->
|
<!--- name of the plugin or the name of the os condition -->
|
||||||
<!ELEMENT name (#PCDATA)>
|
<!ELEMENT name (#PCDATA)>
|
||||||
|
|
||||||
<!--- contains screenshots of the plugin -->
|
|
||||||
<!ELEMENT screenshots (screenshot)*>
|
|
||||||
|
|
||||||
<!--- single screenshot of the plugin -->
|
|
||||||
<!ELEMENT screenshot (#PCDATA)>
|
|
||||||
|
|
||||||
<!--- the url of the plugin homepage -->
|
|
||||||
<!ELEMENT url (#PCDATA)>
|
|
||||||
|
|
||||||
<!--- the current version of the plugin -->
|
<!--- the current version of the plugin -->
|
||||||
<!ELEMENT version (#PCDATA)>
|
<!ELEMENT version (#PCDATA)>
|
||||||
|
|
||||||
<!--- the url of a wiki page -->
|
<!--- plugin displayName -->
|
||||||
<!ELEMENT wiki (#PCDATA)>
|
<!ELEMENT displayName (#PCDATA)>
|
||||||
|
|
||||||
|
<!--- url of the plugin avatar -->
|
||||||
|
<!ELEMENT avatarUrl (#PCDATA)>
|
||||||
|
|
||||||
<!--- true if the plugin should load child classes first, the default is false -->
|
<!--- true if the plugin should load child classes first, the default is false -->
|
||||||
<!ELEMENT child-first-classloader (#PCDATA)>
|
<!ELEMENT child-first-classloader (#PCDATA)>
|
||||||
|
|||||||
BIN
docs/logo/favicon_16x16px.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
docs/logo/favicon_16x16px_transparent.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
1
docs/logo/scm-manager_logo.ai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
%!PS-Adobe-2.0
|
||||||
BIN
docs/logo/scm-manager_logo.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
docs/logo/scm-manager_logo.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/logo/scm-manager_logo_img.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/logo/scm-manager_logo_img.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/logo/scm-manager_logo_img_neg.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/logo/scm-manager_logo_img_neg.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/logo/scm-manager_logo_neg.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
docs/logo/scm-manager_logo_neg.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/logo/scm-manager_logo_neg1.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/logo/scm-manager_logo_neg1.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/logo/scm-manager_logo_pos1.jpg
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/logo/scm-manager_logo_pos1.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
10
pom.xml
@@ -437,8 +437,15 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>sonia.scm.maven</groupId>
|
<groupId>sonia.scm.maven</groupId>
|
||||||
<artifactId>smp-maven-plugin</artifactId>
|
<artifactId>smp-maven-plugin</artifactId>
|
||||||
<version>1.0.0-alpha-4</version>
|
<version>1.0.0-alpha-6</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>2.8.2</version>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
|
||||||
@@ -633,7 +640,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
<version>2.7</version>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class IllegalIdentifierChangeException extends BadRequestException {
|
||||||
|
|
||||||
|
private static final String CODE = "thbsUFokjk";
|
||||||
|
|
||||||
|
public IllegalIdentifierChangeException(ContextEntry.ContextBuilder context, String message) {
|
||||||
|
super(context.build(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IllegalIdentifierChangeException(String message) {
|
||||||
|
super(Collections.emptyList(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return CODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ package sonia.scm.api.v2.resources;
|
|||||||
|
|
||||||
import de.otto.edison.hal.HalRepresentation;
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HalAppender} can be used within an {@link HalEnricher} to append hateoas links to a json response.
|
* The {@link HalAppender} can be used within an {@link HalEnricher} to append hateoas links to a json response.
|
||||||
*
|
*
|
||||||
@@ -34,6 +36,14 @@ public interface HalAppender {
|
|||||||
*/
|
*/
|
||||||
void appendEmbedded(String rel, HalRepresentation embeddedItem);
|
void appendEmbedded(String rel, HalRepresentation embeddedItem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a list of embedded objects to the json response.
|
||||||
|
*
|
||||||
|
* @param rel name of relation
|
||||||
|
* @param embeddedItems embedded objects
|
||||||
|
*/
|
||||||
|
void appendEmbedded(String rel, List<HalRepresentation> embeddedItems);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for link arrays.
|
* Builder for link arrays.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -73,7 +73,12 @@ public class ScmConfiguration implements Configuration {
|
|||||||
* Default plugin url
|
* Default plugin url
|
||||||
*/
|
*/
|
||||||
public static final String DEFAULT_PLUGINURL =
|
public static final String DEFAULT_PLUGINURL =
|
||||||
"http://plugins.scm-manager.org/scm-plugin-backend/api/{version}/plugins?os={os}&arch={arch}&snapshot=false";
|
"http://download.scm-manager.org/api/v2/plugins.json?os={os}&arch={arch}&snapshot=false&version={version}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default url for login information (plugin and feature tips on the login page).
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_LOGIN_INFO_URL = "https://login-info.scm-manager.org/api/v1/login-info";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default plugin url from version 1.0
|
* Default plugin url from version 1.0
|
||||||
@@ -156,7 +161,6 @@ public class ScmConfiguration implements Configuration {
|
|||||||
* Authentication realm for basic authentication.
|
* Authentication realm for basic authentication.
|
||||||
*/
|
*/
|
||||||
private String realmDescription = HttpUtil.AUTHENTICATION_REALM;
|
private String realmDescription = HttpUtil.AUTHENTICATION_REALM;
|
||||||
private boolean enableRepositoryArchive = false;
|
|
||||||
private boolean disableGroupingGrid = false;
|
private boolean disableGroupingGrid = false;
|
||||||
/**
|
/**
|
||||||
* JavaScript date format from moment.js
|
* JavaScript date format from moment.js
|
||||||
@@ -177,6 +181,9 @@ public class ScmConfiguration implements Configuration {
|
|||||||
@XmlElement(name = "namespace-strategy")
|
@XmlElement(name = "namespace-strategy")
|
||||||
private String namespaceStrategy = "UsernameNamespaceStrategy";
|
private String namespaceStrategy = "UsernameNamespaceStrategy";
|
||||||
|
|
||||||
|
@XmlElement(name = "login-info-url")
|
||||||
|
private String loginInfoUrl = DEFAULT_LOGIN_INFO_URL;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls the {@link sonia.scm.ConfigChangedListener#configChanged(Object)}
|
* Calls the {@link sonia.scm.ConfigChangedListener#configChanged(Object)}
|
||||||
@@ -210,12 +217,12 @@ public class ScmConfiguration implements Configuration {
|
|||||||
this.forceBaseUrl = other.forceBaseUrl;
|
this.forceBaseUrl = other.forceBaseUrl;
|
||||||
this.baseUrl = other.baseUrl;
|
this.baseUrl = other.baseUrl;
|
||||||
this.disableGroupingGrid = other.disableGroupingGrid;
|
this.disableGroupingGrid = other.disableGroupingGrid;
|
||||||
this.enableRepositoryArchive = other.enableRepositoryArchive;
|
|
||||||
this.skipFailedAuthenticators = other.skipFailedAuthenticators;
|
this.skipFailedAuthenticators = other.skipFailedAuthenticators;
|
||||||
this.loginAttemptLimit = other.loginAttemptLimit;
|
this.loginAttemptLimit = other.loginAttemptLimit;
|
||||||
this.loginAttemptLimitTimeout = other.loginAttemptLimitTimeout;
|
this.loginAttemptLimitTimeout = other.loginAttemptLimitTimeout;
|
||||||
this.enabledXsrfProtection = other.enabledXsrfProtection;
|
this.enabledXsrfProtection = other.enabledXsrfProtection;
|
||||||
this.namespaceStrategy = other.namespaceStrategy;
|
this.namespaceStrategy = other.namespaceStrategy;
|
||||||
|
this.loginInfoUrl = other.loginInfoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -334,10 +341,6 @@ public class ScmConfiguration implements Configuration {
|
|||||||
return enableProxy;
|
return enableProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnableRepositoryArchive() {
|
|
||||||
return enableRepositoryArchive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isForceBaseUrl() {
|
public boolean isForceBaseUrl() {
|
||||||
return forceBaseUrl;
|
return forceBaseUrl;
|
||||||
}
|
}
|
||||||
@@ -350,6 +353,9 @@ public class ScmConfiguration implements Configuration {
|
|||||||
return namespaceStrategy;
|
return namespaceStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getLoginInfoUrl() {
|
||||||
|
return loginInfoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if failed authenticators are skipped.
|
* Returns true if failed authenticators are skipped.
|
||||||
@@ -381,16 +387,6 @@ public class ScmConfiguration implements Configuration {
|
|||||||
this.enableProxy = enableProxy;
|
this.enableProxy = enableProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable the repository archive. Default is disabled.
|
|
||||||
*
|
|
||||||
* @param enableRepositoryArchive true to disable the repository archive
|
|
||||||
* @since 1.14
|
|
||||||
*/
|
|
||||||
public void setEnableRepositoryArchive(boolean enableRepositoryArchive) {
|
|
||||||
this.enableRepositoryArchive = enableRepositoryArchive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setForceBaseUrl(boolean forceBaseUrl) {
|
public void setForceBaseUrl(boolean forceBaseUrl) {
|
||||||
this.forceBaseUrl = forceBaseUrl;
|
this.forceBaseUrl = forceBaseUrl;
|
||||||
}
|
}
|
||||||
@@ -477,6 +473,10 @@ public class ScmConfiguration implements Configuration {
|
|||||||
this.namespaceStrategy = namespaceStrategy;
|
this.namespaceStrategy = namespaceStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLoginInfoUrl(String loginInfoUrl) {
|
||||||
|
this.loginInfoUrl = loginInfoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
// Only for permission checks, don't serialize to XML
|
// Only for permission checks, don't serialize to XML
|
||||||
@XmlTransient
|
@XmlTransient
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package sonia.scm.group;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents all associated groups which are provided by external systems for a certain user.
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
public class ExternalGroupNames extends GroupNames {
|
|
||||||
public ExternalGroupNames() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExternalGroupNames(String groupName, String... groupNames) {
|
|
||||||
super(groupName, groupNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExternalGroupNames(Collection<String> collection) {
|
|
||||||
super(collection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
scm-core/src/main/java/sonia/scm/group/GroupCollector.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package sonia.scm.group;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface GroupCollector {
|
||||||
|
|
||||||
|
String AUTHENTICATED = "_authenticated";
|
||||||
|
|
||||||
|
Set<String> collect(String principal);
|
||||||
|
}
|
||||||
@@ -1,187 +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.group;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents all associated groups for a user.
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
* @since 1.21
|
|
||||||
*/
|
|
||||||
public class GroupNames implements Serializable, Iterable<String>
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Group for all authenticated users
|
|
||||||
* @since 1.31
|
|
||||||
*/
|
|
||||||
public static final String AUTHENTICATED = "_authenticated";
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = 8615685985213897947L;
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public GroupNames()
|
|
||||||
{
|
|
||||||
this(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param groupName
|
|
||||||
* @param groupNames
|
|
||||||
*/
|
|
||||||
public GroupNames(String groupName, String... groupNames)
|
|
||||||
{
|
|
||||||
this(Lists.asList(groupName, groupNames));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param collection
|
|
||||||
*/
|
|
||||||
public GroupNames(Collection<String> collection)
|
|
||||||
{
|
|
||||||
this.collection = Collections.unmodifiableCollection(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param groupName
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean contains(String groupName)
|
|
||||||
{
|
|
||||||
return collection.contains(groupName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final GroupNames other = (GroupNames) obj;
|
|
||||||
|
|
||||||
return Objects.equal(collection, other.collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hashCode(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Iterator<String> iterator()
|
|
||||||
{
|
|
||||||
return collection.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return Joiner.on(", ").join(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<String> getCollection()
|
|
||||||
{
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
/** Field description */
|
|
||||||
private final Collection<String> collection;
|
|
||||||
}
|
|
||||||
10
scm-core/src/main/java/sonia/scm/group/GroupResolver.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package sonia.scm.group;
|
||||||
|
|
||||||
|
import sonia.scm.plugin.ExtensionPoint;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ExtensionPoint
|
||||||
|
public interface GroupResolver {
|
||||||
|
Set<String> resolve(String principal);
|
||||||
|
}
|
||||||
32
scm-core/src/main/java/sonia/scm/plugin/AvailablePlugin.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
public class AvailablePlugin implements Plugin {
|
||||||
|
|
||||||
|
private final AvailablePluginDescriptor pluginDescriptor;
|
||||||
|
private final boolean pending;
|
||||||
|
|
||||||
|
public AvailablePlugin(AvailablePluginDescriptor pluginDescriptor) {
|
||||||
|
this(pluginDescriptor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AvailablePlugin(AvailablePluginDescriptor pluginDescriptor, boolean pending) {
|
||||||
|
this.pluginDescriptor = pluginDescriptor;
|
||||||
|
this.pending = pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AvailablePluginDescriptor getDescriptor() {
|
||||||
|
return pluginDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPending() {
|
||||||
|
return pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvailablePlugin install() {
|
||||||
|
Preconditions.checkState(!pending, "installation is already pending");
|
||||||
|
return new AvailablePlugin(pluginDescriptor, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public class AvailablePluginDescriptor implements PluginDescriptor {
|
||||||
|
|
||||||
|
private final PluginInformation information;
|
||||||
|
private final PluginCondition condition;
|
||||||
|
private final Set<String> dependencies;
|
||||||
|
private final String url;
|
||||||
|
private final String checksum;
|
||||||
|
|
||||||
|
public AvailablePluginDescriptor(PluginInformation information, PluginCondition condition, Set<String> dependencies, String url, String checksum) {
|
||||||
|
this.information = information;
|
||||||
|
this.condition = condition;
|
||||||
|
this.dependencies = dependencies;
|
||||||
|
this.url = url;
|
||||||
|
this.checksum = checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getChecksum() {
|
||||||
|
return Optional.ofNullable(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluginInformation getInformation() {
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PluginCondition getCondition() {
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getDependencies() {
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,27 +36,27 @@ package sonia.scm.plugin;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for a {@link Plugin}. The wrapper holds the directory,
|
* Wrapper for a {@link InstalledPluginDescriptor}. The wrapper holds the directory,
|
||||||
* {@link ClassLoader} and {@link WebResourceLoader} of a plugin.
|
* {@link ClassLoader} and {@link WebResourceLoader} of a plugin.
|
||||||
*
|
*
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public final class PluginWrapper
|
public final class InstalledPlugin implements Plugin
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new plugin wrapper.
|
* Constructs a new plugin wrapper.
|
||||||
*
|
*
|
||||||
* @param plugin wrapped plugin
|
* @param descriptor wrapped plugin
|
||||||
* @param classLoader plugin class loader
|
* @param classLoader plugin class loader
|
||||||
* @param webResourceLoader web resource loader
|
* @param webResourceLoader web resource loader
|
||||||
* @param directory plugin directory
|
* @param directory plugin directory
|
||||||
*/
|
*/
|
||||||
public PluginWrapper(Plugin plugin, ClassLoader classLoader,
|
public InstalledPlugin(InstalledPluginDescriptor descriptor, ClassLoader classLoader,
|
||||||
WebResourceLoader webResourceLoader, Path directory)
|
WebResourceLoader webResourceLoader, Path directory)
|
||||||
{
|
{
|
||||||
this.plugin = plugin;
|
this.descriptor = descriptor;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.webResourceLoader = webResourceLoader;
|
this.webResourceLoader = webResourceLoader;
|
||||||
this.directory = directory;
|
this.directory = directory;
|
||||||
@@ -94,18 +94,19 @@ public final class PluginWrapper
|
|||||||
*/
|
*/
|
||||||
public String getId()
|
public String getId()
|
||||||
{
|
{
|
||||||
return plugin.getInformation().getId();
|
return descriptor.getInformation().getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin.
|
* Returns the plugin descriptor.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @return plugin
|
* @return plugin descriptor
|
||||||
*/
|
*/
|
||||||
public Plugin getPlugin()
|
@Override
|
||||||
|
public InstalledPluginDescriptor getDescriptor()
|
||||||
{
|
{
|
||||||
return plugin;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +129,7 @@ public final class PluginWrapper
|
|||||||
private final Path directory;
|
private final Path directory;
|
||||||
|
|
||||||
/** plugin */
|
/** plugin */
|
||||||
private final Plugin plugin;
|
private final InstalledPluginDescriptor descriptor;
|
||||||
|
|
||||||
/** plugin web resource loader */
|
/** plugin web resource loader */
|
||||||
private final WebResourceLoader webResourceLoader;
|
private final WebResourceLoader webResourceLoader;
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/**
|
||||||
|
* 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.plugin;
|
||||||
|
|
||||||
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||||
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Sdorra
|
||||||
|
*/
|
||||||
|
@XmlRootElement(name = "plugin")
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
public final class InstalledPluginDescriptor extends ScmModule implements PluginDescriptor
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
InstalledPluginDescriptor() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ...
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param scmVersion
|
||||||
|
* @param information
|
||||||
|
* @param resources
|
||||||
|
* @param condition
|
||||||
|
* @param childFirstClassLoader
|
||||||
|
* @param dependencies
|
||||||
|
*/
|
||||||
|
public InstalledPluginDescriptor(int scmVersion, PluginInformation information,
|
||||||
|
PluginResources resources, PluginCondition condition,
|
||||||
|
boolean childFirstClassLoader, Set<String> dependencies)
|
||||||
|
{
|
||||||
|
this.scmVersion = scmVersion;
|
||||||
|
this.information = information;
|
||||||
|
this.resources = resources;
|
||||||
|
this.condition = condition;
|
||||||
|
this.childFirstClassLoader = childFirstClassLoader;
|
||||||
|
this.dependencies = dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param obj
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final InstalledPluginDescriptor other = (InstalledPluginDescriptor) obj;
|
||||||
|
|
||||||
|
return Objects.equal(scmVersion, other.scmVersion)
|
||||||
|
&& Objects.equal(condition, other.condition)
|
||||||
|
&& Objects.equal(information, other.information)
|
||||||
|
&& Objects.equal(resources, other.resources)
|
||||||
|
&& Objects.equal(childFirstClassLoader, other.childFirstClassLoader)
|
||||||
|
&& Objects.equal(dependencies, other.dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hashCode(scmVersion, condition, information, resources,
|
||||||
|
childFirstClassLoader, dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
//J-
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("scmVersion", scmVersion)
|
||||||
|
.add("condition", condition)
|
||||||
|
.add("information", information)
|
||||||
|
.add("resources", resources)
|
||||||
|
.add("childFirstClassLoader", childFirstClassLoader)
|
||||||
|
.add("dependencies", dependencies)
|
||||||
|
.toString();
|
||||||
|
//J+
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PluginCondition getCondition()
|
||||||
|
{
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Set<String> getDependencies()
|
||||||
|
{
|
||||||
|
if (dependencies == null)
|
||||||
|
{
|
||||||
|
dependencies = ImmutableSet.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PluginInformation getInformation()
|
||||||
|
{
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public PluginResources getResources()
|
||||||
|
{
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getScmVersion()
|
||||||
|
{
|
||||||
|
return scmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method description
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isChildFirstClassLoader()
|
||||||
|
{
|
||||||
|
return childFirstClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@XmlElement(name = "child-first-classloader")
|
||||||
|
private boolean childFirstClassLoader;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@XmlElement(name = "conditions")
|
||||||
|
private PluginCondition condition;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@XmlElement(name = "dependency")
|
||||||
|
@XmlElementWrapper(name = "dependencies")
|
||||||
|
private Set<String> dependencies;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@XmlElement(name = "information")
|
||||||
|
private PluginInformation information;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
private PluginResources resources;
|
||||||
|
|
||||||
|
/** Field description */
|
||||||
|
@XmlElement(name = "scm-version")
|
||||||
|
private int scmVersion = 1;
|
||||||
|
}
|
||||||
@@ -1,255 +1,6 @@
|
|||||||
/**
|
|
||||||
* 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.plugin;
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
public interface Plugin {
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
PluginDescriptor getDescriptor();
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@XmlRootElement
|
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
|
||||||
public final class Plugin extends ScmModule
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
Plugin() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param scmVersion
|
|
||||||
* @param information
|
|
||||||
* @param resources
|
|
||||||
* @param condition
|
|
||||||
* @param childFirstClassLoader
|
|
||||||
* @param dependencies
|
|
||||||
*/
|
|
||||||
public Plugin(int scmVersion, PluginInformation information,
|
|
||||||
PluginResources resources, PluginCondition condition,
|
|
||||||
boolean childFirstClassLoader, Set<String> dependencies)
|
|
||||||
{
|
|
||||||
this.scmVersion = scmVersion;
|
|
||||||
this.information = information;
|
|
||||||
this.resources = resources;
|
|
||||||
this.condition = condition;
|
|
||||||
this.childFirstClassLoader = childFirstClassLoader;
|
|
||||||
this.dependencies = dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param obj
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Plugin other = (Plugin) obj;
|
|
||||||
|
|
||||||
return Objects.equal(scmVersion, other.scmVersion)
|
|
||||||
&& Objects.equal(condition, other.condition)
|
|
||||||
&& Objects.equal(information, other.information)
|
|
||||||
&& Objects.equal(resources, other.resources)
|
|
||||||
&& Objects.equal(childFirstClassLoader, other.childFirstClassLoader)
|
|
||||||
&& Objects.equal(dependencies, other.dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hashCode(scmVersion, condition, information, resources,
|
|
||||||
childFirstClassLoader, dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
//J-
|
|
||||||
return MoreObjects.toStringHelper(this)
|
|
||||||
.add("scmVersion", scmVersion)
|
|
||||||
.add("condition", condition)
|
|
||||||
.add("information", information)
|
|
||||||
.add("resources", resources)
|
|
||||||
.add("childFirstClassLoader", childFirstClassLoader)
|
|
||||||
.add("dependencies", dependencies)
|
|
||||||
.toString();
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public PluginCondition getCondition()
|
|
||||||
{
|
|
||||||
return condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
public Set<String> getDependencies()
|
|
||||||
{
|
|
||||||
if (dependencies == null)
|
|
||||||
{
|
|
||||||
dependencies = ImmutableSet.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
return dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public PluginInformation getInformation()
|
|
||||||
{
|
|
||||||
return information;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public PluginResources getResources()
|
|
||||||
{
|
|
||||||
return resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public int getScmVersion()
|
|
||||||
{
|
|
||||||
return scmVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isChildFirstClassLoader()
|
|
||||||
{
|
|
||||||
return childFirstClassLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "child-first-classloader")
|
|
||||||
private boolean childFirstClassLoader;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "conditions")
|
|
||||||
private PluginCondition condition;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "dependency")
|
|
||||||
@XmlElementWrapper(name = "dependencies")
|
|
||||||
private Set<String> dependencies;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private PluginInformation information;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private PluginResources resources;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "scm-version")
|
|
||||||
private int scmVersion = 1;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,120 +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.plugin;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
@XmlRootElement(name = "plugin-center")
|
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
|
||||||
public class PluginCenter implements Serializable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = -6414175308610267397L;
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Set<PluginInformation> getPlugins()
|
|
||||||
{
|
|
||||||
return plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Set<PluginRepository> getRepositories()
|
|
||||||
{
|
|
||||||
return repositories;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- set methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param plugins
|
|
||||||
*/
|
|
||||||
public void setPlugins(Set<PluginInformation> plugins)
|
|
||||||
{
|
|
||||||
this.plugins = plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param repositories
|
|
||||||
*/
|
|
||||||
public void setRepositories(Set<PluginRepository> repositories)
|
|
||||||
{
|
|
||||||
this.repositories = repositories;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "plugin")
|
|
||||||
@XmlElementWrapper(name = "plugins")
|
|
||||||
private Set<PluginInformation> plugins = new HashSet<PluginInformation>();
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "repository")
|
|
||||||
@XmlElementWrapper(name = "repositories")
|
|
||||||
private Set<PluginRepository> repositories = new HashSet<PluginRepository>();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface PluginDescriptor {
|
||||||
|
|
||||||
|
PluginInformation getInformation();
|
||||||
|
|
||||||
|
PluginCondition getCondition();
|
||||||
|
|
||||||
|
Set<String> getDependencies();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
* Copyright (c) 2010, Sebastian Sdorra
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
* <p>
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
*
|
* <p>
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer.
|
* this list of conditions and the following disclaimer.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived from this
|
* contributors may be used to endorse or promote products derived from this
|
||||||
* software without specific prior written permission.
|
* software without specific prior written permission.
|
||||||
*
|
* <p>
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
@@ -24,558 +24,82 @@
|
|||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
* <p>
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package sonia.scm.plugin;
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.github.sdorra.ssp.PermissionObject;
|
import com.github.sdorra.ssp.PermissionObject;
|
||||||
import com.github.sdorra.ssp.StaticPermissions;
|
import com.github.sdorra.ssp.StaticPermissions;
|
||||||
import com.google.common.base.MoreObjects;
|
import lombok.Data;
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import sonia.scm.Validateable;
|
import sonia.scm.Validateable;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
*/
|
*/
|
||||||
|
@Data
|
||||||
@StaticPermissions(
|
@StaticPermissions(
|
||||||
value = "plugin",
|
value = "plugin",
|
||||||
generatedClass = "PluginPermissions",
|
generatedClass = "PluginPermissions",
|
||||||
permissions = {},
|
permissions = {},
|
||||||
globalPermissions = { "read", "manage" },
|
globalPermissions = {"read", "manage"},
|
||||||
custom = true, customGlobal = true
|
custom = true, customGlobal = true
|
||||||
)
|
)
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
@XmlRootElement(name = "plugin-information")
|
@XmlRootElement(name = "plugin-information")
|
||||||
public class PluginInformation
|
public class PluginInformation implements PermissionObject, Validateable, Cloneable, Serializable {
|
||||||
implements PermissionObject, Validateable, Cloneable, Serializable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = 461382048865977206L;
|
private static final long serialVersionUID = 461382048865977206L;
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
private String name;
|
||||||
|
private String version;
|
||||||
|
private String displayName;
|
||||||
|
private String description;
|
||||||
|
private String author;
|
||||||
|
private String category;
|
||||||
|
private String avatarUrl;
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @since 1.11
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public PluginInformation clone()
|
public PluginInformation clone() {
|
||||||
{
|
|
||||||
PluginInformation clone = new PluginInformation();
|
PluginInformation clone = new PluginInformation();
|
||||||
|
clone.setName(name);
|
||||||
clone.setArtifactId(artifactId);
|
clone.setVersion(version);
|
||||||
|
clone.setDisplayName(displayName);
|
||||||
|
clone.setDescription(description);
|
||||||
clone.setAuthor(author);
|
clone.setAuthor(author);
|
||||||
clone.setCategory(category);
|
clone.setCategory(category);
|
||||||
clone.setTags(tags);
|
clone.setAvatarUrl(avatarUrl);
|
||||||
|
|
||||||
if (condition != null)
|
|
||||||
{
|
|
||||||
clone.setCondition(condition.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
clone.setDescription(description);
|
|
||||||
clone.setGroupId(groupId);
|
|
||||||
clone.setName(name);
|
|
||||||
|
|
||||||
if (Util.isNotEmpty(screenshots))
|
|
||||||
{
|
|
||||||
clone.setScreenshots(new ArrayList<String>(screenshots));
|
|
||||||
}
|
|
||||||
|
|
||||||
clone.setState(state);
|
|
||||||
clone.setUrl(url);
|
|
||||||
clone.setVersion(version);
|
|
||||||
clone.setWiki(wiki);
|
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param obj
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj)
|
public String getId() {
|
||||||
{
|
return getName(true);
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getClass() != obj.getClass())
|
public String getName(boolean withVersion) {
|
||||||
{
|
StringBuilder id = new StringBuilder(name);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PluginInformation other = (PluginInformation) obj;
|
if (withVersion) {
|
||||||
|
|
||||||
//J-
|
|
||||||
return Objects.equal(artifactId, other.artifactId)
|
|
||||||
&& Objects.equal(author, other.author)
|
|
||||||
&& Objects.equal(category, other.category)
|
|
||||||
&& Objects.equal(tags, other.tags)
|
|
||||||
&& Objects.equal(condition, other.condition)
|
|
||||||
&& Objects.equal(description, other.description)
|
|
||||||
&& Objects.equal(groupId, other.groupId)
|
|
||||||
&& Objects.equal(name, other.name)
|
|
||||||
&& Objects.equal(screenshots, other.screenshots)
|
|
||||||
&& Objects.equal(state, other.state)
|
|
||||||
&& Objects.equal(url, other.url)
|
|
||||||
&& Objects.equal(version, other.version)
|
|
||||||
&& Objects.equal(wiki, other.wiki);
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hashCode(artifactId, author, category, tags, condition,
|
|
||||||
description, groupId, name, screenshots, state, url, version, wiki);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
//J-
|
|
||||||
return MoreObjects.toStringHelper(this)
|
|
||||||
.add("artifactId", artifactId)
|
|
||||||
.add("author", author)
|
|
||||||
.add("category", category)
|
|
||||||
.add("tags", tags)
|
|
||||||
.add("condition", condition)
|
|
||||||
.add("description", description)
|
|
||||||
.add("groupId", groupId)
|
|
||||||
.add("name", name)
|
|
||||||
.add("screenshots", screenshots)
|
|
||||||
.add("state", state)
|
|
||||||
.add("url", url)
|
|
||||||
.add("version", version)
|
|
||||||
.add("wiki", wiki)
|
|
||||||
.toString();
|
|
||||||
//J+
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getArtifactId()
|
|
||||||
{
|
|
||||||
return artifactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getAuthor()
|
|
||||||
{
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getCategory()
|
|
||||||
{
|
|
||||||
return category;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public PluginCondition getCondition()
|
|
||||||
{
|
|
||||||
return condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getDescription()
|
|
||||||
{
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getGroupId()
|
|
||||||
{
|
|
||||||
return groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getId()
|
|
||||||
{
|
|
||||||
return getId(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param withVersion
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @since 1.21
|
|
||||||
*/
|
|
||||||
public String getId(boolean withVersion)
|
|
||||||
{
|
|
||||||
StringBuilder id = new StringBuilder(groupId);
|
|
||||||
|
|
||||||
id.append(":").append(artifactId);
|
|
||||||
|
|
||||||
if (withVersion)
|
|
||||||
{
|
|
||||||
id.append(":").append(version);
|
id.append(":").append(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
return id.toString();
|
return id.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<String> getScreenshots()
|
|
||||||
{
|
|
||||||
return screenshots;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public PluginState getState()
|
|
||||||
{
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<String> getTags()
|
|
||||||
{
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getUrl()
|
|
||||||
{
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getVersion()
|
|
||||||
{
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getWiki()
|
|
||||||
{
|
|
||||||
return wiki;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid()
|
public boolean isValid() {
|
||||||
{
|
return Util.isNotEmpty(name) && Util.isNotEmpty(version);
|
||||||
return Util.isNotEmpty(groupId) && Util.isNotEmpty(artifactId)
|
|
||||||
&& Util.isNotEmpty(name) && Util.isNotEmpty(version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- set methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param artifactId
|
|
||||||
*/
|
|
||||||
public void setArtifactId(String artifactId)
|
|
||||||
{
|
|
||||||
this.artifactId = artifactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param author
|
|
||||||
*/
|
|
||||||
public void setAuthor(String author)
|
|
||||||
{
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param category
|
|
||||||
*/
|
|
||||||
public void setCategory(String category)
|
|
||||||
{
|
|
||||||
this.category = category;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param condition
|
|
||||||
*/
|
|
||||||
public void setCondition(PluginCondition condition)
|
|
||||||
{
|
|
||||||
this.condition = condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param description
|
|
||||||
*/
|
|
||||||
public void setDescription(String description)
|
|
||||||
{
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param groupId
|
|
||||||
*/
|
|
||||||
public void setGroupId(String groupId)
|
|
||||||
{
|
|
||||||
this.groupId = groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
*/
|
|
||||||
public void setName(String name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param screenshots
|
|
||||||
*/
|
|
||||||
public void setScreenshots(List<String> screenshots)
|
|
||||||
{
|
|
||||||
this.screenshots = screenshots;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
public void setState(PluginState state)
|
|
||||||
{
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param tags
|
|
||||||
*/
|
|
||||||
public void setTags(List<String> tags)
|
|
||||||
{
|
|
||||||
this.tags = tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
*/
|
|
||||||
public void setUrl(String url)
|
|
||||||
{
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param version
|
|
||||||
*/
|
|
||||||
public void setVersion(String version)
|
|
||||||
{
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param wiki
|
|
||||||
*/
|
|
||||||
public void setWiki(String wiki)
|
|
||||||
{
|
|
||||||
this.wiki = wiki;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String artifactId;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String author;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String category;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private PluginCondition condition;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String groupId;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "screenshot")
|
|
||||||
@XmlElementWrapper(name = "screenshots")
|
|
||||||
private List<String> screenshots;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private PluginState state;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
@XmlElement(name = "tag")
|
|
||||||
@XmlElementWrapper(name = "tags")
|
|
||||||
private List<String> tags;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String wiki;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,106 +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.plugin;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import sonia.scm.util.Util;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public class PluginInformationComparator
|
|
||||||
implements Comparator<PluginInformation>, Serializable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
public static final PluginInformationComparator INSTANCE =
|
|
||||||
new PluginInformationComparator();
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = -8339752498853225668L;
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param plugin
|
|
||||||
* @param other
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int compare(PluginInformation plugin, PluginInformation other)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
result = Util.compare(plugin.getGroupId(), other.getGroupId());
|
|
||||||
|
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
result = Util.compare(plugin.getArtifactId(), other.getArtifactId());
|
|
||||||
|
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
PluginState state = plugin.getState();
|
|
||||||
PluginState otherState = other.getState();
|
|
||||||
|
|
||||||
if ((state != null) && (otherState != null))
|
|
||||||
{
|
|
||||||
result = state.getCompareValue() - otherState.getCompareValue();
|
|
||||||
}
|
|
||||||
else if ((state == null) && (otherState != null))
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
else if ((state != null) && (otherState == null))
|
|
||||||
{
|
|
||||||
result = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -68,7 +68,7 @@ public interface PluginLoader
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Collection<PluginWrapper> getInstalledPlugins();
|
public Collection<InstalledPlugin> getInstalledPlugins();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link ClassLoader} which is able to load classes and resources
|
* Returns a {@link ClassLoader} which is able to load classes and resources
|
||||||
|
|||||||
@@ -33,113 +33,56 @@
|
|||||||
|
|
||||||
package sonia.scm.plugin;
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The plugin manager is responsible for plugin related tasks, such as install, uninstall or updating.
|
||||||
*
|
*
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
*/
|
*/
|
||||||
public interface PluginManager
|
public interface PluginManager {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Returns the available plugin with the given name.
|
||||||
*
|
* @param name of plugin
|
||||||
|
* @return optional available plugin.
|
||||||
*/
|
*/
|
||||||
public void clearCache();
|
Optional<AvailablePlugin> getAvailable(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Returns the installed plugin with the given name.
|
||||||
*
|
* @param name of plugin
|
||||||
*
|
* @return optional installed plugin.
|
||||||
* @param id
|
|
||||||
*/
|
*/
|
||||||
public void install(String id);
|
Optional<InstalledPlugin> getInstalled(String name);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs a plugin package from a inputstream.
|
* Returns all installed plugins.
|
||||||
*
|
*
|
||||||
*
|
* @return a list of installed plugins.
|
||||||
* @param packageStream package input stream
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @since 1.21
|
|
||||||
*/
|
*/
|
||||||
public void installPackage(InputStream packageStream) throws IOException;
|
List<InstalledPlugin> getInstalled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Returns all available plugins. The list contains the plugins which are loaded from the plugin center, but without
|
||||||
|
* the installed plugins.
|
||||||
*
|
*
|
||||||
*
|
* @return a list of available plugins.
|
||||||
* @param id
|
|
||||||
*/
|
*/
|
||||||
public void uninstall(String id);
|
List<AvailablePlugin> getAvailable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Installs the plugin with the given name from the list of available plugins.
|
||||||
*
|
*
|
||||||
*
|
* @param name plugin name
|
||||||
* @param id
|
* @param restartAfterInstallation restart context after plugin installation
|
||||||
*/
|
*/
|
||||||
public void update(String id);
|
void install(String name, boolean restartAfterInstallation);
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Install all pending plugins and restart the scm context.
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public PluginInformation get(String id);
|
void installPendingAndRestart();
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param filter
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<PluginInformation> get(Predicate<PluginInformation> filter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<PluginInformation> getAll();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<PluginInformation> getAvailable();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<PluginInformation> getAvailableUpdates();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<PluginInformation> getInstalled();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,160 +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.plugin;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class PluginRepository implements Serializable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = -9504354306304731L;
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
PluginRepository() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* @param url
|
|
||||||
*/
|
|
||||||
public PluginRepository(String id, String url)
|
|
||||||
{
|
|
||||||
this.id = id;
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param obj
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PluginRepository other = (PluginRepository) obj;
|
|
||||||
|
|
||||||
return Objects.equal(id, other.id) && Objects.equal(url, other.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return Objects.hashCode(id, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return MoreObjects.toStringHelper(this).add("id", id).add("url",
|
|
||||||
url).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getId()
|
|
||||||
{
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getUrl()
|
|
||||||
{
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private String url;
|
|
||||||
}
|
|
||||||
@@ -1,74 +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.plugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public enum PluginState
|
|
||||||
{
|
|
||||||
CORE(100), AVAILABLE(60), INSTALLED(80), NEWER_VERSION_INSTALLED(20),
|
|
||||||
UPDATE_AVAILABLE(40);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param compareValue
|
|
||||||
*/
|
|
||||||
private PluginState(int compareValue)
|
|
||||||
{
|
|
||||||
this.compareValue = compareValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @since 1.6
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public int getCompareValue()
|
|
||||||
{
|
|
||||||
return compareValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final int compareValue;
|
|
||||||
}
|
|
||||||
@@ -65,7 +65,7 @@ public final class Plugins
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
context = JAXBContext.newInstance(Plugin.class, ScmModule.class);
|
context = JAXBContext.newInstance(InstalledPluginDescriptor.class, ScmModule.class);
|
||||||
}
|
}
|
||||||
catch (JAXBException ex)
|
catch (JAXBException ex)
|
||||||
{
|
{
|
||||||
@@ -91,7 +91,7 @@ public final class Plugins
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Plugin parsePluginDescriptor(Path path)
|
public static InstalledPluginDescriptor parsePluginDescriptor(Path path)
|
||||||
{
|
{
|
||||||
return parsePluginDescriptor(Files.asByteSource(path.toFile()));
|
return parsePluginDescriptor(Files.asByteSource(path.toFile()));
|
||||||
}
|
}
|
||||||
@@ -104,15 +104,15 @@ public final class Plugins
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Plugin parsePluginDescriptor(ByteSource data)
|
public static InstalledPluginDescriptor parsePluginDescriptor(ByteSource data)
|
||||||
{
|
{
|
||||||
Preconditions.checkNotNull(data, "data parameter is required");
|
Preconditions.checkNotNull(data, "data parameter is required");
|
||||||
|
|
||||||
Plugin plugin;
|
InstalledPluginDescriptor plugin;
|
||||||
|
|
||||||
try (InputStream stream = data.openStream())
|
try (InputStream stream = data.openStream())
|
||||||
{
|
{
|
||||||
plugin = (Plugin) context.createUnmarshaller().unmarshal(stream);
|
plugin = (InstalledPluginDescriptor) context.createUnmarshaller().unmarshal(stream);
|
||||||
}
|
}
|
||||||
catch (JAXBException ex)
|
catch (JAXBException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public final class SmpArchive
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public Plugin getPlugin() throws IOException
|
public InstalledPluginDescriptor getPlugin() throws IOException
|
||||||
{
|
{
|
||||||
if (plugin == null)
|
if (plugin == null)
|
||||||
{
|
{
|
||||||
@@ -219,16 +219,10 @@ public final class SmpArchive
|
|||||||
throw new PluginException("could not find information section");
|
throw new PluginException("could not find information section");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(info.getGroupId()))
|
if (Strings.isNullOrEmpty(info.getName()))
|
||||||
{
|
{
|
||||||
throw new PluginException(
|
throw new PluginException(
|
||||||
"could not find groupId in plugin descriptor");
|
"could not find name in plugin descriptor");
|
||||||
}
|
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(info.getArtifactId()))
|
|
||||||
{
|
|
||||||
throw new PluginException(
|
|
||||||
"could not find artifactId in plugin descriptor");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(info.getVersion()))
|
if (Strings.isNullOrEmpty(info.getVersion()))
|
||||||
@@ -251,9 +245,9 @@ public final class SmpArchive
|
|||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private Plugin createPlugin() throws IOException
|
private InstalledPluginDescriptor createPlugin() throws IOException
|
||||||
{
|
{
|
||||||
Plugin p = null;
|
InstalledPluginDescriptor p = null;
|
||||||
NonClosingZipInputStream zis = null;
|
NonClosingZipInputStream zis = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -418,5 +412,5 @@ public final class SmpArchive
|
|||||||
private final ByteSource archive;
|
private final ByteSource archive;
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private Plugin plugin;
|
private InstalledPluginDescriptor plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +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.plugin;
|
|
||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*/
|
|
||||||
public class StatePluginPredicate implements Predicate<PluginInformation>
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param state
|
|
||||||
*/
|
|
||||||
public StatePluginPredicate(PluginState state)
|
|
||||||
{
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param plugin
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean apply(PluginInformation plugin)
|
|
||||||
{
|
|
||||||
return state == plugin.getState();
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final PluginState state;
|
|
||||||
}
|
|
||||||
@@ -82,10 +82,9 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
private String namespace;
|
private String namespace;
|
||||||
private String name;
|
private String name;
|
||||||
@XmlElement(name = "permission")
|
@XmlElement(name = "permission")
|
||||||
private final Set<RepositoryPermission> permissions = new HashSet<>();
|
private Set<RepositoryPermission> permissions = new HashSet<>();
|
||||||
@XmlElement(name = "public")
|
@XmlElement(name = "public")
|
||||||
private boolean publicReadable = false;
|
private boolean publicReadable = false;
|
||||||
private boolean archived = false;
|
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
|
||||||
@@ -216,16 +215,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the repository is archived.
|
|
||||||
*
|
|
||||||
* @return true if the repository is archived
|
|
||||||
* @since 1.14
|
|
||||||
*/
|
|
||||||
public boolean isArchived() {
|
|
||||||
return archived;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if the repository is healthy.
|
* Returns {@code true} if the repository is healthy.
|
||||||
*
|
*
|
||||||
@@ -264,16 +253,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
&& ((Util.isEmpty(contact)) || ValidationUtil.isMailAddressValid(contact));
|
&& ((Util.isEmpty(contact)) || ValidationUtil.isMailAddressValid(contact));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Archive or un archive this repository.
|
|
||||||
*
|
|
||||||
* @param archived true to enable archive
|
|
||||||
* @since 1.14
|
|
||||||
*/
|
|
||||||
public void setArchived(boolean archived) {
|
|
||||||
this.archived = archived;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setContact(String contact) {
|
public void setContact(String contact) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
}
|
}
|
||||||
@@ -331,6 +310,8 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
repository = (Repository) super.clone();
|
repository = (Repository) super.clone();
|
||||||
|
// fix permission reference on clone
|
||||||
|
repository.permissions = new HashSet<>(permissions);
|
||||||
} catch (CloneNotSupportedException ex) {
|
} catch (CloneNotSupportedException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
@@ -352,7 +333,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
repository.setDescription(description);
|
repository.setDescription(description);
|
||||||
repository.setPermissions(permissions);
|
repository.setPermissions(permissions);
|
||||||
repository.setPublicReadable(publicReadable);
|
repository.setPublicReadable(publicReadable);
|
||||||
repository.setArchived(archived);
|
|
||||||
|
|
||||||
// do not copy health check results
|
// do not copy health check results
|
||||||
}
|
}
|
||||||
@@ -381,7 +361,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
&& Objects.equal(contact, other.contact)
|
&& Objects.equal(contact, other.contact)
|
||||||
&& Objects.equal(description, other.description)
|
&& Objects.equal(description, other.description)
|
||||||
&& Objects.equal(publicReadable, other.publicReadable)
|
&& Objects.equal(publicReadable, other.publicReadable)
|
||||||
&& Objects.equal(archived, other.archived)
|
|
||||||
&& Objects.equal(permissions, other.permissions)
|
&& Objects.equal(permissions, other.permissions)
|
||||||
&& Objects.equal(type, other.type)
|
&& Objects.equal(type, other.type)
|
||||||
&& Objects.equal(creationDate, other.creationDate)
|
&& Objects.equal(creationDate, other.creationDate)
|
||||||
@@ -393,7 +372,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hashCode(id, namespace, name, contact, description, publicReadable,
|
return Objects.hashCode(id, namespace, name, contact, description, publicReadable,
|
||||||
archived, permissions, type, creationDate, lastModified, properties,
|
permissions, type, creationDate, lastModified, properties,
|
||||||
healthCheckFailures);
|
healthCheckFailures);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +385,6 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
.add("contact", contact)
|
.add("contact", contact)
|
||||||
.add("description", description)
|
.add("description", description)
|
||||||
.add("publicReadable", publicReadable)
|
.add("publicReadable", publicReadable)
|
||||||
.add("archived", archived)
|
|
||||||
.add("permissions", permissions)
|
.add("permissions", permissions)
|
||||||
.add("type", type)
|
.add("type", type)
|
||||||
.add("lastModified", lastModified)
|
.add("lastModified", lastModified)
|
||||||
|
|||||||
@@ -1,48 +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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sebastian Sdorra
|
|
||||||
*
|
|
||||||
* @since 1.14
|
|
||||||
*/
|
|
||||||
public class RepositoryIsNotArchivedException extends RuntimeException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 7728748133123987511L;
|
|
||||||
|
|
||||||
public RepositoryIsNotArchivedException() {
|
|
||||||
super("Repository could not be deleted, because it is not archived.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
import sonia.scm.FeatureNotSupportedException;
|
||||||
|
import sonia.scm.repository.Feature;
|
||||||
|
import sonia.scm.repository.spi.DiffCommandRequest;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
abstract class AbstractDiffCommandBuilder <T extends AbstractDiffCommandBuilder> {
|
||||||
|
|
||||||
|
|
||||||
|
/** request for the diff command implementation */
|
||||||
|
final DiffCommandRequest request = new DiffCommandRequest();
|
||||||
|
|
||||||
|
private final Set<Feature> supportedFeatures;
|
||||||
|
|
||||||
|
AbstractDiffCommandBuilder(Set<Feature> supportedFeatures) {
|
||||||
|
this.supportedFeatures = supportedFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the incoming changes of the branch set with {@link #setRevision(String)} in respect to the changeset given
|
||||||
|
* here. In other words: What changes would be new to the ancestor changeset given here when the branch would
|
||||||
|
* be merged into it. Requires feature {@link sonia.scm.repository.Feature#INCOMING_REVISION}!
|
||||||
|
*
|
||||||
|
* @return {@code this}
|
||||||
|
*/
|
||||||
|
public T setAncestorChangeset(String revision)
|
||||||
|
{
|
||||||
|
if (!supportedFeatures.contains(Feature.INCOMING_REVISION)) {
|
||||||
|
throw new FeatureNotSupportedException(Feature.INCOMING_REVISION.name());
|
||||||
|
}
|
||||||
|
request.setAncestorChangeset(revision);
|
||||||
|
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the difference only for the given path.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param path path for difference
|
||||||
|
*
|
||||||
|
* @return {@code this}
|
||||||
|
*/
|
||||||
|
public T setPath(String path)
|
||||||
|
{
|
||||||
|
request.setPath(path);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the difference only for the given revision or (using {@link #setAncestorChangeset(String)}) between this
|
||||||
|
* and another revision.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param revision revision for difference
|
||||||
|
*
|
||||||
|
* @return {@code this}
|
||||||
|
*/
|
||||||
|
public T setRevision(String revision)
|
||||||
|
{
|
||||||
|
request.setRevision(revision);
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract T self();
|
||||||
|
}
|
||||||
@@ -53,11 +53,6 @@ public enum Command
|
|||||||
*/
|
*/
|
||||||
BRANCHES,
|
BRANCHES,
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
BRANCH,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.31
|
* @since 1.31
|
||||||
*/
|
*/
|
||||||
@@ -71,10 +66,5 @@ public enum Command
|
|||||||
/**
|
/**
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
MODIFICATIONS,
|
MODIFICATIONS, MERGE, DIFF_RESULT, BRANCH;
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
MERGE
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,8 @@ package sonia.scm.repository.api;
|
|||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.FeatureNotSupportedException;
|
|
||||||
import sonia.scm.repository.Feature;
|
import sonia.scm.repository.Feature;
|
||||||
import sonia.scm.repository.spi.DiffCommand;
|
import sonia.scm.repository.spi.DiffCommand;
|
||||||
import sonia.scm.repository.spi.DiffCommandRequest;
|
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -72,7 +70,7 @@ import java.util.Set;
|
|||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
* @since 1.17
|
* @since 1.17
|
||||||
*/
|
*/
|
||||||
public final class DiffCommandBuilder
|
public final class DiffCommandBuilder extends AbstractDiffCommandBuilder<DiffCommandBuilder>
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,6 +79,9 @@ public final class DiffCommandBuilder
|
|||||||
private static final Logger logger =
|
private static final Logger logger =
|
||||||
LoggerFactory.getLogger(DiffCommandBuilder.class);
|
LoggerFactory.getLogger(DiffCommandBuilder.class);
|
||||||
|
|
||||||
|
/** implementation of the diff command */
|
||||||
|
private final DiffCommand diffCommand;
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,8 +93,8 @@ public final class DiffCommandBuilder
|
|||||||
*/
|
*/
|
||||||
DiffCommandBuilder(DiffCommand diffCommand, Set<Feature> supportedFeatures)
|
DiffCommandBuilder(DiffCommand diffCommand, Set<Feature> supportedFeatures)
|
||||||
{
|
{
|
||||||
|
super(supportedFeatures);
|
||||||
this.diffCommand = diffCommand;
|
this.diffCommand = diffCommand;
|
||||||
this.supportedFeatures = supportedFeatures;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -162,54 +163,6 @@ public final class DiffCommandBuilder
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the difference only for the given path.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param path path for difference
|
|
||||||
*
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
public DiffCommandBuilder setPath(String path)
|
|
||||||
{
|
|
||||||
request.setPath(path);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the difference only for the given revision or (using {@link #setAncestorChangeset(String)}) between this
|
|
||||||
* and another revision.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param revision revision for difference
|
|
||||||
*
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
public DiffCommandBuilder setRevision(String revision)
|
|
||||||
{
|
|
||||||
request.setRevision(revision);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Compute the incoming changes of the branch set with {@link #setRevision(String)} in respect to the changeset given
|
|
||||||
* here. In other words: What changes would be new to the ancestor changeset given here when the branch would
|
|
||||||
* be merged into it. Requires feature {@link sonia.scm.repository.Feature#INCOMING_REVISION}!
|
|
||||||
*
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
public DiffCommandBuilder setAncestorChangeset(String revision)
|
|
||||||
{
|
|
||||||
if (!supportedFeatures.contains(Feature.INCOMING_REVISION)) {
|
|
||||||
throw new FeatureNotSupportedException(Feature.INCOMING_REVISION.name());
|
|
||||||
}
|
|
||||||
request.setAncestorChangeset(revision);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,12 +186,8 @@ public final class DiffCommandBuilder
|
|||||||
diffCommand.getDiffResult(request, outputStream);
|
diffCommand.getDiffResult(request, outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
@Override
|
||||||
|
DiffCommandBuilder self() {
|
||||||
/** implementation of the diff command */
|
return this;
|
||||||
private final DiffCommand diffCommand;
|
}
|
||||||
private Set<Feature> supportedFeatures;
|
|
||||||
|
|
||||||
/** request for the diff command implementation */
|
|
||||||
private final DiffCommandRequest request = new DiffCommandRequest();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
public interface DiffFile extends Iterable<Hunk> {
|
||||||
|
|
||||||
|
String getOldRevision();
|
||||||
|
|
||||||
|
String getNewRevision();
|
||||||
|
|
||||||
|
String getOldPath();
|
||||||
|
|
||||||
|
String getNewPath();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
public interface DiffLine {
|
||||||
|
|
||||||
|
OptionalInt getOldLineNumber();
|
||||||
|
|
||||||
|
OptionalInt getNewLineNumber();
|
||||||
|
|
||||||
|
String getContent();
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
public interface DiffResult extends Iterable<DiffFile> {
|
||||||
|
|
||||||
|
String getOldRevision();
|
||||||
|
|
||||||
|
String getNewRevision();
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.repository.Feature;
|
||||||
|
import sonia.scm.repository.spi.DiffResultCommand;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class DiffResultCommandBuilder extends AbstractDiffCommandBuilder<DiffResultCommandBuilder> {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DiffResultCommandBuilder.class);
|
||||||
|
|
||||||
|
private final DiffResultCommand diffResultCommand;
|
||||||
|
|
||||||
|
DiffResultCommandBuilder(DiffResultCommand diffResultCommand, Set<Feature> supportedFeatures) {
|
||||||
|
super(supportedFeatures);
|
||||||
|
this.diffResultCommand = diffResultCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of the difference as parsed objects.
|
||||||
|
*
|
||||||
|
* @return content of the difference
|
||||||
|
*/
|
||||||
|
public DiffResult getDiffResult() throws IOException {
|
||||||
|
Preconditions.checkArgument(request.isValid(),
|
||||||
|
"path and/or revision is required");
|
||||||
|
|
||||||
|
LOG.debug("create diff result for {}", request);
|
||||||
|
|
||||||
|
return diffResultCommand.getDiffResult(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
DiffResultCommandBuilder self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
scm-core/src/main/java/sonia/scm/repository/api/Hunk.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
public interface Hunk extends Iterable<DiffLine> {
|
||||||
|
|
||||||
|
default String getRawHeader() {
|
||||||
|
return String.format("@@ -%s +%s @@", getLineMarker(getOldStart(), getOldLineCount()), getLineMarker(getNewStart(), getNewLineCount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
default String getLineMarker(int start, int lineCount) {
|
||||||
|
if (lineCount == 1) {
|
||||||
|
return Integer.toString(start);
|
||||||
|
} else {
|
||||||
|
return String.format("%s,%s", start, lineCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getOldStart();
|
||||||
|
|
||||||
|
int getOldLineCount();
|
||||||
|
|
||||||
|
int getNewStart();
|
||||||
|
|
||||||
|
int getNewLineCount();
|
||||||
|
}
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
package sonia.scm.repository.api;
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.cache.CacheManager;
|
import sonia.scm.cache.CacheManager;
|
||||||
@@ -239,6 +238,21 @@ public final class RepositoryService implements Closeable {
|
|||||||
return new DiffCommandBuilder(provider.getDiffCommand(), provider.getSupportedFeatures());
|
return new DiffCommandBuilder(provider.getDiffCommand(), provider.getSupportedFeatures());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The diff command shows differences between revisions for a specified file
|
||||||
|
* or the entire revision.
|
||||||
|
*
|
||||||
|
* @return instance of {@link DiffResultCommandBuilder}
|
||||||
|
* @throws CommandNotSupportedException if the command is not supported
|
||||||
|
* by the implementation of the repository service provider.
|
||||||
|
*/
|
||||||
|
public DiffResultCommandBuilder getDiffResultCommand() {
|
||||||
|
LOG.debug("create diff result command for repository {}",
|
||||||
|
repository.getNamespaceAndName());
|
||||||
|
|
||||||
|
return new DiffResultCommandBuilder(provider.getDiffResultCommand(), provider.getSupportedFeatures());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The incoming command shows new {@link Changeset}s found in a different
|
* The incoming command shows new {@link Changeset}s found in a different
|
||||||
* repository location.
|
* repository location.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import sonia.scm.repository.api.DiffResult;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface DiffResultCommand {
|
||||||
|
DiffResult getDiffResult(DiffCommandRequest request) throws IOException;
|
||||||
|
}
|
||||||
@@ -158,6 +158,11 @@ public abstract class RepositoryServiceProvider implements Closeable
|
|||||||
throw new CommandNotSupportedException(Command.DIFF);
|
throw new CommandNotSupportedException(Command.DIFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DiffResultCommand getDiffResultCommand()
|
||||||
|
{
|
||||||
|
throw new CommandNotSupportedException(Command.DIFF_RESULT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -99,15 +99,6 @@ public interface AccessTokenBuilder {
|
|||||||
*/
|
*/
|
||||||
AccessTokenBuilder scope(Scope scope);
|
AccessTokenBuilder scope(Scope scope);
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the logged in user as member of the given groups.
|
|
||||||
*
|
|
||||||
* @param groups group names
|
|
||||||
*
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
|
||||||
AccessTokenBuilder groups(String... groups);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link AccessToken} with the provided settings.
|
* Creates a new {@link AccessToken} with the provided settings.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ import org.apache.shiro.authc.credential.CredentialsMatcher;
|
|||||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.group.GroupDAO;
|
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserDAO;
|
import sonia.scm.user.UserDAO;
|
||||||
|
|
||||||
@@ -71,8 +70,6 @@ public final class DAORealmHelper {
|
|||||||
|
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
|
|
||||||
private final GroupCollector groupCollector;
|
|
||||||
|
|
||||||
private final String realm;
|
private final String realm;
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
//~--- constructors ---------------------------------------------------------
|
||||||
@@ -83,14 +80,12 @@ public final class DAORealmHelper {
|
|||||||
*
|
*
|
||||||
* @param loginAttemptHandler login attempt handler for wrapping credentials matcher
|
* @param loginAttemptHandler login attempt handler for wrapping credentials matcher
|
||||||
* @param userDAO user dao
|
* @param userDAO user dao
|
||||||
* @param groupCollector collect groups for a principal
|
|
||||||
* @param realm name of realm
|
* @param realm name of realm
|
||||||
*/
|
*/
|
||||||
public DAORealmHelper(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, GroupCollector groupCollector, String realm) {
|
public DAORealmHelper(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, String realm) {
|
||||||
this.loginAttemptHandler = loginAttemptHandler;
|
this.loginAttemptHandler = loginAttemptHandler;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
this.groupCollector = groupCollector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
@@ -120,7 +115,7 @@ public final class DAORealmHelper {
|
|||||||
UsernamePasswordToken upt = (UsernamePasswordToken) token;
|
UsernamePasswordToken upt = (UsernamePasswordToken) token;
|
||||||
String principal = upt.getUsername();
|
String principal = upt.getUsername();
|
||||||
|
|
||||||
return getAuthenticationInfo(principal, null, null, Collections.emptySet());
|
return getAuthenticationInfo(principal, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,7 +130,7 @@ public final class DAORealmHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AuthenticationInfo getAuthenticationInfo(String principal, String credentials, Scope scope, Iterable<String> groups) {
|
private AuthenticationInfo getAuthenticationInfo(String principal, String credentials, Scope scope) {
|
||||||
checkArgument(!Strings.isNullOrEmpty(principal), "username is required");
|
checkArgument(!Strings.isNullOrEmpty(principal), "username is required");
|
||||||
|
|
||||||
LOG.debug("try to authenticate {}", principal);
|
LOG.debug("try to authenticate {}", principal);
|
||||||
@@ -153,7 +148,6 @@ public final class DAORealmHelper {
|
|||||||
|
|
||||||
collection.add(principal, realm);
|
collection.add(principal, realm);
|
||||||
collection.add(user, realm);
|
collection.add(user, realm);
|
||||||
collection.add(groupCollector.collect(principal, groups), realm);
|
|
||||||
collection.add(MoreObjects.firstNonNull(scope, Scope.empty()), realm);
|
collection.add(MoreObjects.firstNonNull(scope, Scope.empty()), realm);
|
||||||
|
|
||||||
String creds = credentials;
|
String creds = credentials;
|
||||||
@@ -207,17 +201,17 @@ public final class DAORealmHelper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* With groups adds extra groups, besides those which come from the {@link GroupDAO}, to the authentication info.
|
// * With groups adds extra groups, besides those which come from the {@link GroupDAO}, to the authentication info.
|
||||||
*
|
// *
|
||||||
* @param groups extra groups
|
// * @param groups extra groups
|
||||||
*
|
// *
|
||||||
* @return {@code this}
|
// * @return {@code this}
|
||||||
*/
|
// */
|
||||||
public AuthenticationInfoBuilder withGroups(Iterable<String> groups) {
|
// public AuthenticationInfoBuilder withGroups(Iterable<String> groups) {
|
||||||
this.groups = groups;
|
// this.groups = groups;
|
||||||
return this;
|
// return this;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build creates the authentication info from the given information.
|
* Build creates the authentication info from the given information.
|
||||||
@@ -225,7 +219,7 @@ public final class DAORealmHelper {
|
|||||||
* @return authentication info
|
* @return authentication info
|
||||||
*/
|
*/
|
||||||
public AuthenticationInfo build() {
|
public AuthenticationInfo build() {
|
||||||
return getAuthenticationInfo(principal, credentials, scope, groups);
|
return getAuthenticationInfo(principal, credentials, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
package sonia.scm.security;
|
package sonia.scm.security;
|
||||||
|
|
||||||
import sonia.scm.group.GroupDAO;
|
import sonia.scm.cache.CacheManager;
|
||||||
import sonia.scm.user.UserDAO;
|
import sonia.scm.user.UserDAO;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -45,20 +45,19 @@ public final class DAORealmHelperFactory {
|
|||||||
|
|
||||||
private final LoginAttemptHandler loginAttemptHandler;
|
private final LoginAttemptHandler loginAttemptHandler;
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
private final GroupCollector groupCollector;
|
private final CacheManager cacheManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance.
|
* Constructs a new instance.
|
||||||
*
|
|
||||||
* @param loginAttemptHandler login attempt handler
|
* @param loginAttemptHandler login attempt handler
|
||||||
* @param userDAO user dao
|
* @param userDAO user dao
|
||||||
* @param groupDAO group dao
|
* @param cacheManager
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public DAORealmHelperFactory(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, GroupDAO groupDAO) {
|
public DAORealmHelperFactory(LoginAttemptHandler loginAttemptHandler, UserDAO userDAO, CacheManager cacheManager) {
|
||||||
this.loginAttemptHandler = loginAttemptHandler;
|
this.loginAttemptHandler = loginAttemptHandler;
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
this.groupCollector = new GroupCollector(groupDAO);
|
this.cacheManager = cacheManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +68,7 @@ public final class DAORealmHelperFactory {
|
|||||||
* @return new {@link DAORealmHelper} instance.
|
* @return new {@link DAORealmHelper} instance.
|
||||||
*/
|
*/
|
||||||
public DAORealmHelper create(String realm) {
|
public DAORealmHelper create(String realm) {
|
||||||
return new DAORealmHelper(loginAttemptHandler, userDAO, groupCollector, realm);
|
return new DAORealmHelper(loginAttemptHandler, userDAO, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupDAO;
|
|
||||||
import sonia.scm.group.GroupNames;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collect groups for a certain principal.
|
|
||||||
* <strong>Warning</strong>: The class is only for internal use and should never used directly.
|
|
||||||
*/
|
|
||||||
class GroupCollector {
|
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(GroupCollector.class);
|
|
||||||
|
|
||||||
private final GroupDAO groupDAO;
|
|
||||||
|
|
||||||
GroupCollector(GroupDAO groupDAO) {
|
|
||||||
this.groupDAO = groupDAO;
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupNames collect(String principal, Iterable<String> groupNames) {
|
|
||||||
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
|
|
||||||
|
|
||||||
builder.add(GroupNames.AUTHENTICATED);
|
|
||||||
|
|
||||||
for (String group : groupNames) {
|
|
||||||
builder.add(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Group group : groupDAO.getAll()) {
|
|
||||||
if (group.isMember(principal)) {
|
|
||||||
builder.add(group.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupNames groups = new GroupNames(builder.build());
|
|
||||||
LOG.debug("collected following groups for principal {}: {}", principal, groups);
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,24 +32,15 @@ import com.google.inject.Inject;
|
|||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import sonia.scm.AlreadyExistsException;
|
import sonia.scm.AlreadyExistsException;
|
||||||
import sonia.scm.NotFoundException;
|
import sonia.scm.NotFoundException;
|
||||||
import sonia.scm.group.ExternalGroupNames;
|
|
||||||
import sonia.scm.group.Group;
|
import sonia.scm.group.Group;
|
||||||
import sonia.scm.group.GroupDAO;
|
|
||||||
import sonia.scm.group.GroupManager;
|
import sonia.scm.group.GroupManager;
|
||||||
import sonia.scm.plugin.Extension;
|
import sonia.scm.plugin.Extension;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserManager;
|
import sonia.scm.user.UserManager;
|
||||||
import sonia.scm.web.security.AdministrationContext;
|
import sonia.scm.web.security.AdministrationContext;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for syncing realms. The class should simplify the creation of realms, which are syncing authenticated
|
* Helper class for syncing realms. The class should simplify the creation of realms, which are syncing authenticated
|
||||||
* users with the local database.
|
* users with the local database.
|
||||||
@@ -60,12 +51,9 @@ import static java.util.Arrays.asList;
|
|||||||
@Extension
|
@Extension
|
||||||
public final class SyncingRealmHelper {
|
public final class SyncingRealmHelper {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SyncingRealmHelper.class);
|
|
||||||
|
|
||||||
private final AdministrationContext ctx;
|
private final AdministrationContext ctx;
|
||||||
private final UserManager userManager;
|
private final UserManager userManager;
|
||||||
private final GroupManager groupManager;
|
private final GroupManager groupManager;
|
||||||
private final GroupCollector groupCollector;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new SyncingRealmHelper.
|
* Constructs a new SyncingRealmHelper.
|
||||||
@@ -73,134 +61,28 @@ public final class SyncingRealmHelper {
|
|||||||
* @param ctx administration context
|
* @param ctx administration context
|
||||||
* @param userManager user manager
|
* @param userManager user manager
|
||||||
* @param groupManager group manager
|
* @param groupManager group manager
|
||||||
* @param groupDAO group dao
|
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager, GroupDAO groupDAO) {
|
public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.userManager = userManager;
|
this.userManager = userManager;
|
||||||
this.groupManager = groupManager;
|
this.groupManager = groupManager;
|
||||||
this.groupCollector = new GroupCollector(groupDAO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create {@link AuthenticationInfo} from user and groups.
|
|
||||||
*/
|
|
||||||
public AuthenticationInfoBuilder.ForRealm authenticationInfo() {
|
|
||||||
return new AuthenticationInfoBuilder().new ForRealm();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AuthenticationInfoBuilder {
|
|
||||||
private String realm;
|
|
||||||
private User user;
|
|
||||||
private Collection<String> groups = Collections.emptySet();
|
|
||||||
private Collection<String> externalGroups = Collections.emptySet();
|
|
||||||
|
|
||||||
private AuthenticationInfo build() {
|
|
||||||
return SyncingRealmHelper.this.createAuthenticationInfo(realm, user, groups, externalGroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ForRealm {
|
|
||||||
private ForRealm() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the realm.
|
|
||||||
* @param realm name of the realm
|
|
||||||
*/
|
|
||||||
public ForUser forRealm(String realm) {
|
|
||||||
AuthenticationInfoBuilder.this.realm = realm;
|
|
||||||
return AuthenticationInfoBuilder.this.new ForUser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ForUser {
|
|
||||||
private ForUser() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the user.
|
|
||||||
* @param user authenticated user
|
|
||||||
*/
|
|
||||||
public AuthenticationInfoBuilder.WithGroups andUser(User user) {
|
|
||||||
AuthenticationInfoBuilder.this.user = user;
|
|
||||||
return AuthenticationInfoBuilder.this.new WithGroups();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WithGroups {
|
|
||||||
private WithGroups() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the internal groups for the user.
|
|
||||||
* @param groups groups of the authenticated user
|
|
||||||
* @return builder step for groups
|
|
||||||
*/
|
|
||||||
public WithGroups withGroups(String... groups) {
|
|
||||||
return withGroups(asList(groups));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the internal groups for the user.
|
|
||||||
* @param groups groups of the authenticated user
|
|
||||||
* @return builder step for groups
|
|
||||||
*/
|
|
||||||
public WithGroups withGroups(Collection<String> groups) {
|
|
||||||
AuthenticationInfoBuilder.this.groups = groups;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the external groups for the user.
|
|
||||||
* @param externalGroups external groups of the authenticated user
|
|
||||||
* @return builder step for groups
|
|
||||||
*/
|
|
||||||
public WithGroups withExternalGroups(String... externalGroups) {
|
|
||||||
return withExternalGroups(asList(externalGroups));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the external groups for the user.
|
|
||||||
* @param externalGroups external groups of the authenticated user
|
|
||||||
* @return builder step for groups
|
|
||||||
*/
|
|
||||||
public WithGroups withExternalGroups(Collection<String> externalGroups) {
|
|
||||||
AuthenticationInfoBuilder.this.externalGroups = externalGroups;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the {@link AuthenticationInfo} from the given options.
|
|
||||||
*
|
|
||||||
* @return complete autentication info
|
|
||||||
*/
|
|
||||||
public AuthenticationInfo build() {
|
|
||||||
return AuthenticationInfoBuilder.this.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create {@link AuthenticationInfo} from user and groups.
|
* Create {@link AuthenticationInfo} from user and groups.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param realm name of the realm
|
* @param realm name of the realm
|
||||||
* @param user authenticated user
|
* @param user authenticated user
|
||||||
* @param groups groups of the authenticated user
|
|
||||||
*
|
*
|
||||||
* @return authentication info
|
* @return authentication info
|
||||||
*/
|
*/
|
||||||
private AuthenticationInfo createAuthenticationInfo(String realm, User user,
|
public AuthenticationInfo createAuthenticationInfo(String realm, User user) {
|
||||||
Collection<String> groups, Collection<String> externalGroups) {
|
|
||||||
SimplePrincipalCollection collection = new SimplePrincipalCollection();
|
SimplePrincipalCollection collection = new SimplePrincipalCollection();
|
||||||
|
|
||||||
collection.add(user.getId(), realm);
|
collection.add(user.getId(), realm);
|
||||||
collection.add(user, realm);
|
collection.add(user, realm);
|
||||||
collection.add(groupCollector.collect(user.getId(), groups), realm);
|
|
||||||
collection.add(new ExternalGroupNames(externalGroups), realm);
|
|
||||||
|
|
||||||
return new SimpleAuthenticationInfo(collection, user.getPassword());
|
return new SimpleAuthenticationInfo(collection, user.getPassword());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,14 +37,11 @@ package sonia.scm.util;
|
|||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.io.Command;
|
import sonia.scm.io.Command;
|
||||||
import sonia.scm.io.CommandResult;
|
import sonia.scm.io.CommandResult;
|
||||||
import sonia.scm.io.SimpleCommand;
|
import sonia.scm.io.SimpleCommand;
|
||||||
import sonia.scm.io.ZipUnArchiver;
|
import sonia.scm.io.ZipUnArchiver;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -55,12 +52,13 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
package sonia.scm.web.filter;
|
package sonia.scm.web.filter;
|
||||||
|
|
||||||
import sonia.scm.Priority;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.filter.Filters;
|
|
||||||
import sonia.scm.filter.WebElement;
|
|
||||||
import sonia.scm.util.HttpUtil;
|
import sonia.scm.util.HttpUtil;
|
||||||
import sonia.scm.web.UserAgent;
|
import sonia.scm.web.UserAgent;
|
||||||
import sonia.scm.web.UserAgentParser;
|
import sonia.scm.web.UserAgentParser;
|
||||||
import sonia.scm.web.WebTokenGenerator;
|
import sonia.scm.web.WebTokenGenerator;
|
||||||
import sonia.scm.web.protocol.HttpProtocolServlet;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@@ -18,14 +13,11 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Priority(Filters.PRIORITY_AUTHENTICATION)
|
public class HttpProtocolServletAuthenticationFilterBase extends AuthenticationFilter {
|
||||||
@WebElement(value = HttpProtocolServlet.PATTERN)
|
|
||||||
public class HttpProtocolServletAuthenticationFilter extends AuthenticationFilter {
|
|
||||||
|
|
||||||
private final UserAgentParser userAgentParser;
|
private final UserAgentParser userAgentParser;
|
||||||
|
|
||||||
@Inject
|
protected HttpProtocolServletAuthenticationFilterBase(
|
||||||
public HttpProtocolServletAuthenticationFilter(
|
|
||||||
ScmConfiguration configuration,
|
ScmConfiguration configuration,
|
||||||
Set<WebTokenGenerator> tokenGenerators,
|
Set<WebTokenGenerator> tokenGenerators,
|
||||||
UserAgentParser userAgentParser) {
|
UserAgentParser userAgentParser) {
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package sonia.scm.plugin;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class AvailablePluginTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AvailablePluginDescriptor descriptor;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnNewPendingPluginOnInstall() {
|
||||||
|
AvailablePlugin plugin = new AvailablePlugin(descriptor);
|
||||||
|
assertThat(plugin.isPending()).isFalse();
|
||||||
|
|
||||||
|
AvailablePlugin installed = plugin.install();
|
||||||
|
assertThat(installed.isPending()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldThrowIllegalStateExceptionIfAlreadyPending() {
|
||||||
|
AvailablePlugin plugin = new AvailablePlugin(descriptor).install();
|
||||||
|
assertThrows(IllegalStateException.class, () -> plugin.install());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -85,7 +85,7 @@ public class SmpArchiveTest
|
|||||||
public void testExtract()
|
public void testExtract()
|
||||||
throws IOException, ParserConfigurationException, SAXException
|
throws IOException, ParserConfigurationException, SAXException
|
||||||
{
|
{
|
||||||
File archive = createArchive("sonia.sample", "sample", "1.0");
|
File archive = createArchive("sonia.sample", "1.0");
|
||||||
File target = tempFolder.newFolder();
|
File target = tempFolder.newFolder();
|
||||||
|
|
||||||
IOUtil.mkdirs(target);
|
IOUtil.mkdirs(target);
|
||||||
@@ -112,8 +112,8 @@ public class SmpArchiveTest
|
|||||||
@Test
|
@Test
|
||||||
public void testGetPlugin() throws IOException
|
public void testGetPlugin() throws IOException
|
||||||
{
|
{
|
||||||
File archive = createArchive("sonia.sample", "sample", "1.0");
|
File archive = createArchive("sonia.sample", "1.0");
|
||||||
Plugin plugin = SmpArchive.create(archive).getPlugin();
|
InstalledPluginDescriptor plugin = SmpArchive.create(archive).getPlugin();
|
||||||
|
|
||||||
assertNotNull(plugin);
|
assertNotNull(plugin);
|
||||||
|
|
||||||
@@ -121,8 +121,7 @@ public class SmpArchiveTest
|
|||||||
|
|
||||||
assertNotNull(info);
|
assertNotNull(info);
|
||||||
|
|
||||||
assertEquals("sonia.sample", info.getGroupId());
|
assertEquals("sonia.sample", info.getName());
|
||||||
assertEquals("sample", info.getArtifactId());
|
|
||||||
assertEquals("1.0", info.getVersion());
|
assertEquals("1.0", info.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,22 +131,9 @@ public class SmpArchiveTest
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test(expected = PluginException.class)
|
@Test(expected = PluginException.class)
|
||||||
public void testWithMissingArtifactId() throws IOException
|
public void testWithMissingName() throws IOException
|
||||||
{
|
{
|
||||||
File archive = createArchive("sonia.sample", null, "1.0");
|
File archive = createArchive( null, "1.0");
|
||||||
|
|
||||||
SmpArchive.create(archive).getPlugin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Test(expected = PluginException.class)
|
|
||||||
public void testWithMissingGroupId() throws IOException
|
|
||||||
{
|
|
||||||
File archive = createArchive(null, "sample", "1.0");
|
|
||||||
|
|
||||||
SmpArchive.create(archive).getPlugin();
|
SmpArchive.create(archive).getPlugin();
|
||||||
}
|
}
|
||||||
@@ -160,7 +146,7 @@ public class SmpArchiveTest
|
|||||||
@Test(expected = PluginException.class)
|
@Test(expected = PluginException.class)
|
||||||
public void testWithMissingVersion() throws IOException
|
public void testWithMissingVersion() throws IOException
|
||||||
{
|
{
|
||||||
File archive = createArchive("sonia.sample", "sample", null);
|
File archive = createArchive("sonia.sample", null);
|
||||||
|
|
||||||
SmpArchive.create(archive).getPlugin();
|
SmpArchive.create(archive).getPlugin();
|
||||||
}
|
}
|
||||||
@@ -169,13 +155,12 @@ public class SmpArchiveTest
|
|||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param groupId
|
* @param name
|
||||||
* @param artifactId
|
|
||||||
* @param version
|
* @param version
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private File createArchive(String groupId, String artifactId, String version)
|
private File createArchive(String name, String version)
|
||||||
{
|
{
|
||||||
File archiveFile;
|
File archiveFile;
|
||||||
|
|
||||||
@@ -183,7 +168,7 @@ public class SmpArchiveTest
|
|||||||
{
|
{
|
||||||
File descriptor = tempFolder.newFile();
|
File descriptor = tempFolder.newFile();
|
||||||
|
|
||||||
writeDescriptor(descriptor, groupId, artifactId, version);
|
writeDescriptor(descriptor, name, version);
|
||||||
archiveFile = tempFolder.newFile();
|
archiveFile = tempFolder.newFile();
|
||||||
|
|
||||||
try (ZipOutputStream zos =
|
try (ZipOutputStream zos =
|
||||||
@@ -229,14 +214,13 @@ public class SmpArchiveTest
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param descriptor
|
* @param descriptor
|
||||||
* @param groupId
|
* @param name
|
||||||
* @param artifactId
|
|
||||||
* @param version
|
* @param version
|
||||||
*
|
*
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void writeDescriptor(File descriptor, String groupId,
|
private void writeDescriptor(File descriptor, String name,
|
||||||
String artifactId, String version)
|
String version)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -252,8 +236,7 @@ public class SmpArchiveTest
|
|||||||
writer.writeStartDocument();
|
writer.writeStartDocument();
|
||||||
writer.writeStartElement("plugin");
|
writer.writeStartElement("plugin");
|
||||||
writer.writeStartElement("information");
|
writer.writeStartElement("information");
|
||||||
writeElement(writer, "groupId", groupId);
|
writeElement(writer, "name", name);
|
||||||
writeElement(writer, "artifactId", artifactId);
|
|
||||||
writeElement(writer, "version", version);
|
writeElement(writer, "version", version);
|
||||||
|
|
||||||
writer.writeEndElement();
|
writer.writeEndElement();
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package sonia.scm.repository;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class RepositoryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldCreateNewPermissionOnClone() {
|
||||||
|
Repository repository = new Repository();
|
||||||
|
repository.setPermissions(Arrays.asList(new RepositoryPermission("one", "role", false)));
|
||||||
|
|
||||||
|
Repository cloned = repository.clone();
|
||||||
|
cloned.setPermissions(Arrays.asList(new RepositoryPermission("two", "role", false)));
|
||||||
|
|
||||||
|
assertThat(repository.getPermissions()).extracting(r -> r.getName()).containsOnly("one");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class HunkTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldGetComplexHeader() {
|
||||||
|
String rawHeader = createHunk(2, 3, 4, 5).getRawHeader();
|
||||||
|
|
||||||
|
assertThat(rawHeader).isEqualTo("@@ -2,3 +4,5 @@");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnSingleNumberForOne() {
|
||||||
|
String rawHeader = createHunk(42, 1, 5, 1).getRawHeader();
|
||||||
|
|
||||||
|
assertThat(rawHeader).isEqualTo("@@ -42 +5 @@");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Hunk createHunk(int oldStart, int oldLineCount, int newStart, int newLineCount) {
|
||||||
|
return new Hunk() {
|
||||||
|
@Override
|
||||||
|
public int getOldStart() {
|
||||||
|
return oldStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOldLineCount() {
|
||||||
|
return oldLineCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewStart() {
|
||||||
|
return newStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewLineCount() {
|
||||||
|
return newLineCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<DiffLine> iterator() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,16 @@
|
|||||||
package sonia.scm.security;
|
package sonia.scm.security;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
import org.apache.shiro.authc.DisabledAccountException;
|
import org.apache.shiro.authc.DisabledAccountException;
|
||||||
import org.apache.shiro.authc.UnknownAccountException;
|
import org.apache.shiro.authc.UnknownAccountException;
|
||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
import org.apache.shiro.subject.PrincipalCollection;
|
import org.apache.shiro.subject.PrincipalCollection;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupDAO;
|
import sonia.scm.group.GroupDAO;
|
||||||
import sonia.scm.group.GroupNames;
|
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserDAO;
|
import sonia.scm.user.UserDAO;
|
||||||
|
|
||||||
@@ -38,7 +34,7 @@ class DAORealmHelperTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUpObjectUnderTest() {
|
void setUpObjectUnderTest() {
|
||||||
helper = new DAORealmHelper(loginAttemptHandler, userDAO, new GroupCollector(groupDAO), "hitchhiker");
|
helper = new DAORealmHelper(loginAttemptHandler, userDAO, "hitchhiker");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -73,29 +69,9 @@ class DAORealmHelperTest {
|
|||||||
AuthenticationInfo authenticationInfo = helper.authenticationInfoBuilder("trillian").build();
|
AuthenticationInfo authenticationInfo = helper.authenticationInfoBuilder("trillian").build();
|
||||||
PrincipalCollection principals = authenticationInfo.getPrincipals();
|
PrincipalCollection principals = authenticationInfo.getPrincipals();
|
||||||
assertThat(principals.oneByType(User.class)).isSameAs(user);
|
assertThat(principals.oneByType(User.class)).isSameAs(user);
|
||||||
assertThat(principals.oneByType(GroupNames.class)).containsOnly("_authenticated");
|
|
||||||
assertThat(principals.oneByType(Scope.class)).isEmpty();
|
assertThat(principals.oneByType(Scope.class)).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
void shouldReturnAuthenticationInfoWithGroups() {
|
|
||||||
User user = new User("trillian");
|
|
||||||
when(userDAO.get("trillian")).thenReturn(user);
|
|
||||||
|
|
||||||
Group one = new Group("xml", "one", "trillian");
|
|
||||||
Group two = new Group("xml", "two", "trillian");
|
|
||||||
Group six = new Group("xml", "six", "dent");
|
|
||||||
when(groupDAO.getAll()).thenReturn(ImmutableList.of(one, two, six));
|
|
||||||
|
|
||||||
AuthenticationInfo authenticationInfo = helper.authenticationInfoBuilder("trillian")
|
|
||||||
.withGroups(ImmutableList.of("three"))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
PrincipalCollection principals = authenticationInfo.getPrincipals();
|
|
||||||
assertThat(principals.oneByType(GroupNames.class)).containsOnly("_authenticated", "one", "two", "three");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldReturnAuthenticationInfoWithScope() {
|
void shouldReturnAuthenticationInfoWithScope() {
|
||||||
User user = new User("trillian");
|
User user = new User("trillian");
|
||||||
@@ -148,7 +124,6 @@ class DAORealmHelperTest {
|
|||||||
|
|
||||||
PrincipalCollection principals = authenticationInfo.getPrincipals();
|
PrincipalCollection principals = authenticationInfo.getPrincipals();
|
||||||
assertThat(principals.oneByType(User.class)).isSameAs(user);
|
assertThat(principals.oneByType(User.class)).isSameAs(user);
|
||||||
assertThat(principals.oneByType(GroupNames.class)).containsOnly("_authenticated");
|
|
||||||
assertThat(principals.oneByType(Scope.class)).isEmpty();
|
assertThat(principals.oneByType(Scope.class)).isEmpty();
|
||||||
|
|
||||||
assertThat(authenticationInfo.getCredentials()).isNull();
|
assertThat(authenticationInfo.getCredentials()).isNull();
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package sonia.scm.security;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Nested;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import sonia.scm.group.Group;
|
|
||||||
import sonia.scm.group.GroupDAO;
|
|
||||||
import sonia.scm.group.GroupNames;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class GroupCollectorTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private GroupDAO groupDAO;
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
private GroupCollector collector;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldAlwaysReturnAuthenticatedGroup() {
|
|
||||||
GroupNames groupNames = collector.collect("trillian", Collections.emptySet());
|
|
||||||
assertThat(groupNames).containsOnly("_authenticated");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
class WithGroupsFromDao {
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUpGroupsDao() {
|
|
||||||
List<Group> groups = Lists.newArrayList(
|
|
||||||
new Group("xml", "heartOfGold", "trillian"),
|
|
||||||
new Group("xml", "g42", "dent", "prefect"),
|
|
||||||
new Group("xml", "fjordsOfAfrican", "dent", "trillian")
|
|
||||||
);
|
|
||||||
when(groupDAO.getAll()).thenReturn(groups);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldReturnGroupsFromDao() {
|
|
||||||
GroupNames groupNames = collector.collect("trillian", Collections.emptySet());
|
|
||||||
assertThat(groupNames).contains("_authenticated", "heartOfGold", "fjordsOfAfrican");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldCombineGivenWithDao() {
|
|
||||||
GroupNames groupNames = collector.collect("trillian", ImmutableList.of("awesome", "incredible"));
|
|
||||||
assertThat(groupNames).contains("_authenticated", "heartOfGold", "fjordsOfAfrican", "awesome", "incredible");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -36,31 +36,30 @@ package sonia.scm.security;
|
|||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
import org.assertj.core.api.Assertions;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import sonia.scm.AlreadyExistsException;
|
import sonia.scm.AlreadyExistsException;
|
||||||
import sonia.scm.group.ExternalGroupNames;
|
|
||||||
import sonia.scm.group.Group;
|
import sonia.scm.group.Group;
|
||||||
import sonia.scm.group.GroupDAO;
|
|
||||||
import sonia.scm.group.GroupManager;
|
import sonia.scm.group.GroupManager;
|
||||||
import sonia.scm.group.GroupNames;
|
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserManager;
|
import sonia.scm.user.UserManager;
|
||||||
import sonia.scm.web.security.AdministrationContext;
|
import sonia.scm.web.security.AdministrationContext;
|
||||||
import sonia.scm.web.security.PrivilegedAction;
|
import sonia.scm.web.security.PrivilegedAction;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.hasItem;
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -78,9 +77,6 @@ public class SyncingRealmHelperTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private UserManager userManager;
|
private UserManager userManager;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private GroupDAO groupDAO;
|
|
||||||
|
|
||||||
private SyncingRealmHelper helper;
|
private SyncingRealmHelper helper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,7 +102,7 @@ public class SyncingRealmHelperTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
helper = new SyncingRealmHelper(ctx, userManager, groupManager, groupDAO);
|
helper = new SyncingRealmHelper(ctx, userManager, groupManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,67 +179,15 @@ public class SyncingRealmHelperTest {
|
|||||||
verify(userManager, times(1)).modify(user);
|
verify(userManager, times(1)).modify(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void builderShouldSetInternalGroups() {
|
|
||||||
AuthenticationInfo authenticationInfo = helper
|
|
||||||
.authenticationInfo()
|
|
||||||
.forRealm("unit-test")
|
|
||||||
.andUser(new User("ziltoid"))
|
|
||||||
.withGroups("internal")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
GroupNames groupNames = authenticationInfo.getPrincipals().oneByType(GroupNames.class);
|
|
||||||
Assertions.assertThat(groupNames.getCollection()).contains("_authenticated", "internal");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void builderShouldSetExternalGroups() {
|
|
||||||
AuthenticationInfo authenticationInfo = helper
|
|
||||||
.authenticationInfo()
|
|
||||||
.forRealm("unit-test")
|
|
||||||
.andUser(new User("ziltoid"))
|
|
||||||
.withExternalGroups("external")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
ExternalGroupNames groupNames = authenticationInfo.getPrincipals().oneByType(ExternalGroupNames.class);
|
|
||||||
Assertions.assertThat(groupNames.getCollection()).containsOnly("external");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void builderShouldSetValues() {
|
public void builderShouldSetValues() {
|
||||||
User user = new User("ziltoid");
|
User user = new User("ziltoid");
|
||||||
AuthenticationInfo authInfo = helper
|
AuthenticationInfo authInfo = helper.createAuthenticationInfo("unit-test", user);
|
||||||
.authenticationInfo()
|
|
||||||
.forRealm("unit-test")
|
|
||||||
.andUser(user)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
assertNotNull(authInfo);
|
assertNotNull(authInfo);
|
||||||
assertEquals("ziltoid", authInfo.getPrincipals().getPrimaryPrincipal());
|
assertEquals("ziltoid", authInfo.getPrincipals().getPrimaryPrincipal());
|
||||||
assertThat(authInfo.getPrincipals().getRealmNames(), hasItem("unit-test"));
|
assertThat(authInfo.getPrincipals().getRealmNames(), hasItem("unit-test"));
|
||||||
assertEquals(user, authInfo.getPrincipals().oneByType(User.class));
|
assertEquals(user, authInfo.getPrincipals().oneByType(User.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnCombinedGroupNames() {
|
|
||||||
User user = new User("tricia");
|
|
||||||
|
|
||||||
List<Group> groups = Lists.newArrayList(new Group("xml", "heartOfGold", "tricia"));
|
|
||||||
when(groupDAO.getAll()).thenReturn(groups);
|
|
||||||
|
|
||||||
AuthenticationInfo authInfo = helper
|
|
||||||
.authenticationInfo()
|
|
||||||
.forRealm("unit-test")
|
|
||||||
.andUser(user)
|
|
||||||
.withGroups("fjordsOfAfrican")
|
|
||||||
.withExternalGroups("g42")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
|
|
||||||
GroupNames groupNames = authInfo.getPrincipals().oneByType(GroupNames.class);
|
|
||||||
Assertions.assertThat(groupNames).contains("_authenticated", "heartOfGold", "fjordsOfAfrican");
|
|
||||||
|
|
||||||
ExternalGroupNames externalGroupNames = authInfo.getPrincipals().oneByType(ExternalGroupNames.class);
|
|
||||||
Assertions.assertThat(externalGroupNames).contains("g42");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
class HttpProtocolServletAuthenticationFilterTest {
|
class HttpProtocolServletAuthenticationFilterBaseTest {
|
||||||
|
|
||||||
private ScmConfiguration configuration = new ScmConfiguration();
|
private ScmConfiguration configuration = new ScmConfiguration();
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ class HttpProtocolServletAuthenticationFilterTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private UserAgentParser userAgentParser;
|
private UserAgentParser userAgentParser;
|
||||||
|
|
||||||
private HttpProtocolServletAuthenticationFilter authenticationFilter;
|
private HttpProtocolServletAuthenticationFilterBase authenticationFilter;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private HttpServletRequest request;
|
private HttpServletRequest request;
|
||||||
@@ -48,7 +48,7 @@ class HttpProtocolServletAuthenticationFilterTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUpObjectUnderTest() {
|
void setUpObjectUnderTest() {
|
||||||
authenticationFilter = new HttpProtocolServletAuthenticationFilter(configuration, tokenGenerators, userAgentParser);
|
authenticationFilter = new HttpProtocolServletAuthenticationFilterBase(configuration, tokenGenerators, userAgentParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
mock-maker-inline
|
||||||
@@ -5,6 +5,5 @@
|
|||||||
<namespace>space</namespace>
|
<namespace>space</namespace>
|
||||||
<name>existing</name>
|
<name>existing</name>
|
||||||
<public>false</public>
|
<public>false</public>
|
||||||
<archived>false</archived>
|
|
||||||
<type>xml</type>
|
<type>xml</type>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|||||||
@@ -123,23 +123,6 @@ public class TestData {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void createUserPermission(String username, String roleName, String repositoryType) {
|
|
||||||
String defaultPermissionUrl = TestData.getDefaultPermissionUrl(USER_SCM_ADMIN, USER_SCM_ADMIN, repositoryType);
|
|
||||||
LOG.info("create permission with name {} and role {} using the endpoint: {}", username, roleName, defaultPermissionUrl);
|
|
||||||
given(VndMediaType.REPOSITORY_PERMISSION)
|
|
||||||
.when()
|
|
||||||
.content("{\n" +
|
|
||||||
"\t\"role\": " + roleName + ",\n" +
|
|
||||||
"\t\"name\": \"" + username + "\",\n" +
|
|
||||||
"\t\"groupPermission\": false\n" +
|
|
||||||
"\t\n" +
|
|
||||||
"}")
|
|
||||||
.post(defaultPermissionUrl)
|
|
||||||
.then()
|
|
||||||
.statusCode(HttpStatus.SC_CREATED)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Map> getUserPermissions(String username, String password, String repositoryType) {
|
public static List<Map> getUserPermissions(String username, String password, String repositoryType) {
|
||||||
return callUserPermissions(username, password, repositoryType, HttpStatus.SC_OK)
|
return callUserPermissions(username, password, repositoryType, HttpStatus.SC_OK)
|
||||||
.extract()
|
.extract()
|
||||||
@@ -245,7 +228,6 @@ public class TestData {
|
|||||||
.add("contact", "zaphod.beeblebrox@hitchhiker.com")
|
.add("contact", "zaphod.beeblebrox@hitchhiker.com")
|
||||||
.add("description", "Heart of Gold")
|
.add("description", "Heart of Gold")
|
||||||
.add("name", getDefaultRepoName(repositoryType))
|
.add("name", getDefaultRepoName(repositoryType))
|
||||||
.add("archived", false)
|
|
||||||
.add("type", repositoryType)
|
.add("type", repositoryType)
|
||||||
.build().toString();
|
.build().toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>scm-git-plugin</artifactId>
|
<artifactId>scm-git-plugin</artifactId>
|
||||||
<name>scm-git-plugin</name>
|
|
||||||
<packaging>smp</packaging>
|
<packaging>smp</packaging>
|
||||||
<url>https://bitbucket.org/sdorra/scm-manager</url>
|
<url>https://bitbucket.org/sdorra/scm-manager</url>
|
||||||
<description>Plugin for the version control system Git</description>
|
<description>Plugin for the version control system Git</description>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.eclipse.jgit.api.FetchCommand;
|
|||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.diff.DiffFormatter;
|
import org.eclipse.jgit.diff.DiffFormatter;
|
||||||
|
import org.eclipse.jgit.lib.AnyObjectId;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
@@ -441,7 +442,7 @@ public final class GitUtil
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String getId(ObjectId objectId)
|
public static String getId(AnyObjectId objectId)
|
||||||
{
|
{
|
||||||
String id = Util.EMPTY_STRING;
|
String id = Util.EMPTY_STRING;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevTree;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
|
||||||
|
import org.eclipse.jgit.treewalk.TreeWalk;
|
||||||
|
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
||||||
|
import sonia.scm.repository.GitUtil;
|
||||||
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
final class Differ implements AutoCloseable {
|
||||||
|
|
||||||
|
private final RevWalk walk;
|
||||||
|
private final TreeWalk treeWalk;
|
||||||
|
private final RevCommit commit;
|
||||||
|
|
||||||
|
private Differ(RevCommit commit, RevWalk walk, TreeWalk treeWalk) {
|
||||||
|
this.commit = commit;
|
||||||
|
this.walk = walk;
|
||||||
|
this.treeWalk = treeWalk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Diff diff(Repository repository, DiffCommandRequest request) throws IOException {
|
||||||
|
try (Differ differ = create(repository, request)) {
|
||||||
|
return differ.diff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Differ create(Repository repository, DiffCommandRequest request) throws IOException {
|
||||||
|
RevWalk walk = new RevWalk(repository);
|
||||||
|
|
||||||
|
ObjectId revision = repository.resolve(request.getRevision());
|
||||||
|
RevCommit commit = walk.parseCommit(revision);
|
||||||
|
|
||||||
|
walk.markStart(commit);
|
||||||
|
commit = walk.next();
|
||||||
|
TreeWalk treeWalk = new TreeWalk(repository);
|
||||||
|
treeWalk.reset();
|
||||||
|
treeWalk.setRecursive(true);
|
||||||
|
|
||||||
|
if (Util.isNotEmpty(request.getPath()))
|
||||||
|
{
|
||||||
|
treeWalk.setFilter(PathFilter.create(request.getPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(request.getAncestorChangeset()))
|
||||||
|
{
|
||||||
|
ObjectId otherRevision = repository.resolve(request.getAncestorChangeset());
|
||||||
|
ObjectId ancestorId = computeCommonAncestor(repository, revision, otherRevision);
|
||||||
|
RevTree tree = walk.parseCommit(ancestorId).getTree();
|
||||||
|
treeWalk.addTree(tree);
|
||||||
|
}
|
||||||
|
else if (commit.getParentCount() > 0)
|
||||||
|
{
|
||||||
|
RevTree tree = commit.getParent(0).getTree();
|
||||||
|
|
||||||
|
if (tree != null)
|
||||||
|
{
|
||||||
|
treeWalk.addTree(tree);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
treeWalk.addTree(new EmptyTreeIterator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
treeWalk.addTree(new EmptyTreeIterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
treeWalk.addTree(commit.getTree());
|
||||||
|
|
||||||
|
return new Differ(commit, walk, treeWalk);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ObjectId computeCommonAncestor(org.eclipse.jgit.lib.Repository repository, ObjectId revision1, ObjectId revision2) throws IOException {
|
||||||
|
return GitUtil.computeCommonAncestor(repository, revision1, revision2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Diff diff() throws IOException {
|
||||||
|
List<DiffEntry> entries = DiffEntry.scan(treeWalk);
|
||||||
|
return new Diff(commit, entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
GitUtil.release(walk);
|
||||||
|
GitUtil.release(treeWalk);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Diff {
|
||||||
|
|
||||||
|
private final RevCommit commit;
|
||||||
|
private final List<DiffEntry> entries;
|
||||||
|
|
||||||
|
private Diff(RevCommit commit, List<DiffEntry> entries) {
|
||||||
|
this.commit = commit;
|
||||||
|
this.entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RevCommit getCommit() {
|
||||||
|
return commit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DiffEntry> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
public class FileRange {
|
||||||
|
|
||||||
|
private final int start;
|
||||||
|
private final int lineCount;
|
||||||
|
|
||||||
|
public FileRange(int start, int lineCount) {
|
||||||
|
this.start = start;
|
||||||
|
this.lineCount = lineCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineCount() {
|
||||||
|
return lineCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2010, Sebastian Sdorra
|
* Copyright (c) 2010, Sebastian Sdorra
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
* <p>
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
*
|
* <p>
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer.
|
* this list of conditions and the following disclaimer.
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||||
* contributors may be used to endorse or promote products derived from this
|
* contributors may be used to endorse or promote products derived from this
|
||||||
* software without specific prior written permission.
|
* software without specific prior written permission.
|
||||||
*
|
* <p>
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
@@ -24,9 +24,8 @@
|
|||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
* <p>
|
||||||
* http://bitbucket.org/sdorra/scm-manager
|
* http://bitbucket.org/sdorra/scm-manager
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -34,148 +33,41 @@ package sonia.scm.repository.spi;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import org.eclipse.jgit.diff.DiffEntry;
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
import org.eclipse.jgit.diff.DiffFormatter;
|
import org.eclipse.jgit.diff.DiffFormatter;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
|
||||||
import org.eclipse.jgit.revwalk.RevTree;
|
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
|
||||||
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
|
|
||||||
import org.eclipse.jgit.treewalk.TreeWalk;
|
|
||||||
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import sonia.scm.repository.GitUtil;
|
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.util.Util;
|
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
*/
|
*/
|
||||||
public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
|
public class GitDiffCommand extends AbstractGitCommand implements DiffCommand {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
GitDiffCommand(GitContext context, Repository repository) {
|
||||||
* the logger for GitDiffCommand
|
|
||||||
*/
|
|
||||||
private static final Logger logger =
|
|
||||||
LoggerFactory.getLogger(GitDiffCommand.class);
|
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs ...
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param repository
|
|
||||||
*/
|
|
||||||
public GitDiffCommand(GitContext context, Repository repository)
|
|
||||||
{
|
|
||||||
super(context, repository);
|
super(context, repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param output
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void getDiffResult(DiffCommandRequest request, OutputStream output)
|
public void getDiffResult(DiffCommandRequest request, OutputStream output) throws IOException {
|
||||||
{
|
@SuppressWarnings("squid:S2095") // repository will be closed with the RepositoryService
|
||||||
RevWalk walk = null;
|
org.eclipse.jgit.lib.Repository repository = open();
|
||||||
TreeWalk treeWalk = null;
|
try (DiffFormatter formatter = new DiffFormatter(new BufferedOutputStream(output))) {
|
||||||
DiffFormatter formatter = null;
|
formatter.setRepository(repository);
|
||||||
|
|
||||||
try
|
Differ.Diff diff = Differ.diff(repository, request);
|
||||||
{
|
|
||||||
org.eclipse.jgit.lib.Repository gr = open();
|
|
||||||
|
|
||||||
walk = new RevWalk(gr);
|
for (DiffEntry e : diff.getEntries()) {
|
||||||
|
if (!e.getOldId().equals(e.getNewId())) {
|
||||||
ObjectId revision = gr.resolve(request.getRevision());
|
|
||||||
RevCommit commit = walk.parseCommit(revision);
|
|
||||||
|
|
||||||
walk.markStart(commit);
|
|
||||||
commit = walk.next();
|
|
||||||
treeWalk = new TreeWalk(gr);
|
|
||||||
treeWalk.reset();
|
|
||||||
treeWalk.setRecursive(true);
|
|
||||||
|
|
||||||
if (Util.isNotEmpty(request.getPath()))
|
|
||||||
{
|
|
||||||
treeWalk.setFilter(PathFilter.create(request.getPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(request.getAncestorChangeset()))
|
|
||||||
{
|
|
||||||
ObjectId otherRevision = gr.resolve(request.getAncestorChangeset());
|
|
||||||
ObjectId ancestorId = computeCommonAncestor(gr, revision, otherRevision);
|
|
||||||
RevTree tree = walk.parseCommit(ancestorId).getTree();
|
|
||||||
treeWalk.addTree(tree);
|
|
||||||
}
|
|
||||||
else if (commit.getParentCount() > 0)
|
|
||||||
{
|
|
||||||
RevTree tree = commit.getParent(0).getTree();
|
|
||||||
|
|
||||||
if (tree != null)
|
|
||||||
{
|
|
||||||
treeWalk.addTree(tree);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
treeWalk.addTree(new EmptyTreeIterator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
treeWalk.addTree(new EmptyTreeIterator());
|
|
||||||
}
|
|
||||||
|
|
||||||
treeWalk.addTree(commit.getTree());
|
|
||||||
formatter = new DiffFormatter(new BufferedOutputStream(output));
|
|
||||||
formatter.setRepository(gr);
|
|
||||||
|
|
||||||
List<DiffEntry> entries = DiffEntry.scan(treeWalk);
|
|
||||||
|
|
||||||
for (DiffEntry e : entries)
|
|
||||||
{
|
|
||||||
if (!e.getOldId().equals(e.getNewId()))
|
|
||||||
{
|
|
||||||
formatter.format(e);
|
formatter.format(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
formatter.flush();
|
formatter.flush();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// TODO throw exception
|
|
||||||
logger.error("could not create diff", ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
GitUtil.release(walk);
|
|
||||||
GitUtil.release(treeWalk);
|
|
||||||
GitUtil.release(formatter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ObjectId computeCommonAncestor(org.eclipse.jgit.lib.Repository repository, ObjectId revision1, ObjectId revision2) throws IOException {
|
|
||||||
return GitUtil.computeCommonAncestor(repository, revision1, revision2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
|
import org.eclipse.jgit.diff.DiffFormatter;
|
||||||
|
import sonia.scm.repository.GitUtil;
|
||||||
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.api.DiffFile;
|
||||||
|
import sonia.scm.repository.api.DiffResult;
|
||||||
|
import sonia.scm.repository.api.Hunk;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class GitDiffResultCommand extends AbstractGitCommand implements DiffResultCommand {
|
||||||
|
|
||||||
|
GitDiffResultCommand(GitContext context, Repository repository) {
|
||||||
|
super(context, repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiffResult getDiffResult(DiffCommandRequest diffCommandRequest) throws IOException {
|
||||||
|
org.eclipse.jgit.lib.Repository repository = open();
|
||||||
|
return new GitDiffResult(repository, Differ.diff(repository, diffCommandRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GitDiffResult implements DiffResult {
|
||||||
|
|
||||||
|
private final org.eclipse.jgit.lib.Repository repository;
|
||||||
|
private final Differ.Diff diff;
|
||||||
|
|
||||||
|
private GitDiffResult(org.eclipse.jgit.lib.Repository repository, Differ.Diff diff) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.diff = diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOldRevision() {
|
||||||
|
return GitUtil.getId(diff.getCommit().getParent(0).getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNewRevision() {
|
||||||
|
return GitUtil.getId(diff.getCommit().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<DiffFile> iterator() {
|
||||||
|
return diff.getEntries()
|
||||||
|
.stream()
|
||||||
|
.map(diffEntry -> new GitDiffFile(repository, diffEntry))
|
||||||
|
.collect(Collectors.<DiffFile>toList())
|
||||||
|
.iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GitDiffFile implements DiffFile {
|
||||||
|
|
||||||
|
private final org.eclipse.jgit.lib.Repository repository;
|
||||||
|
private final DiffEntry diffEntry;
|
||||||
|
|
||||||
|
private GitDiffFile(org.eclipse.jgit.lib.Repository repository, DiffEntry diffEntry) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.diffEntry = diffEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOldRevision() {
|
||||||
|
return GitUtil.getId(diffEntry.getOldId().toObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNewRevision() {
|
||||||
|
return GitUtil.getId(diffEntry.getNewId().toObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOldPath() {
|
||||||
|
return diffEntry.getOldPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNewPath() {
|
||||||
|
return diffEntry.getNewPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Hunk> iterator() {
|
||||||
|
String content = format(repository, diffEntry);
|
||||||
|
GitHunkParser parser = new GitHunkParser();
|
||||||
|
return parser.parse(content).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String format(org.eclipse.jgit.lib.Repository repository, DiffEntry entry) {
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); DiffFormatter formatter = new DiffFormatter(baos)) {
|
||||||
|
formatter.setRepository(repository);
|
||||||
|
formatter.format(entry);
|
||||||
|
return baos.toString();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new InternalRepositoryException(GitDiffResultCommand.this.repository, "failed to format diff entry", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import sonia.scm.repository.api.DiffLine;
|
||||||
|
import sonia.scm.repository.api.Hunk;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GitHunk implements Hunk {
|
||||||
|
|
||||||
|
private final FileRange oldFileRange;
|
||||||
|
private final FileRange newFileRange;
|
||||||
|
private List<DiffLine> lines;
|
||||||
|
|
||||||
|
public GitHunk(FileRange oldFileRange, FileRange newFileRange) {
|
||||||
|
this.oldFileRange = oldFileRange;
|
||||||
|
this.newFileRange = newFileRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOldStart() {
|
||||||
|
return oldFileRange.getStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOldLineCount() {
|
||||||
|
return oldFileRange.getLineCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewStart() {
|
||||||
|
return newFileRange.getStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewLineCount() {
|
||||||
|
return newFileRange.getLineCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<DiffLine> iterator() {
|
||||||
|
return lines.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLines(List<DiffLine> lines) {
|
||||||
|
this.lines = lines;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import sonia.scm.repository.api.DiffLine;
|
||||||
|
import sonia.scm.repository.api.Hunk;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import static java.util.OptionalInt.of;
|
||||||
|
|
||||||
|
final class GitHunkParser {
|
||||||
|
private static final int HEADER_PREFIX_LENGTH = "@@ -".length();
|
||||||
|
private static final int HEADER_SUFFIX_LENGTH = " @@".length();
|
||||||
|
|
||||||
|
private GitHunk currentGitHunk = null;
|
||||||
|
private List<DiffLine> collectedLines = null;
|
||||||
|
private int oldLineCounter = 0;
|
||||||
|
private int newLineCounter = 0;
|
||||||
|
|
||||||
|
GitHunkParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Hunk> parse(String content) {
|
||||||
|
List<Hunk> hunks = new ArrayList<>();
|
||||||
|
|
||||||
|
try (Scanner scanner = new Scanner(content)) {
|
||||||
|
while (scanner.hasNextLine()) {
|
||||||
|
String line = scanner.nextLine();
|
||||||
|
if (line.startsWith("@@")) {
|
||||||
|
parseHeader(hunks, line);
|
||||||
|
} else if (currentGitHunk != null) {
|
||||||
|
parseDiffLine(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentGitHunk != null) {
|
||||||
|
currentGitHunk.setLines(collectedLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseHeader(List<Hunk> hunks, String line) {
|
||||||
|
if (currentGitHunk != null) {
|
||||||
|
currentGitHunk.setLines(collectedLines);
|
||||||
|
}
|
||||||
|
String hunkHeader = line.substring(HEADER_PREFIX_LENGTH, line.length() - HEADER_SUFFIX_LENGTH);
|
||||||
|
String[] split = hunkHeader.split("\\s");
|
||||||
|
|
||||||
|
FileRange oldFileRange = createFileRange(split[0]);
|
||||||
|
// TODO merge contains two two block which starts with "-" e.g. -1,3 -2,4 +3,6
|
||||||
|
// check if it is relevant for our use case
|
||||||
|
FileRange newFileRange = createFileRange(split[1]);
|
||||||
|
|
||||||
|
currentGitHunk = new GitHunk(oldFileRange, newFileRange);
|
||||||
|
hunks.add(currentGitHunk);
|
||||||
|
|
||||||
|
collectedLines = new ArrayList<>();
|
||||||
|
oldLineCounter = currentGitHunk.getOldStart();
|
||||||
|
newLineCounter = currentGitHunk.getNewStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseDiffLine(String line) {
|
||||||
|
String content = line.substring(1);
|
||||||
|
switch (line.charAt(0)) {
|
||||||
|
case ' ':
|
||||||
|
collectedLines.add(new UnchangedGitDiffLine(newLineCounter, oldLineCounter, content));
|
||||||
|
++newLineCounter;
|
||||||
|
++oldLineCounter;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
collectedLines.add(new AddedGitDiffLine(newLineCounter, content));
|
||||||
|
++newLineCounter;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
collectedLines.add(new RemovedGitDiffLine(oldLineCounter, content));
|
||||||
|
++oldLineCounter;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("cannot handle diff line: " + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AddedGitDiffLine implements DiffLine {
|
||||||
|
private final int newLineNumber;
|
||||||
|
private final String content;
|
||||||
|
|
||||||
|
private AddedGitDiffLine(int newLineNumber, String content) {
|
||||||
|
this.newLineNumber = newLineNumber;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getOldLineNumber() {
|
||||||
|
return OptionalInt.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getNewLineNumber() {
|
||||||
|
return of(newLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RemovedGitDiffLine implements DiffLine {
|
||||||
|
private final int oldLineNumber;
|
||||||
|
private final String content;
|
||||||
|
|
||||||
|
private RemovedGitDiffLine(int oldLineNumber, String content) {
|
||||||
|
this.oldLineNumber = oldLineNumber;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getOldLineNumber() {
|
||||||
|
return of(oldLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getNewLineNumber() {
|
||||||
|
return OptionalInt.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UnchangedGitDiffLine implements DiffLine {
|
||||||
|
private final int newLineNumber;
|
||||||
|
private final int oldLineNumber;
|
||||||
|
private final String content;
|
||||||
|
|
||||||
|
private UnchangedGitDiffLine(int newLineNumber, int oldLineNumber, String content) {
|
||||||
|
this.newLineNumber = newLineNumber;
|
||||||
|
this.oldLineNumber = oldLineNumber;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getOldLineNumber() {
|
||||||
|
return of(oldLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptionalInt getNewLineNumber() {
|
||||||
|
return of(newLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileRange createFileRange(String fileRangeString) {
|
||||||
|
int start;
|
||||||
|
int lineCount = 1;
|
||||||
|
int commaIndex = fileRangeString.indexOf(',');
|
||||||
|
if (commaIndex > 0) {
|
||||||
|
start = Integer.parseInt(fileRangeString.substring(0, commaIndex));
|
||||||
|
lineCount = Integer.parseInt(fileRangeString.substring(commaIndex + 1));
|
||||||
|
} else {
|
||||||
|
start = Integer.parseInt(fileRangeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FileRange(start, lineCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
|
|||||||
Command.BROWSE,
|
Command.BROWSE,
|
||||||
Command.CAT,
|
Command.CAT,
|
||||||
Command.DIFF,
|
Command.DIFF,
|
||||||
|
Command.DIFF_RESULT,
|
||||||
Command.LOG,
|
Command.LOG,
|
||||||
Command.TAGS,
|
Command.TAGS,
|
||||||
Command.BRANCHES,
|
Command.BRANCHES,
|
||||||
@@ -168,6 +169,11 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
|
|||||||
return new GitDiffCommand(context, repository);
|
return new GitDiffCommand(context, repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DiffResultCommand getDiffResultCommand() {
|
||||||
|
return new GitDiffResultCommand(context, repository);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -46,14 +46,10 @@
|
|||||||
<scm-version>2</scm-version>
|
<scm-version>2</scm-version>
|
||||||
|
|
||||||
<information>
|
<information>
|
||||||
<author>Sebastian Sdorra</author>
|
<displayName>Git</displayName>
|
||||||
<category>Git</category>
|
<author>Cloudogu GmbH</author>
|
||||||
<tags>
|
<category>Source Code Management</category>
|
||||||
<tag>git</tag>
|
<avatarUrl>/images/git-logo.png</avatarUrl>
|
||||||
<tag>scm</tag>
|
|
||||||
<tag>vcs</tag>
|
|
||||||
<tag>dvcs</tag>
|
|
||||||
</tags>
|
|
||||||
</information>
|
</information>
|
||||||
|
|
||||||
<conditions>
|
<conditions>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package sonia.scm.repository.spi;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ public class GitDiffCommandTest extends AbstractGitCommandTestBase {
|
|||||||
"+f\n";
|
"+f\n";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void diffForOneRevisionShouldCreateDiff() {
|
public void diffForOneRevisionShouldCreateDiff() throws IOException {
|
||||||
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
||||||
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
||||||
diffCommandRequest.setRevision("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
diffCommandRequest.setRevision("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
||||||
@@ -48,7 +49,7 @@ public class GitDiffCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void diffForOneBranchShouldCreateDiff() {
|
public void diffForOneBranchShouldCreateDiff() throws IOException {
|
||||||
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
||||||
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
||||||
diffCommandRequest.setRevision("test-branch");
|
diffCommandRequest.setRevision("test-branch");
|
||||||
@@ -58,7 +59,7 @@ public class GitDiffCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void diffForPathShouldCreateLimitedDiff() {
|
public void diffForPathShouldCreateLimitedDiff() throws IOException {
|
||||||
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
||||||
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
||||||
diffCommandRequest.setRevision("test-branch");
|
diffCommandRequest.setRevision("test-branch");
|
||||||
@@ -69,7 +70,7 @@ public class GitDiffCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void diffBetweenTwoBranchesShouldCreateDiff() {
|
public void diffBetweenTwoBranchesShouldCreateDiff() throws IOException {
|
||||||
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
||||||
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
||||||
diffCommandRequest.setRevision("master");
|
diffCommandRequest.setRevision("master");
|
||||||
@@ -80,7 +81,7 @@ public class GitDiffCommandTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void diffBetweenTwoBranchesForPathShouldCreateLimitedDiff() {
|
public void diffBetweenTwoBranchesForPathShouldCreateLimitedDiff() throws IOException {
|
||||||
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
GitDiffCommand gitDiffCommand = new GitDiffCommand(createContext(), repository);
|
||||||
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
||||||
diffCommandRequest.setRevision("master");
|
diffCommandRequest.setRevision("master");
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import sonia.scm.repository.api.DiffFile;
|
||||||
|
import sonia.scm.repository.api.DiffResult;
|
||||||
|
import sonia.scm.repository.api.Hunk;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class GitDiffResultCommandTest extends AbstractGitCommandTestBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnOldAndNewRevision() throws IOException {
|
||||||
|
DiffResult diffResult = createDiffResult("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
||||||
|
|
||||||
|
assertThat(diffResult.getNewRevision()).isEqualTo("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
||||||
|
assertThat(diffResult.getOldRevision()).isEqualTo("592d797cd36432e591416e8b2b98154f4f163411");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnFilePaths() throws IOException {
|
||||||
|
DiffResult diffResult = createDiffResult("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
||||||
|
Iterator<DiffFile> iterator = diffResult.iterator();
|
||||||
|
DiffFile a = iterator.next();
|
||||||
|
assertThat(a.getNewPath()).isEqualTo("a.txt");
|
||||||
|
assertThat(a.getOldPath()).isEqualTo("a.txt");
|
||||||
|
|
||||||
|
DiffFile b = iterator.next();
|
||||||
|
assertThat(b.getOldPath()).isEqualTo("b.txt");
|
||||||
|
assertThat(b.getNewPath()).isEqualTo("/dev/null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnFileRevisions() throws IOException {
|
||||||
|
DiffResult diffResult = createDiffResult("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
||||||
|
Iterator<DiffFile> iterator = diffResult.iterator();
|
||||||
|
|
||||||
|
DiffFile a = iterator.next();
|
||||||
|
assertThat(a.getOldRevision()).isEqualTo("78981922613b2afb6025042ff6bd878ac1994e85");
|
||||||
|
assertThat(a.getNewRevision()).isEqualTo("1dc60c7504f4326bc83b9b628c384ec8d7e57096");
|
||||||
|
|
||||||
|
DiffFile b = iterator.next();
|
||||||
|
assertThat(b.getOldRevision()).isEqualTo("61780798228d17af2d34fce4cfbdf35556832472");
|
||||||
|
assertThat(b.getNewRevision()).isEqualTo("0000000000000000000000000000000000000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnFileHunks() throws IOException {
|
||||||
|
DiffResult diffResult = createDiffResult("3f76a12f08a6ba0dc988c68b7f0b2cd190efc3c4");
|
||||||
|
Iterator<DiffFile> iterator = diffResult.iterator();
|
||||||
|
|
||||||
|
DiffFile a = iterator.next();
|
||||||
|
Iterator<Hunk> hunks = a.iterator();
|
||||||
|
|
||||||
|
Hunk hunk = hunks.next();
|
||||||
|
assertThat(hunk.getOldStart()).isEqualTo(1);
|
||||||
|
assertThat(hunk.getOldLineCount()).isEqualTo(1);
|
||||||
|
|
||||||
|
assertThat(hunk.getNewStart()).isEqualTo(1);
|
||||||
|
assertThat(hunk.getNewLineCount()).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnFileHunksWithFullFileRange() throws IOException {
|
||||||
|
DiffResult diffResult = createDiffResult("fcd0ef1831e4002ac43ea539f4094334c79ea9ec");
|
||||||
|
Iterator<DiffFile> iterator = diffResult.iterator();
|
||||||
|
|
||||||
|
DiffFile a = iterator.next();
|
||||||
|
Iterator<Hunk> hunks = a.iterator();
|
||||||
|
|
||||||
|
Hunk hunk = hunks.next();
|
||||||
|
assertThat(hunk.getOldStart()).isEqualTo(1);
|
||||||
|
assertThat(hunk.getOldLineCount()).isEqualTo(1);
|
||||||
|
|
||||||
|
assertThat(hunk.getNewStart()).isEqualTo(1);
|
||||||
|
assertThat(hunk.getNewLineCount()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiffResult createDiffResult(String s) throws IOException {
|
||||||
|
GitDiffResultCommand gitDiffResultCommand = new GitDiffResultCommand(createContext(), repository);
|
||||||
|
DiffCommandRequest diffCommandRequest = new DiffCommandRequest();
|
||||||
|
diffCommandRequest.setRevision(s);
|
||||||
|
|
||||||
|
return gitDiffResultCommand.getDiffResult(diffCommandRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import sonia.scm.repository.api.DiffLine;
|
||||||
|
import sonia.scm.repository.api.Hunk;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
class GitHunkParserTest {
|
||||||
|
|
||||||
|
private static final String DIFF_001 = "diff --git a/a.txt b/a.txt\n" +
|
||||||
|
"index 7898192..2f8bc28 100644\n" +
|
||||||
|
"--- a/a.txt\n" +
|
||||||
|
"+++ b/a.txt\n" +
|
||||||
|
"@@ -1 +1,2 @@\n" +
|
||||||
|
" a\n" +
|
||||||
|
"+added line\n";
|
||||||
|
|
||||||
|
private static final String DIFF_002 = "diff --git a/file b/file\n" +
|
||||||
|
"index 5e89957..e8823e1 100644\n" +
|
||||||
|
"--- a/file\n" +
|
||||||
|
"+++ b/file\n" +
|
||||||
|
"@@ -2,6 +2,9 @@\n" +
|
||||||
|
" 2\n" +
|
||||||
|
" 3\n" +
|
||||||
|
" 4\n" +
|
||||||
|
"+5\n" +
|
||||||
|
"+6\n" +
|
||||||
|
"+7\n" +
|
||||||
|
" 8\n" +
|
||||||
|
" 9\n" +
|
||||||
|
" 10\n" +
|
||||||
|
"@@ -15,14 +18,13 @@\n" +
|
||||||
|
" 18\n" +
|
||||||
|
" 19\n" +
|
||||||
|
" 20\n" +
|
||||||
|
"+21\n" +
|
||||||
|
"+22\n" +
|
||||||
|
" 23\n" +
|
||||||
|
" 24\n" +
|
||||||
|
" 25\n" +
|
||||||
|
" 26\n" +
|
||||||
|
" 27\n" +
|
||||||
|
"-a\n" +
|
||||||
|
"-b\n" +
|
||||||
|
"-c\n" +
|
||||||
|
" 28\n" +
|
||||||
|
" 29\n" +
|
||||||
|
" 30";
|
||||||
|
|
||||||
|
private static final String DIFF_003 = "diff --git a/a.txt b/a.txt\n" +
|
||||||
|
"index 7898192..2f8bc28 100644\n" +
|
||||||
|
"--- a/a.txt\n" +
|
||||||
|
"+++ b/a.txt\n" +
|
||||||
|
"@@ -1,2 +1 @@\n" +
|
||||||
|
" a\n" +
|
||||||
|
"-removed line\n";
|
||||||
|
|
||||||
|
private static final String ILLEGAL_DIFF = "diff --git a/a.txt b/a.txt\n" +
|
||||||
|
"index 7898192..2f8bc28 100644\n" +
|
||||||
|
"--- a/a.txt\n" +
|
||||||
|
"+++ b/a.txt\n" +
|
||||||
|
"@@ -1,2 +1 @@\n" +
|
||||||
|
" a\n" +
|
||||||
|
"~illegal line\n";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldParseHunks() {
|
||||||
|
List<Hunk> hunks = new GitHunkParser().parse(DIFF_001);
|
||||||
|
assertThat(hunks).hasSize(1);
|
||||||
|
assertHunk(hunks.get(0), 1, 1, 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldParseMultipleHunks() {
|
||||||
|
List<Hunk> hunks = new GitHunkParser().parse(DIFF_002);
|
||||||
|
|
||||||
|
assertThat(hunks).hasSize(2);
|
||||||
|
assertHunk(hunks.get(0), 2, 6, 2, 9);
|
||||||
|
assertHunk(hunks.get(1), 15, 14, 18, 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldParseAddedHunkLines() {
|
||||||
|
List<Hunk> hunks = new GitHunkParser().parse(DIFF_001);
|
||||||
|
|
||||||
|
Hunk hunk = hunks.get(0);
|
||||||
|
|
||||||
|
Iterator<DiffLine> lines = hunk.iterator();
|
||||||
|
|
||||||
|
DiffLine line1 = lines.next();
|
||||||
|
assertThat(line1.getOldLineNumber()).hasValue(1);
|
||||||
|
assertThat(line1.getNewLineNumber()).hasValue(1);
|
||||||
|
assertThat(line1.getContent()).isEqualTo("a");
|
||||||
|
|
||||||
|
DiffLine line2 = lines.next();
|
||||||
|
assertThat(line2.getOldLineNumber()).isEmpty();
|
||||||
|
assertThat(line2.getNewLineNumber()).hasValue(2);
|
||||||
|
assertThat(line2.getContent()).isEqualTo("added line");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldParseRemovedHunkLines() {
|
||||||
|
List<Hunk> hunks = new GitHunkParser().parse(DIFF_003);
|
||||||
|
|
||||||
|
Hunk hunk = hunks.get(0);
|
||||||
|
|
||||||
|
Iterator<DiffLine> lines = hunk.iterator();
|
||||||
|
|
||||||
|
DiffLine line1 = lines.next();
|
||||||
|
assertThat(line1.getOldLineNumber()).hasValue(1);
|
||||||
|
assertThat(line1.getNewLineNumber()).hasValue(1);
|
||||||
|
assertThat(line1.getContent()).isEqualTo("a");
|
||||||
|
|
||||||
|
DiffLine line2 = lines.next();
|
||||||
|
assertThat(line2.getOldLineNumber()).hasValue(2);
|
||||||
|
assertThat(line2.getNewLineNumber()).isEmpty();
|
||||||
|
assertThat(line2.getContent()).isEqualTo("removed line");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldFailForIllegalLine() {
|
||||||
|
assertThrows(IllegalStateException.class, () -> new GitHunkParser().parse(ILLEGAL_DIFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertHunk(Hunk hunk, int oldStart, int oldLineCount, int newStart, int newLineCount) {
|
||||||
|
assertThat(hunk.getOldStart()).isEqualTo(oldStart);
|
||||||
|
assertThat(hunk.getOldLineCount()).isEqualTo(oldLineCount);
|
||||||
|
|
||||||
|
assertThat(hunk.getNewStart()).isEqualTo(newStart);
|
||||||
|
assertThat(hunk.getNewLineCount()).isEqualTo(newLineCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>scm-hg-plugin</artifactId>
|
<artifactId>scm-hg-plugin</artifactId>
|
||||||
<name>scm-hg-plugin</name>
|
|
||||||
<packaging>smp</packaging>
|
<packaging>smp</packaging>
|
||||||
<url>https://bitbucket.org/sdorra/scm-manager</url>
|
<url>https://bitbucket.org/sdorra/scm-manager</url>
|
||||||
<description>Plugin for the version control system Mercurial</description>
|
<description>Plugin for the version control system Mercurial</description>
|
||||||
|
|||||||
@@ -40,11 +40,10 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.web.HgUtil;
|
import sonia.scm.web.HgUtil;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -46,15 +46,10 @@ jo
|
|||||||
<scm-version>2</scm-version>
|
<scm-version>2</scm-version>
|
||||||
|
|
||||||
<information>
|
<information>
|
||||||
<author>Sebastian Sdorra</author>
|
<displayName>Mercurial</displayName>
|
||||||
<category>Mercurial</category>
|
<author>Cloudogu GmbH</author>
|
||||||
<tags>
|
<category>Source Code Management</category>
|
||||||
<tag>mercurial</tag>
|
<avatarUrl>/images/hg-logo.png</avatarUrl>
|
||||||
<tag>hg</tag>
|
|
||||||
<tag>scm</tag>
|
|
||||||
<tag>vcs</tag>
|
|
||||||
<tag>dvcs</tag>
|
|
||||||
</tags>
|
|
||||||
</information>
|
</information>
|
||||||
|
|
||||||
<conditions>
|
<conditions>
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
<artifactId>scm-plugins</artifactId>
|
<artifactId>scm-plugins</artifactId>
|
||||||
<version>2.0.0-SNAPSHOT</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>sonia.scm.plugins</groupId>
|
|
||||||
<artifactId>scm-legacy-plugin</artifactId>
|
<artifactId>scm-legacy-plugin</artifactId>
|
||||||
|
<description>Support migrated repository urls and v1 passwords</description>
|
||||||
<version>2.0.0-SNAPSHOT</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
<packaging>smp</packaging>
|
<packaging>smp</packaging>
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
<version>${servlet.version}</version>
|
<version>${servlet.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.ws.rs</groupId>
|
<groupId>javax.ws.rs</groupId>
|
||||||
<artifactId>jsr311-api</artifactId>
|
<artifactId>jsr311-api</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package sonia.scm.legacy;
|
||||||
|
|
||||||
|
import sonia.scm.Priority;
|
||||||
|
import sonia.scm.config.ScmConfiguration;
|
||||||
|
import sonia.scm.filter.Filters;
|
||||||
|
import sonia.scm.filter.WebElement;
|
||||||
|
import sonia.scm.web.UserAgentParser;
|
||||||
|
import sonia.scm.web.WebTokenGenerator;
|
||||||
|
import sonia.scm.web.filter.HttpProtocolServletAuthenticationFilterBase;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Priority(Filters.PRIORITY_AUTHENTICATION)
|
||||||
|
@WebElement(value = "/git/*", morePatterns = {"/hg/*", "/svn/*"})
|
||||||
|
public class LegacyProtocolServletAuthenticationFilter extends HttpProtocolServletAuthenticationFilterBase {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public LegacyProtocolServletAuthenticationFilter(ScmConfiguration configuration, Set<WebTokenGenerator> tokenGenerators, UserAgentParser userAgentParser) {
|
||||||
|
super(configuration, tokenGenerators, userAgentParser);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { withRouter } from "react-router-dom";
|
import {withRouter} from "react-router-dom";
|
||||||
|
|
||||||
class DummyComponent extends React.Component<Props, State> {
|
class DummyComponent extends React.Component<Props, State> {
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { withRouter } from "react-router-dom";
|
import {withRouter} from "react-router-dom";
|
||||||
import { binder } from "@scm-manager/ui-extensions";
|
import {binder} from "@scm-manager/ui-extensions";
|
||||||
import {
|
import {apiClient, ErrorBoundary, ErrorNotification, ProtectedRoute} from "@scm-manager/ui-components";
|
||||||
ProtectedRoute,
|
|
||||||
apiClient,
|
|
||||||
ErrorNotification,
|
|
||||||
ErrorBoundary
|
|
||||||
} from "@scm-manager/ui-components";
|
|
||||||
import DummyComponent from "./DummyComponent";
|
import DummyComponent from "./DummyComponent";
|
||||||
import type {Links} from "@scm-manager/ui-types";
|
import type {Links} from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,9 @@
|
|||||||
<scm-version>2</scm-version>
|
<scm-version>2</scm-version>
|
||||||
|
|
||||||
<information>
|
<information>
|
||||||
<author>Sebastian Sdorra</author>
|
<displayName>Legacy</displayName>
|
||||||
|
<author>Cloudogu GmbH</author>
|
||||||
|
<category>Legacy Support</category>
|
||||||
</information>
|
</information>
|
||||||
|
|
||||||
<conditions>
|
<conditions>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import sonia.scm.repository.Repository;
|
|||||||
import sonia.scm.repository.RepositoryManager;
|
import sonia.scm.repository.RepositoryManager;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.*;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>scm-svn-plugin</artifactId>
|
<artifactId>scm-svn-plugin</artifactId>
|
||||||
<name>scm-svn-plugin</name>
|
|
||||||
<packaging>smp</packaging>
|
<packaging>smp</packaging>
|
||||||
<url>https://bitbucket.org/sdorra/scm-manager</url>
|
<url>https://bitbucket.org/sdorra/scm-manager</url>
|
||||||
<description>Plugin for the version control system Subversion</description>
|
<description>Plugin for the version control system Subversion</description>
|
||||||
|
|||||||
@@ -46,14 +46,10 @@
|
|||||||
<scm-version>2</scm-version>
|
<scm-version>2</scm-version>
|
||||||
|
|
||||||
<information>
|
<information>
|
||||||
<author>Sebastian Sdorra</author>
|
<displayName>Subversion</displayName>
|
||||||
<category>Subversion</category>
|
<author>Cloudogu GmbH</author>
|
||||||
<tags>
|
<category>Source Code Management</category>
|
||||||
<tag>subversion</tag>
|
<avatarUrl>/images/svn-logo.gif</avatarUrl>
|
||||||
<tag>scm</tag>
|
|
||||||
<tag>vcs</tag>
|
|
||||||
<tag>svn</tag>
|
|
||||||
</tags>
|
|
||||||
</information>
|
</information>
|
||||||
|
|
||||||
<conditions>
|
<conditions>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { AsyncCreatable, Async } from "react-select";
|
import {Async, AsyncCreatable} from "react-select";
|
||||||
import type { AutocompleteObject, SelectValue } from "@scm-manager/ui-types";
|
import type {AutocompleteObject, SelectValue} from "@scm-manager/ui-types";
|
||||||
import LabelWithHelpIcon from "./forms/LabelWithHelpIcon";
|
import LabelWithHelpIcon from "./forms/LabelWithHelpIcon";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -25,12 +25,17 @@ const styles = {
|
|||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexGrow: 1
|
flexGrow: 1,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between"
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
marginTop: "auto",
|
marginTop: "auto",
|
||||||
paddingBottom: "1.5rem"
|
paddingBottom: "1.5rem"
|
||||||
|
},
|
||||||
|
noBottomMargin: {
|
||||||
|
marginBottom: "0 !important"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,24 +43,37 @@ type Props = {
|
|||||||
title: string,
|
title: string,
|
||||||
description: string,
|
description: string,
|
||||||
avatar: React.Node,
|
avatar: React.Node,
|
||||||
|
contentRight?: React.Node,
|
||||||
footerLeft: React.Node,
|
footerLeft: React.Node,
|
||||||
footerRight: React.Node,
|
footerRight: React.Node,
|
||||||
link: string,
|
link?: string,
|
||||||
|
action?: () => void,
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
classes: any
|
classes: any
|
||||||
};
|
};
|
||||||
|
|
||||||
class CardColumn extends React.Component<Props> {
|
class CardColumn extends React.Component<Props> {
|
||||||
createLink = () => {
|
createLink = () => {
|
||||||
const { link } = this.props;
|
const { link, action } = this.props;
|
||||||
if (link) {
|
if (link) {
|
||||||
return <Link className="overlay-column" to={link} />;
|
return <Link className="overlay-column" to={link} />;
|
||||||
|
} else if (action) {
|
||||||
|
return <a className="overlay-column" onClick={e => {e.preventDefault(); action();}} href="#" />;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { avatar, title, description, footerLeft, footerRight, classes } = this.props;
|
const {
|
||||||
|
avatar,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
contentRight,
|
||||||
|
footerLeft,
|
||||||
|
footerRight,
|
||||||
|
classes
|
||||||
|
} = this.props;
|
||||||
const link = this.createLink();
|
const link = this.createLink();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -64,16 +82,29 @@ class CardColumn extends React.Component<Props> {
|
|||||||
<figure className={classNames(classes.centerImage, "media-left")}>
|
<figure className={classNames(classes.centerImage, "media-left")}>
|
||||||
{avatar}
|
{avatar}
|
||||||
</figure>
|
</figure>
|
||||||
<div className={classNames("media-content", "text-box", classes.flexFullHeight)}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"media-content",
|
||||||
|
"text-box",
|
||||||
|
classes.flexFullHeight
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div className={classes.content}>
|
<div className={classes.content}>
|
||||||
<div className="content shorten-text">
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"content",
|
||||||
|
"shorten-text",
|
||||||
|
classes.noBottomMargin
|
||||||
|
)}
|
||||||
|
>
|
||||||
<p className="is-marginless">
|
<p className="is-marginless">
|
||||||
<strong>{title}</strong>
|
<strong>{title}</strong>
|
||||||
</p>
|
</p>
|
||||||
<p className="shorten-text">{description}</p>
|
<p className="shorten-text">{description}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{contentRight && contentRight}
|
||||||
</div>
|
</div>
|
||||||
<div className={classNames(classes.footer, "level")}>
|
<div className={classNames("level", classes.footer)}>
|
||||||
<div className="level-left is-hidden-mobile">{footerLeft}</div>
|
<div className="level-left is-hidden-mobile">{footerLeft}</div>
|
||||||
<div className="level-right is-mobile">{footerRight}</div>
|
<div className="level-right is-mobile">{footerRight}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import {translate} from "react-i18next";
|
||||||
import { BackendError, ForbiddenError, UnauthorizedError } from "./errors";
|
import {BackendError, ForbiddenError, UnauthorizedError} from "./errors";
|
||||||
import Notification from "./Notification";
|
import Notification from "./Notification";
|
||||||
import BackendErrorNotification from "./BackendErrorNotification";
|
import BackendErrorNotification from "./BackendErrorNotification";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { translate } from "react-i18next";
|
import {translate} from "react-i18next";
|
||||||
import type AutocompleteProps from "./UserGroupAutocomplete";
|
import type AutocompleteProps from "./UserGroupAutocomplete";
|
||||||
import UserGroupAutocomplete from "./UserGroupAutocomplete";
|
import UserGroupAutocomplete from "./UserGroupAutocomplete";
|
||||||
|
|
||||||
|
|||||||