mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 16:35:45 +01:00
merge with develop
This commit is contained in:
@@ -5,9 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Introduced merge detection for receive hooks ([#1278](https://github.com/scm-manager/scm-manager/pull/1278))
|
||||||
- Anonymous mode for the web ui ([#1284](https://github.com/scm-manager/scm-manager/pull/1284))
|
- Anonymous mode for the web ui ([#1284](https://github.com/scm-manager/scm-manager/pull/1284))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Repository names may not end with ".git" ([#1277](https://github.com/scm-manager/scm-manager/pull/1277))
|
||||||
|
|
||||||
## [2.3.1] - 2020-08-04
|
## [2.3.1] - 2020-08-04
|
||||||
### Added
|
### Added
|
||||||
- New api to resolve SCM-Manager root url ([#1276](https://github.com/scm-manager/scm-manager/pull/1276))
|
- New api to resolve SCM-Manager root url ([#1276](https://github.com/scm-manager/scm-manager/pull/1276))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ The location of the file depends also on the type of installation.
|
|||||||
|
|
||||||
| Type of Installation | Path |
|
| Type of Installation | Path |
|
||||||
|----------------------|---------|
|
|----------------------|---------|
|
||||||
| Docker | /opt/scm-server/conf/logging.xml |
|
| Docker | /etc/scm/logging.xml |
|
||||||
| RPM | /etc/scm/logging.xml |
|
| RPM | /etc/scm/logging.xml |
|
||||||
| DEB | /etc/scm/logging.xml |
|
| DEB | /etc/scm/logging.xml |
|
||||||
| Unix | $EXTRACT_PATH/scm-server/conf/logging.xml |
|
| Unix | $EXTRACT_PATH/scm-server/conf/logging.xml |
|
||||||
|
|||||||
24
docs/en/development/integration-tests.md
Normal file
24
docs/en/development/integration-tests.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
title: Integration Tests
|
||||||
|
subtitle: How to run integration tests
|
||||||
|
displayToc: false
|
||||||
|
---
|
||||||
|
|
||||||
|
You can find the integration tests in the module **scm-it** (and a few still in **scm-webapp**). To run them,
|
||||||
|
simply start maven with the profile `it`:
|
||||||
|
|
||||||
|
```
|
||||||
|
mvn install -Pit -DskipUnitTests -pl :scm-webapp,:scm-it
|
||||||
|
```
|
||||||
|
|
||||||
|
This will start a jetty server and execute all integration tests in the maven phase `integration-test` using the
|
||||||
|
normal failsafe plugin. Integration tests are all classes ending with `ITCase` and are written using JUnit.
|
||||||
|
|
||||||
|
To develop integration tests, you should start a local server with the **scm-integration-test-plugin**. This plugin is
|
||||||
|
used as a way to introspect server internals. For example you can register event listeners here and access their
|
||||||
|
triggers with a REST endpoint. Of course, this plugin is not and should not be installed in productive systems.
|
||||||
|
You can start the server with this plugin using the following maven call:
|
||||||
|
|
||||||
|
```
|
||||||
|
mvn run -pl :scm-integration-test-plugin
|
||||||
|
```
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
- /development/definition-of-done/
|
- /development/definition-of-done/
|
||||||
- /development/ui-dod/
|
- /development/ui-dod/
|
||||||
- /development/decision-table/
|
- /development/decision-table/
|
||||||
|
- /development/integration-tests/
|
||||||
|
|
||||||
- section: Plugin Development
|
- section: Plugin Development
|
||||||
entries:
|
entries:
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import sonia.scm.repository.Changeset;
|
|||||||
import sonia.scm.repository.PreProcessorUtil;
|
import sonia.scm.repository.PreProcessorUtil;
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.spi.HookContextProvider;
|
import sonia.scm.repository.spi.HookContextProvider;
|
||||||
|
import sonia.scm.repository.spi.HookMergeDetectionProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The context for all repository hooks. With the {@link HookContext} class it
|
* The context for all repository hooks. With the {@link HookContext} class it
|
||||||
@@ -43,8 +44,7 @@ import sonia.scm.repository.spi.HookContextProvider;
|
|||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
* @since 1.33
|
* @since 1.33
|
||||||
*/
|
*/
|
||||||
public final class HookContext
|
public final class HookContext {
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the logger for HookContext
|
* the logger for HookContext
|
||||||
@@ -52,8 +52,6 @@ public final class HookContext
|
|||||||
private static final Logger logger =
|
private static final Logger logger =
|
||||||
LoggerFactory.getLogger(HookContext.class);
|
LoggerFactory.getLogger(HookContext.class);
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs ...
|
* Constructs ...
|
||||||
*
|
*
|
||||||
@@ -62,9 +60,7 @@ public final class HookContext
|
|||||||
* @param repository
|
* @param repository
|
||||||
* @param preProcessorUtil
|
* @param preProcessorUtil
|
||||||
*/
|
*/
|
||||||
HookContext(HookContextProvider provider, Repository repository,
|
HookContext(HookContextProvider provider, Repository repository, PreProcessorUtil preProcessorUtil) {
|
||||||
PreProcessorUtil preProcessorUtil)
|
|
||||||
{
|
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.preProcessorUtil = preProcessorUtil;
|
this.preProcessorUtil = preProcessorUtil;
|
||||||
@@ -83,13 +79,9 @@ public final class HookContext
|
|||||||
*
|
*
|
||||||
* @since 1.45
|
* @since 1.45
|
||||||
*/
|
*/
|
||||||
public HookBranchProvider getBranchProvider()
|
public HookBranchProvider getBranchProvider() {
|
||||||
{
|
logger.debug("create branch provider for repository {}",
|
||||||
if (logger.isDebugEnabled())
|
repository.getName());
|
||||||
{
|
|
||||||
logger.debug("create branch provider for repository {}",
|
|
||||||
repository.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider.getBranchProvider();
|
return provider.getBranchProvider();
|
||||||
}
|
}
|
||||||
@@ -105,13 +97,9 @@ public final class HookContext
|
|||||||
*
|
*
|
||||||
* @since 1.50
|
* @since 1.50
|
||||||
*/
|
*/
|
||||||
public HookTagProvider getTagProvider()
|
public HookTagProvider getTagProvider() {
|
||||||
{
|
logger.debug("create tag provider for repository {}",
|
||||||
if (logger.isDebugEnabled())
|
repository.getName());
|
||||||
{
|
|
||||||
logger.debug("create tag provider for repository {}",
|
|
||||||
repository.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider.getTagProvider();
|
return provider.getTagProvider();
|
||||||
}
|
}
|
||||||
@@ -126,21 +114,15 @@ public final class HookContext
|
|||||||
* @throws HookFeatureIsNotSupportedException if the feature is not supported
|
* @throws HookFeatureIsNotSupportedException if the feature is not supported
|
||||||
* by the underlying provider
|
* by the underlying provider
|
||||||
*/
|
*/
|
||||||
public HookChangesetBuilder getChangesetProvider()
|
public HookChangesetBuilder getChangesetProvider() {
|
||||||
{
|
logger.debug("create changeset provider for repository {}",
|
||||||
if (logger.isDebugEnabled())
|
repository.getName());
|
||||||
{
|
|
||||||
logger.debug("create changeset provider for repository {}",
|
|
||||||
repository.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
//J-
|
|
||||||
return new HookChangesetBuilder(
|
return new HookChangesetBuilder(
|
||||||
repository,
|
repository,
|
||||||
preProcessorUtil,
|
preProcessorUtil,
|
||||||
provider.getChangesetProvider()
|
provider.getChangesetProvider()
|
||||||
);
|
);
|
||||||
//J+
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,17 +138,29 @@ public final class HookContext
|
|||||||
* @throws HookFeatureIsNotSupportedException if the feature is not supported
|
* @throws HookFeatureIsNotSupportedException if the feature is not supported
|
||||||
* by the underlying provider
|
* by the underlying provider
|
||||||
*/
|
*/
|
||||||
public HookMessageProvider getMessageProvider()
|
public HookMessageProvider getMessageProvider() {
|
||||||
{
|
logger.debug("create message provider for repository {}",
|
||||||
if (logger.isDebugEnabled())
|
repository.getName());
|
||||||
{
|
|
||||||
logger.debug("create message provider for repository {}",
|
|
||||||
repository.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider.getMessageProvider();
|
return provider.getMessageProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link HookMergeDetectionProvider} which is able to check whether two
|
||||||
|
* branches have been merged with the incoming changesets.
|
||||||
|
*
|
||||||
|
* @return {@link HookMergeDetectionProvider} which is able to detect merges.
|
||||||
|
*
|
||||||
|
* @throws HookFeatureIsNotSupportedException if the feature is not supported
|
||||||
|
* by the underlying provider
|
||||||
|
*/
|
||||||
|
public HookMergeDetectionProvider getMergeDetectionProvider() {
|
||||||
|
logger.debug("create merge detection provider for repository {}",
|
||||||
|
repository.getName());
|
||||||
|
|
||||||
|
return provider.getMergeDetectionProvider();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the underlying provider support the requested feature.
|
* Returns true if the underlying provider support the requested feature.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -55,5 +55,12 @@ public enum HookFeature
|
|||||||
*
|
*
|
||||||
* @since 1.50
|
* @since 1.50
|
||||||
*/
|
*/
|
||||||
TAG_PROVIDER;
|
TAG_PROVIDER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider to detect merges
|
||||||
|
*
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
MERGE_DETECTION_PROVIDER
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,16 @@ public abstract class HookContextProvider
|
|||||||
throw new HookFeatureIsNotSupportedException(HookFeature.CHANGESET_PROVIDER);
|
throw new HookFeatureIsNotSupportedException(HookFeature.CHANGESET_PROVIDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the provider specific {@link HookMergeDetectionProvider} or throws a {@link HookFeatureIsNotSupportedException}.
|
||||||
|
*
|
||||||
|
* @return provider specific {@link HookMergeDetectionProvider}
|
||||||
|
*/
|
||||||
|
public HookMergeDetectionProvider getMergeDetectionProvider()
|
||||||
|
{
|
||||||
|
throw new HookFeatureIsNotSupportedException(HookFeature.MERGE_DETECTION_PROVIDER);
|
||||||
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public interface HookMergeDetectionProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether <code>branch</code> has been merged into <code>target</code>. So this will also return
|
||||||
|
* <code>true</code>, when <code>branch</code> has been deleted with this change.
|
||||||
|
*
|
||||||
|
* @param target The name of the branch to check, whether the other branch has been merged into.
|
||||||
|
* @param branch The name of the branch to check, whether it has been merged into the other branch.
|
||||||
|
* @return <code>true</code> when <code>branch</code> has been merged into <code>target</code>, <code>false</code>
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
boolean branchesMerged(String target, String branch);
|
||||||
|
}
|
||||||
@@ -192,6 +192,7 @@
|
|||||||
<version>2.10</version>
|
<version>2.10</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<artifactItems>
|
<artifactItems>
|
||||||
|
<!-- Copy war file -->
|
||||||
<artifactItem>
|
<artifactItem>
|
||||||
<groupId>sonia.scm</groupId>
|
<groupId>sonia.scm</groupId>
|
||||||
<artifactId>scm-webapp</artifactId>
|
<artifactId>scm-webapp</artifactId>
|
||||||
@@ -200,6 +201,15 @@
|
|||||||
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
||||||
<destFileName>scm-webapp.war</destFileName>
|
<destFileName>scm-webapp.war</destFileName>
|
||||||
</artifactItem>
|
</artifactItem>
|
||||||
|
<!-- Copy integration test plugin -->
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>sonia.scm.plugins</groupId>
|
||||||
|
<artifactId>scm-integration-test-plugin</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>smp</type>
|
||||||
|
<outputDirectory>${scm.home}/plugins</outputDirectory>
|
||||||
|
<destFileName>scm-integration-test-plugin.smp</destFileName>
|
||||||
|
</artifactItem>
|
||||||
</artifactItems>
|
</artifactItems>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
@@ -273,7 +283,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<scm.stage>DEVELOPMENT</scm.stage>
|
<scm.stage>DEVELOPMENT</scm.stage>
|
||||||
<scm.home>target/scm-it</scm.home>
|
<scm.home>${project.parent.build.directory}/scm-it</scm.home>
|
||||||
<scm-it.logbackConfiguration>${project.basedir}/../scm-webapp/src/main/resources/logback.default.xml</scm-it.logbackConfiguration>
|
<scm-it.logbackConfiguration>${project.basedir}/../scm-webapp/src/main/resources/logback.default.xml</scm-it.logbackConfiguration>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|||||||
185
scm-it/src/test/java/sonia/scm/it/MergeDetectionITCase.java
Normal file
185
scm-it/src/test/java/sonia/scm/it/MergeDetectionITCase.java
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.it;
|
||||||
|
|
||||||
|
import io.restassured.RestAssured;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import sonia.scm.it.utils.RepositoryUtil;
|
||||||
|
import sonia.scm.it.utils.RestUtil;
|
||||||
|
import sonia.scm.it.utils.TestData;
|
||||||
|
import sonia.scm.repository.Person;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClient;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static sonia.scm.it.utils.TestData.USER_SCM_ADMIN;
|
||||||
|
|
||||||
|
class MergeDetectionITCase {
|
||||||
|
|
||||||
|
private static final Person ARTHUR = new Person("arthur", "arthur@hitchhiker.com");
|
||||||
|
|
||||||
|
RepositoryClient client;
|
||||||
|
String masterFile;
|
||||||
|
String developFile;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void createRepository(@TempDir Path tempDir) throws IOException {
|
||||||
|
TestData.createDefault();
|
||||||
|
|
||||||
|
client = RepositoryUtil.createRepositoryClient("git", tempDir.toFile());
|
||||||
|
|
||||||
|
masterFile = createFile(tempDir, "hg2g.md");
|
||||||
|
developFile = createFile(tempDir, "how_to_make_tea.md");
|
||||||
|
|
||||||
|
client.getAddCommand().add(masterFile);
|
||||||
|
client.getCommitCommand().commit(ARTHUR, "Add base file");
|
||||||
|
client.getPushCommand().push();
|
||||||
|
|
||||||
|
client.getBranchCommand().branch("develop");
|
||||||
|
client.getCheckoutCommand().checkout("develop");
|
||||||
|
client.getAddCommand().add(developFile);
|
||||||
|
client.getCommitCommand().commit(ARTHUR, "add more important things");
|
||||||
|
client.getPushCommand().push();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void disableMergeDetection() {
|
||||||
|
RestAssured.given()
|
||||||
|
.auth().preemptive().basic(USER_SCM_ADMIN, USER_SCM_ADMIN)
|
||||||
|
.when()
|
||||||
|
.contentType("application/json")
|
||||||
|
.accept("application/json")
|
||||||
|
.body(toJson("{}"))
|
||||||
|
.post(RestUtil.createResourceUrl("integration-test/merge-detection/"))
|
||||||
|
.then()
|
||||||
|
.statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDetectSimpleMergeAsMerged() throws IOException {
|
||||||
|
client.getCheckoutCommand().checkout("master");
|
||||||
|
client.getMergeCommand().noFf().merge("develop");
|
||||||
|
|
||||||
|
initializeMergeDetection("master", "develop");
|
||||||
|
|
||||||
|
client.getPushCommand().push();
|
||||||
|
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("preMergeDetection", 0)).isTrue();
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("postMergeDetection", 0)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDetectFastForwardAsMerged() throws IOException {
|
||||||
|
client.getCheckoutCommand().checkout("master");
|
||||||
|
client.getMergeCommand().merge("develop");
|
||||||
|
|
||||||
|
initializeMergeDetection("master", "develop");
|
||||||
|
|
||||||
|
client.getPushCommand().push();
|
||||||
|
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("preMergeDetection", 0)).isTrue();
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("postMergeDetection", 0)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDetectMergeWhenBranchHasBeenDeletedAsMerged() throws IOException {
|
||||||
|
client.getCheckoutCommand().checkout("master");
|
||||||
|
client.getMergeCommand().merge("develop");
|
||||||
|
client.getPushCommand().push();
|
||||||
|
|
||||||
|
initializeMergeDetection("master", "develop");
|
||||||
|
|
||||||
|
client.getDeleteRemoteBranchCommand().delete("develop");
|
||||||
|
client.getPushCommand().push();
|
||||||
|
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("preMergeDetection", 0)).isTrue();
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("postMergeDetection", 0)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDetectNormalPushAsNotMerged(@TempDir Path tempDir) throws IOException {
|
||||||
|
client.getCheckoutCommand().checkout("develop");
|
||||||
|
writeFile(tempDir, developFile, "other content");
|
||||||
|
client.getAddCommand().add(developFile);
|
||||||
|
client.getCommitCommand().commit(ARTHUR, "simple commit");
|
||||||
|
|
||||||
|
initializeMergeDetection("master", "develop");
|
||||||
|
|
||||||
|
client.getPushCommand().push();
|
||||||
|
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("preMergeDetection", 0)).isFalse();
|
||||||
|
Assertions.assertThat(getMergeDetectionResult("postMergeDetection", 0)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getMergeDetectionResult(String type, int n) {
|
||||||
|
return RestAssured.given()
|
||||||
|
.auth().preemptive().basic(USER_SCM_ADMIN, USER_SCM_ADMIN)
|
||||||
|
.when()
|
||||||
|
.accept("application/json")
|
||||||
|
.get(RestUtil.createResourceUrl("integration-test/"))
|
||||||
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
|
.extract()
|
||||||
|
.jsonPath()
|
||||||
|
.getBoolean("_embedded." +
|
||||||
|
type +
|
||||||
|
"[" + n + "].merged");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeMergeDetection(String target, String branch) {
|
||||||
|
RestAssured.given()
|
||||||
|
.auth().preemptive().basic(USER_SCM_ADMIN, USER_SCM_ADMIN)
|
||||||
|
.when()
|
||||||
|
.contentType("application/json")
|
||||||
|
.accept("application/json")
|
||||||
|
.body(toJson(format("{'target': '%s', 'branch': '%s'}", target, branch)))
|
||||||
|
.post(RestUtil.createResourceUrl("integration-test/merge-detection/"))
|
||||||
|
.then()
|
||||||
|
.statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createFile(Path tempDir, String name) throws IOException {
|
||||||
|
Files.createFile(tempDir.resolve(name));
|
||||||
|
writeFile(tempDir, name, "Some content");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFile(Path tempDir, String name, String content) throws IOException {
|
||||||
|
Path file = tempDir.resolve(name);
|
||||||
|
Files.write(file, singletonList(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toJson(String json) {
|
||||||
|
return json.replaceAll("'", "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
<module>scm-git-plugin</module>
|
<module>scm-git-plugin</module>
|
||||||
<module>scm-svn-plugin</module>
|
<module>scm-svn-plugin</module>
|
||||||
<module>scm-legacy-plugin</module>
|
<module>scm-legacy-plugin</module>
|
||||||
|
<module>scm-integration-test-plugin</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -337,6 +337,16 @@ public final class GitUtil
|
|||||||
return Strings.nullToEmpty(refName).startsWith(PREFIX_HEADS);
|
return Strings.nullToEmpty(refName).startsWith(PREFIX_HEADS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Ref getBranchIdOrCurrentHead(org.eclipse.jgit.lib.Repository gitRepository, String requestedBranch) throws IOException {
|
||||||
|
if ( Strings.isNullOrEmpty(requestedBranch) ) {
|
||||||
|
logger.trace("no default branch configured, use repository head as default");
|
||||||
|
Optional<Ref> repositoryHeadRef = GitUtil.getRepositoryHeadRef(gitRepository);
|
||||||
|
return repositoryHeadRef.orElse(null);
|
||||||
|
} else {
|
||||||
|
return GitUtil.getBranchId(gitRepository, requestedBranch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.api;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.AnyObjectId;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||||
|
import sonia.scm.repository.GitUtil;
|
||||||
|
import sonia.scm.repository.spi.GitLogComputer;
|
||||||
|
import sonia.scm.repository.spi.HookMergeDetectionProvider;
|
||||||
|
import sonia.scm.repository.spi.LogCommandRequest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GitReceiveHookMergeDetectionProvider implements HookMergeDetectionProvider {
|
||||||
|
private final Repository repository;
|
||||||
|
private final String repositoryId;
|
||||||
|
private final List<ReceiveCommand> receiveCommands;
|
||||||
|
|
||||||
|
public GitReceiveHookMergeDetectionProvider(Repository repository, String repositoryId, List<ReceiveCommand> receiveCommands) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.repositoryId = repositoryId;
|
||||||
|
this.receiveCommands = receiveCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean branchesMerged(String target, String branch) {
|
||||||
|
LogCommandRequest request = new LogCommandRequest();
|
||||||
|
request.setBranch(findRelevantRevisionForBranchIfToBeUpdated(branch));
|
||||||
|
request.setAncestorChangeset(findRelevantRevisionForBranchIfToBeUpdated(target));
|
||||||
|
request.setPagingLimit(1);
|
||||||
|
|
||||||
|
return new GitLogComputer(repositoryId, repository).compute(request).getTotal() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String findRelevantRevisionForBranchIfToBeUpdated(String branch) {
|
||||||
|
return receiveCommands
|
||||||
|
.stream()
|
||||||
|
.filter(receiveCommand -> isReceiveCommandForBranch(branch, receiveCommand))
|
||||||
|
.map(this::getRelevantRevision)
|
||||||
|
.map(AnyObjectId::getName)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReceiveCommandForBranch(String branch, ReceiveCommand receiveCommand) {
|
||||||
|
return receiveCommand.getType() != ReceiveCommand.Type.CREATE
|
||||||
|
&& GitUtil.getBranch(receiveCommand.getRef()).equals(branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObjectId getRelevantRevision(ReceiveCommand receiveCommand) {
|
||||||
|
if (receiveCommand.getType() == ReceiveCommand.Type.DELETE) {
|
||||||
|
return receiveCommand.getOldId();
|
||||||
|
} else {
|
||||||
|
return receiveCommand.getNewId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,6 @@ import org.eclipse.jgit.transport.PushResult;
|
|||||||
import org.eclipse.jgit.transport.RemoteRefUpdate;
|
import org.eclipse.jgit.transport.RemoteRefUpdate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.repository.GitUtil;
|
|
||||||
import sonia.scm.repository.GitWorkingCopyFactory;
|
import sonia.scm.repository.GitWorkingCopyFactory;
|
||||||
import sonia.scm.repository.InternalRepositoryException;
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
import sonia.scm.repository.Person;
|
import sonia.scm.repository.Person;
|
||||||
@@ -59,6 +58,7 @@ import static java.util.Optional.empty;
|
|||||||
import static java.util.Optional.of;
|
import static java.util.Optional.of;
|
||||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||||
import static sonia.scm.NotFoundException.notFound;
|
import static sonia.scm.NotFoundException.notFound;
|
||||||
|
import static sonia.scm.repository.GitUtil.getBranchIdOrCurrentHead;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -123,15 +123,9 @@ class AbstractGitCommand
|
|||||||
Ref getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException {
|
Ref getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException {
|
||||||
if ( Strings.isNullOrEmpty(requestedBranch) ) {
|
if ( Strings.isNullOrEmpty(requestedBranch) ) {
|
||||||
String defaultBranchName = context.getConfig().getDefaultBranch();
|
String defaultBranchName = context.getConfig().getDefaultBranch();
|
||||||
if (!Strings.isNullOrEmpty(defaultBranchName)) {
|
return getBranchIdOrCurrentHead(gitRepository, defaultBranchName);
|
||||||
return GitUtil.getBranchId(gitRepository, defaultBranchName);
|
|
||||||
} else {
|
|
||||||
logger.trace("no default branch configured, use repository head as default");
|
|
||||||
Optional<Ref> repositoryHeadRef = GitUtil.getRepositoryHeadRef(gitRepository);
|
|
||||||
return repositoryHeadRef.orElse(null);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return GitUtil.getBranchId(gitRepository, requestedBranch);
|
return getBranchIdOrCurrentHead(gitRepository, requestedBranch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,22 +26,21 @@ package sonia.scm.repository.spi;
|
|||||||
|
|
||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||||
import org.eclipse.jgit.transport.ReceivePack;
|
import org.eclipse.jgit.transport.ReceivePack;
|
||||||
|
|
||||||
import sonia.scm.repository.api.GitHookBranchProvider;
|
import sonia.scm.repository.api.GitHookBranchProvider;
|
||||||
import sonia.scm.repository.api.GitHookMessageProvider;
|
import sonia.scm.repository.api.GitHookMessageProvider;
|
||||||
|
import sonia.scm.repository.api.GitHookTagProvider;
|
||||||
|
import sonia.scm.repository.api.GitReceiveHookMergeDetectionProvider;
|
||||||
import sonia.scm.repository.api.HookBranchProvider;
|
import sonia.scm.repository.api.HookBranchProvider;
|
||||||
import sonia.scm.repository.api.HookFeature;
|
import sonia.scm.repository.api.HookFeature;
|
||||||
import sonia.scm.repository.api.HookMessageProvider;
|
import sonia.scm.repository.api.HookMessageProvider;
|
||||||
|
import sonia.scm.repository.api.HookTagProvider;
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import sonia.scm.repository.api.GitHookTagProvider;
|
|
||||||
import sonia.scm.repository.api.HookTagProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -50,24 +49,34 @@ import sonia.scm.repository.api.HookTagProvider;
|
|||||||
public class GitHookContextProvider extends HookContextProvider
|
public class GitHookContextProvider extends HookContextProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
/** Field description */
|
/**
|
||||||
private static final Set<HookFeature> SUPPORTED_FEATURES =
|
* Field description
|
||||||
EnumSet.of(HookFeature.MESSAGE_PROVIDER, HookFeature.CHANGESET_PROVIDER,
|
*/
|
||||||
HookFeature.BRANCH_PROVIDER, HookFeature.TAG_PROVIDER);
|
private static final Set<HookFeature> SUPPORTED_FEATURES = EnumSet.of(
|
||||||
|
HookFeature.MESSAGE_PROVIDER,
|
||||||
|
HookFeature.CHANGESET_PROVIDER,
|
||||||
|
HookFeature.BRANCH_PROVIDER,
|
||||||
|
HookFeature.TAG_PROVIDER,
|
||||||
|
HookFeature.MERGE_DETECTION_PROVIDER
|
||||||
|
);
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance
|
* Constructs a new instance
|
||||||
*
|
|
||||||
* @param receivePack git receive pack
|
* @param receivePack git receive pack
|
||||||
* @param receiveCommands received commands
|
* @param receiveCommands received commands
|
||||||
*/
|
*/
|
||||||
public GitHookContextProvider(ReceivePack receivePack,
|
public GitHookContextProvider(
|
||||||
List<ReceiveCommand> receiveCommands)
|
ReceivePack receivePack,
|
||||||
{
|
List<ReceiveCommand> receiveCommands,
|
||||||
|
Repository repository,
|
||||||
|
String repositoryId
|
||||||
|
) {
|
||||||
this.receivePack = receivePack;
|
this.receivePack = receivePack;
|
||||||
this.receiveCommands = receiveCommands;
|
this.receiveCommands = receiveCommands;
|
||||||
|
this.repository = repository;
|
||||||
|
this.repositoryId = repositoryId;
|
||||||
this.changesetProvider = new GitHookChangesetProvider(receivePack,
|
this.changesetProvider = new GitHookChangesetProvider(receivePack,
|
||||||
receiveCommands);
|
receiveCommands);
|
||||||
}
|
}
|
||||||
@@ -99,20 +108,20 @@ public class GitHookContextProvider extends HookContextProvider
|
|||||||
return changesetProvider;
|
return changesetProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HookMergeDetectionProvider getMergeDetectionProvider() {
|
||||||
|
return new GitReceiveHookMergeDetectionProvider(repository, repositoryId, receiveCommands);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<HookFeature> getSupportedFeatures()
|
public Set<HookFeature> getSupportedFeatures()
|
||||||
{
|
{
|
||||||
return SUPPORTED_FEATURES;
|
return SUPPORTED_FEATURES;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final GitHookChangesetProvider changesetProvider;
|
private final GitHookChangesetProvider changesetProvider;
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final List<ReceiveCommand> receiveCommands;
|
private final List<ReceiveCommand> receiveCommands;
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final ReceivePack receivePack;
|
private final ReceivePack receivePack;
|
||||||
|
private final Repository repository;
|
||||||
|
private final String repositoryId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,19 +27,12 @@ package sonia.scm.repository.spi;
|
|||||||
//~--- non-JDK imports --------------------------------------------------------
|
//~--- non-JDK imports --------------------------------------------------------
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.eclipse.jgit.errors.MissingObjectException;
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
|
|
||||||
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
|
||||||
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.NotFoundException;
|
|
||||||
import sonia.scm.repository.Changeset;
|
import sonia.scm.repository.Changeset;
|
||||||
import sonia.scm.repository.ChangesetPagingResult;
|
import sonia.scm.repository.ChangesetPagingResult;
|
||||||
import sonia.scm.repository.GitChangesetConverter;
|
import sonia.scm.repository.GitChangesetConverter;
|
||||||
@@ -48,9 +41,6 @@ import sonia.scm.repository.InternalRepositoryException;
|
|||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||||
import static sonia.scm.NotFoundException.notFound;
|
import static sonia.scm.NotFoundException.notFound;
|
||||||
@@ -183,123 +173,14 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public ChangesetPagingResult getChangesets(LogCommandRequest request) {
|
public ChangesetPagingResult getChangesets(LogCommandRequest request) {
|
||||||
if (logger.isDebugEnabled()) {
|
try (org.eclipse.jgit.lib.Repository gitRepository = open()) {
|
||||||
logger.debug("fetch changesets for request: {}", request);
|
if (Strings.isNullOrEmpty(request.getBranch())) {
|
||||||
}
|
request.setBranch(context.getConfig().getDefaultBranch());
|
||||||
|
|
||||||
ChangesetPagingResult changesets = null;
|
|
||||||
GitChangesetConverter converter = null;
|
|
||||||
RevWalk revWalk = null;
|
|
||||||
|
|
||||||
try (org.eclipse.jgit.lib.Repository repository = open()) {
|
|
||||||
if (!repository.getAllRefs().isEmpty()) {
|
|
||||||
int counter = 0;
|
|
||||||
int start = request.getPagingStart();
|
|
||||||
|
|
||||||
if (start < 0) {
|
|
||||||
if (logger.isErrorEnabled()) {
|
|
||||||
logger.error("start parameter is negative, reset to 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Changeset> changesetList = Lists.newArrayList();
|
|
||||||
int limit = request.getPagingLimit();
|
|
||||||
ObjectId startId = null;
|
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(request.getStartChangeset())) {
|
|
||||||
startId = repository.resolve(request.getStartChangeset());
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectId endId = null;
|
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(request.getEndChangeset())) {
|
|
||||||
endId = repository.resolve(request.getEndChangeset());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref branch = getBranchOrDefault(repository,request.getBranch());
|
|
||||||
|
|
||||||
ObjectId ancestorId = null;
|
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(request.getAncestorChangeset())) {
|
|
||||||
ancestorId = repository.resolve(request.getAncestorChangeset());
|
|
||||||
if (ancestorId == null) {
|
|
||||||
throw notFound(entity(REVISION, request.getAncestorChangeset()).in(this.repository));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
revWalk = new RevWalk(repository);
|
|
||||||
|
|
||||||
converter = new GitChangesetConverter(repository, revWalk);
|
|
||||||
|
|
||||||
if (!Strings.isNullOrEmpty(request.getPath())) {
|
|
||||||
revWalk.setTreeFilter(
|
|
||||||
AndTreeFilter.create(
|
|
||||||
PathFilter.create(request.getPath()), TreeFilter.ANY_DIFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (branch != null) {
|
|
||||||
if (startId != null) {
|
|
||||||
revWalk.markStart(revWalk.lookupCommit(startId));
|
|
||||||
} else {
|
|
||||||
revWalk.markStart(revWalk.lookupCommit(branch.getObjectId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ancestorId != null) {
|
|
||||||
revWalk.markUninteresting(revWalk.lookupCommit(ancestorId));
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<RevCommit> iterator = revWalk.iterator();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
RevCommit commit = iterator.next();
|
|
||||||
|
|
||||||
if ((counter >= start)
|
|
||||||
&& ((limit < 0) || (counter < start + limit))) {
|
|
||||||
changesetList.add(converter.createChangeset(commit));
|
|
||||||
}
|
|
||||||
|
|
||||||
counter++;
|
|
||||||
|
|
||||||
if (commit.getId().equals(endId)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ancestorId != null) {
|
|
||||||
throw notFound(entity(REVISION, request.getBranch()).in(this.repository));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (branch != null) {
|
|
||||||
changesets = new ChangesetPagingResult(counter, changesetList, GitUtil.getBranch(branch.getName()));
|
|
||||||
} else {
|
|
||||||
changesets = new ChangesetPagingResult(counter, changesetList);
|
|
||||||
}
|
|
||||||
} else if (logger.isWarnEnabled()) {
|
|
||||||
logger.warn("the repository {} seems to be empty",
|
|
||||||
this.repository.getName());
|
|
||||||
|
|
||||||
changesets = new ChangesetPagingResult(0, Collections.EMPTY_LIST);
|
|
||||||
}
|
}
|
||||||
|
return new GitLogComputer(this.repository.getId(), gitRepository).compute(request);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new InternalRepositoryException(repository, "could not create change log", e);
|
||||||
}
|
}
|
||||||
catch (MissingObjectException e)
|
|
||||||
{
|
|
||||||
throw notFound(entity(REVISION, e.getObjectId().getName()).in(repository));
|
|
||||||
}
|
|
||||||
catch (NotFoundException e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new InternalRepositoryException(repository, "could not create change log", ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
IOUtil.close(converter);
|
|
||||||
GitUtil.release(revWalk);
|
|
||||||
}
|
|
||||||
|
|
||||||
return changesets;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.eclipse.jgit.errors.InvalidObjectIdException;
|
||||||
|
import org.eclipse.jgit.errors.MissingObjectException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
|
||||||
|
import org.eclipse.jgit.treewalk.filter.PathFilter;
|
||||||
|
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.NotFoundException;
|
||||||
|
import sonia.scm.repository.Changeset;
|
||||||
|
import sonia.scm.repository.ChangesetPagingResult;
|
||||||
|
import sonia.scm.repository.GitChangesetConverter;
|
||||||
|
import sonia.scm.repository.GitUtil;
|
||||||
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||||
|
import static sonia.scm.NotFoundException.notFound;
|
||||||
|
|
||||||
|
public class GitLogComputer {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GitLogComputer.class);
|
||||||
|
|
||||||
|
private final String repositoryId;
|
||||||
|
private final Repository gitRepository;
|
||||||
|
|
||||||
|
public GitLogComputer(String repositoryId, Repository repository) {
|
||||||
|
this.repositoryId = repositoryId;
|
||||||
|
this.gitRepository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangesetPagingResult compute(LogCommandRequest request) {
|
||||||
|
LOG.debug("fetch changesets for request: {}", request);
|
||||||
|
|
||||||
|
GitChangesetConverter converter = null;
|
||||||
|
RevWalk revWalk = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!gitRepository.getAllRefs().isEmpty()) {
|
||||||
|
int counter = 0;
|
||||||
|
int start = request.getPagingStart();
|
||||||
|
|
||||||
|
if (start < 0) {
|
||||||
|
LOG.error("start parameter is negative, reset to 0");
|
||||||
|
|
||||||
|
start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Changeset> changesetList = Lists.newArrayList();
|
||||||
|
int limit = request.getPagingLimit();
|
||||||
|
ObjectId startId = null;
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(request.getStartChangeset())) {
|
||||||
|
startId = gitRepository.resolve(request.getStartChangeset());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectId endId = null;
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(request.getEndChangeset())) {
|
||||||
|
endId = gitRepository.resolve(request.getEndChangeset());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref branch = GitUtil.getBranchIdOrCurrentHead(gitRepository, request.getBranch());
|
||||||
|
ObjectId branchId;
|
||||||
|
if (branch == null) {
|
||||||
|
if (request.getBranch() != null) {
|
||||||
|
try {
|
||||||
|
branchId = ObjectId.fromString(request.getBranch());
|
||||||
|
} catch (InvalidObjectIdException e) {
|
||||||
|
throw notFound(entity(GitLogCommand.REVISION, request.getBranch()).in(sonia.scm.repository.Repository.class, repositoryId));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
branchId = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
branchId = branch.getObjectId();
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectId ancestorId = null;
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(request.getAncestorChangeset())) {
|
||||||
|
ancestorId = gitRepository.resolve(request.getAncestorChangeset());
|
||||||
|
if (ancestorId == null) {
|
||||||
|
throw notFound(entity(GitLogCommand.REVISION, request.getAncestorChangeset()).in(sonia.scm.repository.Repository.class, repositoryId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
revWalk = new RevWalk(gitRepository);
|
||||||
|
|
||||||
|
converter = new GitChangesetConverter(gitRepository, revWalk);
|
||||||
|
|
||||||
|
if (!Strings.isNullOrEmpty(request.getPath())) {
|
||||||
|
revWalk.setTreeFilter(
|
||||||
|
AndTreeFilter.create(
|
||||||
|
PathFilter.create(request.getPath()), TreeFilter.ANY_DIFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branchId != null) {
|
||||||
|
if (startId != null) {
|
||||||
|
revWalk.markStart(revWalk.lookupCommit(startId));
|
||||||
|
} else {
|
||||||
|
revWalk.markStart(revWalk.lookupCommit(branchId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ancestorId != null) {
|
||||||
|
revWalk.markUninteresting(revWalk.lookupCommit(ancestorId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<RevCommit> iterator = revWalk.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
RevCommit commit = iterator.next();
|
||||||
|
|
||||||
|
if ((counter >= start)
|
||||||
|
&& ((limit < 0) || (counter < start + limit))) {
|
||||||
|
changesetList.add(converter.createChangeset(commit));
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
if (commit.getId().equals(endId)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ancestorId != null) {
|
||||||
|
throw notFound(entity(GitLogCommand.REVISION, request.getBranch()).in(sonia.scm.repository.Repository.class, repositoryId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branch != null) {
|
||||||
|
return new ChangesetPagingResult(counter, changesetList, GitUtil.getBranch(branch.getName()));
|
||||||
|
} else {
|
||||||
|
return new ChangesetPagingResult(counter, changesetList);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.debug("the repository with id {} seems to be empty", this.repositoryId);
|
||||||
|
|
||||||
|
return new ChangesetPagingResult(0, Collections.emptyList());
|
||||||
|
}
|
||||||
|
} catch (MissingObjectException e) {
|
||||||
|
throw notFound(entity(GitLogCommand.REVISION, e.getObjectId().getName()).in(sonia.scm.repository.Repository.class, repositoryId));
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new InternalRepositoryException(entity(sonia.scm.repository.Repository.class, repositoryId).build(), "could not create change log", ex);
|
||||||
|
} finally {
|
||||||
|
IOUtil.close(converter);
|
||||||
|
GitUtil.release(revWalk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -122,8 +122,7 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
|
|||||||
|
|
||||||
logger.trace("resolved repository to {}", repositoryId);
|
logger.trace("resolved repository to {}", repositoryId);
|
||||||
|
|
||||||
GitHookContextProvider context = new GitHookContextProvider(rpack,
|
GitHookContextProvider context = new GitHookContextProvider(rpack, receiveCommands, repository, repositoryId);
|
||||||
receiveCommands);
|
|
||||||
|
|
||||||
hookEventFacade.handle(repositoryId).fireHookEvent(type, context);
|
hookEventFacade.handle(repositoryId).fireHookEvent(type, context);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GitCheckoutCommand implements CheckoutCommand {
|
||||||
|
|
||||||
|
private Git git;
|
||||||
|
|
||||||
|
GitCheckoutCommand(Git git) {
|
||||||
|
this.git = git;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkout(String name) throws IOException {
|
||||||
|
try {
|
||||||
|
git.checkout().setName(name).call();
|
||||||
|
} catch (GitAPIException ex) {
|
||||||
|
throw new RepositoryClientException("could not checkout branch or revision", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.PushCommand;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||||
|
import org.eclipse.jgit.transport.RefSpec;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GitDeleteRemoteBranchCommand implements DeleteRemoteBranchCommand {
|
||||||
|
|
||||||
|
private final Git git;
|
||||||
|
private final CredentialsProvider credentialsProvider;
|
||||||
|
|
||||||
|
GitDeleteRemoteBranchCommand(Git git, CredentialsProvider credentialsProvider) {
|
||||||
|
this.git = git;
|
||||||
|
this.credentialsProvider = credentialsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String name) throws IOException {
|
||||||
|
try {
|
||||||
|
git.branchDelete().setBranchNames("refs/heads/" + name).call();
|
||||||
|
RefSpec refSpec = new RefSpec()
|
||||||
|
.setSource(null)
|
||||||
|
.setDestination("refs/heads/" + name);
|
||||||
|
PushCommand push = git.push();
|
||||||
|
if (credentialsProvider != null) {
|
||||||
|
push.setCredentialsProvider(credentialsProvider);
|
||||||
|
}
|
||||||
|
push.setRefSpecs(refSpec).call();
|
||||||
|
} catch (GitAPIException ex) {
|
||||||
|
throw new RepositoryClientException("could not delete branch", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.MergeResult;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import sonia.scm.repository.Changeset;
|
||||||
|
import sonia.scm.repository.GitChangesetConverter;
|
||||||
|
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GitMergeCommand implements MergeCommand {
|
||||||
|
|
||||||
|
private final Git git;
|
||||||
|
|
||||||
|
GitMergeCommand(Git git) {
|
||||||
|
this.git = git;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Changeset merge(MergeRequest request) throws IOException {
|
||||||
|
try (GitChangesetConverter converter = new GitChangesetConverter(git.getRepository())) {
|
||||||
|
ObjectId resolved = git.getRepository().resolve(request.getBranch());
|
||||||
|
org.eclipse.jgit.api.MergeCommand mergeCommand = git.merge()
|
||||||
|
.include(request.getBranch(), resolved)
|
||||||
|
.setMessage(request.getMessage());
|
||||||
|
|
||||||
|
switch (request.getFfMode()) {
|
||||||
|
case FF:
|
||||||
|
mergeCommand.setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.FF);
|
||||||
|
break;
|
||||||
|
case NO_FF:
|
||||||
|
mergeCommand.setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.NO_FF);
|
||||||
|
break;
|
||||||
|
case FF_ONLY:
|
||||||
|
mergeCommand.setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.FF_ONLY);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown FF mode: " + request.getFfMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
MergeResult mergeResult = mergeCommand
|
||||||
|
.call();
|
||||||
|
|
||||||
|
try (RevWalk revWalk = new RevWalk(git.getRepository())) {
|
||||||
|
RevCommit commit = revWalk.parseCommit(mergeResult.getNewHead());
|
||||||
|
return converter.createChangeset(commit);
|
||||||
|
}
|
||||||
|
} catch (GitAPIException ex) {
|
||||||
|
throw new RepositoryClientException("could not commit changes to repository", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,7 @@ public class GitRepositoryClientProvider extends RepositoryClientProvider
|
|||||||
private static final Set<ClientCommand> SUPPORTED_COMMANDS =
|
private static final Set<ClientCommand> SUPPORTED_COMMANDS =
|
||||||
ImmutableSet.of(ClientCommand.ADD, ClientCommand.REMOVE,
|
ImmutableSet.of(ClientCommand.ADD, ClientCommand.REMOVE,
|
||||||
ClientCommand.COMMIT, ClientCommand.TAG, ClientCommand.BRANCH,
|
ClientCommand.COMMIT, ClientCommand.TAG, ClientCommand.BRANCH,
|
||||||
ClientCommand.PUSH);
|
ClientCommand.DELETE_REMOTE_BRANCH, ClientCommand.MERGE, ClientCommand.PUSH);
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
@@ -118,6 +118,16 @@ public class GitRepositoryClientProvider extends RepositoryClientProvider
|
|||||||
return new GitBranchCommand(git);
|
return new GitBranchCommand(git);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeleteRemoteBranchCommand getDeleteRemoteBranchCommand() {
|
||||||
|
return new GitDeleteRemoteBranchCommand(git, credentialsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CheckoutCommand getCheckoutCommand() {
|
||||||
|
return new GitCheckoutCommand(git);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
@@ -178,6 +188,11 @@ public class GitRepositoryClientProvider extends RepositoryClientProvider
|
|||||||
return new GitTagCommand(git);
|
return new GitTagCommand(git);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MergeCommand getMergeCommand() {
|
||||||
|
return new GitMergeCommand(git);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getWorkingCopy() {
|
public File getWorkingCopy() {
|
||||||
return git.getRepository().getWorkTree();
|
return git.getRepository().getWorkTree();
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class GitDiffCommand_DequoteOutputStreamTest {
|
|||||||
stream.write(bytes, 0, bytes.length);
|
stream.write(bytes, 0, bytes.length);
|
||||||
stream.flush();
|
stream.flush();
|
||||||
|
|
||||||
Assertions.assertThat(buffer.toString()).isEqualTo("diff --git a/file úüþëéåëåé a b/file úüþëéåëåé b\n" +
|
Assertions.assertThat(buffer.toString("UTF-8")).isEqualTo("diff --git a/file úüþëéåëåé a b/file úüþëéåëåé b\n" +
|
||||||
"new file mode 100644\n" +
|
"new file mode 100644\n" +
|
||||||
"index 0000000..8cb0607\n" +
|
"index 0000000..8cb0607\n" +
|
||||||
"--- /dev/null\n" +
|
"--- /dev/null\n" +
|
||||||
|
|||||||
50
scm-plugins/scm-integration-test-plugin/pom.xml
Normal file
50
scm-plugins/scm-integration-test-plugin/pom.xml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>sonia.scm.plugins</groupId>
|
||||||
|
<artifactId>scm-plugins</artifactId>
|
||||||
|
<version>2.4.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>scm-integration-test-plugin</artifactId>
|
||||||
|
<description>Add functions for integration tests. This is not intended for production systems.</description>
|
||||||
|
<version>2.4.0-SNAPSHOT</version>
|
||||||
|
<packaging>smp</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>${servlet.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.it.resource;
|
||||||
|
|
||||||
|
import de.otto.edison.hal.Embedded;
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import sonia.scm.api.v2.resources.LinkBuilder;
|
||||||
|
import sonia.scm.api.v2.resources.ScmPathInfoStore;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
|
||||||
|
import static de.otto.edison.hal.Embedded.embeddedBuilder;
|
||||||
|
import static de.otto.edison.hal.Links.linkingTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web Service Resource to support integration tests.
|
||||||
|
*/
|
||||||
|
@Path(IntegrationTestResource.INTEGRATION_TEST_PATH_V2)
|
||||||
|
public class IntegrationTestResource {
|
||||||
|
|
||||||
|
static final String INTEGRATION_TEST_PATH_V2 = "v2/integration-test";
|
||||||
|
|
||||||
|
private final ScmPathInfoStore scmPathInfoStore;
|
||||||
|
private final MergeDetectionHelper mergeDetectionHelper;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public IntegrationTestResource(ScmPathInfoStore scmPathInfoStore, MergeDetectionHelper mergeDetectionHelper) {
|
||||||
|
this.scmPathInfoStore = scmPathInfoStore;
|
||||||
|
this.mergeDetectionHelper = mergeDetectionHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
@Produces("application/json")
|
||||||
|
public CollectionDto get() {
|
||||||
|
Links links = linkingTo()
|
||||||
|
.self(self())
|
||||||
|
.build();
|
||||||
|
Embedded embedded = embeddedBuilder()
|
||||||
|
.with("preMergeDetection", mergeDetectionHelper.getPreMergeDetections())
|
||||||
|
.with("postMergeDetection", mergeDetectionHelper.getPostMergeDetections())
|
||||||
|
.build();
|
||||||
|
return new CollectionDto(links, embedded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("merge-detection")
|
||||||
|
@Consumes("application/json")
|
||||||
|
public void initMergeDetection(MergeDetectionConfigurationDto mergeDetectionConfiguration) {
|
||||||
|
mergeDetectionHelper.initialize(mergeDetectionConfiguration.getTarget(), mergeDetectionConfiguration.getBranch());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String self() {
|
||||||
|
LinkBuilder linkBuilder = new LinkBuilder(scmPathInfoStore.get(), IntegrationTestResource.class);
|
||||||
|
return linkBuilder.method("get").parameters().href();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CollectionDto extends HalRepresentation {
|
||||||
|
|
||||||
|
CollectionDto(Links links, Embedded embedded) {
|
||||||
|
super(links, embedded);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HalRepresentation withEmbedded(String rel, HalRepresentation embeddedItem) {
|
||||||
|
return super.withEmbedded(rel, embeddedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
static class MergeDetectionConfigurationDto {
|
||||||
|
private String target;
|
||||||
|
private String branch;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.it.resource;
|
||||||
|
|
||||||
|
import com.github.legman.Subscribe;
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import sonia.scm.EagerSingleton;
|
||||||
|
import sonia.scm.plugin.Extension;
|
||||||
|
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
||||||
|
import sonia.scm.repository.PreReceiveRepositoryHookEvent;
|
||||||
|
import sonia.scm.repository.RepositoryHookEvent;
|
||||||
|
import sonia.scm.repository.spi.HookMergeDetectionProvider;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@EagerSingleton
|
||||||
|
@Extension
|
||||||
|
public class MergeDetectionHelper {
|
||||||
|
|
||||||
|
private final List<ResultDto> preMergeDetections = new ArrayList<>();
|
||||||
|
private final List<ResultDto> postMergeDetections = new ArrayList<>();
|
||||||
|
|
||||||
|
private String target;
|
||||||
|
private String branch;
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void handlePreReceiveEvent(PreReceiveRepositoryHookEvent event) {
|
||||||
|
if (target == null || branch == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
preMergeDetections.add(createDto(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void handlePostReceiveEvent(PostReceiveRepositoryHookEvent event) {
|
||||||
|
if (target == null || branch == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
postMergeDetections.add(createDto(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultDto createDto(RepositoryHookEvent event) {
|
||||||
|
HookMergeDetectionProvider mergeDetectionProvider = event.getContext().getMergeDetectionProvider();
|
||||||
|
boolean merged = mergeDetectionProvider.branchesMerged(target, branch);
|
||||||
|
return new ResultDto(
|
||||||
|
event.getClass().getSimpleName(),
|
||||||
|
event.getRepository().getNamespace(),
|
||||||
|
event.getRepository().getName(),
|
||||||
|
merged
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize(String target, String branch) {
|
||||||
|
this.target = target;
|
||||||
|
this.branch = branch;
|
||||||
|
preMergeDetections.clear();
|
||||||
|
postMergeDetections.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ResultDto> getPreMergeDetections() {
|
||||||
|
return preMergeDetections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ResultDto> getPostMergeDetections() {
|
||||||
|
return postMergeDetections;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
static class ResultDto extends HalRepresentation {
|
||||||
|
private String type;
|
||||||
|
private String namespace;
|
||||||
|
private String name;
|
||||||
|
private boolean merged;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<!DOCTYPE plugin SYSTEM "https://download.scm-manager.org/dtd/plugin/2.0.0-01.dtd">
|
||||||
|
<plugin>
|
||||||
|
|
||||||
|
<scm-version>2</scm-version>
|
||||||
|
|
||||||
|
<information>
|
||||||
|
<displayName>Integration Test Support</displayName>
|
||||||
|
<author>Cloudogu GmbH</author>
|
||||||
|
<category>Test</category>
|
||||||
|
</information>
|
||||||
|
|
||||||
|
<conditions>
|
||||||
|
<min-version>${project.parent.version}</min-version>
|
||||||
|
</conditions>
|
||||||
|
|
||||||
|
</plugin>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.api;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.repository.client.spi.CheckoutCommand;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public final class CheckoutCommandBuilder {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CheckoutCommandBuilder.class);
|
||||||
|
|
||||||
|
private final CheckoutCommand command;
|
||||||
|
|
||||||
|
public CheckoutCommandBuilder(CheckoutCommand command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckoutCommandBuilder checkout(String name) throws IOException {
|
||||||
|
LOG.debug("checkout {}", name);
|
||||||
|
|
||||||
|
command.checkout(name);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,5 +31,5 @@ package sonia.scm.repository.client.api;
|
|||||||
*/
|
*/
|
||||||
public enum ClientCommand
|
public enum ClientCommand
|
||||||
{
|
{
|
||||||
ADD, REMOVE, COMMIT, PUSH, TAG, BRANCH
|
ADD, REMOVE, COMMIT, PUSH, TAG, BRANCH, DELETE_REMOTE_BRANCH, CHECKOUT, MERGE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.api;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import sonia.scm.repository.client.spi.DeleteRemoteBranchCommand;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public final class DeleteRemoteBranchCommandBuilder {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DeleteRemoteBranchCommandBuilder.class);
|
||||||
|
|
||||||
|
private DeleteRemoteBranchCommand command;
|
||||||
|
|
||||||
|
public DeleteRemoteBranchCommandBuilder(DeleteRemoteBranchCommand command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeleteRemoteBranchCommandBuilder delete(String name) throws IOException {
|
||||||
|
LOG.debug("delete branch {}", name);
|
||||||
|
|
||||||
|
command.delete(name);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.api;
|
||||||
|
|
||||||
|
import sonia.scm.repository.client.spi.MergeCommand;
|
||||||
|
import sonia.scm.repository.client.spi.MergeRequest;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public final class MergeCommandBuilder {
|
||||||
|
|
||||||
|
private final MergeCommand command;
|
||||||
|
private final MergeRequest request = new MergeRequest();
|
||||||
|
|
||||||
|
MergeCommandBuilder(MergeCommand command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MergeCommandBuilder ffOnly() {
|
||||||
|
request.setFfMode(MergeRequest.FastForwardMode.FF_ONLY);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MergeCommandBuilder noFf() {
|
||||||
|
request.setFfMode(MergeRequest.FastForwardMode.NO_FF);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MergeCommandBuilder ffIfPossible() {
|
||||||
|
request.setFfMode(MergeRequest.FastForwardMode.FF);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void merge(String branch) throws IOException {
|
||||||
|
request.setBranch(branch);
|
||||||
|
command.merge(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,18 @@ public final class RepositoryClient implements Closeable {
|
|||||||
return new BranchCommandBuilder(clientProvider.getBranchCommand());
|
return new BranchCommandBuilder(clientProvider.getBranchCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DeleteRemoteBranchCommandBuilder getDeleteRemoteBranchCommand() {
|
||||||
|
logger.trace("delete branch command");
|
||||||
|
|
||||||
|
return new DeleteRemoteBranchCommandBuilder(clientProvider.getDeleteRemoteBranchCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckoutCommandBuilder getCheckoutCommand() {
|
||||||
|
logger.trace("create checkout command");
|
||||||
|
|
||||||
|
return new CheckoutCommandBuilder(clientProvider.getCheckoutCommand());
|
||||||
|
}
|
||||||
|
|
||||||
public CommitCommandBuilder getCommitCommand() {
|
public CommitCommandBuilder getCommitCommand() {
|
||||||
logger.trace("create commit command");
|
logger.trace("create commit command");
|
||||||
|
|
||||||
@@ -84,6 +96,12 @@ public final class RepositoryClient implements Closeable {
|
|||||||
return new TagCommandBuilder(clientProvider.getTagCommand());
|
return new TagCommandBuilder(clientProvider.getTagCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MergeCommandBuilder getMergeCommand() {
|
||||||
|
logger.trace("create merge command");
|
||||||
|
|
||||||
|
return new MergeCommandBuilder(clientProvider.getMergeCommand());
|
||||||
|
}
|
||||||
|
|
||||||
public File getWorkingCopy() {
|
public File getWorkingCopy() {
|
||||||
return clientProvider.getWorkingCopy();
|
return clientProvider.getWorkingCopy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public interface CheckoutCommand {
|
||||||
|
|
||||||
|
void checkout(String name) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface DeleteRemoteBranchCommand {
|
||||||
|
|
||||||
|
void delete(String name) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import sonia.scm.repository.Changeset;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public interface MergeCommand {
|
||||||
|
|
||||||
|
Changeset merge(MergeRequest request) throws IOException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.repository.client.spi;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
public final class MergeRequest {
|
||||||
|
|
||||||
|
private String branch;
|
||||||
|
private String message;
|
||||||
|
private FastForwardMode ffMode = FastForwardMode.FF;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final MergeRequest other = (MergeRequest) obj;
|
||||||
|
|
||||||
|
return Objects.equal(branch, other.branch)
|
||||||
|
&& Objects.equal(message, other.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(branch, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
this.branch = null;
|
||||||
|
this.message = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("branch", branch)
|
||||||
|
.add("message", message)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBranch(String branch) {
|
||||||
|
this.branch = branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFfMode(FastForwardMode ffMode) {
|
||||||
|
this.ffMode = ffMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getBranch() {
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FastForwardMode getFfMode() {
|
||||||
|
return ffMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FastForwardMode {
|
||||||
|
FF_ONLY, FF, NO_FF
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,6 +87,14 @@ public abstract class RepositoryClientProvider implements Closeable
|
|||||||
throw new ClientCommandNotSupportedException(ClientCommand.BRANCH);
|
throw new ClientCommandNotSupportedException(ClientCommand.BRANCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DeleteRemoteBranchCommand getDeleteRemoteBranchCommand() {
|
||||||
|
throw new ClientCommandNotSupportedException(ClientCommand.DELETE_REMOTE_BRANCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckoutCommand getCheckoutCommand() {
|
||||||
|
throw new ClientCommandNotSupportedException(ClientCommand.CHECKOUT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Method description
|
||||||
*
|
*
|
||||||
@@ -131,6 +139,10 @@ public abstract class RepositoryClientProvider implements Closeable
|
|||||||
throw new ClientCommandNotSupportedException(ClientCommand.TAG);
|
throw new ClientCommandNotSupportedException(ClientCommand.TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MergeCommand getMergeCommand() {
|
||||||
|
throw new ClientCommandNotSupportedException(ClientCommand.MERGE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the working copy of the repository client.
|
* Returns the working copy of the repository client.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ describe("repository name validation", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should allow same names as the backend", () => {
|
it("should allow same names as the backend", () => {
|
||||||
const validPaths = ["scm", "s", "sc", ".hiddenrepo", "b.", "...", "..c", "d..", "a..c"];
|
const validPaths = ["scm", "scm.gitz", "s", "sc", ".hiddenrepo", "b.", "...", "..c", "d..", "a..c"];
|
||||||
|
|
||||||
validPaths.forEach(path => expect(validator.isNameValid(path)).toBe(true));
|
validPaths.forEach(path => expect(validator.isNameValid(path)).toBe(true));
|
||||||
});
|
});
|
||||||
@@ -91,7 +91,8 @@ describe("repository name validation", () => {
|
|||||||
"a/..b",
|
"a/..b",
|
||||||
"scm/main",
|
"scm/main",
|
||||||
"scm/plugins/git-plugin",
|
"scm/plugins/git-plugin",
|
||||||
"scm/plugins/git-plugin"
|
"scm/plugins/git-plugin",
|
||||||
|
"scm.git"
|
||||||
];
|
];
|
||||||
|
|
||||||
invalidPaths.forEach(path => expect(validator.isNameValid(path)).toBe(false));
|
invalidPaths.forEach(path => expect(validator.isNameValid(path)).toBe(false));
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
import { validation } from "@scm-manager/ui-components";
|
import { validation } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
const nameRegex = /(?!^\.\.$)(?!^\.$)(?!.*[\\\[\]])^[A-Za-z0-9\.][A-Za-z0-9\.\-_]*$/;
|
const nameRegex = /(?!^\.\.$)(?!^\.$)(?!.*[.]git$)(?!.*[\\\[\]])^[A-Za-z0-9\.][A-Za-z0-9\.\-_]*$/;
|
||||||
|
|
||||||
export const isNameValid = (name: string) => {
|
export const isNameValid = (name: string) => {
|
||||||
return nameRegex.test(name);
|
return nameRegex.test(name);
|
||||||
|
|||||||
@@ -324,7 +324,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.java.dev.jna</groupId>
|
<groupId>net.java.dev.jna</groupId>
|
||||||
<artifactId>jna</artifactId>
|
<artifactId>jna</artifactId>
|
||||||
<version>5.5.0</version>
|
<version>5.6.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- test scope -->
|
<!-- test scope -->
|
||||||
@@ -675,7 +675,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<scm.stage>DEVELOPMENT</scm.stage>
|
<scm.stage>DEVELOPMENT</scm.stage>
|
||||||
<scm.home>target/scm-it</scm.home>
|
<scm.home>${project.parent.build.directory}/scm-it</scm.home>
|
||||||
<environment.profile>default</environment.profile>
|
<environment.profile>default</environment.profile>
|
||||||
<jjwt.version>0.11.2</jjwt.version>
|
<jjwt.version>0.11.2</jjwt.version>
|
||||||
<selenium.version>2.53.1</selenium.version>
|
<selenium.version>2.53.1</selenium.version>
|
||||||
@@ -814,7 +814,7 @@
|
|||||||
<systemProperties>
|
<systemProperties>
|
||||||
<systemProperty>
|
<systemProperty>
|
||||||
<name>scm.home</name>
|
<name>scm.home</name>
|
||||||
<value>target/scm-it</value>
|
<value>${scm.home}</value>
|
||||||
</systemProperty>
|
</systemProperty>
|
||||||
<systemProperty>
|
<systemProperty>
|
||||||
<name>scm.stage</name>
|
<name>scm.stage</name>
|
||||||
@@ -903,7 +903,7 @@
|
|||||||
<systemProperties>
|
<systemProperties>
|
||||||
<systemProperty>
|
<systemProperty>
|
||||||
<name>scm.home</name>
|
<name>scm.home</name>
|
||||||
<value>target/scm-it</value>
|
<value>${scm.home}</value>
|
||||||
</systemProperty>
|
</systemProperty>
|
||||||
</systemProperties>
|
</systemProperties>
|
||||||
<jettyXml>${project.basedir}/src/main/conf/jetty.xml</jettyXml>
|
<jettyXml>${project.basedir}/src/main/conf/jetty.xml</jettyXml>
|
||||||
|
|||||||
Reference in New Issue
Block a user