From d273b19f683adb8fc1ba8b966a46793a7ae1cdcf Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Wed, 14 Oct 2020 10:47:03 +0200 Subject: [PATCH 01/26] add null check on parsing svn properties in browsecommand --- CHANGELOG.md | 1 + .../scm/repository/spi/SvnBrowseCommand.java | 33 +++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e94d216088..e14e58db6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Fixed - Null Pointer Exception on anonymous migration with deleted repositories ([#1371](https://github.com/scm-manager/scm-manager/pull/1371)) +- Null Pointer Exception on parsing SVN properties ([#1373](https://github.com/scm-manager/scm-manager/pull/1373)) ## [2.7.0] - 2020-10-12 ### Added diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java index 00a135dd82..e83a0dc365 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnBrowseCommand.java @@ -193,23 +193,28 @@ public class SvnBrowseCommand extends AbstractSvnCommand repository.getDir(entry.getRelativePath(), revision, properties, (Collection) null); - String[] externals = properties.getStringValue(SVNProperty.EXTERNALS).split("\\r?\\n"); - for (String external : externals) { - String subRepoUrl = ""; - String subRepoPath = ""; - for (String externalPart : external.split(" ")) { - if (shouldSetExternal(externalPart)) { - subRepoUrl = externalPart; - } else if (!externalPart.contains("-r")) { - subRepoPath = externalPart; + String externals = properties.getStringValue(SVNProperty.EXTERNALS); + + if (!Strings.isNullOrEmpty(externals)) { + String[] splitExternals = externals.split("\\r?\\n"); + for (String external : splitExternals) { + String subRepoUrl = ""; + String subRepoPath = ""; + for (String externalPart : external.split(" ")) { + if (shouldSetExternal(externalPart)) { + subRepoUrl = externalPart; + } else if (!externalPart.contains("-r")) { + subRepoPath = externalPart; + } + } + + if (Util.isNotEmpty(external)) { + SubRepository subRepository = new SubRepository(subRepoUrl); + fileObject.addChild(createSubRepoDirectory(subRepository, subRepoPath)); } } - - if (Util.isNotEmpty(external)) { - SubRepository subRepository = new SubRepository(subRepoUrl); - fileObject.addChild(createSubRepoDirectory(subRepository, subRepoPath)); - } } + } catch (SVNException ex) { logger.error("could not fetch file properties", ex); } From 07a85ef9c16b5e0e0d23d1f1bbbc9c7fd4ddf827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 14 Oct 2020 11:03:42 +0200 Subject: [PATCH 02/26] Check token content before handling them This adds plausibility checks before handling tokens as for example jwt or api keys. Doing so we generate less error logs and therefore we cause less confusion. --- CHANGELOG.md | 2 ++ .../java/sonia/scm/security/ApiKeyRealm.java | 13 ++++++++++++- .../java/sonia/scm/security/BearerRealm.java | 17 +++++++++++++++-- .../scm/web/security/TokenRefreshFilter.java | 6 +++++- .../sonia/scm/security/ApiKeyRealmTest.java | 9 +++++++++ .../scm/security/ApiKeyTokenHandlerTest.java | 7 +++++++ .../sonia/scm/security/BearerRealmTest.java | 10 ++++++++++ .../web/security/TokenRefreshFilterTest.java | 11 ++++++++--- 8 files changed, 68 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e94d216088..314f94b374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Fixed - Null Pointer Exception on anonymous migration with deleted repositories ([#1371](https://github.com/scm-manager/scm-manager/pull/1371)) +### Changed +- Reduced logging for invalid JWT or api keys ([#1374](https://github.com/scm-manager/scm-manager/pull/1374)) ## [2.7.0] - 2020-10-12 ### Added diff --git a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java index ed2954eb32..d9c1536e0e 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java @@ -30,6 +30,8 @@ import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.realm.AuthenticatingRealm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.plugin.Extension; import sonia.scm.repository.RepositoryRole; import sonia.scm.repository.RepositoryRoleManager; @@ -43,6 +45,8 @@ import static com.google.common.base.Preconditions.checkArgument; @Extension public class ApiKeyRealm extends AuthenticatingRealm { + private static final Logger LOG = LoggerFactory.getLogger(ApiKeyRealm.class); + private final ApiKeyService apiKeyService; private final DAORealmHelper helper; private final RepositoryRoleManager repositoryRoleManager; @@ -58,7 +62,14 @@ public class ApiKeyRealm extends AuthenticatingRealm { @Override public boolean supports(AuthenticationToken token) { - return token instanceof UsernamePasswordToken || token instanceof BearerToken; + if (token instanceof UsernamePasswordToken || token instanceof BearerToken) { + boolean containsDot = getPassword(token).contains("."); + if (containsDot) { + LOG.debug("Ignoring token with at least one dot ('.'); this is probably a JWT token"); + } + return !containsDot; + } + return false; } @Override diff --git a/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java b/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java index e037590db6..f554c92d04 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/BearerRealm.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.security; import com.google.common.annotations.VisibleForTesting; @@ -29,6 +29,8 @@ import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher; import org.apache.shiro.realm.AuthenticatingRealm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.group.GroupDAO; import sonia.scm.plugin.Extension; import sonia.scm.user.UserDAO; @@ -54,6 +56,7 @@ public class BearerRealm extends AuthenticatingRealm @VisibleForTesting static final String REALM = "BearerRealm"; + private static final Logger LOG = LoggerFactory.getLogger(BearerRealm.class); /** dao realm helper */ private final DAORealmHelper helper; @@ -76,7 +79,17 @@ public class BearerRealm extends AuthenticatingRealm setAuthenticationTokenClass(BearerToken.class); } - //~--- methods -------------------------------------------------------------- + @Override + public boolean supports(AuthenticationToken token) { + if (token instanceof BearerToken) { + boolean containsDot = ((BearerToken) token).getCredentials().contains("."); + if (!containsDot) { + LOG.debug("Ignoring token without a dot ('.'); this probably is an API key"); + } + return containsDot; + } + return false; + } /** * Validates the given bearer token and retrieves authentication data from diff --git a/scm-webapp/src/main/java/sonia/scm/web/security/TokenRefreshFilter.java b/scm-webapp/src/main/java/sonia/scm/web/security/TokenRefreshFilter.java index 47da2d5718..be691da1d8 100644 --- a/scm-webapp/src/main/java/sonia/scm/web/security/TokenRefreshFilter.java +++ b/scm-webapp/src/main/java/sonia/scm/web/security/TokenRefreshFilter.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web.security; import org.apache.shiro.authc.AuthenticationException; @@ -90,6 +90,10 @@ public class TokenRefreshFilter extends HttpFilter { private void examineToken(HttpServletRequest request, HttpServletResponse response, BearerToken token) { AccessToken accessToken; + if (!token.getCredentials().contains(".")) { + LOG.trace("Ignoring token without dot. This probably is an API key, no JWT"); + return; + } try { accessToken = resolver.resolve(token); } catch (AuthenticationException e) { diff --git a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java index 48a014dfb2..0f4171b8d9 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyRealmTest.java @@ -96,6 +96,15 @@ class ApiKeyRealmTest { assertThrows(AuthorizationException.class, () -> realm.doGetAuthenticationInfo(token)); } + @Test + void shouldIgnoreTokensWithDots() { + BearerToken token = valueOf("this.is.no.api.token"); + + boolean supports = realm.supports(token); + + assertThat(supports).isFalse(); + } + void verifyScopeSet(String... permissions) { verify(authenticationInfoBuilder).withScope(argThat(scope -> { assertThat(scope).containsExactly(permissions); diff --git a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java index 390d5e6ba2..151d3e2c10 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java @@ -61,4 +61,11 @@ class ApiKeyTokenHandlerTest { assertThat(token).isEmpty(); } + + @Test + void shouldParseRealWorldExample() { + Optional token = handler.readToken("JhcGlLZXlJZCI6IkE2U0ROWmV0MjEiLCJ1c2VyIjoiaG9yc3QiLCJwYXNzcGhyYXNlIjoiWGNKQ01PMnZuZ1JaOEhVU21BSVoifQ"); + + assertThat(token).get().extracting("user").isEqualTo("horst"); + } } diff --git a/scm-webapp/src/test/java/sonia/scm/security/BearerRealmTest.java b/scm-webapp/src/test/java/sonia/scm/security/BearerRealmTest.java index c0ac82b7f6..c9d834cdbc 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/BearerRealmTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/BearerRealmTest.java @@ -40,6 +40,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static sonia.scm.security.BearerToken.valueOf; /** * Unit tests for {@link BearerRealm}. @@ -96,4 +97,13 @@ class BearerRealmTest { void shouldThrowIllegalArgumentExceptionForWrongTypeOfToken() { assertThrows(IllegalArgumentException.class, () -> realm.doGetAuthenticationInfo(new UsernamePasswordToken())); } + + @Test + void shouldIgnoreTokensWithoutDot() { + BearerToken token = valueOf("this-is-no-jwt-token"); + + boolean supports = realm.supports(token); + + assertThat(supports).isFalse(); + } } diff --git a/scm-webapp/src/test/java/sonia/scm/web/security/TokenRefreshFilterTest.java b/scm-webapp/src/test/java/sonia/scm/web/security/TokenRefreshFilterTest.java index d74a5eef7f..410eb1f368 100644 --- a/scm-webapp/src/test/java/sonia/scm/web/security/TokenRefreshFilterTest.java +++ b/scm-webapp/src/test/java/sonia/scm/web/security/TokenRefreshFilterTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.web.security; import org.apache.shiro.authc.AuthenticationToken; @@ -52,6 +52,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static sonia.scm.security.BearerToken.valueOf; @ExtendWith({MockitoExtension.class}) class TokenRefreshFilterTest { @@ -103,7 +104,7 @@ class TokenRefreshFilterTest { @Test void shouldNotRefreshNonJwtToken() throws IOException, ServletException { - BearerToken token = mock(BearerToken.class); + BearerToken token = createValidToken(); JwtAccessToken jwtToken = mock(JwtAccessToken.class); when(tokenGenerator.createToken(request)).thenReturn(token); when(resolver.resolve(token)).thenReturn(jwtToken); @@ -116,7 +117,7 @@ class TokenRefreshFilterTest { @Test void shouldRefreshIfRefreshable() throws IOException, ServletException { - BearerToken token = mock(BearerToken.class); + BearerToken token = createValidToken(); JwtAccessToken jwtToken = mock(JwtAccessToken.class); JwtAccessToken newJwtToken = mock(JwtAccessToken.class); when(tokenGenerator.createToken(request)).thenReturn(token); @@ -128,4 +129,8 @@ class TokenRefreshFilterTest { verify(issuer).authenticate(request, response, newJwtToken); verify(filterChain).doFilter(request, response); } + + BearerToken createValidToken() { + return valueOf("some.jwt.token"); + } } From f35fddc505f80468fee8163d44c3d4317a311cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 14 Oct 2020 11:28:21 +0200 Subject: [PATCH 03/26] Add debug log for successful login --- scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java | 1 + 1 file changed, 1 insertion(+) diff --git a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java index d9c1536e0e..672f972dab 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java +++ b/scm-webapp/src/main/java/sonia/scm/security/ApiKeyRealm.java @@ -85,6 +85,7 @@ public class ApiKeyRealm extends AuthenticatingRealm { private AuthenticationInfo buildAuthenticationInfo(AuthenticationToken token, ApiKeyService.CheckResult check) { RepositoryRole repositoryRole = determineRole(check); Scope scope = createScope(repositoryRole); + LOG.debug("login for user {} with api key limited to role {}", check.getUser(), check.getPermissionRole()); return helper .authenticationInfoBuilder(check.getUser()) .withSessionId(getPrincipal(token)) From ab6e5fd6d6ff0547b5cd52674f4b288f46f0a23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 14 Oct 2020 11:43:47 +0200 Subject: [PATCH 04/26] Fix unit test --- .../test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java index 151d3e2c10..ac0ee44040 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/ApiKeyTokenHandlerTest.java @@ -64,7 +64,7 @@ class ApiKeyTokenHandlerTest { @Test void shouldParseRealWorldExample() { - Optional token = handler.readToken("JhcGlLZXlJZCI6IkE2U0ROWmV0MjEiLCJ1c2VyIjoiaG9yc3QiLCJwYXNzcGhyYXNlIjoiWGNKQ01PMnZuZ1JaOEhVU21BSVoifQ"); + Optional token = handler.readToken("eyJhcGlLZXlJZCI6IkE2U0ROWmV0MjEiLCJ1c2VyIjoiaG9yc3QiLCJwYXNzcGhyYXNlIjoiWGNKQ01PMnZuZ1JaOEhVU21BSVoifQ"); assertThat(token).get().extracting("user").isEqualTo("horst"); } From 0847a3eda0a94873848c592a3abc531ff2f6f159 Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Wed, 14 Oct 2020 12:02:05 +0200 Subject: [PATCH 05/26] add unit tests --- .../spi/AbstractSvnCommandTestBase.java | 4 +- .../repository/spi/SvnBrowseCommandTest.java | 67 ++++++++++++++++--- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/AbstractSvnCommandTestBase.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/AbstractSvnCommandTestBase.java index b6d9e4ba26..8228d42f39 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/AbstractSvnCommandTestBase.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/AbstractSvnCommandTestBase.java @@ -21,15 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import org.junit.After; -//~--- JDK imports ------------------------------------------------------------ - import java.io.IOException; /** diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnBrowseCommandTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnBrowseCommandTest.java index 3d3a3131e5..698fec8f37 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnBrowseCommandTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnBrowseCommandTest.java @@ -24,10 +24,20 @@ package sonia.scm.repository.spi; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.tmatesoft.svn.core.SVNDepth; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNPropertyValue; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.SVNClientManager; +import org.tmatesoft.svn.core.wc.SVNRevision; import sonia.scm.repository.BrowserResult; import sonia.scm.repository.FileObject; +import sonia.scm.repository.SubRepository; +import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Iterator; @@ -36,14 +46,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** - * * @author Sebastian Sdorra */ -public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase -{ +public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void testBrowseWithFilePath() { @@ -83,7 +95,6 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase /** * Method description * - * * @throws IOException */ @Test @@ -260,14 +271,51 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase .containsExactly("e.txt"); } + @Test + public void shouldNotAddSubRepositoryIfNotSetInProperties() { + BrowserResult browserResult = new SvnBrowseCommand(createContext()).getBrowserResult(new BrowseCommandRequest()); + + boolean containsSubRepository = browserResult.getFile().getChildren() + .stream() + .anyMatch(c -> c.getSubRepository() != null); + + assertFalse(containsSubRepository); + } + + @Test + public void shouldAddSubRepositoryIfSetInProperties() throws IOException, SVNException { + String externalLink = "https://scm-manager.org/svn-repo"; + SvnContext svnContext = setProp("svn:externals", "external -r1 " + externalLink); + + BrowserResult browserResult = new SvnBrowseCommand(svnContext).getBrowserResult(new BrowseCommandRequest()); + + boolean containsSubRepository = browserResult.getFile().getChildren() + .stream() + .anyMatch(c -> c.getSubRepository().getRepositoryUrl().equals(externalLink)); + + assertTrue(containsSubRepository); + } + + private SvnContext setProp(String propName, String propValue) throws SVNException, IOException { + SvnContext context = createContext(); + SVNClientManager client = SVNClientManager.newInstance(); + + File workingCopyDirectory = temporaryFolder.newFolder("working-copy"); + + SVNURL url = SVNURL.fromFile(context.getDirectory()); + client.getUpdateClient().doCheckout(url, workingCopyDirectory, SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, true); + + client.getWCClient().doSetProperty(workingCopyDirectory, propName, SVNPropertyValue.create(propValue), true, SVNDepth.UNKNOWN, null, null); + client.getCommitClient().doCommit(new File[]{workingCopyDirectory}, false, "set prop", null, null, false, false, SVNDepth.UNKNOWN); + return context; + } + /** * Method description * - * * @return */ - private SvnBrowseCommand createCommand() - { + private SvnBrowseCommand createCommand() { return new SvnBrowseCommand(createContext()); } @@ -276,14 +324,11 @@ public class SvnBrowseCommandTest extends AbstractSvnCommandTestBase /** * Method description * - * * @param foList * @param name - * * @return */ - private FileObject getFileObject(Collection foList, String name) - { + private FileObject getFileObject(Collection foList, String name) { return foList.stream() .filter(f -> name.equals(f.getName())) .findFirst() From fbffdea2a566dc4ac54ea38d4aade5aaf541e7f2 Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Wed, 14 Oct 2020 13:57:39 +0200 Subject: [PATCH 06/26] Adjust changelog for release 2.7.1 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de732d6da1..148eb799f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. 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). -## Unreleased +## [2.7.1] - 2020-10-14 ### Fixed - Null Pointer Exception on anonymous migration with deleted repositories ([#1371](https://github.com/scm-manager/scm-manager/pull/1371)) - Null Pointer Exception on parsing SVN properties ([#1373](https://github.com/scm-manager/scm-manager/pull/1373)) From eb126a5bbe2a43d63fce3fead8ddaaaa9da39a77 Mon Sep 17 00:00:00 2001 From: CES Marvin Date: Wed, 14 Oct 2020 12:03:24 +0000 Subject: [PATCH 07/26] release version 2.7.1 --- lerna.json | 2 +- pom.xml | 2 +- scm-annotation-processor/pom.xml | 6 ++--- scm-annotations/pom.xml | 4 +-- scm-core/pom.xml | 8 +++--- scm-dao-xml/pom.xml | 8 +++--- scm-it/pom.xml | 20 +++++++------- scm-packaging/deb/pom.xml | 6 ++--- scm-packaging/docker/pom.xml | 4 +-- scm-packaging/helm/pom.xml | 4 +-- scm-packaging/pom.xml | 4 +-- scm-packaging/release-yaml/pom.xml | 4 +-- scm-packaging/rpm/pom.xml | 6 ++--- scm-packaging/unix/pom.xml | 4 +-- scm-packaging/windows/pom.xml | 4 +-- scm-plugins/pom.xml | 10 +++---- scm-plugins/scm-git-plugin/package.json | 4 +-- scm-plugins/scm-git-plugin/pom.xml | 2 +- scm-plugins/scm-hg-plugin/package.json | 4 +-- scm-plugins/scm-hg-plugin/pom.xml | 2 +- .../scm-integration-test-plugin/pom.xml | 4 +-- scm-plugins/scm-legacy-plugin/package.json | 4 +-- scm-plugins/scm-legacy-plugin/pom.xml | 4 +-- scm-plugins/scm-svn-plugin/package.json | 4 +-- scm-plugins/scm-svn-plugin/pom.xml | 2 +- scm-server/pom.xml | 4 +-- scm-test/pom.xml | 6 ++--- scm-ui/babel-preset/package.json | 2 +- scm-ui/e2e-tests/package.json | 2 +- scm-ui/eslint-config/package.json | 2 +- scm-ui/jest-preset/package.json | 2 +- scm-ui/pom.xml | 4 +-- scm-ui/prettier-config/package.json | 2 +- scm-ui/tsconfig/package.json | 2 +- scm-ui/ui-components/package.json | 8 +++--- scm-ui/ui-extensions/package.json | 2 +- scm-ui/ui-plugins/package.json | 22 ++++++++-------- scm-ui/ui-polyfill/package.json | 2 +- scm-ui/ui-scripts/package.json | 2 +- scm-ui/ui-styles/package.json | 2 +- scm-ui/ui-tests/package.json | 2 +- scm-ui/ui-types/package.json | 2 +- scm-ui/ui-webapp/package.json | 8 +++--- scm-webapp/pom.xml | 26 +++++++++---------- 44 files changed, 114 insertions(+), 114 deletions(-) diff --git a/lerna.json b/lerna.json index 2eb3066367..848b7032b3 100644 --- a/lerna.json +++ b/lerna.json @@ -5,5 +5,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.8.0-SNAPSHOT" + "version": "2.7.1" } diff --git a/pom.xml b/pom.xml index 506c11920f..96f8d3766f 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ sonia.scm scm pom - 2.8.0-SNAPSHOT + 2.7.1 The easiest way to share your Git, Mercurial and Subversion repositories. diff --git a/scm-annotation-processor/pom.xml b/scm-annotation-processor/pom.xml index 28702106db..b75f79c6d8 100644 --- a/scm-annotation-processor/pom.xml +++ b/scm-annotation-processor/pom.xml @@ -31,12 +31,12 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-annotation-processor - 2.8.0-SNAPSHOT + 2.7.1 scm-annotation-processor @@ -46,7 +46,7 @@ sonia.scm scm-annotations - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-annotations/pom.xml b/scm-annotations/pom.xml index f48c2dfb58..719c61e57d 100644 --- a/scm-annotations/pom.xml +++ b/scm-annotations/pom.xml @@ -31,11 +31,11 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 scm-annotations - 2.8.0-SNAPSHOT + 2.7.1 scm-annotations diff --git a/scm-core/pom.xml b/scm-core/pom.xml index e6b41a4e6c..d17664f51b 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -31,11 +31,11 @@ scm sonia.scm - 2.8.0-SNAPSHOT + 2.7.1 scm-core - 2.8.0-SNAPSHOT + 2.7.1 scm-core @@ -54,7 +54,7 @@ sonia.scm scm-annotations - 2.8.0-SNAPSHOT + 2.7.1 @@ -227,7 +227,7 @@ sonia.scm scm-annotation-processor - 2.8.0-SNAPSHOT + 2.7.1 provided diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 25231dc4e7..00a35cfb16 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -31,11 +31,11 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 scm-dao-xml - 2.8.0-SNAPSHOT + 2.7.1 scm-dao-xml @@ -50,7 +50,7 @@ sonia.scm scm-core - 2.8.0-SNAPSHOT + 2.7.1 @@ -58,7 +58,7 @@ sonia.scm scm-test - 2.8.0-SNAPSHOT + 2.7.1 test diff --git a/scm-it/pom.xml b/scm-it/pom.xml index ff9a7d87f8..782d092fe6 100644 --- a/scm-it/pom.xml +++ b/scm-it/pom.xml @@ -31,40 +31,40 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-it war - 2.8.0-SNAPSHOT + 2.7.1 scm-it sonia.scm scm-core - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-test - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm.plugins scm-git-plugin - 2.8.0-SNAPSHOT + 2.7.1 test sonia.scm.plugins scm-git-plugin - 2.8.0-SNAPSHOT + 2.7.1 tests test @@ -72,14 +72,14 @@ sonia.scm.plugins scm-hg-plugin - 2.8.0-SNAPSHOT + 2.7.1 test sonia.scm.plugins scm-hg-plugin - 2.8.0-SNAPSHOT + 2.7.1 tests test @@ -87,14 +87,14 @@ sonia.scm.plugins scm-svn-plugin - 2.8.0-SNAPSHOT + 2.7.1 test sonia.scm.plugins scm-svn-plugin - 2.8.0-SNAPSHOT + 2.7.1 tests test diff --git a/scm-packaging/deb/pom.xml b/scm-packaging/deb/pom.xml index 6f0657736f..5ec93a2ed1 100644 --- a/scm-packaging/deb/pom.xml +++ b/scm-packaging/deb/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 deb deb - 2.8.0-SNAPSHOT + 2.7.1 Packaging for Debian/Ubuntu deb @@ -46,7 +46,7 @@ sonia.scm scm-server - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-packaging/docker/pom.xml b/scm-packaging/docker/pom.xml index 941a5c1516..a55a0bd42a 100644 --- a/scm-packaging/docker/pom.xml +++ b/scm-packaging/docker/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 docker pom - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-packaging/helm/pom.xml b/scm-packaging/helm/pom.xml index 5ad0cf6fd3..389a88c3e5 100644 --- a/scm-packaging/helm/pom.xml +++ b/scm-packaging/helm/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 helm helm - 2.8.0-SNAPSHOT + 2.7.1 3.2.1 diff --git a/scm-packaging/pom.xml b/scm-packaging/pom.xml index 300f088af6..60208278e1 100644 --- a/scm-packaging/pom.xml +++ b/scm-packaging/pom.xml @@ -31,13 +31,13 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm.packaging scm-packaging pom - 2.8.0-SNAPSHOT + 2.7.1 packages.scm-manager.org diff --git a/scm-packaging/release-yaml/pom.xml b/scm-packaging/release-yaml/pom.xml index 27c2731b87..0283d8ed2a 100644 --- a/scm-packaging/release-yaml/pom.xml +++ b/scm-packaging/release-yaml/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 release-yaml pom - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-packaging/rpm/pom.xml b/scm-packaging/rpm/pom.xml index fee0719a8d..d2d316030b 100644 --- a/scm-packaging/rpm/pom.xml +++ b/scm-packaging/rpm/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 rpm rpm - 2.8.0-SNAPSHOT + 2.7.1 Packaging for RedHat/Centos/Fedora rpm @@ -52,7 +52,7 @@ sonia.scm scm-server - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-packaging/unix/pom.xml b/scm-packaging/unix/pom.xml index 5cd9e36a97..f74fcdc3df 100644 --- a/scm-packaging/unix/pom.xml +++ b/scm-packaging/unix/pom.xml @@ -31,12 +31,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 unix pom - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-packaging/windows/pom.xml b/scm-packaging/windows/pom.xml index 593c17a151..22211c8fc6 100644 --- a/scm-packaging/windows/pom.xml +++ b/scm-packaging/windows/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.8.0-SNAPSHOT + 2.7.1 windows pom - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index 24e002fc17..e5de4992e5 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -31,13 +31,13 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm.plugins scm-plugins pom - 2.8.0-SNAPSHOT + 2.7.1 scm-plugins @@ -60,7 +60,7 @@ sonia.scm scm-core - 2.8.0-SNAPSHOT + 2.7.1 provided @@ -69,7 +69,7 @@ sonia.scm scm-annotation-processor - 2.8.0-SNAPSHOT + 2.7.1 provided @@ -99,7 +99,7 @@ sonia.scm scm-test - 2.8.0-SNAPSHOT + 2.7.1 test diff --git a/scm-plugins/scm-git-plugin/package.json b/scm-plugins/scm-git-plugin/package.json index 1e61547668..69d77cb454 100644 --- a/scm-plugins/scm-git-plugin/package.json +++ b/scm-plugins/scm-git-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-git-plugin", "private": true, - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -20,6 +20,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" + "@scm-manager/ui-plugins": "^2.7.1" } } diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index d1d18f1329..bc8b579f3d 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -31,7 +31,7 @@ scm-plugins sonia.scm.plugins - 2.8.0-SNAPSHOT + 2.7.1 scm-git-plugin diff --git a/scm-plugins/scm-hg-plugin/package.json b/scm-plugins/scm-hg-plugin/package.json index 6683453f24..410e9c7a58 100644 --- a/scm-plugins/scm-hg-plugin/package.json +++ b/scm-plugins/scm-hg-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-hg-plugin", "private": true, - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" + "@scm-manager/ui-plugins": "^2.7.1" } } diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 0a03731bd3..18ac32897f 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -31,7 +31,7 @@ sonia.scm.plugins scm-plugins - 2.8.0-SNAPSHOT + 2.7.1 scm-hg-plugin diff --git a/scm-plugins/scm-integration-test-plugin/pom.xml b/scm-plugins/scm-integration-test-plugin/pom.xml index 755348c9d7..5166e42524 100644 --- a/scm-plugins/scm-integration-test-plugin/pom.xml +++ b/scm-plugins/scm-integration-test-plugin/pom.xml @@ -29,12 +29,12 @@ sonia.scm.plugins scm-plugins - 2.8.0-SNAPSHOT + 2.7.1 scm-integration-test-plugin Add functions for integration tests. This is not intended for production systems. - 2.8.0-SNAPSHOT + 2.7.1 smp diff --git a/scm-plugins/scm-legacy-plugin/package.json b/scm-plugins/scm-legacy-plugin/package.json index 510cdae1a6..4b9fe6a6cc 100644 --- a/scm-plugins/scm-legacy-plugin/package.json +++ b/scm-plugins/scm-legacy-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-legacy-plugin", "private": true, - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "main": "./src/main/js/index.tsx", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" + "@scm-manager/ui-plugins": "^2.7.1" } } diff --git a/scm-plugins/scm-legacy-plugin/pom.xml b/scm-plugins/scm-legacy-plugin/pom.xml index 51c7e718a0..6d85526ffb 100644 --- a/scm-plugins/scm-legacy-plugin/pom.xml +++ b/scm-plugins/scm-legacy-plugin/pom.xml @@ -29,12 +29,12 @@ sonia.scm.plugins scm-plugins - 2.8.0-SNAPSHOT + 2.7.1 scm-legacy-plugin Support migrated repository urls and v1 passwords - 2.8.0-SNAPSHOT + 2.7.1 smp diff --git a/scm-plugins/scm-svn-plugin/package.json b/scm-plugins/scm-svn-plugin/package.json index c0b0051b1e..d99381a930 100644 --- a/scm-plugins/scm-svn-plugin/package.json +++ b/scm-plugins/scm-svn-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-svn-plugin", "private": true, - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" + "@scm-manager/ui-plugins": "^2.7.1" } } diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 26c16a221c..1fe6caf5c4 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -31,7 +31,7 @@ scm-plugins sonia.scm.plugins - 2.8.0-SNAPSHOT + 2.7.1 scm-svn-plugin diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 5a10a9c098..530caabdc0 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -31,12 +31,12 @@ scm sonia.scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-server - 2.8.0-SNAPSHOT + 2.7.1 scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 0544a10524..0cb3be6409 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -31,12 +31,12 @@ scm sonia.scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-test - 2.8.0-SNAPSHOT + 2.7.1 scm-test @@ -50,7 +50,7 @@ sonia.scm scm-core - 2.8.0-SNAPSHOT + 2.7.1 diff --git a/scm-ui/babel-preset/package.json b/scm-ui/babel-preset/package.json index 37a15f5131..f6b9602291 100644 --- a/scm-ui/babel-preset/package.json +++ b/scm-ui/babel-preset/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/babel-preset", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "description": "Babel configuration for scm-manager and its plugins", "main": "index.js", diff --git a/scm-ui/e2e-tests/package.json b/scm-ui/e2e-tests/package.json index bc1af44bbd..4333e19254 100644 --- a/scm-ui/e2e-tests/package.json +++ b/scm-ui/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/e2e-tests", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "End to end Tests for SCM-Manager", "main": "index.js", "author": "Eduard Heimbuch ", diff --git a/scm-ui/eslint-config/package.json b/scm-ui/eslint-config/package.json index 17cec9c9ee..4d4e167ef0 100644 --- a/scm-ui/eslint-config/package.json +++ b/scm-ui/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/eslint-config", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "ESLint configuration for scm-manager and its plugins", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/jest-preset/package.json b/scm-ui/jest-preset/package.json index 6f8c5d71fc..3bff24508b 100644 --- a/scm-ui/jest-preset/package.json +++ b/scm-ui/jest-preset/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/jest-preset", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "Jest presets for SCM-Manager and its plugins", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/pom.xml b/scm-ui/pom.xml index fce99381c3..227b3efc81 100644 --- a/scm-ui/pom.xml +++ b/scm-ui/pom.xml @@ -32,13 +32,13 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-ui war - 2.8.0-SNAPSHOT + 2.7.1 scm-ui diff --git a/scm-ui/prettier-config/package.json b/scm-ui/prettier-config/package.json index 27c6e63597..92f67c880d 100644 --- a/scm-ui/prettier-config/package.json +++ b/scm-ui/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/prettier-config", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "description": "Prettier configuration", "author": "Sebastian Sdorra ", diff --git a/scm-ui/tsconfig/package.json b/scm-ui/tsconfig/package.json index 7801717520..e7213af1ae 100644 --- a/scm-ui/tsconfig/package.json +++ b/scm-ui/tsconfig/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/tsconfig", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "description": "TypeScript configuration", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-components/package.json b/scm-ui/ui-components/package.json index 3e5889c081..5177dd6a66 100644 --- a/scm-ui/ui-components/package.json +++ b/scm-ui/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-components", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "UI Components for SCM-Manager and its plugins", "main": "src/index.ts", "files": [ @@ -18,7 +18,7 @@ "update-storyshots": "jest --testPathPattern=\"storyshots.test.ts\" --collectCoverage=false -u" }, "devDependencies": { - "@scm-manager/ui-tests": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-tests": "^2.7.1", "@storybook/addon-actions": "^5.2.3", "@storybook/addon-storyshots": "^5.2.3", "@storybook/react": "^5.2.3", @@ -46,8 +46,8 @@ "worker-plugin": "^3.2.0" }, "dependencies": { - "@scm-manager/ui-extensions": "^2.8.0-SNAPSHOT", - "@scm-manager/ui-types": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-extensions": "^2.7.1", + "@scm-manager/ui-types": "^2.7.1", "classnames": "^2.2.6", "date-fns": "^2.4.1", "gitdiff-parser": "^0.1.2", diff --git a/scm-ui/ui-extensions/package.json b/scm-ui/ui-extensions/package.json index 049d153b07..5e6262a76b 100644 --- a/scm-ui/ui-extensions/package.json +++ b/scm-ui/ui-extensions/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-extensions", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "main": "src/index.ts", "license": "MIT", "private": false, diff --git a/scm-ui/ui-plugins/package.json b/scm-ui/ui-plugins/package.json index 6bd7d2a93a..e7d752a84f 100644 --- a/scm-ui/ui-plugins/package.json +++ b/scm-ui/ui-plugins/package.json @@ -1,13 +1,13 @@ { "name": "@scm-manager/ui-plugins", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "license": "MIT", "bin": { "ui-plugins": "./bin/ui-plugins.js" }, "dependencies": { - "@scm-manager/ui-components": "^2.8.0-SNAPSHOT", - "@scm-manager/ui-extensions": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-components": "^2.7.1", + "@scm-manager/ui-extensions": "^2.7.1", "classnames": "^2.2.6", "query-string": "^5.0.1", "react": "^16.10.2", @@ -18,14 +18,14 @@ "styled-components": "^5.1.0" }, "devDependencies": { - "@scm-manager/babel-preset": "^2.8.0-SNAPSHOT", - "@scm-manager/eslint-config": "^2.8.0-SNAPSHOT", - "@scm-manager/jest-preset": "^2.8.0-SNAPSHOT", - "@scm-manager/prettier-config": "^2.8.0-SNAPSHOT", - "@scm-manager/tsconfig": "^2.8.0-SNAPSHOT", - "@scm-manager/ui-scripts": "^2.8.0-SNAPSHOT", - "@scm-manager/ui-tests": "^2.8.0-SNAPSHOT", - "@scm-manager/ui-types": "^2.8.0-SNAPSHOT", + "@scm-manager/babel-preset": "^2.7.1", + "@scm-manager/eslint-config": "^2.7.1", + "@scm-manager/jest-preset": "^2.7.1", + "@scm-manager/prettier-config": "^2.7.1", + "@scm-manager/tsconfig": "^2.7.1", + "@scm-manager/ui-scripts": "^2.7.1", + "@scm-manager/ui-tests": "^2.7.1", + "@scm-manager/ui-types": "^2.7.1", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", diff --git a/scm-ui/ui-polyfill/package.json b/scm-ui/ui-polyfill/package.json index bed6f43cb2..30d17424d6 100644 --- a/scm-ui/ui-polyfill/package.json +++ b/scm-ui/ui-polyfill/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-polyfill", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "Polyfills for SCM-Manager UI", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-scripts/package.json b/scm-ui/ui-scripts/package.json index bbd3caac00..606ec00e03 100644 --- a/scm-ui/ui-scripts/package.json +++ b/scm-ui/ui-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-scripts", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "Build scripts for SCM-Manager", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-styles/package.json b/scm-ui/ui-styles/package.json index 4f4b7d8023..aa71da2a4c 100644 --- a/scm-ui/ui-styles/package.json +++ b/scm-ui/ui-styles/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-styles", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "Styles for SCM-Manager", "main": "src/scm.scss", "license": "MIT", diff --git a/scm-ui/ui-tests/package.json b/scm-ui/ui-tests/package.json index 0c8f3d3aae..e79d175f81 100644 --- a/scm-ui/ui-tests/package.json +++ b/scm-ui/ui-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-tests", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "UI-Tests helpers", "author": "Sebastian Sdorra ", "license": "MIT", diff --git a/scm-ui/ui-types/package.json b/scm-ui/ui-types/package.json index 9ffb7f4251..751a43af3e 100644 --- a/scm-ui/ui-types/package.json +++ b/scm-ui/ui-types/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-types", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "description": "Flow types for SCM-Manager related Objects", "main": "src/index.ts", "files": [ diff --git a/scm-ui/ui-webapp/package.json b/scm-ui/ui-webapp/package.json index 1d5a332dc6..4e0c4d4bb6 100644 --- a/scm-ui/ui-webapp/package.json +++ b/scm-ui/ui-webapp/package.json @@ -1,10 +1,10 @@ { "name": "@scm-manager/ui-webapp", - "version": "2.8.0-SNAPSHOT", + "version": "2.7.1", "private": true, "dependencies": { - "@scm-manager/ui-components": "^2.8.0-SNAPSHOT", - "@scm-manager/ui-extensions": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-components": "^2.7.1", + "@scm-manager/ui-extensions": "^2.7.1", "classnames": "^2.2.5", "history": "^4.10.1", "i18next": "^19.6.0", @@ -29,7 +29,7 @@ "test": "jest" }, "devDependencies": { - "@scm-manager/ui-tests": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-tests": "^2.7.1", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index f30c2cdb99..8f914afe2d 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -32,13 +32,13 @@ sonia.scm scm - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-webapp war - 2.8.0-SNAPSHOT + 2.7.1 scm-webapp @@ -48,7 +48,7 @@ sonia.scm scm-annotation-processor - 2.8.0-SNAPSHOT + 2.7.1 provided @@ -73,13 +73,13 @@ sonia.scm scm-core - 2.8.0-SNAPSHOT + 2.7.1 sonia.scm scm-dao-xml - 2.8.0-SNAPSHOT + 2.7.1 @@ -343,7 +343,7 @@ sonia.scm scm-test - 2.8.0-SNAPSHOT + 2.7.1 test @@ -405,7 +405,7 @@ sonia.scm.plugins scm-git-plugin - 2.8.0-SNAPSHOT + 2.7.1 tests test @@ -413,14 +413,14 @@ sonia.scm.plugins scm-git-plugin - 2.8.0-SNAPSHOT + 2.7.1 test sonia.scm.plugins scm-hg-plugin - 2.8.0-SNAPSHOT + 2.7.1 tests test @@ -428,14 +428,14 @@ sonia.scm.plugins scm-hg-plugin - 2.8.0-SNAPSHOT + 2.7.1 test sonia.scm.plugins scm-svn-plugin - 2.8.0-SNAPSHOT + 2.7.1 tests test @@ -443,7 +443,7 @@ sonia.scm.plugins scm-svn-plugin - 2.8.0-SNAPSHOT + 2.7.1 test @@ -729,7 +729,7 @@ sonia.scm scm-ui - 2.8.0-SNAPSHOT + 2.7.1 war From bb9f1adc5265d1d56232297fd2faa0830cfba04f Mon Sep 17 00:00:00 2001 From: CES Marvin Date: Wed, 14 Oct 2020 12:38:13 +0000 Subject: [PATCH 08/26] prepare for next development iteration --- lerna.json | 2 +- pom.xml | 2 +- scm-annotation-processor/pom.xml | 6 ++--- scm-annotations/pom.xml | 4 +-- scm-core/pom.xml | 8 +++--- scm-dao-xml/pom.xml | 8 +++--- scm-it/pom.xml | 20 +++++++------- scm-packaging/deb/pom.xml | 6 ++--- scm-packaging/docker/pom.xml | 4 +-- scm-packaging/helm/pom.xml | 4 +-- scm-packaging/pom.xml | 4 +-- scm-packaging/release-yaml/pom.xml | 4 +-- scm-packaging/rpm/pom.xml | 6 ++--- scm-packaging/unix/pom.xml | 4 +-- scm-packaging/windows/pom.xml | 4 +-- scm-plugins/pom.xml | 10 +++---- scm-plugins/scm-git-plugin/package.json | 4 +-- scm-plugins/scm-git-plugin/pom.xml | 2 +- scm-plugins/scm-hg-plugin/package.json | 4 +-- scm-plugins/scm-hg-plugin/pom.xml | 2 +- .../scm-integration-test-plugin/pom.xml | 4 +-- scm-plugins/scm-legacy-plugin/package.json | 4 +-- scm-plugins/scm-legacy-plugin/pom.xml | 4 +-- scm-plugins/scm-svn-plugin/package.json | 4 +-- scm-plugins/scm-svn-plugin/pom.xml | 2 +- scm-server/pom.xml | 4 +-- scm-test/pom.xml | 6 ++--- scm-ui/babel-preset/package.json | 2 +- scm-ui/e2e-tests/package.json | 2 +- scm-ui/eslint-config/package.json | 2 +- scm-ui/jest-preset/package.json | 2 +- scm-ui/pom.xml | 4 +-- scm-ui/prettier-config/package.json | 2 +- scm-ui/tsconfig/package.json | 2 +- scm-ui/ui-components/package.json | 8 +++--- scm-ui/ui-extensions/package.json | 2 +- scm-ui/ui-plugins/package.json | 22 ++++++++-------- scm-ui/ui-polyfill/package.json | 2 +- scm-ui/ui-scripts/package.json | 2 +- scm-ui/ui-styles/package.json | 2 +- scm-ui/ui-tests/package.json | 2 +- scm-ui/ui-types/package.json | 2 +- scm-ui/ui-webapp/package.json | 8 +++--- scm-webapp/pom.xml | 26 +++++++++---------- 44 files changed, 114 insertions(+), 114 deletions(-) diff --git a/lerna.json b/lerna.json index 848b7032b3..2eb3066367 100644 --- a/lerna.json +++ b/lerna.json @@ -5,5 +5,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.7.1" + "version": "2.8.0-SNAPSHOT" } diff --git a/pom.xml b/pom.xml index 96f8d3766f..506c11920f 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ sonia.scm scm pom - 2.7.1 + 2.8.0-SNAPSHOT The easiest way to share your Git, Mercurial and Subversion repositories. diff --git a/scm-annotation-processor/pom.xml b/scm-annotation-processor/pom.xml index b75f79c6d8..28702106db 100644 --- a/scm-annotation-processor/pom.xml +++ b/scm-annotation-processor/pom.xml @@ -31,12 +31,12 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-annotation-processor - 2.7.1 + 2.8.0-SNAPSHOT scm-annotation-processor @@ -46,7 +46,7 @@ sonia.scm scm-annotations - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-annotations/pom.xml b/scm-annotations/pom.xml index 719c61e57d..f48c2dfb58 100644 --- a/scm-annotations/pom.xml +++ b/scm-annotations/pom.xml @@ -31,11 +31,11 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT scm-annotations - 2.7.1 + 2.8.0-SNAPSHOT scm-annotations diff --git a/scm-core/pom.xml b/scm-core/pom.xml index d17664f51b..e6b41a4e6c 100644 --- a/scm-core/pom.xml +++ b/scm-core/pom.xml @@ -31,11 +31,11 @@ scm sonia.scm - 2.7.1 + 2.8.0-SNAPSHOT scm-core - 2.7.1 + 2.8.0-SNAPSHOT scm-core @@ -54,7 +54,7 @@ sonia.scm scm-annotations - 2.7.1 + 2.8.0-SNAPSHOT @@ -227,7 +227,7 @@ sonia.scm scm-annotation-processor - 2.7.1 + 2.8.0-SNAPSHOT provided diff --git a/scm-dao-xml/pom.xml b/scm-dao-xml/pom.xml index 00a35cfb16..25231dc4e7 100644 --- a/scm-dao-xml/pom.xml +++ b/scm-dao-xml/pom.xml @@ -31,11 +31,11 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT scm-dao-xml - 2.7.1 + 2.8.0-SNAPSHOT scm-dao-xml @@ -50,7 +50,7 @@ sonia.scm scm-core - 2.7.1 + 2.8.0-SNAPSHOT @@ -58,7 +58,7 @@ sonia.scm scm-test - 2.7.1 + 2.8.0-SNAPSHOT test diff --git a/scm-it/pom.xml b/scm-it/pom.xml index 782d092fe6..ff9a7d87f8 100644 --- a/scm-it/pom.xml +++ b/scm-it/pom.xml @@ -31,40 +31,40 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-it war - 2.7.1 + 2.8.0-SNAPSHOT scm-it sonia.scm scm-core - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-test - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm.plugins scm-git-plugin - 2.7.1 + 2.8.0-SNAPSHOT test sonia.scm.plugins scm-git-plugin - 2.7.1 + 2.8.0-SNAPSHOT tests test @@ -72,14 +72,14 @@ sonia.scm.plugins scm-hg-plugin - 2.7.1 + 2.8.0-SNAPSHOT test sonia.scm.plugins scm-hg-plugin - 2.7.1 + 2.8.0-SNAPSHOT tests test @@ -87,14 +87,14 @@ sonia.scm.plugins scm-svn-plugin - 2.7.1 + 2.8.0-SNAPSHOT test sonia.scm.plugins scm-svn-plugin - 2.7.1 + 2.8.0-SNAPSHOT tests test diff --git a/scm-packaging/deb/pom.xml b/scm-packaging/deb/pom.xml index 5ec93a2ed1..6f0657736f 100644 --- a/scm-packaging/deb/pom.xml +++ b/scm-packaging/deb/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT deb deb - 2.7.1 + 2.8.0-SNAPSHOT Packaging for Debian/Ubuntu deb @@ -46,7 +46,7 @@ sonia.scm scm-server - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-packaging/docker/pom.xml b/scm-packaging/docker/pom.xml index a55a0bd42a..941a5c1516 100644 --- a/scm-packaging/docker/pom.xml +++ b/scm-packaging/docker/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT docker pom - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-packaging/helm/pom.xml b/scm-packaging/helm/pom.xml index 389a88c3e5..5ad0cf6fd3 100644 --- a/scm-packaging/helm/pom.xml +++ b/scm-packaging/helm/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT helm helm - 2.7.1 + 2.8.0-SNAPSHOT 3.2.1 diff --git a/scm-packaging/pom.xml b/scm-packaging/pom.xml index 60208278e1..300f088af6 100644 --- a/scm-packaging/pom.xml +++ b/scm-packaging/pom.xml @@ -31,13 +31,13 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm.packaging scm-packaging pom - 2.7.1 + 2.8.0-SNAPSHOT packages.scm-manager.org diff --git a/scm-packaging/release-yaml/pom.xml b/scm-packaging/release-yaml/pom.xml index 0283d8ed2a..27c2731b87 100644 --- a/scm-packaging/release-yaml/pom.xml +++ b/scm-packaging/release-yaml/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT release-yaml pom - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-packaging/rpm/pom.xml b/scm-packaging/rpm/pom.xml index d2d316030b..fee0719a8d 100644 --- a/scm-packaging/rpm/pom.xml +++ b/scm-packaging/rpm/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT rpm rpm - 2.7.1 + 2.8.0-SNAPSHOT Packaging for RedHat/Centos/Fedora rpm @@ -52,7 +52,7 @@ sonia.scm scm-server - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-packaging/unix/pom.xml b/scm-packaging/unix/pom.xml index f74fcdc3df..5cd9e36a97 100644 --- a/scm-packaging/unix/pom.xml +++ b/scm-packaging/unix/pom.xml @@ -31,12 +31,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT unix pom - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-packaging/windows/pom.xml b/scm-packaging/windows/pom.xml index 22211c8fc6..593c17a151 100644 --- a/scm-packaging/windows/pom.xml +++ b/scm-packaging/windows/pom.xml @@ -32,12 +32,12 @@ sonia.scm.packaging scm-packaging - 2.7.1 + 2.8.0-SNAPSHOT windows pom - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-plugins/pom.xml b/scm-plugins/pom.xml index e5de4992e5..24e002fc17 100644 --- a/scm-plugins/pom.xml +++ b/scm-plugins/pom.xml @@ -31,13 +31,13 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm.plugins scm-plugins pom - 2.7.1 + 2.8.0-SNAPSHOT scm-plugins @@ -60,7 +60,7 @@ sonia.scm scm-core - 2.7.1 + 2.8.0-SNAPSHOT provided @@ -69,7 +69,7 @@ sonia.scm scm-annotation-processor - 2.7.1 + 2.8.0-SNAPSHOT provided @@ -99,7 +99,7 @@ sonia.scm scm-test - 2.7.1 + 2.8.0-SNAPSHOT test diff --git a/scm-plugins/scm-git-plugin/package.json b/scm-plugins/scm-git-plugin/package.json index 69d77cb454..1e61547668 100644 --- a/scm-plugins/scm-git-plugin/package.json +++ b/scm-plugins/scm-git-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-git-plugin", "private": true, - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -20,6 +20,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.7.1" + "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index bc8b579f3d..d1d18f1329 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -31,7 +31,7 @@ scm-plugins sonia.scm.plugins - 2.7.1 + 2.8.0-SNAPSHOT scm-git-plugin diff --git a/scm-plugins/scm-hg-plugin/package.json b/scm-plugins/scm-hg-plugin/package.json index 410e9c7a58..6683453f24 100644 --- a/scm-plugins/scm-hg-plugin/package.json +++ b/scm-plugins/scm-hg-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-hg-plugin", "private": true, - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.7.1" + "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-hg-plugin/pom.xml b/scm-plugins/scm-hg-plugin/pom.xml index 18ac32897f..0a03731bd3 100644 --- a/scm-plugins/scm-hg-plugin/pom.xml +++ b/scm-plugins/scm-hg-plugin/pom.xml @@ -31,7 +31,7 @@ sonia.scm.plugins scm-plugins - 2.7.1 + 2.8.0-SNAPSHOT scm-hg-plugin diff --git a/scm-plugins/scm-integration-test-plugin/pom.xml b/scm-plugins/scm-integration-test-plugin/pom.xml index 5166e42524..755348c9d7 100644 --- a/scm-plugins/scm-integration-test-plugin/pom.xml +++ b/scm-plugins/scm-integration-test-plugin/pom.xml @@ -29,12 +29,12 @@ sonia.scm.plugins scm-plugins - 2.7.1 + 2.8.0-SNAPSHOT scm-integration-test-plugin Add functions for integration tests. This is not intended for production systems. - 2.7.1 + 2.8.0-SNAPSHOT smp diff --git a/scm-plugins/scm-legacy-plugin/package.json b/scm-plugins/scm-legacy-plugin/package.json index 4b9fe6a6cc..510cdae1a6 100644 --- a/scm-plugins/scm-legacy-plugin/package.json +++ b/scm-plugins/scm-legacy-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-legacy-plugin", "private": true, - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.tsx", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.7.1" + "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-legacy-plugin/pom.xml b/scm-plugins/scm-legacy-plugin/pom.xml index 6d85526ffb..51c7e718a0 100644 --- a/scm-plugins/scm-legacy-plugin/pom.xml +++ b/scm-plugins/scm-legacy-plugin/pom.xml @@ -29,12 +29,12 @@ sonia.scm.plugins scm-plugins - 2.7.1 + 2.8.0-SNAPSHOT scm-legacy-plugin Support migrated repository urls and v1 passwords - 2.7.1 + 2.8.0-SNAPSHOT smp diff --git a/scm-plugins/scm-svn-plugin/package.json b/scm-plugins/scm-svn-plugin/package.json index d99381a930..c0b0051b1e 100644 --- a/scm-plugins/scm-svn-plugin/package.json +++ b/scm-plugins/scm-svn-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@scm-manager/scm-svn-plugin", "private": true, - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "main": "./src/main/js/index.ts", "scripts": { @@ -19,6 +19,6 @@ }, "prettier": "@scm-manager/prettier-config", "dependencies": { - "@scm-manager/ui-plugins": "^2.7.1" + "@scm-manager/ui-plugins": "^2.8.0-SNAPSHOT" } } diff --git a/scm-plugins/scm-svn-plugin/pom.xml b/scm-plugins/scm-svn-plugin/pom.xml index 1fe6caf5c4..26c16a221c 100644 --- a/scm-plugins/scm-svn-plugin/pom.xml +++ b/scm-plugins/scm-svn-plugin/pom.xml @@ -31,7 +31,7 @@ scm-plugins sonia.scm.plugins - 2.7.1 + 2.8.0-SNAPSHOT scm-svn-plugin diff --git a/scm-server/pom.xml b/scm-server/pom.xml index 530caabdc0..5a10a9c098 100644 --- a/scm-server/pom.xml +++ b/scm-server/pom.xml @@ -31,12 +31,12 @@ scm sonia.scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-server - 2.7.1 + 2.8.0-SNAPSHOT scm-server jar diff --git a/scm-test/pom.xml b/scm-test/pom.xml index 0cb3be6409..0544a10524 100644 --- a/scm-test/pom.xml +++ b/scm-test/pom.xml @@ -31,12 +31,12 @@ scm sonia.scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-test - 2.7.1 + 2.8.0-SNAPSHOT scm-test @@ -50,7 +50,7 @@ sonia.scm scm-core - 2.7.1 + 2.8.0-SNAPSHOT diff --git a/scm-ui/babel-preset/package.json b/scm-ui/babel-preset/package.json index f6b9602291..37a15f5131 100644 --- a/scm-ui/babel-preset/package.json +++ b/scm-ui/babel-preset/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/babel-preset", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "description": "Babel configuration for scm-manager and its plugins", "main": "index.js", diff --git a/scm-ui/e2e-tests/package.json b/scm-ui/e2e-tests/package.json index 4333e19254..bc1af44bbd 100644 --- a/scm-ui/e2e-tests/package.json +++ b/scm-ui/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/e2e-tests", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "End to end Tests for SCM-Manager", "main": "index.js", "author": "Eduard Heimbuch ", diff --git a/scm-ui/eslint-config/package.json b/scm-ui/eslint-config/package.json index 4d4e167ef0..17cec9c9ee 100644 --- a/scm-ui/eslint-config/package.json +++ b/scm-ui/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/eslint-config", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "ESLint configuration for scm-manager and its plugins", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/jest-preset/package.json b/scm-ui/jest-preset/package.json index 3bff24508b..6f8c5d71fc 100644 --- a/scm-ui/jest-preset/package.json +++ b/scm-ui/jest-preset/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/jest-preset", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "Jest presets for SCM-Manager and its plugins", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/pom.xml b/scm-ui/pom.xml index 227b3efc81..fce99381c3 100644 --- a/scm-ui/pom.xml +++ b/scm-ui/pom.xml @@ -32,13 +32,13 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-ui war - 2.7.1 + 2.8.0-SNAPSHOT scm-ui diff --git a/scm-ui/prettier-config/package.json b/scm-ui/prettier-config/package.json index 92f67c880d..27c6e63597 100644 --- a/scm-ui/prettier-config/package.json +++ b/scm-ui/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/prettier-config", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "description": "Prettier configuration", "author": "Sebastian Sdorra ", diff --git a/scm-ui/tsconfig/package.json b/scm-ui/tsconfig/package.json index e7213af1ae..7801717520 100644 --- a/scm-ui/tsconfig/package.json +++ b/scm-ui/tsconfig/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/tsconfig", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "description": "TypeScript configuration", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-components/package.json b/scm-ui/ui-components/package.json index 5177dd6a66..3e5889c081 100644 --- a/scm-ui/ui-components/package.json +++ b/scm-ui/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-components", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "UI Components for SCM-Manager and its plugins", "main": "src/index.ts", "files": [ @@ -18,7 +18,7 @@ "update-storyshots": "jest --testPathPattern=\"storyshots.test.ts\" --collectCoverage=false -u" }, "devDependencies": { - "@scm-manager/ui-tests": "^2.7.1", + "@scm-manager/ui-tests": "^2.8.0-SNAPSHOT", "@storybook/addon-actions": "^5.2.3", "@storybook/addon-storyshots": "^5.2.3", "@storybook/react": "^5.2.3", @@ -46,8 +46,8 @@ "worker-plugin": "^3.2.0" }, "dependencies": { - "@scm-manager/ui-extensions": "^2.7.1", - "@scm-manager/ui-types": "^2.7.1", + "@scm-manager/ui-extensions": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-types": "^2.8.0-SNAPSHOT", "classnames": "^2.2.6", "date-fns": "^2.4.1", "gitdiff-parser": "^0.1.2", diff --git a/scm-ui/ui-extensions/package.json b/scm-ui/ui-extensions/package.json index 5e6262a76b..049d153b07 100644 --- a/scm-ui/ui-extensions/package.json +++ b/scm-ui/ui-extensions/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-extensions", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "main": "src/index.ts", "license": "MIT", "private": false, diff --git a/scm-ui/ui-plugins/package.json b/scm-ui/ui-plugins/package.json index e7d752a84f..6bd7d2a93a 100644 --- a/scm-ui/ui-plugins/package.json +++ b/scm-ui/ui-plugins/package.json @@ -1,13 +1,13 @@ { "name": "@scm-manager/ui-plugins", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "license": "MIT", "bin": { "ui-plugins": "./bin/ui-plugins.js" }, "dependencies": { - "@scm-manager/ui-components": "^2.7.1", - "@scm-manager/ui-extensions": "^2.7.1", + "@scm-manager/ui-components": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-extensions": "^2.8.0-SNAPSHOT", "classnames": "^2.2.6", "query-string": "^5.0.1", "react": "^16.10.2", @@ -18,14 +18,14 @@ "styled-components": "^5.1.0" }, "devDependencies": { - "@scm-manager/babel-preset": "^2.7.1", - "@scm-manager/eslint-config": "^2.7.1", - "@scm-manager/jest-preset": "^2.7.1", - "@scm-manager/prettier-config": "^2.7.1", - "@scm-manager/tsconfig": "^2.7.1", - "@scm-manager/ui-scripts": "^2.7.1", - "@scm-manager/ui-tests": "^2.7.1", - "@scm-manager/ui-types": "^2.7.1", + "@scm-manager/babel-preset": "^2.8.0-SNAPSHOT", + "@scm-manager/eslint-config": "^2.8.0-SNAPSHOT", + "@scm-manager/jest-preset": "^2.8.0-SNAPSHOT", + "@scm-manager/prettier-config": "^2.8.0-SNAPSHOT", + "@scm-manager/tsconfig": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-scripts": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-tests": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-types": "^2.8.0-SNAPSHOT", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", diff --git a/scm-ui/ui-polyfill/package.json b/scm-ui/ui-polyfill/package.json index 30d17424d6..bed6f43cb2 100644 --- a/scm-ui/ui-polyfill/package.json +++ b/scm-ui/ui-polyfill/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-polyfill", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "Polyfills for SCM-Manager UI", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-scripts/package.json b/scm-ui/ui-scripts/package.json index 606ec00e03..bbd3caac00 100644 --- a/scm-ui/ui-scripts/package.json +++ b/scm-ui/ui-scripts/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-scripts", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "Build scripts for SCM-Manager", "main": "src/index.js", "author": "Sebastian Sdorra ", diff --git a/scm-ui/ui-styles/package.json b/scm-ui/ui-styles/package.json index aa71da2a4c..4f4b7d8023 100644 --- a/scm-ui/ui-styles/package.json +++ b/scm-ui/ui-styles/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-styles", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "Styles for SCM-Manager", "main": "src/scm.scss", "license": "MIT", diff --git a/scm-ui/ui-tests/package.json b/scm-ui/ui-tests/package.json index e79d175f81..0c8f3d3aae 100644 --- a/scm-ui/ui-tests/package.json +++ b/scm-ui/ui-tests/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-tests", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "UI-Tests helpers", "author": "Sebastian Sdorra ", "license": "MIT", diff --git a/scm-ui/ui-types/package.json b/scm-ui/ui-types/package.json index 751a43af3e..9ffb7f4251 100644 --- a/scm-ui/ui-types/package.json +++ b/scm-ui/ui-types/package.json @@ -1,6 +1,6 @@ { "name": "@scm-manager/ui-types", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "description": "Flow types for SCM-Manager related Objects", "main": "src/index.ts", "files": [ diff --git a/scm-ui/ui-webapp/package.json b/scm-ui/ui-webapp/package.json index 4e0c4d4bb6..1d5a332dc6 100644 --- a/scm-ui/ui-webapp/package.json +++ b/scm-ui/ui-webapp/package.json @@ -1,10 +1,10 @@ { "name": "@scm-manager/ui-webapp", - "version": "2.7.1", + "version": "2.8.0-SNAPSHOT", "private": true, "dependencies": { - "@scm-manager/ui-components": "^2.7.1", - "@scm-manager/ui-extensions": "^2.7.1", + "@scm-manager/ui-components": "^2.8.0-SNAPSHOT", + "@scm-manager/ui-extensions": "^2.8.0-SNAPSHOT", "classnames": "^2.2.5", "history": "^4.10.1", "i18next": "^19.6.0", @@ -29,7 +29,7 @@ "test": "jest" }, "devDependencies": { - "@scm-manager/ui-tests": "^2.7.1", + "@scm-manager/ui-tests": "^2.8.0-SNAPSHOT", "@types/classnames": "^2.2.9", "@types/enzyme": "^3.10.3", "@types/fetch-mock": "^7.3.1", diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index 8f914afe2d..f30c2cdb99 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -32,13 +32,13 @@ sonia.scm scm - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-webapp war - 2.7.1 + 2.8.0-SNAPSHOT scm-webapp @@ -48,7 +48,7 @@ sonia.scm scm-annotation-processor - 2.7.1 + 2.8.0-SNAPSHOT provided @@ -73,13 +73,13 @@ sonia.scm scm-core - 2.7.1 + 2.8.0-SNAPSHOT sonia.scm scm-dao-xml - 2.7.1 + 2.8.0-SNAPSHOT @@ -343,7 +343,7 @@ sonia.scm scm-test - 2.7.1 + 2.8.0-SNAPSHOT test @@ -405,7 +405,7 @@ sonia.scm.plugins scm-git-plugin - 2.7.1 + 2.8.0-SNAPSHOT tests test @@ -413,14 +413,14 @@ sonia.scm.plugins scm-git-plugin - 2.7.1 + 2.8.0-SNAPSHOT test sonia.scm.plugins scm-hg-plugin - 2.7.1 + 2.8.0-SNAPSHOT tests test @@ -428,14 +428,14 @@ sonia.scm.plugins scm-hg-plugin - 2.7.1 + 2.8.0-SNAPSHOT test sonia.scm.plugins scm-svn-plugin - 2.7.1 + 2.8.0-SNAPSHOT tests test @@ -443,7 +443,7 @@ sonia.scm.plugins scm-svn-plugin - 2.7.1 + 2.8.0-SNAPSHOT test @@ -729,7 +729,7 @@ sonia.scm scm-ui - 2.7.1 + 2.8.0-SNAPSHOT war From 9c233c19263ed3cfc14ca10ed68176711c45f69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 12 Oct 2020 20:32:53 +0200 Subject: [PATCH 09/26] Add fallback mail host to global config --- .../sonia/scm/config/ScmConfiguration.java | 28 +++++++++++++++++++ scm-ui/ui-types/src/Config.ts | 1 + .../ui-webapp/public/locales/de/config.json | 2 ++ .../ui-webapp/public/locales/en/config.json | 2 ++ .../src/admin/components/form/ConfigForm.tsx | 1 + .../admin/components/form/GeneralSettings.tsx | 16 ++++++++++- .../sonia/scm/api/v2/resources/ConfigDto.java | 3 +- ...ConfigDtoToScmConfigurationMapperTest.java | 2 ++ ...ScmConfigurationToConfigDtoMapperTest.java | 1 + 9 files changed, 54 insertions(+), 2 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index 7bb64a9454..fe67e43820 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -80,6 +80,12 @@ public class ScmConfiguration implements Configuration { */ public static final String DEFAULT_LOGIN_INFO_URL = "https://login-info.scm-manager.org/api/v1/login-info"; + /** + * Default e-mail host that will be used whenever we have to generate an e-mail address for a user that has no mail + * address configured. + */ + public static final String DEFAULT_MAIL_HOST = "scm-manager.local"; + /** * Default plugin url from version 1.0 */ @@ -187,6 +193,8 @@ public class ScmConfiguration implements Configuration { @XmlElement(name = "login-info-url") private String loginInfoUrl = DEFAULT_LOGIN_INFO_URL; + @XmlElement(name = "mail-host") + private String mailHost = DEFAULT_MAIL_HOST; /** * Calls the {@link sonia.scm.ConfigChangedListener#configChanged(Object)} @@ -227,6 +235,7 @@ public class ScmConfiguration implements Configuration { this.namespaceStrategy = other.namespaceStrategy; this.loginInfoUrl = other.loginInfoUrl; this.releaseFeedUrl = other.releaseFeedUrl; + this.mailHost = other.mailHost; } /** @@ -291,6 +300,15 @@ public class ScmConfiguration implements Configuration { return releaseFeedUrl; } + /** + * Returns the mail host, that will be used to create e-mail addresses for users without one whenever one is required. + * + * @since 2.8.0 + */ + public String getMailHost() { + return mailHost; + } + /** * Returns a set of glob patterns for urls which should excluded from * proxy settings. @@ -471,6 +489,16 @@ public class ScmConfiguration implements Configuration { this.releaseFeedUrl = releaseFeedUrl; } + /** + * Sets the mail host, that will be used to create e-mail addresses for users without one whenever one is required. + * + * @param mailHost The new mail host to use. + * @since 2.8.0 + */ + public void setMailHost(String mailHost) { + this.mailHost = mailHost; + } + /** * Set glob patterns for urls which are should be excluded from proxy * settings. diff --git a/scm-ui/ui-types/src/Config.ts b/scm-ui/ui-types/src/Config.ts index 667aa7b199..4369b98e6e 100644 --- a/scm-ui/ui-types/src/Config.ts +++ b/scm-ui/ui-types/src/Config.ts @@ -48,5 +48,6 @@ export type Config = { namespaceStrategy: string; loginInfoUrl: string; releaseFeedUrl: string; + mailHost: string; _links: Links; }; diff --git a/scm-ui/ui-webapp/public/locales/de/config.json b/scm-ui/ui-webapp/public/locales/de/config.json index ad749c12c8..9ab2d38675 100644 --- a/scm-ui/ui-webapp/public/locales/de/config.json +++ b/scm-ui/ui-webapp/public/locales/de/config.json @@ -47,6 +47,7 @@ "skip-failed-authenticators": "Fehlgeschlagene Authentifizierer überspringen", "plugin-url": "Plugin Center URL", "release-feed-url": "Release Feed URL", + "mail-host": "Fallback Mail Host", "enabled-xsrf-protection": "XSRF Protection aktivieren", "namespace-strategy": "Namespace Strategie", "login-info-url": "Login Info URL" @@ -62,6 +63,7 @@ "dateFormatHelpText": "Moments Datumsformat. Zulässige Formate sind in der MomentJS Dokumentation beschrieben.", "pluginUrlHelpText": "Die URL der Plugin Center API. Beschreibung der Platzhalter: version = SCM-Manager Version; os = Betriebssystem; arch = Architektur", "releaseFeedUrlHelpText": "Die URL des RSS Release Feed des SCM-Manager. Darüber wird über die neue SCM-Manager Version informiert. Um diese Funktion zu deaktivieren lassen Sie dieses Feld leer.", + "mailHostHelpText": "Dieser Host Name wird genutzt, wenn für einen User eine E-Mail-Adresse benötigt wird, für den keine hinterlegt ist. Dieser Host wird nicht zum Versenden von E-Mails genutzt und auch keine anderweitige Verbindung aufgebaut.", "enableForwardingHelpText": "mod_proxy Port Weiterleitung aktivieren.", "disableGroupingGridHelpText": "Repository Gruppen deaktivieren. Nach einer Änderung an dieser Einstellung muss die Seite komplett neu geladen werden.", "allowAnonymousAccessHelpText": "Anonyme Benutzer haben Zugriff auf freigegebene Repositories.", diff --git a/scm-ui/ui-webapp/public/locales/en/config.json b/scm-ui/ui-webapp/public/locales/en/config.json index 1150dd4e3d..12d38694a5 100644 --- a/scm-ui/ui-webapp/public/locales/en/config.json +++ b/scm-ui/ui-webapp/public/locales/en/config.json @@ -47,6 +47,7 @@ "skip-failed-authenticators": "Skip Failed Authenticators", "plugin-url": "Plugin Center URL", "release-feed-url": "Release Feed URL", + "mail-host": "Fallback Mail Host", "enabled-xsrf-protection": "Enabled XSRF Protection", "namespace-strategy": "Namespace Strategy", "login-info-url": "Login Info URL" @@ -62,6 +63,7 @@ "dateFormatHelpText": "Moments date format. Please have a look at the MomentJS documentation.", "pluginUrlHelpText": "The url of the Plugin Center API. Explanation of the placeholders: version = SCM-Manager Version; os = Operation System; arch = Architecture", "releaseFeedUrlHelpText": "The url of the RSS Release Feed for SCM-Manager. This provides up-to-date version information. To disable this feature just leave the url blank.", + "mailHostHelpText": "This host name will be used to create email addresses for users when needed and they have none configured. It will not be used to send mails nor will be accessed otherwise.", "enableForwardingHelpText": "Enable mod_proxy port forwarding.", "disableGroupingGridHelpText": "Disable repository Groups. A complete page reload is required after a change of this value.", "allowAnonymousAccessHelpText": "Anonymous users have access on granted repositories.", diff --git a/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx b/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx index f412acf8e8..b38113831f 100644 --- a/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx +++ b/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx @@ -144,6 +144,7 @@ class ConfigForm extends React.Component { skipFailedAuthenticators={config.skipFailedAuthenticators} pluginUrl={config.pluginUrl} releaseFeedUrl={config.releaseFeedUrl} + mailHost={config.mailHost} enabledXsrfProtection={config.enabledXsrfProtection} namespaceStrategy={config.namespaceStrategy} onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)} diff --git a/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx b/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx index 580a3546da..49871ed2aa 100644 --- a/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx +++ b/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx @@ -36,6 +36,7 @@ type Props = WithTranslation & { skipFailedAuthenticators: boolean; pluginUrl: string; releaseFeedUrl: string; + mailHost: string; enabledXsrfProtection: boolean; namespaceStrategy: string; namespaceStrategies?: NamespaceStrategies; @@ -51,6 +52,7 @@ class GeneralSettings extends React.Component { loginInfoUrl, pluginUrl, releaseFeedUrl, + mailHost, enabledXsrfProtection, anonymousMode, namespaceStrategy, @@ -129,7 +131,7 @@ class GeneralSettings extends React.Component {
-
+
{ helpText={t("help.releaseFeedUrlHelpText")} />
+
+ +
); @@ -164,6 +175,9 @@ class GeneralSettings extends React.Component { handleReleaseFeedUrlChange = (value: string) => { this.props.onChange(true, value, "releaseFeedUrl"); }; + handleMailHostChange = (value: string) => { + this.props.onChange(true, value, "mailHost"); + }; } export default withTranslation("config")(GeneralSettings); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java index bec72a552b..42ae1ca6f0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; @@ -59,6 +59,7 @@ public class ConfigDto extends HalRepresentation { private String namespaceStrategy; private String loginInfoUrl; private String releaseFeedUrl; + private String mailHost; @Override @SuppressWarnings("squid:S1185") // We want to have this method available in this package diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java index 3e01a1e4cc..e693d78cea 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java @@ -75,6 +75,7 @@ public class ConfigDtoToScmConfigurationMapperTest { assertTrue(config.isEnabledXsrfProtection()); assertEquals("username", config.getNamespaceStrategy()); assertEquals("https://scm-manager.org/login-info", config.getLoginInfoUrl()); + assertEquals("hitchhiker.mail", config.getMailHost()); } @Test @@ -113,6 +114,7 @@ public class ConfigDtoToScmConfigurationMapperTest { configDto.setEnabledXsrfProtection(true); configDto.setNamespaceStrategy("username"); configDto.setLoginInfoUrl("https://scm-manager.org/login-info"); + configDto.setMailHost("hitchhiker.mail"); return configDto; } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java index cef98c4062..42bf6e7e3b 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java @@ -106,6 +106,7 @@ public class ScmConfigurationToConfigDtoMapperTest { assertEquals("username", dto.getNamespaceStrategy()); assertEquals("https://scm-manager.org/login-info", dto.getLoginInfoUrl()); assertEquals("https://www.scm-manager.org/download/rss.xml", dto.getReleaseFeedUrl()); + assertEquals("scm-manager.local", dto.getMailHost()); assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("self").get().getHref()); assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("update").get().getHref()); From 343d0b942544cc1e74ed5ec151c6db4abdd99bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Mon, 12 Oct 2020 20:48:17 +0200 Subject: [PATCH 10/26] Create util class to get mail address --- .../src/main/java/sonia/scm/user/EMail.java | 52 ++++++++++++++++ .../test/java/sonia/scm/user/EMailTest.java | 62 +++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 scm-core/src/main/java/sonia/scm/user/EMail.java create mode 100644 scm-core/src/test/java/sonia/scm/user/EMailTest.java diff --git a/scm-core/src/main/java/sonia/scm/user/EMail.java b/scm-core/src/main/java/sonia/scm/user/EMail.java new file mode 100644 index 0000000000..121825157c --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/user/EMail.java @@ -0,0 +1,52 @@ +/* + * 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.user; + +import com.google.common.base.Strings; +import sonia.scm.config.ScmConfiguration; + +import javax.inject.Inject; + +public class EMail { + + private final ScmConfiguration scmConfiguration; + + @Inject + public EMail(ScmConfiguration scmConfiguration) { + this.scmConfiguration = scmConfiguration; + } + + public String createFallbackMailAddress(User user) { + if (Strings.isNullOrEmpty(user.getMail())) { + if (user.getId().contains("@")) { + return user.getId(); + } else { + return user.getId() + "@" + scmConfiguration.getMailHost(); + } + } else { + return user.getMail(); + } + } +} diff --git a/scm-core/src/test/java/sonia/scm/user/EMailTest.java b/scm-core/src/test/java/sonia/scm/user/EMailTest.java new file mode 100644 index 0000000000..21f6181757 --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/user/EMailTest.java @@ -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.user; + +import org.junit.jupiter.api.Test; +import sonia.scm.config.ScmConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +class EMailTest { + + EMail eMail = new EMail(new ScmConfiguration()); + + @Test + void shouldUserUsersAddressIfAvailable() { + User user = new User("dent", "Arthur Dent", "arthur@hitchhiker.com"); + + String mailAddress = eMail.createFallbackMailAddress(user); + + assertThat(mailAddress).isEqualTo("arthur@hitchhiker.com"); + } + + @Test + void shouldCreateAddressIfNoneAvailable() { + User user = new User("dent", "Arthur Dent", ""); + + String mailAddress = eMail.createFallbackMailAddress(user); + + assertThat(mailAddress).isEqualTo("dent@scm-manager.local"); + } + + @Test + void shouldUserUsersIdIfItLooksLikeAnMailAddress() { + User user = new User("dent@hitchhiker.com", "Arthur Dent", ""); + + String mailAddress = eMail.createFallbackMailAddress(user); + + assertThat(mailAddress).isEqualTo("dent@hitchhiker.com"); + } +} From 7fc7e33c0cf22a6db61a998b215acf5d021a6db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 13 Oct 2020 08:51:48 +0200 Subject: [PATCH 11/26] Add fallback email to me dto --- scm-ui/ui-types/src/Me.ts | 3 ++- .../sonia/scm/api/v2/resources/MeDto.java | 6 ++++- .../scm/api/v2/resources/MeDtoFactory.java | 13 ++++++++++- .../api/v2/resources/MeDtoFactoryTest.java | 22 ++++++++++++++++--- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/scm-ui/ui-types/src/Me.ts b/scm-ui/ui-types/src/Me.ts index 38a3a23278..d8595e0771 100644 --- a/scm-ui/ui-types/src/Me.ts +++ b/scm-ui/ui-types/src/Me.ts @@ -27,7 +27,8 @@ import { Links } from "./hal"; export type Me = { name: string; displayName: string; - mail: string; + mail?: string; + fallbackMail?: string; groups: string[]; _links: Links; }; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java index 968d892536..b4e011f7bb 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDto.java @@ -21,9 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; +import com.fasterxml.jackson.annotation.JsonInclude; import de.otto.edison.hal.Embedded; import de.otto.edison.hal.HalRepresentation; import de.otto.edison.hal.Links; @@ -40,7 +41,10 @@ public class MeDto extends HalRepresentation { private String name; private String displayName; + @JsonInclude(JsonInclude.Include.NON_NULL) private String mail; + @JsonInclude(JsonInclude.Include.NON_NULL) + private String fallbackMail; private Set groups; MeDto(Links links, Embedded embedded) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java index 2101ba2ffb..2bc72d509a 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java @@ -24,12 +24,14 @@ package sonia.scm.api.v2.resources; +import com.google.common.base.Strings; import de.otto.edison.hal.Embedded; import de.otto.edison.hal.Links; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import sonia.scm.group.GroupCollector; +import sonia.scm.user.EMail; import sonia.scm.user.User; import sonia.scm.user.UserManager; import sonia.scm.user.UserPermissions; @@ -46,12 +48,14 @@ public class MeDtoFactory extends HalAppenderMapper { private final ResourceLinks resourceLinks; private final UserManager userManager; private final GroupCollector groupCollector; + private final EMail eMail; @Inject - public MeDtoFactory(ResourceLinks resourceLinks, UserManager userManager, GroupCollector groupCollector) { + public MeDtoFactory(ResourceLinks resourceLinks, UserManager userManager, GroupCollector groupCollector, EMail eMail) { this.resourceLinks = resourceLinks; this.userManager = userManager; this.groupCollector = groupCollector; + this.eMail = eMail; } public MeDto create() { @@ -61,6 +65,7 @@ public class MeDtoFactory extends HalAppenderMapper { MeDto dto = createDto(user); mapUserProperties(user, dto); mapGroups(user, dto); + setGeneratedMail(user, dto); return dto; } @@ -79,6 +84,12 @@ public class MeDtoFactory extends HalAppenderMapper { return subject.getPrincipals(); } + private void setGeneratedMail(User user, MeDto dto) { + if (Strings.isNullOrEmpty(user.getMail())) { + dto.setFallbackMail(eMail.createFallbackMailAddress(user)); + } + } + private MeDto createDto(User user) { Links.Builder linksBuilder = linkingTo().self(resourceLinks.me().self()); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java index 901d625579..2a4cea9626 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import com.google.common.collect.ImmutableSet; @@ -38,9 +38,9 @@ import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import sonia.scm.SCMContext; import sonia.scm.group.GroupCollector; +import sonia.scm.user.EMail; import sonia.scm.user.User; import sonia.scm.user.UserManager; -import sonia.scm.user.UserPermissions; import sonia.scm.user.UserTestData; import java.net.URI; @@ -65,13 +65,16 @@ class MeDtoFactoryTest { @Mock private Subject subject; + @Mock + private EMail eMail; + private MeDtoFactory meDtoFactory; @BeforeEach void setUpContext() { ThreadContext.bind(subject); ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); - meDtoFactory = new MeDtoFactory(resourceLinks, userManager, groupCollector); + meDtoFactory = new MeDtoFactory(resourceLinks, userManager, groupCollector, eMail); } @AfterEach @@ -235,4 +238,17 @@ class MeDtoFactoryTest { MeDto dto = meDtoFactory.create(); assertThat(dto.getLinks().getLinkBy("profile").get().getHref()).isEqualTo("http://hitchhiker.com/users/trillian"); } + + @Test + void shouldUserGeneratedMailOnlyWhenUserHasNone() { + User user = UserTestData.createTrillian(); + user.setMail(null); + prepareSubject(user); + when(eMail.createFallbackMailAddress(user)).thenReturn("trillian@hitchhiker.local"); + + MeDto dto = meDtoFactory.create(); + + assertThat(dto.getMail()).isNull(); + assertThat(dto.getFallbackMail()).isEqualTo("trillian@hitchhiker.local"); + } } From bb2b8450157e953ce61a8d2e288e824c341d80ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 13 Oct 2020 16:27:24 +0200 Subject: [PATCH 12/26] Use email util to compute fallback mail address --- .../repository/api/MergeCommandBuilder.java | 8 +- .../repository/api/ModifyCommandBuilder.java | 8 +- .../scm/repository/api/RepositoryService.java | 14 +- .../api/RepositoryServiceFactory.java | 170 +++++----- .../sonia/scm/repository/util/AuthorUtil.java | 13 +- .../api/ModifyCommandBuilderTest.java | 315 +++++++++++------- .../api/RepositoryServiceFactoryTest.java | 9 +- .../repository/api/RepositoryServiceTest.java | 16 +- 8 files changed, 315 insertions(+), 238 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java index 06a3b489a1..a751832d8f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java @@ -30,6 +30,7 @@ import sonia.scm.repository.spi.MergeCommand; import sonia.scm.repository.spi.MergeCommandRequest; import sonia.scm.repository.spi.MergeConflictResult; import sonia.scm.repository.util.AuthorUtil; +import sonia.scm.user.EMail; import java.util.Set; @@ -75,11 +76,14 @@ import java.util.Set; */ public class MergeCommandBuilder { + private final EMail eMail; + private final MergeCommand mergeCommand; private final MergeCommandRequest request = new MergeCommandRequest(); - MergeCommandBuilder(MergeCommand mergeCommand) { + MergeCommandBuilder(MergeCommand mergeCommand, EMail eMail) { this.mergeCommand = mergeCommand; + this.eMail = eMail; } /** @@ -209,7 +213,7 @@ public class MergeCommandBuilder { * @return The result of the merge. */ public MergeCommandResult executeMerge() { - AuthorUtil.setAuthorIfNotAvailable(request); + AuthorUtil.setAuthorIfNotAvailable(request, eMail); Preconditions.checkArgument(request.isValid(), "revision to merge and target revision is required"); return mergeCommand.merge(request); } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java index aeccb24b99..795de5d43d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java @@ -35,6 +35,7 @@ import sonia.scm.repository.spi.ModifyCommand; import sonia.scm.repository.spi.ModifyCommandRequest; import sonia.scm.repository.util.AuthorUtil; import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.user.EMail; import sonia.scm.util.IOUtil; import java.io.File; @@ -72,14 +73,17 @@ public class ModifyCommandBuilder { private static final Logger LOG = LoggerFactory.getLogger(ModifyCommandBuilder.class); + private final EMail eMail; + private final ModifyCommand command; private final File workdir; private final ModifyCommandRequest request = new ModifyCommandRequest(); - ModifyCommandBuilder(ModifyCommand command, WorkdirProvider workdirProvider) { + ModifyCommandBuilder(ModifyCommand command, WorkdirProvider workdirProvider, EMail eMail) { this.command = command; this.workdir = workdirProvider.createNewWorkdir(); + this.eMail = eMail; } /** @@ -124,7 +128,7 @@ public class ModifyCommandBuilder { * @return The revision of the new commit. */ public String execute() { - AuthorUtil.setAuthorIfNotAvailable(request); + AuthorUtil.setAuthorIfNotAvailable(request, eMail); try { Preconditions.checkArgument(request.isValid(), "commit message and at least one request are required"); return command.execute(request); diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 15f84a4ecd..029dc6fa34 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -34,6 +34,7 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermissions; import sonia.scm.repository.spi.RepositoryServiceProvider; import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.user.EMail; import java.io.Closeable; import java.io.IOException; @@ -87,6 +88,7 @@ public final class RepositoryService implements Closeable { @SuppressWarnings("rawtypes") private final Set protocolProviders; private final WorkdirProvider workdirProvider; + private final EMail eMail; /** * Constructs a new {@link RepositoryService}. This constructor should only @@ -94,20 +96,22 @@ public final class RepositoryService implements Closeable { * @param cacheManager cache manager * @param provider implementation for {@link RepositoryServiceProvider} * @param repository the repository - * @param workdirProvider + * @param workdirProvider provider for workdirs + * @param eMail utility to compute email addresses if missing */ RepositoryService(CacheManager cacheManager, RepositoryServiceProvider provider, Repository repository, PreProcessorUtil preProcessorUtil, @SuppressWarnings("rawtypes") Set protocolProviders, - WorkdirProvider workdirProvider - ) { + WorkdirProvider workdirProvider, + EMail eMail) { this.cacheManager = cacheManager; this.provider = provider; this.repository = repository; this.preProcessorUtil = preProcessorUtil; this.protocolProviders = protocolProviders; this.workdirProvider = workdirProvider; + this.eMail = eMail; } /** @@ -397,7 +401,7 @@ public final class RepositoryService implements Closeable { LOG.debug("create merge command for repository {}", repository.getNamespaceAndName()); - return new MergeCommandBuilder(provider.getMergeCommand()); + return new MergeCommandBuilder(provider.getMergeCommand(), eMail); } /** @@ -418,7 +422,7 @@ public final class RepositoryService implements Closeable { LOG.debug("create modify command for repository {}", repository.getNamespaceAndName()); - return new ModifyCommandBuilder(provider.getModifyCommand(), workdirProvider); + return new ModifyCommandBuilder(provider.getModifyCommand(), workdirProvider, eMail); } /** diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java index b030d1cb0c..15cec9d210 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java @@ -40,9 +40,7 @@ import sonia.scm.HandlerEventType; import sonia.scm.NotFoundException; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; -import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; -import sonia.scm.repository.BranchCreatedEvent; import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.PostReceiveRepositoryHookEvent; @@ -58,6 +56,7 @@ import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.security.PublicKeyCreatedEvent; import sonia.scm.security.PublicKeyDeletedEvent; import sonia.scm.security.ScmSecurityException; +import sonia.scm.user.EMail; import java.util.Set; @@ -117,47 +116,9 @@ public final class RepositoryServiceFactory { //~--- constructors --------------------------------------------------------- - /** - * Constructs a new {@link RepositoryServiceFactory}. This constructor - * should not be called manually, it should only be used by the injection - * container. - * - * @param configuration configuration - * @param cacheManager cache manager - * @param repositoryManager manager for repositories - * @param resolvers a set of {@link RepositoryServiceResolver} - * @param preProcessorUtil helper object for pre processor handling - * @param protocolProviders - * @param workdirProvider - * @since 1.21 - */ - @Inject - public RepositoryServiceFactory(ScmConfiguration configuration, - CacheManager cacheManager, RepositoryManager repositoryManager, - Set resolvers, PreProcessorUtil preProcessorUtil, - @SuppressWarnings("rawtypes") Set protocolProviders, WorkdirProvider workdirProvider) { - this( - configuration, cacheManager, repositoryManager, resolvers, - preProcessorUtil, protocolProviders, workdirProvider, ScmEventBus.getInstance() - ); - } - - @VisibleForTesting - RepositoryServiceFactory(ScmConfiguration configuration, - CacheManager cacheManager, RepositoryManager repositoryManager, - Set resolvers, PreProcessorUtil preProcessorUtil, - Set protocolProviders, WorkdirProvider workdirProvider, - ScmEventBus eventBus) { - this.configuration = configuration; - this.cacheManager = cacheManager; - this.repositoryManager = repositoryManager; - this.resolvers = resolvers; - this.preProcessorUtil = preProcessorUtil; - this.protocolProviders = protocolProviders; - this.workdirProvider = workdirProvider; - - eventBus.register(new CacheClearHook(cacheManager)); - } + private final EMail eMail; + @SuppressWarnings("rawtypes") + private Set protocolProviders; //~--- methods -------------------------------------------------------------- @@ -216,47 +177,27 @@ public final class RepositoryServiceFactory { } /** - * Creates a new RepositoryService for the given repository. + * Constructs a new {@link RepositoryServiceFactory}. This constructor + * should not be called manually, it should only be used by the injection + * container. * - * @param repository the repository - * @return a implementation of RepositoryService - * for the given type of repository - * @throws RepositoryServiceNotFoundException if no repository service - * implementation for this kind of repository is available - * @throws NullPointerException if the repository is null - * @throws ScmSecurityException if current user has not read permissions - * for that repository + * @param cacheManager cache manager + * @param repositoryManager manager for repositories + * @param resolvers a set of {@link RepositoryServiceResolver} + * @param preProcessorUtil helper object for pre processor handling + * @param protocolProviders + * @param workdirProvider + * @since 1.21 */ - public RepositoryService create(Repository repository) { - Preconditions.checkNotNull(repository, "repository is required"); - - // check for read permissions of current user - RepositoryPermissions.read(repository).check(); - - RepositoryService service = null; - - for (RepositoryServiceResolver resolver : resolvers) { - RepositoryServiceProvider provider = resolver.resolve(repository); - - if (provider != null) { - if (logger.isDebugEnabled()) { - logger.debug( - "create new repository service for repository {} of type {}", - repository.getName(), repository.getType()); - } - - service = new RepositoryService(cacheManager, provider, repository, - preProcessorUtil, protocolProviders, workdirProvider); - - break; - } - } - - if (service == null) { - throw new RepositoryServiceNotFoundException(repository); - } - - return service; + @Inject + public RepositoryServiceFactory(CacheManager cacheManager, RepositoryManager repositoryManager, + Set resolvers, PreProcessorUtil preProcessorUtil, + @SuppressWarnings("rawtypes") Set protocolProviders, + WorkdirProvider workdirProvider, EMail eMail) { + this( + cacheManager, repositoryManager, resolvers, + preProcessorUtil, protocolProviders, workdirProvider, eMail, ScmEventBus.getInstance() + ); } //~--- inner classes -------------------------------------------------------- @@ -355,11 +296,6 @@ public final class RepositoryServiceFactory { */ private final CacheManager cacheManager; - /** - * scm-manager configuration - */ - private final ScmConfiguration configuration; - /** * pre processor util */ @@ -375,7 +311,65 @@ public final class RepositoryServiceFactory { */ private final Set resolvers; - private Set protocolProviders; + @VisibleForTesting + RepositoryServiceFactory(CacheManager cacheManager, RepositoryManager repositoryManager, + Set resolvers, PreProcessorUtil preProcessorUtil, + @SuppressWarnings("rawtypes") Set protocolProviders, + WorkdirProvider workdirProvider, EMail eMail, ScmEventBus eventBus) { + this.cacheManager = cacheManager; + this.repositoryManager = repositoryManager; + this.resolvers = resolvers; + this.preProcessorUtil = preProcessorUtil; + this.protocolProviders = protocolProviders; + this.workdirProvider = workdirProvider; + this.eMail = eMail; + + eventBus.register(new CacheClearHook(cacheManager)); + } private final WorkdirProvider workdirProvider; + + /** + * Creates a new RepositoryService for the given repository. + * + * @param repository the repository + * @return a implementation of RepositoryService + * for the given type of repository + * @throws RepositoryServiceNotFoundException if no repository service + * implementation for this kind of repository is available + * @throws NullPointerException if the repository is null + * @throws ScmSecurityException if current user has not read permissions + * for that repository + */ + public RepositoryService create(Repository repository) { + Preconditions.checkNotNull(repository, "repository is required"); + + // check for read permissions of current user + RepositoryPermissions.read(repository).check(); + + RepositoryService service = null; + + for (RepositoryServiceResolver resolver : resolvers) { + RepositoryServiceProvider provider = resolver.resolve(repository); + + if (provider != null) { + if (logger.isDebugEnabled()) { + logger.debug( + "create new repository service for repository {} of type {}", + repository.getName(), repository.getType()); + } + + service = new RepositoryService(cacheManager, provider, repository, + preProcessorUtil, protocolProviders, workdirProvider, eMail); + + break; + } + } + + if (service == null) { + throw new RepositoryServiceNotFoundException(repository); + } + + return service; + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java index fa2c598f03..5bc62fbecf 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java @@ -21,28 +21,29 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.util; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import sonia.scm.repository.Person; +import sonia.scm.user.EMail; import sonia.scm.user.User; public class AuthorUtil { - public static void setAuthorIfNotAvailable(CommandWithAuthor request) { + public static void setAuthorIfNotAvailable(CommandWithAuthor request, EMail eMail) { if (request.getAuthor() == null) { - request.setAuthor(createAuthorFromSubject()); + request.setAuthor(createAuthorFromSubject(eMail)); } } - private static Person createAuthorFromSubject() { + private static Person createAuthorFromSubject(EMail eMail) { Subject subject = SecurityUtils.getSubject(); User user = subject.getPrincipals().oneByType(User.class); String name = user.getDisplayName(); - String email = user.getMail(); - return new Person(name, email); + String mailAddress = eMail.createFallbackMailAddress(user); + return new Person(name, mailAddress); } public interface CommandWithAuthor { diff --git a/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java b/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java index 5583261e52..15a4b909f1 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java @@ -25,7 +25,12 @@ package sonia.scm.repository.api; import com.google.common.io.ByteSource; +import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.util.ThreadContext; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; @@ -34,10 +39,12 @@ import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.stubbing.Answer; -import sonia.scm.repository.Person; +import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.spi.ModifyCommand; import sonia.scm.repository.spi.ModifyCommandRequest; import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.user.EMail; +import sonia.scm.user.User; import java.io.ByteArrayInputStream; import java.io.File; @@ -50,15 +57,19 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ModifyCommandBuilderTest { + private static final ScmConfiguration SCM_CONFIGURATION = new ScmConfiguration(); + @Mock ModifyCommand command; @Mock @@ -73,7 +84,7 @@ class ModifyCommandBuilderTest { void initWorkdir(@TempDir Path temp) throws IOException { workdir = Files.createDirectory(temp.resolve("workdir")); lenient().when(workdirProvider.createNewWorkdir()).thenReturn(workdir.toFile()); - commandBuilder = new ModifyCommandBuilder(command, workdirProvider); + commandBuilder = new ModifyCommandBuilder(command, workdirProvider, new EMail(SCM_CONFIGURATION)); } @BeforeEach @@ -89,136 +100,27 @@ class ModifyCommandBuilderTest { ); } - @Test - void shouldReturnTargetRevisionFromCommit() { - String targetRevision = initCommand() - .deleteFile("toBeDeleted") - .execute(); - - assertThat(targetRevision).isEqualTo("target"); - } - - @Test - void shouldExecuteDelete() throws IOException { - initCommand() - .deleteFile("toBeDeleted") - .execute(); - - verify(worker).delete("toBeDeleted"); - } - - @Test - void shouldExecuteCreateWithByteSourceContent() throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - List contentCaptor = new ArrayList<>(); - doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), anyBoolean()); - - initCommand() - .createFile("toBeCreated").withData(ByteSource.wrap("content".getBytes())) - .execute(); - - assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); - assertThat(contentCaptor).contains("content"); - } - - @Test - void shouldExecuteCreateWithInputStreamContent() throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - List contentCaptor = new ArrayList<>(); - doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), anyBoolean()); - - initCommand() - .createFile("toBeCreated").withData(new ByteArrayInputStream("content".getBytes())) - .execute(); - - assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); - assertThat(contentCaptor).contains("content"); - } - - @Test - void shouldExecuteCreateWithOverwriteFalseAsDefault() throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor overwriteCaptor = ArgumentCaptor.forClass(Boolean.class); - List contentCaptor = new ArrayList<>(); - doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), overwriteCaptor.capture()); - - initCommand() - .createFile("toBeCreated").withData(new ByteArrayInputStream("content".getBytes())) - .execute(); - - assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); - assertThat(overwriteCaptor.getValue()).isFalse(); - assertThat(contentCaptor).contains("content"); - } - - @Test - void shouldExecuteCreateWithOverwriteIfSet() throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor overwriteCaptor = ArgumentCaptor.forClass(Boolean.class); - List contentCaptor = new ArrayList<>(); - doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), overwriteCaptor.capture()); - - initCommand() - .createFile("toBeCreated").setOverwrite(true).withData(new ByteArrayInputStream("content".getBytes())) - .execute(); - - assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); - assertThat(overwriteCaptor.getValue()).isTrue(); - assertThat(contentCaptor).contains("content"); - } - - @Test - void shouldExecuteCreateMultipleTimes() throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - List contentCaptor = new ArrayList<>(); - doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), anyBoolean()); - - initCommand() - .createFile("toBeCreated_1").withData(new ByteArrayInputStream("content_1".getBytes())) - .createFile("toBeCreated_2").withData(new ByteArrayInputStream("content_2".getBytes())) - .execute(); - - List createdNames = nameCaptor.getAllValues(); - assertThat(createdNames.get(0)).isEqualTo("toBeCreated_1"); - assertThat(createdNames.get(1)).isEqualTo("toBeCreated_2"); - assertThat(contentCaptor).contains("content_1", "content_2"); - } - - @Test - void shouldExecuteModify() throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - List contentCaptor = new ArrayList<>(); - doAnswer(new ExtractContent(contentCaptor)).when(worker).modify(nameCaptor.capture(), any()); - - initCommand() - .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) - .execute(); - - assertThat(nameCaptor.getValue()).isEqualTo("toBeModified"); - assertThat(contentCaptor).contains("content"); - } - private ModifyCommandBuilder initCommand() { return commandBuilder .setBranch("branch") - .setCommitMessage("message") - .setAuthor(new Person()); + .setCommitMessage("message"); } - @Test - void shouldDeleteTemporaryFiles(@TempDir Path temp) throws IOException { - ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor fileCaptor = ArgumentCaptor.forClass(File.class); - doNothing().when(worker).modify(nameCaptor.capture(), fileCaptor.capture()); + private void mockLoggedInUser(User loggedInUser) { + Subject subject = mock(Subject.class); + ThreadContext.bind(subject); + PrincipalCollection principals = mock(PrincipalCollection.class); + when(subject.getPrincipals()).thenReturn(principals); + when(principals.oneByType(User.class)).thenReturn(loggedInUser); + } - initCommand() - .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) - .execute(); - - assertThat(Files.list(temp)).isEmpty(); + @AfterEach + void unbindSubjec() { + ThreadContext.unbindSubject(); } private static class ExtractContent implements Answer { + private final List contentCaptor; public ExtractContent(List contentCaptor) { @@ -230,4 +132,171 @@ class ModifyCommandBuilderTest { return contentCaptor.add(Files.readAllLines(((File) invocation.getArgument(1)).toPath()).get(0)); } } + + @Nested + class WithUserWithMail { + + @BeforeEach + void initSubject() { + User loggedInUser = new User("dent", "Arthur", "dent@hitchhiker.com"); + mockLoggedInUser(loggedInUser); + } + + @Test + void shouldReturnTargetRevisionFromCommit() { + String targetRevision = initCommand() + .deleteFile("toBeDeleted") + .execute(); + + assertThat(targetRevision).isEqualTo("target"); + } + + @Test + void shouldExecuteDelete() throws IOException { + initCommand() + .deleteFile("toBeDeleted") + .execute(); + + verify(worker).delete("toBeDeleted"); + } + + @Test + void shouldExecuteCreateWithByteSourceContent() throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + List contentCaptor = new ArrayList<>(); + doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), anyBoolean()); + + initCommand() + .createFile("toBeCreated").withData(ByteSource.wrap("content".getBytes())) + .execute(); + + assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); + assertThat(contentCaptor).contains("content"); + } + + @Test + void shouldExecuteCreateWithInputStreamContent() throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + List contentCaptor = new ArrayList<>(); + doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), anyBoolean()); + + initCommand() + .createFile("toBeCreated").withData(new ByteArrayInputStream("content".getBytes())) + .execute(); + + assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); + assertThat(contentCaptor).contains("content"); + } + + @Test + void shouldExecuteCreateWithOverwriteFalseAsDefault() throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor overwriteCaptor = ArgumentCaptor.forClass(Boolean.class); + List contentCaptor = new ArrayList<>(); + doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), overwriteCaptor.capture()); + + initCommand() + .createFile("toBeCreated").withData(new ByteArrayInputStream("content".getBytes())) + .execute(); + + assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); + assertThat(overwriteCaptor.getValue()).isFalse(); + assertThat(contentCaptor).contains("content"); + } + + @Test + void shouldExecuteCreateWithOverwriteIfSet() throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor overwriteCaptor = ArgumentCaptor.forClass(Boolean.class); + List contentCaptor = new ArrayList<>(); + doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), overwriteCaptor.capture()); + + initCommand() + .createFile("toBeCreated").setOverwrite(true).withData(new ByteArrayInputStream("content".getBytes())) + .execute(); + + assertThat(nameCaptor.getValue()).isEqualTo("toBeCreated"); + assertThat(overwriteCaptor.getValue()).isTrue(); + assertThat(contentCaptor).contains("content"); + } + + @Test + void shouldExecuteCreateMultipleTimes() throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + List contentCaptor = new ArrayList<>(); + doAnswer(new ExtractContent(contentCaptor)).when(worker).create(nameCaptor.capture(), any(), anyBoolean()); + + initCommand() + .createFile("toBeCreated_1").withData(new ByteArrayInputStream("content_1".getBytes())) + .createFile("toBeCreated_2").withData(new ByteArrayInputStream("content_2".getBytes())) + .execute(); + + List createdNames = nameCaptor.getAllValues(); + assertThat(createdNames.get(0)).isEqualTo("toBeCreated_1"); + assertThat(createdNames.get(1)).isEqualTo("toBeCreated_2"); + assertThat(contentCaptor).contains("content_1", "content_2"); + } + + @Test + void shouldExecuteModify() throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + List contentCaptor = new ArrayList<>(); + doAnswer(new ExtractContent(contentCaptor)).when(worker).modify(nameCaptor.capture(), any()); + + initCommand() + .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) + .execute(); + + assertThat(nameCaptor.getValue()).isEqualTo("toBeModified"); + assertThat(contentCaptor).contains("content"); + } + + @Test + void shouldDeleteTemporaryFiles(@TempDir Path temp) throws IOException { + ArgumentCaptor nameCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor fileCaptor = ArgumentCaptor.forClass(File.class); + doNothing().when(worker).modify(nameCaptor.capture(), fileCaptor.capture()); + + initCommand() + .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) + .execute(); + + assertThat(Files.list(temp)).isEmpty(); + } + + @Test + void shouldUseMailFromUser() throws IOException { + initCommand() + .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) + .execute(); + + verify(command).execute(argThat(modifyCommandRequest -> { + assertThat(modifyCommandRequest.getAuthor().getMail()).isEqualTo("dent@hitchhiker.com"); + return true; + })); + } + } + + @Nested + class WithUserWithoutMail { + + @BeforeEach + void initSubject() { + User loggedInUser = new User("dent", "Arthur", null); + mockLoggedInUser(loggedInUser); + } + + @Test + void shouldUseMailFromUser() throws IOException { + SCM_CONFIGURATION.setMailHost("heart-of-gold.local"); + initCommand() + .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) + .execute(); + + verify(command).execute(argThat(modifyCommandRequest -> { + assertThat(modifyCommandRequest.getAuthor().getMail()).isEqualTo("dent@heart-of-gold.local"); + return true; + })); + } + } } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java index 492d23dec8..d77d0d072b 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceFactoryTest.java @@ -46,6 +46,7 @@ import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.spi.RepositoryServiceProvider; import sonia.scm.repository.spi.RepositoryServiceResolver; import sonia.scm.repository.work.WorkdirProvider; +import sonia.scm.user.EMail; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -56,9 +57,6 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class RepositoryServiceFactoryTest { - @Mock - private ScmConfiguration configuration; - @Mock(answer = Answers.RETURNS_MOCKS) private CacheManager cacheManager; @@ -94,8 +92,9 @@ class RepositoryServiceFactoryTest { builder.add(repositoryServiceResolver); } return new RepositoryServiceFactory( - configuration, cacheManager, repositoryManager, builder.build(), - preProcessorUtil, ImmutableSet.of(), workdirProvider, eventBus + cacheManager, repositoryManager, builder.build(), + preProcessorUtil, ImmutableSet.of(), workdirProvider, + new EMail(new ScmConfiguration()), eventBus ); } diff --git a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java index 901666cb87..8394e3c582 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/RepositoryServiceTest.java @@ -21,13 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.api; import org.junit.Test; +import sonia.scm.config.ScmConfiguration; import sonia.scm.repository.Repository; import sonia.scm.repository.spi.HttpScmProtocol; import sonia.scm.repository.spi.RepositoryServiceProvider; +import sonia.scm.user.EMail; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; @@ -46,9 +48,11 @@ public class RepositoryServiceTest { private final RepositoryServiceProvider provider = mock(RepositoryServiceProvider.class); private final Repository repository = new Repository("", "git", "space", "repo"); + private final EMail eMail = new EMail(new ScmConfiguration()); + @Test public void shouldReturnMatchingProtocolsFromProvider() { - RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null); + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null, eMail); Stream supportedProtocols = repositoryService.getSupportedProtocols(); assertThat(sizeOf(supportedProtocols.collect(Collectors.toList()))).isEqualTo(1); @@ -56,7 +60,7 @@ public class RepositoryServiceTest { @Test public void shouldFindKnownProtocol() { - RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null); + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null, eMail); HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class); @@ -65,11 +69,9 @@ public class RepositoryServiceTest { @Test public void shouldFailForUnknownProtocol() { - RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null); + RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null, eMail); - assertThrows(IllegalArgumentException.class, () -> { - repositoryService.getProtocol(UnknownScmProtocol.class); - }); + assertThrows(IllegalArgumentException.class, () -> repositoryService.getProtocol(UnknownScmProtocol.class)); } private static class DummyHttpProtocol extends HttpScmProtocol { From e60ea987dda1aa633da78ab91e56d7c26506c4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Tue, 13 Oct 2020 20:40:30 +0200 Subject: [PATCH 13/26] Make mail optional for user --- scm-ui/ui-types/src/User.ts | 4 ++-- scm-ui/ui-webapp/src/users/components/UserForm.tsx | 6 +++--- .../src/main/java/sonia/scm/api/v2/resources/UserDto.java | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/scm-ui/ui-types/src/User.ts b/scm-ui/ui-types/src/User.ts index 43ff64b9fa..29009b5d0d 100644 --- a/scm-ui/ui-types/src/User.ts +++ b/scm-ui/ui-types/src/User.ts @@ -27,13 +27,13 @@ import { Links } from "./hal"; export type DisplayedUser = { id: string; displayName: string; - mail: string; + mail?: string; }; export type User = { displayName: string; name: string; - mail: string; + mail?: string; password: string; active: boolean; type?: string; diff --git a/scm-ui/ui-webapp/src/users/components/UserForm.tsx b/scm-ui/ui-webapp/src/users/components/UserForm.tsx index cd0856fa84..9c78ef8476 100644 --- a/scm-ui/ui-webapp/src/users/components/UserForm.tsx +++ b/scm-ui/ui-webapp/src/users/components/UserForm.tsx @@ -113,8 +113,7 @@ class UserForm extends React.Component { this.editUserComponentsAreUnchanged() || this.state.mailValidationError || this.state.displayNameValidationError || - this.isFalsy(user.displayName) || - this.isFalsy(user.mail) + this.isFalsy(user.displayName) ); }; @@ -152,6 +151,7 @@ class UserForm extends React.Component { // edit existing user subtitle = ; } + return ( <> {subtitle} @@ -218,7 +218,7 @@ class UserForm extends React.Component { handleEmailChange = (mail: string) => { this.setState({ - mailValidationError: !validator.isMailValid(mail), + mailValidationError: !!mail && !validator.isMailValid(mail), user: { ...this.state.user, mail diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserDto.java index 0e4e9b34c2..027cc59621 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserDto.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.api.v2.resources; import com.fasterxml.jackson.annotation.JsonInclude; @@ -46,7 +46,8 @@ public class UserDto extends HalRepresentation { private String displayName; @JsonInclude(JsonInclude.Include.NON_NULL) private Instant lastModified; - @NotEmpty @Email + @JsonInclude(JsonInclude.Include.NON_NULL) + @Email private String mail; @Pattern(regexp = ValidationUtil.REGEX_NAME) private String name; From be6bb8bf372a9b63332f8a7ee212419845f0e085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 14 Oct 2020 08:17:33 +0200 Subject: [PATCH 14/26] Rename "mail host" to "mail domain name" --- .../sonia/scm/config/ScmConfiguration.java | 22 +++++++++---------- .../src/main/java/sonia/scm/user/EMail.java | 2 +- .../api/ModifyCommandBuilderTest.java | 2 +- scm-ui/ui-types/src/Config.ts | 2 +- .../ui-webapp/public/locales/de/config.json | 4 ++-- .../ui-webapp/public/locales/en/config.json | 4 ++-- .../src/admin/components/form/ConfigForm.tsx | 2 +- .../admin/components/form/GeneralSettings.tsx | 16 +++++++------- .../sonia/scm/api/v2/resources/ConfigDto.java | 2 +- ...ConfigDtoToScmConfigurationMapperTest.java | 4 ++-- ...ScmConfigurationToConfigDtoMapperTest.java | 2 +- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index fe67e43820..2fed4058f7 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -81,10 +81,10 @@ public class ScmConfiguration implements Configuration { public static final String DEFAULT_LOGIN_INFO_URL = "https://login-info.scm-manager.org/api/v1/login-info"; /** - * Default e-mail host that will be used whenever we have to generate an e-mail address for a user that has no mail - * address configured. + * Default e-mail domain name that will be used whenever we have to generate an e-mail address for a user that has no + * mail address configured. */ - public static final String DEFAULT_MAIL_HOST = "scm-manager.local"; + public static final String DEFAULT_MAIL_DOMAIN_NAME = "scm-manager.local"; /** * Default plugin url from version 1.0 @@ -193,8 +193,8 @@ public class ScmConfiguration implements Configuration { @XmlElement(name = "login-info-url") private String loginInfoUrl = DEFAULT_LOGIN_INFO_URL; - @XmlElement(name = "mail-host") - private String mailHost = DEFAULT_MAIL_HOST; + @XmlElement(name = "mail-domain-name") + private String mailDomainName = DEFAULT_MAIL_DOMAIN_NAME; /** * Calls the {@link sonia.scm.ConfigChangedListener#configChanged(Object)} @@ -235,7 +235,7 @@ public class ScmConfiguration implements Configuration { this.namespaceStrategy = other.namespaceStrategy; this.loginInfoUrl = other.loginInfoUrl; this.releaseFeedUrl = other.releaseFeedUrl; - this.mailHost = other.mailHost; + this.mailDomainName = other.mailDomainName; } /** @@ -305,8 +305,8 @@ public class ScmConfiguration implements Configuration { * * @since 2.8.0 */ - public String getMailHost() { - return mailHost; + public String getMailDomainName() { + return mailDomainName; } /** @@ -492,11 +492,11 @@ public class ScmConfiguration implements Configuration { /** * Sets the mail host, that will be used to create e-mail addresses for users without one whenever one is required. * - * @param mailHost The new mail host to use. + * @param mailDomainName The new mail host to use. * @since 2.8.0 */ - public void setMailHost(String mailHost) { - this.mailHost = mailHost; + public void setMailDomainName(String mailDomainName) { + this.mailDomainName = mailDomainName; } /** diff --git a/scm-core/src/main/java/sonia/scm/user/EMail.java b/scm-core/src/main/java/sonia/scm/user/EMail.java index 121825157c..0718a3c722 100644 --- a/scm-core/src/main/java/sonia/scm/user/EMail.java +++ b/scm-core/src/main/java/sonia/scm/user/EMail.java @@ -43,7 +43,7 @@ public class EMail { if (user.getId().contains("@")) { return user.getId(); } else { - return user.getId() + "@" + scmConfiguration.getMailHost(); + return user.getId() + "@" + scmConfiguration.getMailDomainName(); } } else { return user.getMail(); diff --git a/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java b/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java index 15a4b909f1..281e793cbb 100644 --- a/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/api/ModifyCommandBuilderTest.java @@ -288,7 +288,7 @@ class ModifyCommandBuilderTest { @Test void shouldUseMailFromUser() throws IOException { - SCM_CONFIGURATION.setMailHost("heart-of-gold.local"); + SCM_CONFIGURATION.setMailDomainName("heart-of-gold.local"); initCommand() .modifyFile("toBeModified").withData(ByteSource.wrap("content".getBytes())) .execute(); diff --git a/scm-ui/ui-types/src/Config.ts b/scm-ui/ui-types/src/Config.ts index 4369b98e6e..92b678e491 100644 --- a/scm-ui/ui-types/src/Config.ts +++ b/scm-ui/ui-types/src/Config.ts @@ -48,6 +48,6 @@ export type Config = { namespaceStrategy: string; loginInfoUrl: string; releaseFeedUrl: string; - mailHost: string; + mailDomainName: string; _links: Links; }; diff --git a/scm-ui/ui-webapp/public/locales/de/config.json b/scm-ui/ui-webapp/public/locales/de/config.json index 9ab2d38675..24830f2f4d 100644 --- a/scm-ui/ui-webapp/public/locales/de/config.json +++ b/scm-ui/ui-webapp/public/locales/de/config.json @@ -47,7 +47,7 @@ "skip-failed-authenticators": "Fehlgeschlagene Authentifizierer überspringen", "plugin-url": "Plugin Center URL", "release-feed-url": "Release Feed URL", - "mail-host": "Fallback Mail Host", + "mail-domain-name": "Fallback E-Mail Domain Name", "enabled-xsrf-protection": "XSRF Protection aktivieren", "namespace-strategy": "Namespace Strategie", "login-info-url": "Login Info URL" @@ -63,7 +63,7 @@ "dateFormatHelpText": "Moments Datumsformat. Zulässige Formate sind in der MomentJS Dokumentation beschrieben.", "pluginUrlHelpText": "Die URL der Plugin Center API. Beschreibung der Platzhalter: version = SCM-Manager Version; os = Betriebssystem; arch = Architektur", "releaseFeedUrlHelpText": "Die URL des RSS Release Feed des SCM-Manager. Darüber wird über die neue SCM-Manager Version informiert. Um diese Funktion zu deaktivieren lassen Sie dieses Feld leer.", - "mailHostHelpText": "Dieser Host Name wird genutzt, wenn für einen User eine E-Mail-Adresse benötigt wird, für den keine hinterlegt ist. Dieser Host wird nicht zum Versenden von E-Mails genutzt und auch keine anderweitige Verbindung aufgebaut.", + "mailDomainNameHelpText": "Dieser Domain Name wird genutzt, wenn für einen User eine E-Mail-Adresse benötigt wird, für den keine hinterlegt ist. Diese Domain wird nicht zum Versenden von E-Mails genutzt und auch keine anderweitige Verbindung aufgebaut.", "enableForwardingHelpText": "mod_proxy Port Weiterleitung aktivieren.", "disableGroupingGridHelpText": "Repository Gruppen deaktivieren. Nach einer Änderung an dieser Einstellung muss die Seite komplett neu geladen werden.", "allowAnonymousAccessHelpText": "Anonyme Benutzer haben Zugriff auf freigegebene Repositories.", diff --git a/scm-ui/ui-webapp/public/locales/en/config.json b/scm-ui/ui-webapp/public/locales/en/config.json index 12d38694a5..6cb06ecb25 100644 --- a/scm-ui/ui-webapp/public/locales/en/config.json +++ b/scm-ui/ui-webapp/public/locales/en/config.json @@ -47,7 +47,7 @@ "skip-failed-authenticators": "Skip Failed Authenticators", "plugin-url": "Plugin Center URL", "release-feed-url": "Release Feed URL", - "mail-host": "Fallback Mail Host", + "mail-domain-name": "Fallback Mail Domain Name", "enabled-xsrf-protection": "Enabled XSRF Protection", "namespace-strategy": "Namespace Strategy", "login-info-url": "Login Info URL" @@ -63,7 +63,7 @@ "dateFormatHelpText": "Moments date format. Please have a look at the MomentJS documentation.", "pluginUrlHelpText": "The url of the Plugin Center API. Explanation of the placeholders: version = SCM-Manager Version; os = Operation System; arch = Architecture", "releaseFeedUrlHelpText": "The url of the RSS Release Feed for SCM-Manager. This provides up-to-date version information. To disable this feature just leave the url blank.", - "mailHostHelpText": "This host name will be used to create email addresses for users when needed and they have none configured. It will not be used to send mails nor will be accessed otherwise.", + "mailDomainNameHelpText": "This domain name will be used to create email addresses for users without one when needed. It will not be used to send mails nor will be accessed otherwise.", "enableForwardingHelpText": "Enable mod_proxy port forwarding.", "disableGroupingGridHelpText": "Disable repository Groups. A complete page reload is required after a change of this value.", "allowAnonymousAccessHelpText": "Anonymous users have access on granted repositories.", diff --git a/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx b/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx index b38113831f..c284df3180 100644 --- a/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx +++ b/scm-ui/ui-webapp/src/admin/components/form/ConfigForm.tsx @@ -144,7 +144,7 @@ class ConfigForm extends React.Component { skipFailedAuthenticators={config.skipFailedAuthenticators} pluginUrl={config.pluginUrl} releaseFeedUrl={config.releaseFeedUrl} - mailHost={config.mailHost} + mailDomainName={config.mailDomainName} enabledXsrfProtection={config.enabledXsrfProtection} namespaceStrategy={config.namespaceStrategy} onChange={(isValid, changedValue, name) => this.onChange(isValid, changedValue, name)} diff --git a/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx b/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx index 49871ed2aa..e9ed50a3b5 100644 --- a/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx +++ b/scm-ui/ui-webapp/src/admin/components/form/GeneralSettings.tsx @@ -36,7 +36,7 @@ type Props = WithTranslation & { skipFailedAuthenticators: boolean; pluginUrl: string; releaseFeedUrl: string; - mailHost: string; + mailDomainName: string; enabledXsrfProtection: boolean; namespaceStrategy: string; namespaceStrategies?: NamespaceStrategies; @@ -52,7 +52,7 @@ class GeneralSettings extends React.Component { loginInfoUrl, pluginUrl, releaseFeedUrl, - mailHost, + mailDomainName, enabledXsrfProtection, anonymousMode, namespaceStrategy, @@ -142,11 +142,11 @@ class GeneralSettings extends React.Component {
@@ -175,8 +175,8 @@ class GeneralSettings extends React.Component { handleReleaseFeedUrlChange = (value: string) => { this.props.onChange(true, value, "releaseFeedUrl"); }; - handleMailHostChange = (value: string) => { - this.props.onChange(true, value, "mailHost"); + handleMailDomainNameChange = (value: string) => { + this.props.onChange(true, value, "mailDomainName"); }; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java index 42ae1ca6f0..f7025f141f 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ConfigDto.java @@ -59,7 +59,7 @@ public class ConfigDto extends HalRepresentation { private String namespaceStrategy; private String loginInfoUrl; private String releaseFeedUrl; - private String mailHost; + private String mailDomainName; @Override @SuppressWarnings("squid:S1185") // We want to have this method available in this package diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java index e693d78cea..f938c7f655 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ConfigDtoToScmConfigurationMapperTest.java @@ -75,7 +75,7 @@ public class ConfigDtoToScmConfigurationMapperTest { assertTrue(config.isEnabledXsrfProtection()); assertEquals("username", config.getNamespaceStrategy()); assertEquals("https://scm-manager.org/login-info", config.getLoginInfoUrl()); - assertEquals("hitchhiker.mail", config.getMailHost()); + assertEquals("hitchhiker.mail", config.getMailDomainName()); } @Test @@ -114,7 +114,7 @@ public class ConfigDtoToScmConfigurationMapperTest { configDto.setEnabledXsrfProtection(true); configDto.setNamespaceStrategy("username"); configDto.setLoginInfoUrl("https://scm-manager.org/login-info"); - configDto.setMailHost("hitchhiker.mail"); + configDto.setMailDomainName("hitchhiker.mail"); return configDto; } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java index 42bf6e7e3b..49769bf1b3 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ScmConfigurationToConfigDtoMapperTest.java @@ -106,7 +106,7 @@ public class ScmConfigurationToConfigDtoMapperTest { assertEquals("username", dto.getNamespaceStrategy()); assertEquals("https://scm-manager.org/login-info", dto.getLoginInfoUrl()); assertEquals("https://www.scm-manager.org/download/rss.xml", dto.getReleaseFeedUrl()); - assertEquals("scm-manager.local", dto.getMailHost()); + assertEquals("scm-manager.local", dto.getMailDomainName()); assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("self").get().getHref()); assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("update").get().getHref()); From 1d717acca0bcbf4a3c67cf6cb14fc1a1c6c781bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 14 Oct 2020 08:59:34 +0200 Subject: [PATCH 15/26] Log change --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 148eb799f3..11ae2b2fbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. 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). +## Unreleased +### Added +- Generation of email addresses for users, where none is configured ([#1370](https://github.com/scm-manager/scm-manager/pull/1370/files)) + ## [2.7.1] - 2020-10-14 ### Fixed - Null Pointer Exception on anonymous migration with deleted repositories ([#1371](https://github.com/scm-manager/scm-manager/pull/1371)) From 8e93248dd6f33b719e8072b2f426fa1777ee2370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 14 Oct 2020 16:26:25 +0200 Subject: [PATCH 16/26] Add component for commit author --- .../ui-components/src/repos/CommitAuthor.tsx | 63 +++++++++++++++++++ scm-ui/ui-components/src/repos/index.ts | 1 + scm-ui/ui-webapp/public/locales/de/repos.json | 8 ++- scm-ui/ui-webapp/public/locales/en/repos.json | 6 ++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 scm-ui/ui-components/src/repos/CommitAuthor.tsx diff --git a/scm-ui/ui-components/src/repos/CommitAuthor.tsx b/scm-ui/ui-components/src/repos/CommitAuthor.tsx new file mode 100644 index 0000000000..e371069ad3 --- /dev/null +++ b/scm-ui/ui-components/src/repos/CommitAuthor.tsx @@ -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. + */ + +import React from "react"; +import { WithTranslation, withTranslation } from "react-i18next"; +import Notification from "../Notification"; +import { Me } from "@scm-manager/ui-types"; +import { connect } from "react-redux"; +import { compose } from "redux"; + +type Props = WithTranslation & { + // props from global state + me: Me; +}; + +class CommitAuthor extends React.Component { + render() { + const { me, t } = this.props; + + const mail = me.mail ? me.mail : me.fallbackMail; + + return ( + <> + {!me.mail && {t("commit.commitAuthor.noMail")}} + + {t("commit.commitAuthor.author")} {`${me.displayName} <${mail}>`} + + + ); + } +} + +const mapStateToProps = (state: any) => { + const { auth } = state; + const me = auth.me; + + return { + me + }; +}; + +export default compose(connect(mapStateToProps), withTranslation("repos"))(CommitAuthor); diff --git a/scm-ui/ui-components/src/repos/index.ts b/scm-ui/ui-components/src/repos/index.ts index 36b26495b8..f33ffbc4cb 100644 --- a/scm-ui/ui-components/src/repos/index.ts +++ b/scm-ui/ui-components/src/repos/index.ts @@ -52,6 +52,7 @@ export { default as RepositoryAvatar } from "./RepositoryAvatar"; export { default as RepositoryEntry } from "./RepositoryEntry"; export { default as RepositoryEntryLink } from "./RepositoryEntryLink"; export { default as JumpToFileButton } from "./JumpToFileButton"; +export { default as CommitAuthor } from "./CommitAuthor"; export { File, diff --git a/scm-ui/ui-webapp/public/locales/de/repos.json b/scm-ui/ui-webapp/public/locales/de/repos.json index a1303555f4..ae0f222765 100644 --- a/scm-ui/ui-webapp/public/locales/de/repos.json +++ b/scm-ui/ui-webapp/public/locales/de/repos.json @@ -135,6 +135,12 @@ "sources": "Sources" } }, + "commit": { + "commitAuthor": { + "author": "Autor", + "noMail": "Für den aktuellen Benutzer existiert keine E-Mail-Adresse. Es wird die unten angezeigte generierte Adresse genutzt." + } + }, "repositoryForm": { "subtitle": "Repository bearbeiten", "submit": "Speichern", @@ -269,4 +275,4 @@ "clickHere": "Klicken Sie hier um Ihre Datei hochzuladen.", "dragAndDrop": "Sie können Ihre Datei auch direkt in die Dropzone ziehen." } -} +}, diff --git a/scm-ui/ui-webapp/public/locales/en/repos.json b/scm-ui/ui-webapp/public/locales/en/repos.json index bbc21d3cad..3b05c1f48c 100644 --- a/scm-ui/ui-webapp/public/locales/en/repos.json +++ b/scm-ui/ui-webapp/public/locales/en/repos.json @@ -135,6 +135,12 @@ "count_plural": "{{count}} Contributors" } }, + "commit": { + "commitAuthor": { + "author": "Author", + "noMail": "We have found no email address for your current user. We will use the generated address shown below." + } + }, "repositoryForm": { "subtitle": "Edit Repository", "submit": "Save", From 92f7e7fba9e094c0426b5d23b08e233a9825327e Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Wed, 14 Oct 2020 21:57:55 +0000 Subject: [PATCH 17/26] fix: upgrade org.jboss.resteasy:resteasy-core from 4.5.7.Final to 4.5.8.Final Snyk has created this PR to upgrade org.jboss.resteasy:resteasy-core from 4.5.7.Final to 4.5.8.Final. See this package in Maven Repository: https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-core/ See this project in Snyk: https://app.snyk.io/org/scm-manager/project/c575ed09-e310-44e7-afc8-22b77c5873cf?utm_source=github&utm_medium=upgrade-pr --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 506c11920f..7ce1d3c1c0 100644 --- a/pom.xml +++ b/pom.xml @@ -913,7 +913,7 @@ 3.1.0 2.1.1 - 4.5.7.Final + 4.5.8.Final 1.19.4 2.11.2 4.2.3 From e67ca28c5f338db0c5ebf6bd4d68b6c69b36dde1 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 08:29:21 +0200 Subject: [PATCH 18/26] Do not break existing core api --- .../sonia/scm/repository/util/AuthorUtil.java | 6 +- .../scm/repository/util/AuthorUtilTest.java | 116 ++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java diff --git a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java index 5bc62fbecf..1df0e5ef76 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java @@ -32,6 +32,10 @@ import sonia.scm.user.User; public class AuthorUtil { + public static void setAuthorIfNotAvailable(CommandWithAuthor request) { + setAuthorIfNotAvailable(request, null); + } + public static void setAuthorIfNotAvailable(CommandWithAuthor request, EMail eMail) { if (request.getAuthor() == null) { request.setAuthor(createAuthorFromSubject(eMail)); @@ -42,7 +46,7 @@ public class AuthorUtil { Subject subject = SecurityUtils.getSubject(); User user = subject.getPrincipals().oneByType(User.class); String name = user.getDisplayName(); - String mailAddress = eMail.createFallbackMailAddress(user); + String mailAddress = eMail != null ? eMail.createFallbackMailAddress(user) : user.getMail(); return new Person(name, mailAddress); } diff --git a/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java b/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java new file mode 100644 index 0000000000..efd5b0e69a --- /dev/null +++ b/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java @@ -0,0 +1,116 @@ +/* + * 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.util; + +import org.apache.shiro.subject.Subject; +import org.apache.shiro.util.ThreadContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.repository.Person; +import sonia.scm.user.EMail; +import sonia.scm.user.User; +import sonia.scm.web.UserAgentParserTest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class AuthorUtilTest { + + @Mock + private EMail eMail; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Subject subject; + + @BeforeEach + void setUpSubject() { + ThreadContext.bind(subject); + } + + @AfterEach + void tearDownSubject() { + ThreadContext.unbindSubject(); + } + + @Test + void shouldCreateMailAddressFromEmail() { + User trillian = new User("trillian"); + when(subject.getPrincipals().oneByType(User.class)).thenReturn(trillian); + when(eMail.createFallbackMailAddress(trillian)).thenReturn("tricia@hitchhicker.com"); + + Command command = new Command(null); + AuthorUtil.setAuthorIfNotAvailable(command, eMail); + + assertThat(command.getAuthor().getMail()).isEqualTo("tricia@hitchhicker.com"); + } + + @Test + void shouldUseUsersMailAddressWithoutEMail() { + User trillian = new User("trillian", "Trillian", "trillian.mcmillan@hitchhiker.com"); + when(subject.getPrincipals().oneByType(User.class)).thenReturn(trillian); + + Command command = new Command(null); + AuthorUtil.setAuthorIfNotAvailable(command); + + assertThat(command.getAuthor().getMail()).isEqualTo("trillian.mcmillan@hitchhiker.com"); + } + + @Test + void shouldKeepExistingAuthor() { + Person person = new Person("Trillian McMillan", "trillian.mcmillian@hitchhiker.com"); + + Command command = new Command(person); + AuthorUtil.setAuthorIfNotAvailable(command); + + assertThat(command.getAuthor()).isSameAs(person); + } + + public static class Command implements AuthorUtil.CommandWithAuthor { + + private Person person; + + public Command(Person person) { + this.person = person; + } + + @Override + public Person getAuthor() { + return person; + } + + @Override + public void setAuthor(Person person) { + this.person = person; + } + } + +} From ffd1daba522be1751e446c51a5fb922234f0b62f Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 08:34:36 +0200 Subject: [PATCH 19/26] There is no need for a class component here We should use function component as much as possible, because their are easier to read and less confusing. --- .../ui-components/src/repos/CommitAuthor.tsx | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/scm-ui/ui-components/src/repos/CommitAuthor.tsx b/scm-ui/ui-components/src/repos/CommitAuthor.tsx index e371069ad3..f845582267 100644 --- a/scm-ui/ui-components/src/repos/CommitAuthor.tsx +++ b/scm-ui/ui-components/src/repos/CommitAuthor.tsx @@ -22,34 +22,31 @@ * SOFTWARE. */ -import React from "react"; -import { WithTranslation, withTranslation } from "react-i18next"; +import React, { FC } from "react"; +import { useTranslation } from "react-i18next"; import Notification from "../Notification"; import { Me } from "@scm-manager/ui-types"; import { connect } from "react-redux"; -import { compose } from "redux"; -type Props = WithTranslation & { +type Props = { // props from global state me: Me; }; -class CommitAuthor extends React.Component { - render() { - const { me, t } = this.props; +const CommitAuthor: FC = ({ me }) => { + const [t] = useTranslation("repos"); - const mail = me.mail ? me.mail : me.fallbackMail; + const mail = me.mail ? me.mail : me.fallbackMail; - return ( - <> - {!me.mail && {t("commit.commitAuthor.noMail")}} - - {t("commit.commitAuthor.author")} {`${me.displayName} <${mail}>`} - - - ); - } -} + return ( + <> + {!me.mail && {t("commit.commitAuthor.noMail")}} + + {t("commit.commitAuthor.author")} {`${me.displayName} <${mail}>`} + + + ); +}; const mapStateToProps = (state: any) => { const { auth } = state; @@ -60,4 +57,4 @@ const mapStateToProps = (state: any) => { }; }; -export default compose(connect(mapStateToProps), withTranslation("repos"))(CommitAuthor); +export default connect(mapStateToProps)(CommitAuthor); From 208fa0dcc8a8583144576b3abc346254411c560b Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 11:22:01 +0200 Subject: [PATCH 20/26] Fix breaking change in RepositoryServiceFactory constructor Deprecate old RepositoryServiceFactory constructor and create a new one to avoid breaking change in api --- .../api/RepositoryServiceFactory.java | 231 +++++++++--------- 1 file changed, 120 insertions(+), 111 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java index 15cec9d210..2c13cb63be 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryServiceFactory.java @@ -40,6 +40,7 @@ import sonia.scm.HandlerEventType; import sonia.scm.NotFoundException; import sonia.scm.cache.Cache; import sonia.scm.cache.CacheManager; +import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.NamespaceAndName; @@ -58,6 +59,7 @@ import sonia.scm.security.PublicKeyDeletedEvent; import sonia.scm.security.ScmSecurityException; import sonia.scm.user.EMail; +import javax.annotation.Nullable; import java.util.Set; import static sonia.scm.ContextEntry.ContextBuilder.entity; @@ -114,13 +116,88 @@ public final class RepositoryServiceFactory { private static final Logger logger = LoggerFactory.getLogger(RepositoryServiceFactory.class); - //~--- constructors --------------------------------------------------------- + private final CacheManager cacheManager; + private final RepositoryManager repositoryManager; + private final Set resolvers; + private final PreProcessorUtil preProcessorUtil; + @SuppressWarnings({"rawtypes", "java:S3740"}) + private final Set protocolProviders; + private final WorkdirProvider workdirProvider; + @Nullable private final EMail eMail; - @SuppressWarnings("rawtypes") - private Set protocolProviders; - //~--- methods -------------------------------------------------------------- + + /** + * Constructs a new {@link RepositoryServiceFactory}. This constructor + * should not be called manually, it should only be used by the injection + * container. + * + * @param configuration configuration + * @param cacheManager cache manager + * @param repositoryManager manager for repositories + * @param resolvers a set of {@link RepositoryServiceResolver} + * @param preProcessorUtil helper object for pre processor handling + * @param protocolProviders providers for repository protocols + * @param workdirProvider provider for working directories + * + * @deprecated use {@link RepositoryServiceFactory#RepositoryServiceFactory(CacheManager, RepositoryManager, Set, PreProcessorUtil, Set, WorkdirProvider, EMail)} instead + * @since 1.21 + */ + @Deprecated + public RepositoryServiceFactory(ScmConfiguration configuration, + CacheManager cacheManager, RepositoryManager repositoryManager, + Set resolvers, PreProcessorUtil preProcessorUtil, + @SuppressWarnings({"rawtypes", "java:S3740"}) Set protocolProviders, + WorkdirProvider workdirProvider) { + this( + cacheManager, repositoryManager, resolvers, + preProcessorUtil, protocolProviders, workdirProvider, null, ScmEventBus.getInstance() + ); + } + + /** + * Constructs a new {@link RepositoryServiceFactory}. This constructor + * should not be called manually, it should only be used by the injection + * container. + * + * @param cacheManager cache manager + * @param repositoryManager manager for repositories + * @param resolvers a set of {@link RepositoryServiceResolver} + * @param preProcessorUtil helper object for pre processor handling + * @param protocolProviders providers for repository protocols + * @param workdirProvider provider for working directories + * @param eMail handling user emails + * @since 2.8.0 + */ + @Inject + public RepositoryServiceFactory(CacheManager cacheManager, RepositoryManager repositoryManager, + Set resolvers, PreProcessorUtil preProcessorUtil, + @SuppressWarnings({"rawtypes", "java:S3740"}) Set protocolProviders, + WorkdirProvider workdirProvider, EMail eMail) { + this( + cacheManager, repositoryManager, resolvers, + preProcessorUtil, protocolProviders, workdirProvider, + eMail, ScmEventBus.getInstance() + ); + } + + @VisibleForTesting + @SuppressWarnings("java:S107") // to keep backward compatibility, we can not reduce amount of parameters + RepositoryServiceFactory(CacheManager cacheManager, RepositoryManager repositoryManager, + Set resolvers, PreProcessorUtil preProcessorUtil, + @SuppressWarnings({"rawtypes", "java:S3740"}) Set protocolProviders, + WorkdirProvider workdirProvider, @Nullable EMail eMail, ScmEventBus eventBus) { + this.cacheManager = cacheManager; + this.repositoryManager = repositoryManager; + this.resolvers = resolvers; + this.preProcessorUtil = preProcessorUtil; + this.protocolProviders = protocolProviders; + this.workdirProvider = workdirProvider; + this.eMail = eMail; + + eventBus.register(new CacheClearHook(cacheManager)); + } /** * Creates a new RepositoryService for the given repository. @@ -177,30 +254,48 @@ public final class RepositoryServiceFactory { } /** - * Constructs a new {@link RepositoryServiceFactory}. This constructor - * should not be called manually, it should only be used by the injection - * container. + * Creates a new RepositoryService for the given repository. * - * @param cacheManager cache manager - * @param repositoryManager manager for repositories - * @param resolvers a set of {@link RepositoryServiceResolver} - * @param preProcessorUtil helper object for pre processor handling - * @param protocolProviders - * @param workdirProvider - * @since 1.21 + * @param repository the repository + * @return a implementation of RepositoryService + * for the given type of repository + * @throws RepositoryServiceNotFoundException if no repository service + * implementation for this kind of repository is available + * @throws NullPointerException if the repository is null + * @throws ScmSecurityException if current user has not read permissions + * for that repository */ - @Inject - public RepositoryServiceFactory(CacheManager cacheManager, RepositoryManager repositoryManager, - Set resolvers, PreProcessorUtil preProcessorUtil, - @SuppressWarnings("rawtypes") Set protocolProviders, - WorkdirProvider workdirProvider, EMail eMail) { - this( - cacheManager, repositoryManager, resolvers, - preProcessorUtil, protocolProviders, workdirProvider, eMail, ScmEventBus.getInstance() - ); - } + public RepositoryService create(Repository repository) { + Preconditions.checkNotNull(repository, "repository is required"); - //~--- inner classes -------------------------------------------------------- + // check for read permissions of current user + RepositoryPermissions.read(repository).check(); + + RepositoryService service = null; + + for (RepositoryServiceResolver resolver : resolvers) { + RepositoryServiceProvider provider = resolver.resolve(repository); + + if (provider != null) { + if (logger.isDebugEnabled()) { + logger.debug( + "create new repository service for repository {} of type {}", + repository.getName(), repository.getType()); + } + + service = new RepositoryService(cacheManager, provider, repository, + preProcessorUtil, protocolProviders, workdirProvider, eMail); + + break; + } + } + + if (service == null) { + throw new RepositoryServiceNotFoundException(repository); + } + + return service; + } /** * Hook and listener to clear all relevant repository caches. @@ -225,8 +320,6 @@ public final class RepositoryServiceFactory { this.caches.add(cacheManager.getCache(BranchesCommandBuilder.CACHE_NAME)); } - //~--- methods ------------------------------------------------------------ - /** * Clear caches on explicit repository cache clear event. * @@ -288,88 +381,4 @@ public final class RepositoryServiceFactory { } } - - //~--- fields --------------------------------------------------------------- - - /** - * cache manager - */ - private final CacheManager cacheManager; - - /** - * pre processor util - */ - private final PreProcessorUtil preProcessorUtil; - - /** - * repository manager - */ - private final RepositoryManager repositoryManager; - - /** - * service resolvers - */ - private final Set resolvers; - - @VisibleForTesting - RepositoryServiceFactory(CacheManager cacheManager, RepositoryManager repositoryManager, - Set resolvers, PreProcessorUtil preProcessorUtil, - @SuppressWarnings("rawtypes") Set protocolProviders, - WorkdirProvider workdirProvider, EMail eMail, ScmEventBus eventBus) { - this.cacheManager = cacheManager; - this.repositoryManager = repositoryManager; - this.resolvers = resolvers; - this.preProcessorUtil = preProcessorUtil; - this.protocolProviders = protocolProviders; - this.workdirProvider = workdirProvider; - this.eMail = eMail; - - eventBus.register(new CacheClearHook(cacheManager)); - } - - private final WorkdirProvider workdirProvider; - - /** - * Creates a new RepositoryService for the given repository. - * - * @param repository the repository - * @return a implementation of RepositoryService - * for the given type of repository - * @throws RepositoryServiceNotFoundException if no repository service - * implementation for this kind of repository is available - * @throws NullPointerException if the repository is null - * @throws ScmSecurityException if current user has not read permissions - * for that repository - */ - public RepositoryService create(Repository repository) { - Preconditions.checkNotNull(repository, "repository is required"); - - // check for read permissions of current user - RepositoryPermissions.read(repository).check(); - - RepositoryService service = null; - - for (RepositoryServiceResolver resolver : resolvers) { - RepositoryServiceProvider provider = resolver.resolve(repository); - - if (provider != null) { - if (logger.isDebugEnabled()) { - logger.debug( - "create new repository service for repository {} of type {}", - repository.getName(), repository.getType()); - } - - service = new RepositoryService(cacheManager, provider, repository, - preProcessorUtil, protocolProviders, workdirProvider, eMail); - - break; - } - } - - if (service == null) { - throw new RepositoryServiceNotFoundException(repository); - } - - return service; - } } From e839ad32ea08a13d960c435b9e4299cc710c1d74 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 11:23:27 +0200 Subject: [PATCH 21/26] Use Nullable annotation to make clear that Email must be checked for null --- .../scm/repository/api/MergeCommandBuilder.java | 8 +++++--- .../scm/repository/api/ModifyCommandBuilder.java | 9 +++++---- .../scm/repository/api/RepositoryService.java | 14 +++++++++----- .../java/sonia/scm/repository/util/AuthorUtil.java | 6 ++++-- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java index a751832d8f..6cbf2caa8c 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/MergeCommandBuilder.java @@ -32,6 +32,7 @@ import sonia.scm.repository.spi.MergeConflictResult; import sonia.scm.repository.util.AuthorUtil; import sonia.scm.user.EMail; +import javax.annotation.Nullable; import java.util.Set; /** @@ -76,12 +77,13 @@ import java.util.Set; */ public class MergeCommandBuilder { - private final EMail eMail; - private final MergeCommand mergeCommand; private final MergeCommandRequest request = new MergeCommandRequest(); - MergeCommandBuilder(MergeCommand mergeCommand, EMail eMail) { + @Nullable + private final EMail eMail; + + MergeCommandBuilder(MergeCommand mergeCommand, @Nullable EMail eMail) { this.mergeCommand = mergeCommand; this.eMail = eMail; } diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java index 795de5d43d..f2b11a00a0 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/ModifyCommandBuilder.java @@ -38,6 +38,7 @@ import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.user.EMail; import sonia.scm.util.IOUtil; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -52,7 +53,6 @@ import java.util.function.Consumer; * default a {@link sonia.scm.AlreadyExistsException} will be thrown) *
  • modify existing files ({@link #modifyFile(String)}
  • *
  • delete existing files ({@link #deleteFile(String)}
  • - *
  • move/rename existing files ({@link #moveFile(String, String)}
  • * * * You can collect multiple changes before they are executed with a call to {@link #execute()}. @@ -73,14 +73,15 @@ public class ModifyCommandBuilder { private static final Logger LOG = LoggerFactory.getLogger(ModifyCommandBuilder.class); - private final EMail eMail; - private final ModifyCommand command; private final File workdir; + @Nullable + private final EMail eMail; + private final ModifyCommandRequest request = new ModifyCommandRequest(); - ModifyCommandBuilder(ModifyCommand command, WorkdirProvider workdirProvider, EMail eMail) { + ModifyCommandBuilder(ModifyCommand command, WorkdirProvider workdirProvider, @Nullable EMail eMail) { this.command = command; this.workdir = workdirProvider.createNewWorkdir(); this.eMail = eMail; diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index 029dc6fa34..aa2a41782d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -36,6 +36,7 @@ import sonia.scm.repository.spi.RepositoryServiceProvider; import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.user.EMail; +import javax.annotation.Nullable; import java.io.Closeable; import java.io.IOException; import java.util.Set; @@ -85,9 +86,11 @@ public final class RepositoryService implements Closeable { private final PreProcessorUtil preProcessorUtil; private final RepositoryServiceProvider provider; private final Repository repository; - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "java:S3740"}) private final Set protocolProviders; private final WorkdirProvider workdirProvider; + + @Nullable private final EMail eMail; /** @@ -100,11 +103,12 @@ public final class RepositoryService implements Closeable { * @param eMail utility to compute email addresses if missing */ RepositoryService(CacheManager cacheManager, - RepositoryServiceProvider provider, Repository repository, + RepositoryServiceProvider provider, + Repository repository, PreProcessorUtil preProcessorUtil, - @SuppressWarnings("rawtypes") Set protocolProviders, + @SuppressWarnings({"rawtypes", "java:S3740"}) Set protocolProviders, WorkdirProvider workdirProvider, - EMail eMail) { + @Nullable EMail eMail) { this.cacheManager = cacheManager; this.provider = provider; this.repository = repository; @@ -452,7 +456,7 @@ public final class RepositoryService implements Closeable { .map(this::createProviderInstanceForRepository); } - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "java:S3740"}) private ScmProtocol createProviderInstanceForRepository(ScmProtocolProvider protocolProvider) { return protocolProvider.get(repository); } diff --git a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java index 1df0e5ef76..21142ba95d 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java @@ -30,19 +30,21 @@ import sonia.scm.repository.Person; import sonia.scm.user.EMail; import sonia.scm.user.User; +import javax.annotation.Nullable; + public class AuthorUtil { public static void setAuthorIfNotAvailable(CommandWithAuthor request) { setAuthorIfNotAvailable(request, null); } - public static void setAuthorIfNotAvailable(CommandWithAuthor request, EMail eMail) { + public static void setAuthorIfNotAvailable(CommandWithAuthor request, @Nullable EMail eMail) { if (request.getAuthor() == null) { request.setAuthor(createAuthorFromSubject(eMail)); } } - private static Person createAuthorFromSubject(EMail eMail) { + private static Person createAuthorFromSubject(@Nullable EMail eMail) { Subject subject = SecurityUtils.getSubject(); User user = subject.getPrincipals().oneByType(User.class); String name = user.getDisplayName(); From 3cdc1faaa3ae9a6a159298ebc2deeaf683824f58 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 11:24:07 +0200 Subject: [PATCH 22/26] Improve javadoc of new configuration option mailDomainName --- .../src/main/java/sonia/scm/config/ScmConfiguration.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java index 2fed4058f7..6f1414b8e0 100644 --- a/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java +++ b/scm-core/src/main/java/sonia/scm/config/ScmConfiguration.java @@ -83,6 +83,8 @@ public class ScmConfiguration implements Configuration { /** * Default e-mail domain name that will be used whenever we have to generate an e-mail address for a user that has no * mail address configured. + * + * @since 2.8.0 */ public static final String DEFAULT_MAIL_DOMAIN_NAME = "scm-manager.local"; @@ -301,8 +303,8 @@ public class ScmConfiguration implements Configuration { } /** - * Returns the mail host, that will be used to create e-mail addresses for users without one whenever one is required. - * + * Returns the mail domain, that will be used to create e-mail addresses for users without one whenever one is required. + * @return default mail domain * @since 2.8.0 */ public String getMailDomainName() { @@ -492,7 +494,7 @@ public class ScmConfiguration implements Configuration { /** * Sets the mail host, that will be used to create e-mail addresses for users without one whenever one is required. * - * @param mailDomainName The new mail host to use. + * @param mailDomainName The default mail domain to use * @since 2.8.0 */ public void setMailDomainName(String mailDomainName) { From 775b37980d11959698158ab99d44e8ff4f75baec Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 11:24:37 +0200 Subject: [PATCH 23/26] Use pull request root instead of files --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ae2b2fbf..e6810df880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added -- Generation of email addresses for users, where none is configured ([#1370](https://github.com/scm-manager/scm-manager/pull/1370/files)) +- Generation of email addresses for users, where none is configured ([#1370](https://github.com/scm-manager/scm-manager/pull/1370)) ## [2.7.1] - 2020-10-14 ### Fixed From 465a9e635bcc2d2743623032d35705339a10bf30 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 11:48:17 +0200 Subject: [PATCH 24/26] Rename createFallbackMailAddress to more explicit getMailOrFallback --- .../sonia/scm/repository/util/AuthorUtil.java | 2 +- .../src/main/java/sonia/scm/user/EMail.java | 18 ++++++++++++++++-- .../scm/repository/util/AuthorUtilTest.java | 4 +--- .../test/java/sonia/scm/user/EMailTest.java | 6 +++--- .../scm/api/v2/resources/MeDtoFactory.java | 2 +- .../scm/api/v2/resources/MeDtoFactoryTest.java | 2 +- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java index 21142ba95d..e5a6501604 100644 --- a/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java +++ b/scm-core/src/main/java/sonia/scm/repository/util/AuthorUtil.java @@ -48,7 +48,7 @@ public class AuthorUtil { Subject subject = SecurityUtils.getSubject(); User user = subject.getPrincipals().oneByType(User.class); String name = user.getDisplayName(); - String mailAddress = eMail != null ? eMail.createFallbackMailAddress(user) : user.getMail(); + String mailAddress = eMail != null ? eMail.getMailOrFallback(user) : user.getMail(); return new Person(name, mailAddress); } diff --git a/scm-core/src/main/java/sonia/scm/user/EMail.java b/scm-core/src/main/java/sonia/scm/user/EMail.java index 0718a3c722..8da1377c94 100644 --- a/scm-core/src/main/java/sonia/scm/user/EMail.java +++ b/scm-core/src/main/java/sonia/scm/user/EMail.java @@ -29,6 +29,11 @@ import sonia.scm.config.ScmConfiguration; import javax.inject.Inject; +/** + * Email is able to resolve email addresses of users. + * + * @since 2.8.0 + */ public class EMail { private final ScmConfiguration scmConfiguration; @@ -38,15 +43,24 @@ public class EMail { this.scmConfiguration = scmConfiguration; } - public String createFallbackMailAddress(User user) { + /** + * Returns the email address of the given user or a generated fallback address. + * @param user user to resolve address from + * @return email address or fallback + */ + public String getMailOrFallback(User user) { if (Strings.isNullOrEmpty(user.getMail())) { if (user.getId().contains("@")) { return user.getId(); } else { - return user.getId() + "@" + scmConfiguration.getMailDomainName(); + return createFallbackMail(user); } } else { return user.getMail(); } } + + private String createFallbackMail(User user) { + return user.getId() + "@" + scmConfiguration.getMailDomainName(); + } } diff --git a/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java b/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java index efd5b0e69a..08a49cea44 100644 --- a/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java +++ b/scm-core/src/test/java/sonia/scm/repository/util/AuthorUtilTest.java @@ -36,10 +36,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import sonia.scm.repository.Person; import sonia.scm.user.EMail; import sonia.scm.user.User; -import sonia.scm.web.UserAgentParserTest; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -65,7 +63,7 @@ class AuthorUtilTest { void shouldCreateMailAddressFromEmail() { User trillian = new User("trillian"); when(subject.getPrincipals().oneByType(User.class)).thenReturn(trillian); - when(eMail.createFallbackMailAddress(trillian)).thenReturn("tricia@hitchhicker.com"); + when(eMail.getMailOrFallback(trillian)).thenReturn("tricia@hitchhicker.com"); Command command = new Command(null); AuthorUtil.setAuthorIfNotAvailable(command, eMail); diff --git a/scm-core/src/test/java/sonia/scm/user/EMailTest.java b/scm-core/src/test/java/sonia/scm/user/EMailTest.java index 21f6181757..49842223ba 100644 --- a/scm-core/src/test/java/sonia/scm/user/EMailTest.java +++ b/scm-core/src/test/java/sonia/scm/user/EMailTest.java @@ -37,7 +37,7 @@ class EMailTest { void shouldUserUsersAddressIfAvailable() { User user = new User("dent", "Arthur Dent", "arthur@hitchhiker.com"); - String mailAddress = eMail.createFallbackMailAddress(user); + String mailAddress = eMail.getMailOrFallback(user); assertThat(mailAddress).isEqualTo("arthur@hitchhiker.com"); } @@ -46,7 +46,7 @@ class EMailTest { void shouldCreateAddressIfNoneAvailable() { User user = new User("dent", "Arthur Dent", ""); - String mailAddress = eMail.createFallbackMailAddress(user); + String mailAddress = eMail.getMailOrFallback(user); assertThat(mailAddress).isEqualTo("dent@scm-manager.local"); } @@ -55,7 +55,7 @@ class EMailTest { void shouldUserUsersIdIfItLooksLikeAnMailAddress() { User user = new User("dent@hitchhiker.com", "Arthur Dent", ""); - String mailAddress = eMail.createFallbackMailAddress(user); + String mailAddress = eMail.getMailOrFallback(user); assertThat(mailAddress).isEqualTo("dent@hitchhiker.com"); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java index 2bc72d509a..ff3914654d 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MeDtoFactory.java @@ -86,7 +86,7 @@ public class MeDtoFactory extends HalAppenderMapper { private void setGeneratedMail(User user, MeDto dto) { if (Strings.isNullOrEmpty(user.getMail())) { - dto.setFallbackMail(eMail.createFallbackMailAddress(user)); + dto.setFallbackMail(eMail.getMailOrFallback(user)); } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java index 2a4cea9626..ea539c4631 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/MeDtoFactoryTest.java @@ -244,7 +244,7 @@ class MeDtoFactoryTest { User user = UserTestData.createTrillian(); user.setMail(null); prepareSubject(user); - when(eMail.createFallbackMailAddress(user)).thenReturn("trillian@hitchhiker.local"); + when(eMail.getMailOrFallback(user)).thenReturn("trillian@hitchhiker.local"); MeDto dto = meDtoFactory.create(); From 2ea019231a70361f84f0b7aed640c0edeedbe296 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 11:58:20 +0200 Subject: [PATCH 25/26] Document configuration for null checks --- docs/en/development/intellij-idea-configuration.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/development/intellij-idea-configuration.md b/docs/en/development/intellij-idea-configuration.md index f740281518..d415b4d206 100644 --- a/docs/en/development/intellij-idea-configuration.md +++ b/docs/en/development/intellij-idea-configuration.md @@ -11,6 +11,12 @@ title: Intellij IDEA Configuration ### Settings +* Build, Execution, Deployment / Compiler + * Add runtime assertions for non-null-annotated methods and parameters (must be checked) + * Configure annotation ... (of "Add runtime assertions...") + * Nullable annotations: select (✓) `javax.annotation.Nullable` + * NotNull annotations: select (✓) `javax.annotation.Nonnull` and check Instrument + * Run Configurations / Edit Configuration * Add Maven * Name: run-backend From 27236cdbbdaa5a6e54958a3618da5cae8f61fef7 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Oct 2020 14:28:57 +0200 Subject: [PATCH 26/26] Use ValidatioUtil to check if the user id is a mail --- scm-core/src/main/java/sonia/scm/user/EMail.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scm-core/src/main/java/sonia/scm/user/EMail.java b/scm-core/src/main/java/sonia/scm/user/EMail.java index 8da1377c94..e525b8d46c 100644 --- a/scm-core/src/main/java/sonia/scm/user/EMail.java +++ b/scm-core/src/main/java/sonia/scm/user/EMail.java @@ -26,6 +26,7 @@ package sonia.scm.user; import com.google.common.base.Strings; import sonia.scm.config.ScmConfiguration; +import sonia.scm.util.ValidationUtil; import javax.inject.Inject; @@ -50,7 +51,7 @@ public class EMail { */ public String getMailOrFallback(User user) { if (Strings.isNullOrEmpty(user.getMail())) { - if (user.getId().contains("@")) { + if (isMailUsedAsId(user)) { return user.getId(); } else { return createFallbackMail(user); @@ -60,6 +61,10 @@ public class EMail { } } + private boolean isMailUsedAsId(User user) { + return ValidationUtil.isMailAddressValid(user.getId()); + } + private String createFallbackMail(User user) { return user.getId() + "@" + scmConfiguration.getMailDomainName(); }