diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fdf6874ef..2da21cbfae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added +- Rename repository name (and namespace if permitted) ([#1218](https://github.com/scm-manager/scm-manager/pull/1218)) - enrich commit mentions in markdown viewer by internal links ([#1210](https://github.com/scm-manager/scm-manager/pull/1210)) - New extension point `changeset.description.tokens` to "enrich" commit messages ([#1231](https://github.com/scm-manager/scm-manager/pull/1231)) +- restart service after rpm or deb package upgrade ### Changed - Checkboxes can now be 'indeterminate' ([#1215](https://github.com/scm-manager/scm-manager/pull/1215)) @@ -16,6 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed installation of debian packages on distros without preinstalled `at` ([#1216](https://github.com/scm-manager/scm-manager/issues/1216) and [#1217](https://github.com/scm-manager/scm-manager/pull/1217)) +- Fixed restart with deb or rpm installation ([#1222](https://github.com/scm-manager/scm-manager/issues/1222) and [#1227](https://github.com/scm-manager/scm-manager/pull/1227)) +- Fixed broken migration with empty security.xml ([#1219](https://github.com/scm-manager/scm-manager/issues/1219) and [#1221](https://github.com/scm-manager/scm-manager/pull/1221)) +- Added missing architecture to debian installation documentation ([#1230](https://github.com/scm-manager/scm-manager/pull/1230)) +- Fixed wrong package information for deb and rpm packages ([#1229](https://github.com/scm-manager/scm-manager/pull/1229)) + ## [2.1.1] - 2020-06-23 ### Fixed diff --git a/README.md b/README.md index 543956310a..4386fbe026 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,12 @@

The easiest way to share and manage your Git, Mercurial and Subversion -repositories over http. +repositories. - Very easy installation - No need to hack configuration files, SCM-Manager is completely - configureable from its Web-Interface -- No Apache and no database installation is required + configurable from its Web-Interface +- No Apache and no database installation required - Central user, group and permission management - Out of the box support for Git, Mercurial and Subversion - Full RESTFul Web Service API (JSON and XML) @@ -19,34 +19,32 @@ repositories over http. - Useful plugins available - Licensed under the MIT-License -This branch (default) is for the development of SCM-Manager 2.x. If you are interested in the development of version 1.x, please checkout the 1.x branch. +This branch (`develop`) is for the development of SCM-Manager 2.x. If you are interested in the development of version +1.x, please checkout the branch `support/1.x`. ## News -- **2018-09-25** - [SCM-Manager 2 gets a boost by Cloudogu - GmbH](https://www.scm-manager.org/scm-manager-2/scm-manager-2-gets-a-boost-by-cloudogu-gmbh/) -- **2018-05-04** - SCM-Manager 1.60 released - ([download](http://www.scm-manager.org/download/) \| - [release notes](release-notes.md)) -- **2018-04-11** - SCM-Manager 1.59 released - -[All news](http://www.scm-manager.org/news/) +All news regarding SCM-Manager will be published in our [blog](https://www.scm-manager.org/blog/). ## Mailing List - - [archive](http://groups.google.com/group/scmmanager) \| - [subscribe](mailto:scmmanager+subscribe@googlegroups.com) - \| + [subscribe](mailto:scmmanager+subscribe@googlegroups.com) \| [unsubscribe](mailto:scmmanager+unsubscribe@googlegroups.com) ## Documentation -You can find the complete documentation in the [docs/](docs/Home.md) directory. +You can find the complete documentation on our [homepage](https://www.scm-manager.org/docs/). ## Need help? -Looking for more guidance? Full documentation lives [in the SCM-Manager repository](https://github.com/scm-manager/scm-manager/blob/develop/docs/Home.md). Do you have further ideas or need support? +Looking for more guidance? Full documentation lives on our [homepage](https://www.scm-manager.org/docs/) or the +dedicated pages for our [plugins](https://www.scm-manager.org/plugins/). Do you have further ideas or need support? -- **Community Support** - Contact the SCM-Manager support team for questions about SCM-Manager, to report bugs or to request features through the official channels. [Find more about this here](https://www.scm-manager.org/support/). +- **Community Support** - Contact the SCM-Manager support team for questions about SCM-Manager, to report bugs or to + request features through the official channels. [Find more about this here](https://www.scm-manager.org/support/). -- **Enterprise Support** - Do you require support with the integration of SCM-Manager into your processes, with the customization of the tool or simply a service level agreement (SLA)? **Contact our development partner Cloudogu! Their team is looking forward to discussing your individual requirements with you and will be more than happy to give you a quote.** [Request Enterprise Support](https://cloudogu.com/en/scm-manager-enterprise/). +- **Enterprise Support** - Do you require support with the integration of SCM-Manager into your processes, with the + customization of the tool or simply a service level agreement (SLA)? **Contact our development partner Cloudogu! + Their team is looking forward to discussing your individual requirements with you and will be more than happy to + give you a quote.** [Request Enterprise Support](https://cloudogu.com/en/scm-manager-enterprise/). diff --git a/docs/en/installation/debian.md b/docs/en/installation/debian.md index 79344139b3..fb4e7d0a06 100644 --- a/docs/en/installation/debian.md +++ b/docs/en/installation/debian.md @@ -9,7 +9,7 @@ displayToc: true The following code block will configure an apt repository for scm-manager and install it. ```bash -echo 'deb https://packages.scm-manager.org/repository/apt-v2-releases/ stable main' | sudo tee /etc/apt/sources.list.d/scm-manager.list +echo 'deb [arch=all] https://packages.scm-manager.org/repository/apt-v2-releases/ stable main' | sudo tee /etc/apt/sources.list.d/scm-manager.list sudo apt-key adv --recv-keys --keyserver hkps://keys.openpgp.org 0x975922F193B07D6E sudo apt-get update sudo apt-get install scm-server @@ -24,7 +24,7 @@ To install SCM-Manager as a debian package (.deb), we have to configure an apt r Create a file at `/etc/apt/sources.list.d/scm-manager.list` with the following content: ```text -deb https://packages.scm-manager.org/repository/apt-v2-releases/ stable main +deb [arch=all] https://packages.scm-manager.org/repository/apt-v2-releases/ stable main ``` This will add the apt repository of the scm-manager stable releases to the list of your apt repositories. diff --git a/pom.xml b/pom.xml index db981176f6..e2a51b1a4d 100644 --- a/pom.xml +++ b/pom.xml @@ -35,12 +35,17 @@ 2.2.0-SNAPSHOT The easiest way to share your Git, Mercurial - and Subversion repositories over http. + and Subversion repositories. scm https://github.com/scm-manager/scm-manager + + Cloudogu GmbH + https://cloudogu.com + + MIT License @@ -50,9 +55,33 @@ - sdorra + sebastian.sdorra Sebastian Sdorra - s.sdorra@gmail.com + sebastian.sdorra@cloudogu.com + Europe/Berlin + + + rene.pfeuffer + Rene Pfeufer + rene.pfeuffer@cloudogu.com + Europe/Berlin + + + eduard.heimbuch + Eduard Heimbuch + eduard.heimbuch@cloudogu.com + Europe/Berlin + + + florian.scholdei + Florian Scholdei + florian.scholdei@cloudogu.com + Europe/Berlin + + + Konstantin Schaper + Konstantin Schaper + konstantin.schaper@cloudogu.com Europe/Berlin diff --git a/scm-core/src/main/java/sonia/scm/repository/ChangeNamespaceNotAllowedException.java b/scm-core/src/main/java/sonia/scm/repository/ChangeNamespaceNotAllowedException.java new file mode 100644 index 0000000000..a9d4f8a631 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/ChangeNamespaceNotAllowedException.java @@ -0,0 +1,43 @@ +/* + * 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; + +import sonia.scm.BadRequestException; +import sonia.scm.ContextEntry; + +@SuppressWarnings("squid:MaximumInheritanceDepth") // exceptions have a deep inheritance depth themselves; therefore we accept this here +public class ChangeNamespaceNotAllowedException extends BadRequestException { + + public ChangeNamespaceNotAllowedException(Repository repository) { + super(ContextEntry.ContextBuilder.entity(repository).build(), "change of namespace is not allowed in current namespace strategy"); + } + + private static final String CODE = "ERS2vYb7U1"; + + @Override + public String getCode() { + return CODE; + } +} diff --git a/scm-core/src/main/java/sonia/scm/repository/NamespaceStrategy.java b/scm-core/src/main/java/sonia/scm/repository/NamespaceStrategy.java index 4cb7cc32d9..4548d2b82b 100644 --- a/scm-core/src/main/java/sonia/scm/repository/NamespaceStrategy.java +++ b/scm-core/src/main/java/sonia/scm/repository/NamespaceStrategy.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.repository; import sonia.scm.plugin.ExtensionPoint; @@ -36,8 +36,16 @@ public interface NamespaceStrategy { * Create new namespace for the given repository. * * @param repository repository - * * @return namespace */ String createNamespace(Repository repository); + + /** + * Checks if the namespace can be changed when using this namespace strategy + * + * @return namespace can be changed + */ + default boolean canBeChanged() { + return false; + } } diff --git a/scm-core/src/main/java/sonia/scm/repository/Repository.java b/scm-core/src/main/java/sonia/scm/repository/Repository.java index b1de749cdf..bd02021ed6 100644 --- a/scm-core/src/main/java/sonia/scm/repository/Repository.java +++ b/scm-core/src/main/java/sonia/scm/repository/Repository.java @@ -53,7 +53,7 @@ import java.util.Set; */ @StaticPermissions( value = "repository", - permissions = {"read", "modify", "delete", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"}, + permissions = {"read", "modify", "delete", "rename", "healthCheck", "pull", "push", "permissionRead", "permissionWrite"}, custom = true, customGlobal = true ) @XmlAccessorType(XmlAccessType.FIELD) diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java index b05a8fd01f..7269b3517f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.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.repository; //~--- non-JDK imports -------------------------------------------------------- @@ -38,18 +38,15 @@ import java.util.Collection; * This class is a singleton and is available via injection. * * @author Sebastian Sdorra - * * @apiviz.uses sonia.scm.repository.RepositoryHandler */ public interface RepositoryManager - extends TypeManager -{ + extends TypeManager { /** * Fire {@link RepositoryHookEvent} to the event bus. * * @param event hook event - * * @since 2.0.0 */ public void fireHookEvent(RepositoryHookEvent event); @@ -58,9 +55,7 @@ public interface RepositoryManager * Imports an existing {@link Repository}. * Note: This method should only be called from a {@link RepositoryHandler}. * - * * @param repository {@link Repository} to import - * * @throws IOException */ public void importRepository(Repository repository) throws IOException; @@ -71,10 +66,7 @@ public interface RepositoryManager * Returns a {@link Repository} by its namespace and name or * null if the {@link Repository} could not be found. * - * * @param namespaceAndName namespace and name of the {@link Repository} - * - * * @return {@link Repository} by its namespace and name or null * if the {@link Repository} could not be found */ @@ -83,7 +75,6 @@ public interface RepositoryManager /** * Returns all configured repository types. * - * * @return all configured repository types */ public Collection getConfiguredTypes(); @@ -91,11 +82,17 @@ public interface RepositoryManager /** * Returns a {@link RepositoryHandler} by the given type (hg, git, svn ...). * - * * @param type the type of the {@link RepositoryHandler} - * * @return {@link RepositoryHandler} by the given type */ @Override public RepositoryHandler getHandler(String type); + + /** + * @param repository the repository {@link Repository} + * @param newNameSpace the new repository namespace + * @param newName the new repository name + * @return {@link Repository} the renamed repository + */ + public Repository rename(Repository repository, String newNameSpace, String newName); } diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java index fa45106ab9..fdb8dfc1a8 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.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.repository; //~--- non-JDK imports -------------------------------------------------------- @@ -42,17 +42,14 @@ import java.util.Collection; */ public class RepositoryManagerDecorator extends ManagerDecorator - implements RepositoryManager -{ + implements RepositoryManager { /** * Constructs ... * - * * @param decorated */ - public RepositoryManagerDecorator(RepositoryManager decorated) - { + public RepositoryManagerDecorator(RepositoryManager decorated) { super(decorated); this.decorated = decorated; } @@ -63,8 +60,7 @@ public class RepositoryManagerDecorator * {@inheritDoc} */ @Override - public void fireHookEvent(RepositoryHookEvent event) - { + public void fireHookEvent(RepositoryHookEvent event) { decorated.fireHookEvent(event); } @@ -79,65 +75,66 @@ public class RepositoryManagerDecorator //~--- get methods ---------------------------------------------------------- @Override - public Repository get(NamespaceAndName namespaceAndName) - { + public Repository get(NamespaceAndName namespaceAndName) { return decorated.get(namespaceAndName); } /** * {@inheritDoc} * - * * @return */ @Override - public Collection getConfiguredTypes() - { + public Collection getConfiguredTypes() { return decorated.getConfiguredTypes(); } /** * Returns the decorated {@link RepositoryManager}. * - * * @return decorated {@link RepositoryManager} - * * @since 1.34 */ - public RepositoryManager getDecorated() - { + public RepositoryManager getDecorated() { return decorated; } /** * {@inheritDoc} * - * * @param type - * * @return */ @Override @SuppressWarnings("unchecked") - public RepositoryHandler getHandler(String type) - { + public RepositoryHandler getHandler(String type) { return decorated.getHandler(type); } /** * {@inheritDoc} * + * @return + */ + @Override + public Collection getTypes() { + return decorated.getTypes(); + } + + /** + * {@inheritDoc} * * @return */ @Override - public Collection getTypes() - { - return decorated.getTypes(); + public Repository rename(Repository repository, String newNamespace, String newName) { + return decorated.rename(repository, newNamespace, newName); } //~--- fields --------------------------------------------------------------- - /** Field description */ + /** + * Field description + */ private final RepositoryManager decorated; } diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java index c61bbd2f03..8b199622d4 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java @@ -49,7 +49,7 @@ public final class RepositoryModificationEvent extends RepositoryEvent implement */ public RepositoryModificationEvent(HandlerEventType eventType, Repository item, Repository itemBeforeModification) { - super(eventType, item); + super(eventType, item, itemBeforeModification); this.itemBeforeModification = itemBeforeModification; } diff --git a/scm-packaging/deb/pom.xml b/scm-packaging/deb/pom.xml index 7a3d0c9b47..a4f3a2e11e 100644 --- a/scm-packaging/deb/pom.xml +++ b/scm-packaging/deb/pom.xml @@ -73,30 +73,6 @@ true - - copy-jsvc - prepare-package - - unpack - - - - - commons-daemon - commons-daemon-native - 1.1.0 - tar.gz - - - - - - **/jsvc-linux-* - ${project.build.directory}/deb/libexec - false - true - - copy-webapp prepare-package @@ -157,7 +133,6 @@ - file src/main/fs/etc/scm/logging.xml @@ -208,18 +183,6 @@ - - directory - ${project.build.directory}/deb/libexec - - perm - /opt/scm-server/libexec - root - scm - 0755 - - - file src/main/fs/opt/scm-server/var/webapp/docroot/index.html diff --git a/scm-packaging/deb/src/main/bin/scm-server b/scm-packaging/deb/src/main/bin/scm-server index 1321985a59..4adbc09294 100755 --- a/scm-packaging/deb/src/main/bin/scm-server +++ b/scm-packaging/deb/src/main/bin/scm-server @@ -18,58 +18,14 @@ # Copyright (c) 2001-2002 The Apache Software Foundation. All rights # reserved. -# user used to run the daemon (defaults to current user) -USER="scm" - # extra jvm arguments EXTRA_JVM_ARGUMENTS="-Djava.awt.headless=true -Dlogback.configurationFile=logging.xml" BASEDIR="/opt/scm-server" -# set pid path for jsvc -PIDFILE="/var/run/scm-server.pid" - -# set log dir for jsvc -LOGDIR="/var/log/scm" - # load settings from defaults directory [ -r /etc/default/scm-server ] && . /etc/default/scm-server -OS=`uname | tr '[:upper:]' '[:lower:]'` -ARCH=`uname -m` - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -case "$OS" in - sunos*) OS="solaris" - ARCH=`uname -p` - ;; - cygwin*) cygwin=true ;; - darwin*) darwin=true - if [ -z "$JAVA_VERSION" ] ; then - JAVA_VERSION="CurrentJDK" - else - echo "Using Java version: $JAVA_VERSION" - fi - if [ -z "$JAVA_HOME" ] ; then - JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - # If a specific java binary isn't specified search for the standard 'java' binary if [ -z "$JAVACMD" ] ; then if [ -n "$JAVA_HOME" ] ; then @@ -97,96 +53,12 @@ fi CLASSPATH=$CLASSPATH_PREFIX:"$BASEDIR"/conf:"$REPO"/* -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"` - [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"` - [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"` -fi - -jsvc=false; -stop=""; - -if [ "$1" == "start" ] -then - jsvc=true; -else - if [ "$1" == "stop" ] - then - jsvc=true; - stop='-stop'; - fi -fi - -USER_ARGUMENT="" - -if [ "x$USER" != "x" ] -then - USER_ARGUMENT="-user $USER" -fi - -DARWIN_USE_ARCH="false" - -if $jsvc; then - - JSVCCMD="" - if [ "$OS" == "darwin" ]; then - if [ "$DARWIN_USE_ARCH" == "true" ]; then - JSVCCMD="/usr/bin/arch -arch $ARCH $BASEDIR/libexec/jsvc-$OS" - else - JSVCCMD="exec $BASEDIR/libexec/jsvc-$OS" - fi - else - JSVCCMD="exec $BASEDIR/libexec/jsvc-$OS-$ARCH" - fi - - # try to extract JAVA_HOME from JAVACMD - if [ -z "$JAVA_HOME" ] ; then - PRG="$JAVACMD" - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - DIR="$(dirname "$PRG")" - DIR="$(dirname "$DIR")" - if [ -d "$DIR" ] ; then - JAVA_HOME="$DIR" - fi - fi - - # TODO JVM Arguments - - $JSVCCMD -cp "$CLASSPATH" $JAVA_OPTS \ - $EXTRA_JVM_ARGUMENTS $USER_ARGUMENT \ - -outfile "$LOGDIR/scm-server.out" \ - -errfile "$LOGDIR/scm-server.err" \ - -pidfile "$PIDFILE" \ - -jvm server \ - -home "$JAVA_HOME" \ - -Dapp.name="scm-server" \ - -Dapp.pid="$$" \ - -Dapp.repo="$REPO" \ - -Dbasedir="$BASEDIR" \ - $stop sonia.scm.server.ScmServerDaemon \ - "$@" - -else - - exec "$JAVACMD" $JAVA_OPTS \ - $EXTRA_JVM_ARGUMENTS \ - -classpath "$CLASSPATH" \ - -Dapp.name="scm-server" \ - -Dapp.pid="$$" \ - -Dapp.repo="$REPO" \ - -Dbasedir="$BASEDIR" \ - sonia.scm.server.ScmServerDaemon \ - "$@" - -fi +exec "$JAVACMD" $JAVA_OPTS \ + $EXTRA_JVM_ARGUMENTS \ + -classpath "$CLASSPATH" \ + -Dapp.name="scm-server" \ + -Dapp.pid="$$" \ + -Dapp.repo="$REPO" \ + -Dbasedir="$BASEDIR" \ + sonia.scm.server.ScmServerDaemon \ + "$@" diff --git a/scm-packaging/deb/src/main/deb/control/control b/scm-packaging/deb/src/main/deb/control/control index 06a721b7ff..29926baf5b 100644 --- a/scm-packaging/deb/src/main/deb/control/control +++ b/scm-packaging/deb/src/main/deb/control/control @@ -3,7 +3,8 @@ Version: [[version]] Section: devel Priority: extra Architecture: all -Description: The easiest way to share and manage your Git, Mercurial and Subversion repositories over http -Maintainer: Sebastian Sdorra +Description: The easiest way to share and manage your Git, Mercurial and Subversion repositories +Maintainer: SCM-Team +Homepage: https://scm-manager.org Depends: adduser, procps, psmisc, net-tools Recommends: openjdk-11-jre-headless, mercurial diff --git a/scm-packaging/deb/src/main/deb/control/postinst b/scm-packaging/deb/src/main/deb/control/postinst index 0bd5ff952d..0ca852da1f 100644 --- a/scm-packaging/deb/src/main/deb/control/postinst +++ b/scm-packaging/deb/src/main/deb/control/postinst @@ -37,7 +37,22 @@ systemctl daemon-reload # enable and start the service sudo systemctl enable scm-server -# we start scm-manager after 5 seconds -# this is required, because if we install scm-manager with recommend java -# java is not fully setup if we ran our postint script -nohup sh -c "sleep 5; systemctl start scm-server" >/dev/null 2>&1 & +# reload systemd and make service available +systemctl --system daemon-reload || true + +# enable service +if ! systemctl is-enabled scm-server >/dev/null +then + systemctl enable scm-server +fi + +# start or restart service +if systemctl is-active scm-server >/dev/null +then + systemctl restart scm-server +else + # we start scm-manager after 5 seconds + # this is required, because if we install scm-manager with recommend java + # java is not fully setup if we ran our postint script + nohup sh -c "sleep 5; systemctl start scm-server" >/dev/null 2>&1 & +fi diff --git a/scm-packaging/deb/src/main/fs/etc/default/scm-server b/scm-packaging/deb/src/main/fs/etc/default/scm-server index 959947d33f..619e61eaf9 100644 --- a/scm-packaging/deb/src/main/fs/etc/default/scm-server +++ b/scm-packaging/deb/src/main/fs/etc/default/scm-server @@ -29,21 +29,12 @@ HOST=0.0.0.0 # scm-server port PORT=8080 -# change user -USER=scm - # home of scm-manager export SCM_HOME=/var/lib/scm # force jvm path # JAVA_HOME="/usr/lib/jvm/java-11-openjdk-amd64" -# path to pid -PIDFILE=/var/run/scm/scm.pid - -# path to log directory -LOGDIR=/var/log/scm - # increase memory # EXTRA_JVM_ARGUMENTS="$EXTRA_JVM_ARGUMENTS -Xms1g -Xmx1g" diff --git a/scm-packaging/deb/src/main/fs/etc/scm/logging.xml b/scm-packaging/deb/src/main/fs/etc/scm/logging.xml index b3f4014265..b048b71c29 100644 --- a/scm-packaging/deb/src/main/fs/etc/scm/logging.xml +++ b/scm-packaging/deb/src/main/fs/etc/scm/logging.xml @@ -100,7 +100,8 @@ - + + diff --git a/scm-packaging/deb/src/main/fs/etc/systemd/system/scm-server.service b/scm-packaging/deb/src/main/fs/etc/systemd/system/scm-server.service index 58ef9de558..e37e8f5ee7 100644 --- a/scm-packaging/deb/src/main/fs/etc/systemd/system/scm-server.service +++ b/scm-packaging/deb/src/main/fs/etc/systemd/system/scm-server.service @@ -3,14 +3,19 @@ Description=SCM-Manager Server After=syslog.target network.target [Service] -Type=forking +Type=simple User=scm Group=scm WorkingDirectory=/opt/scm-server -ExecStart=/opt/scm-server/bin/scm-server start -ExecStop=/opt/scm-server/bin/scm-server stop +ExecStart=/opt/scm-server/bin/scm-server +Restart=on-failure + +# Exit code 143 means that the program received a SIGTERM signal to instruct it to exit, +# but it did not handle the signal properly. +# we suppress that warning for now +SuccessExitStatus=143 [Install] WantedBy=multi-user.target diff --git a/scm-packaging/rpm/pom.xml b/scm-packaging/rpm/pom.xml index fa5743c9c5..9d4c7d9ed1 100644 --- a/scm-packaging/rpm/pom.xml +++ b/scm-packaging/rpm/pom.xml @@ -41,6 +41,12 @@ Packaging for RedHat/Centos/Fedora rpm + + https://scm-manager.org + @@ -73,30 +79,6 @@ true - - copy-jsvc - prepare-package - - unpack - - - - - commons-daemon - commons-daemon-native - 1.1.0 - tar.gz - - - - - - **/jsvc-linux-* - ${project.build.directory}/rpm/libexec - false - true - - copy-webapp prepare-package @@ -127,6 +109,8 @@ true scm-server + SCM-Manager Server + The easiest way to share and manage your Git, Mercurial and Subversion repositories Development/Tools MIT true @@ -163,15 +147,6 @@ scm 0644 - - - file - /opt/scm-server/libexec - - root - scm - 0755 - @@ -229,14 +204,6 @@ default - - /opt/scm-server/libexec - - ${project.build.directory}/rpm/libexec - - default - - /opt/scm-server/var/webapp/docroot/index.html src/main/fs/opt/scm-server/var/webapp/docroot/index.html @@ -319,7 +286,6 @@ - org.apache.maven.plugins maven-deploy-plugin diff --git a/scm-packaging/rpm/src/main/bin/scm-server b/scm-packaging/rpm/src/main/bin/scm-server index 1321985a59..4adbc09294 100755 --- a/scm-packaging/rpm/src/main/bin/scm-server +++ b/scm-packaging/rpm/src/main/bin/scm-server @@ -18,58 +18,14 @@ # Copyright (c) 2001-2002 The Apache Software Foundation. All rights # reserved. -# user used to run the daemon (defaults to current user) -USER="scm" - # extra jvm arguments EXTRA_JVM_ARGUMENTS="-Djava.awt.headless=true -Dlogback.configurationFile=logging.xml" BASEDIR="/opt/scm-server" -# set pid path for jsvc -PIDFILE="/var/run/scm-server.pid" - -# set log dir for jsvc -LOGDIR="/var/log/scm" - # load settings from defaults directory [ -r /etc/default/scm-server ] && . /etc/default/scm-server -OS=`uname | tr '[:upper:]' '[:lower:]'` -ARCH=`uname -m` - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -case "$OS" in - sunos*) OS="solaris" - ARCH=`uname -p` - ;; - cygwin*) cygwin=true ;; - darwin*) darwin=true - if [ -z "$JAVA_VERSION" ] ; then - JAVA_VERSION="CurrentJDK" - else - echo "Using Java version: $JAVA_VERSION" - fi - if [ -z "$JAVA_HOME" ] ; then - JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - # If a specific java binary isn't specified search for the standard 'java' binary if [ -z "$JAVACMD" ] ; then if [ -n "$JAVA_HOME" ] ; then @@ -97,96 +53,12 @@ fi CLASSPATH=$CLASSPATH_PREFIX:"$BASEDIR"/conf:"$REPO"/* -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"` - [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"` - [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"` -fi - -jsvc=false; -stop=""; - -if [ "$1" == "start" ] -then - jsvc=true; -else - if [ "$1" == "stop" ] - then - jsvc=true; - stop='-stop'; - fi -fi - -USER_ARGUMENT="" - -if [ "x$USER" != "x" ] -then - USER_ARGUMENT="-user $USER" -fi - -DARWIN_USE_ARCH="false" - -if $jsvc; then - - JSVCCMD="" - if [ "$OS" == "darwin" ]; then - if [ "$DARWIN_USE_ARCH" == "true" ]; then - JSVCCMD="/usr/bin/arch -arch $ARCH $BASEDIR/libexec/jsvc-$OS" - else - JSVCCMD="exec $BASEDIR/libexec/jsvc-$OS" - fi - else - JSVCCMD="exec $BASEDIR/libexec/jsvc-$OS-$ARCH" - fi - - # try to extract JAVA_HOME from JAVACMD - if [ -z "$JAVA_HOME" ] ; then - PRG="$JAVACMD" - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - DIR="$(dirname "$PRG")" - DIR="$(dirname "$DIR")" - if [ -d "$DIR" ] ; then - JAVA_HOME="$DIR" - fi - fi - - # TODO JVM Arguments - - $JSVCCMD -cp "$CLASSPATH" $JAVA_OPTS \ - $EXTRA_JVM_ARGUMENTS $USER_ARGUMENT \ - -outfile "$LOGDIR/scm-server.out" \ - -errfile "$LOGDIR/scm-server.err" \ - -pidfile "$PIDFILE" \ - -jvm server \ - -home "$JAVA_HOME" \ - -Dapp.name="scm-server" \ - -Dapp.pid="$$" \ - -Dapp.repo="$REPO" \ - -Dbasedir="$BASEDIR" \ - $stop sonia.scm.server.ScmServerDaemon \ - "$@" - -else - - exec "$JAVACMD" $JAVA_OPTS \ - $EXTRA_JVM_ARGUMENTS \ - -classpath "$CLASSPATH" \ - -Dapp.name="scm-server" \ - -Dapp.pid="$$" \ - -Dapp.repo="$REPO" \ - -Dbasedir="$BASEDIR" \ - sonia.scm.server.ScmServerDaemon \ - "$@" - -fi +exec "$JAVACMD" $JAVA_OPTS \ + $EXTRA_JVM_ARGUMENTS \ + -classpath "$CLASSPATH" \ + -Dapp.name="scm-server" \ + -Dapp.pid="$$" \ + -Dapp.repo="$REPO" \ + -Dbasedir="$BASEDIR" \ + sonia.scm.server.ScmServerDaemon \ + "$@" diff --git a/scm-packaging/rpm/src/main/fs/etc/default/scm-server b/scm-packaging/rpm/src/main/fs/etc/default/scm-server index 4a5d2fe86c..8f882580c4 100644 --- a/scm-packaging/rpm/src/main/fs/etc/default/scm-server +++ b/scm-packaging/rpm/src/main/fs/etc/default/scm-server @@ -29,21 +29,12 @@ HOST=0.0.0.0 # scm-server port PORT=8080 -# change user -USER=scm - # home of scm-manager export SCM_HOME=/var/lib/scm # force jvm path # JAVA_HOME="/usr/lib/jvm/jre-11" -# path to pid -PIDFILE=/var/run/scm/scm.pid - -# path to log directory -LOGDIR=/var/log/scm - # increase memory # EXTRA_JVM_ARGUMENTS="$EXTRA_JVM_ARGUMENTS -Xms1g -Xmx1g" diff --git a/scm-packaging/rpm/src/main/fs/etc/scm/logging.xml b/scm-packaging/rpm/src/main/fs/etc/scm/logging.xml index b3f4014265..b048b71c29 100644 --- a/scm-packaging/rpm/src/main/fs/etc/scm/logging.xml +++ b/scm-packaging/rpm/src/main/fs/etc/scm/logging.xml @@ -100,7 +100,8 @@ - + + diff --git a/scm-packaging/rpm/src/main/fs/etc/systemd/system/scm-server.service b/scm-packaging/rpm/src/main/fs/etc/systemd/system/scm-server.service index 58ef9de558..e37e8f5ee7 100644 --- a/scm-packaging/rpm/src/main/fs/etc/systemd/system/scm-server.service +++ b/scm-packaging/rpm/src/main/fs/etc/systemd/system/scm-server.service @@ -3,14 +3,19 @@ Description=SCM-Manager Server After=syslog.target network.target [Service] -Type=forking +Type=simple User=scm Group=scm WorkingDirectory=/opt/scm-server -ExecStart=/opt/scm-server/bin/scm-server start -ExecStop=/opt/scm-server/bin/scm-server stop +ExecStart=/opt/scm-server/bin/scm-server +Restart=on-failure + +# Exit code 143 means that the program received a SIGTERM signal to instruct it to exit, +# but it did not handle the signal properly. +# we suppress that warning for now +SuccessExitStatus=143 [Install] WantedBy=multi-user.target diff --git a/scm-packaging/rpm/src/main/scripts/after-installation.sh b/scm-packaging/rpm/src/main/scripts/after-installation.sh index 474eae5df9..6bd95afbe0 100644 --- a/scm-packaging/rpm/src/main/scripts/after-installation.sh +++ b/scm-packaging/rpm/src/main/scripts/after-installation.sh @@ -32,8 +32,18 @@ if [ -d "${WORKDIR}" ]; then fi # reload systemd and make service available -systemctl daemon-reload +systemctl --system daemon-reload || true -# enable and start the service -sudo systemctl enable scm-server -sudo systemctl start scm-server +# enable service +if ! systemctl is-enabled scm-server >/dev/null +then + systemctl enable scm-server +fi + +# start or restart service +if systemctl is-active scm-server >/dev/null +then + systemctl restart scm-server +else + systemctl start scm-server +fi diff --git a/scm-ui/ui-webapp/public/locales/de/repos.json b/scm-ui/ui-webapp/public/locales/de/repos.json index 808bf431e9..e5c16389ea 100644 --- a/scm-ui/ui-webapp/public/locales/de/repos.json +++ b/scm-ui/ui-webapp/public/locales/de/repos.json @@ -113,7 +113,8 @@ "repositoryForm": { "subtitle": "Repository bearbeiten", "submit": "Speichern", - "initializeRepository": "Repository initiieren" + "initializeRepository": "Repository initiieren", + "dangerZone": "Gefahrenzone" }, "sources": { "file-tree": { @@ -196,6 +197,8 @@ }, "deleteRepo": { "button": "Repository löschen", + "subtitle": "Löscht dieses Repository", + "description": "Diese Aktion kann nicht rückgangig gemacht werden.", "confirmAlert": { "title": "Repository löschen", "message": "Soll das Repository wirklich gelöscht werden?", @@ -203,6 +206,22 @@ "cancel": "Nein" } }, + "renameRepo": { + "button": "Repository umbenennen", + "subtitle": "Benennt dieses Repository um", + "description": "Es werden keine Weiterleitung auf den neuen Namen eingerichtet.", + "modal": { + "title": "Repository umbenennen", + "label": { + "repoName": "Repository Name", + "repoNamespace": "Repository Namespace" + }, + "button": { + "rename": "Umbenennen", + "cancel": "Abbrechen" + } + } + }, "diff": { "sideBySide": "Zur zweispaltigen Ansicht wechseln", "combined": "Zur kombinierten Ansicht wechseln", diff --git a/scm-ui/ui-webapp/public/locales/en/repos.json b/scm-ui/ui-webapp/public/locales/en/repos.json index e98052aba3..09d54ff58a 100644 --- a/scm-ui/ui-webapp/public/locales/en/repos.json +++ b/scm-ui/ui-webapp/public/locales/en/repos.json @@ -113,7 +113,8 @@ "repositoryForm": { "subtitle": "Edit Repository", "submit": "Save", - "initializeRepository": "Initialize repository" + "initializeRepository": "Initialize repository", + "dangerZone": "Danger Zone" }, "sources": { "file-tree": { @@ -196,6 +197,8 @@ }, "deleteRepo": { "button": "Delete Repository", + "subtitle": "Deletes this repository", + "description": "Once a repository was deleted, this cannot be undone. Please be careful with this action.", "confirmAlert": { "title": "Delete repository", "message": "Do you really want to delete the repository?", @@ -203,6 +206,22 @@ "cancel": "No" } }, + "renameRepo": { + "button": "Rename Repository", + "subtitle": "Renames this repository", + "description": "There will be no redirects to the renamed repository.", + "modal": { + "title": "Rename repository", + "label": { + "repoName": "Repository name", + "repoNamespace": "Repository namespace" + }, + "button": { + "rename": "Rename", + "cancel": "Cancel" + } + } + }, "diff": { "changes": { "add": "added", diff --git a/scm-ui/ui-webapp/src/admin/containers/Admin.tsx b/scm-ui/ui-webapp/src/admin/containers/Admin.tsx index 089cb959fb..51308f5af1 100644 --- a/scm-ui/ui-webapp/src/admin/containers/Admin.tsx +++ b/scm-ui/ui-webapp/src/admin/containers/Admin.tsx @@ -44,7 +44,7 @@ import GlobalConfig from "./GlobalConfig"; import RepositoryRoles from "../roles/containers/RepositoryRoles"; import SingleRepositoryRole from "../roles/containers/SingleRepositoryRole"; import CreateRepositoryRole from "../roles/containers/CreateRepositoryRole"; -import { StateMenuContextProvider } from "@scm-manager/ui-components/src/navigation/MenuContext"; +import { StateMenuContextProvider } from "@scm-manager/ui-components"; type Props = RouteComponentProps & WithTranslation & { diff --git a/scm-ui/ui-webapp/src/admin/plugins/containers/PluginsOverview.tsx b/scm-ui/ui-webapp/src/admin/plugins/containers/PluginsOverview.tsx index 74a89d3828..7605495810 100644 --- a/scm-ui/ui-webapp/src/admin/plugins/containers/PluginsOverview.tsx +++ b/scm-ui/ui-webapp/src/admin/plugins/containers/PluginsOverview.tsx @@ -54,7 +54,7 @@ import PluginBottomActions from "../components/PluginBottomActions"; import ExecutePendingActionModal from "../components/ExecutePendingActionModal"; import CancelPendingActionModal from "../components/CancelPendingActionModal"; import UpdateAllActionModal from "../components/UpdateAllActionModal"; -import { Plugin } from "@scm-manager/ui-types/src"; +import { Plugin } from "@scm-manager/ui-types"; import ShowPendingModal from "../components/ShowPendingModal"; type Props = WithTranslation & { diff --git a/scm-ui/ui-webapp/src/groups/containers/CreateGroup.tsx b/scm-ui/ui-webapp/src/groups/containers/CreateGroup.tsx index 0709681199..ceeeae20f8 100644 --- a/scm-ui/ui-webapp/src/groups/containers/CreateGroup.tsx +++ b/scm-ui/ui-webapp/src/groups/containers/CreateGroup.tsx @@ -31,7 +31,7 @@ import { Page } from "@scm-manager/ui-components"; import { getGroupsLink, getUserAutoCompleteLink } from "../../modules/indexResource"; import { createGroup, createGroupReset, getCreateGroupFailure, isCreateGroupPending } from "../modules/groups"; import GroupForm from "../components/GroupForm"; -import { apiClient } from "@scm-manager/ui-components/src"; +import { apiClient } from "@scm-manager/ui-components"; type Props = WithTranslation & { createGroup: (link: string, group: Group, callback?: () => void) => void; diff --git a/scm-ui/ui-webapp/src/groups/containers/EditGroup.tsx b/scm-ui/ui-webapp/src/groups/containers/EditGroup.tsx index df3991cfd0..d1471b59e3 100644 --- a/scm-ui/ui-webapp/src/groups/containers/EditGroup.tsx +++ b/scm-ui/ui-webapp/src/groups/containers/EditGroup.tsx @@ -31,7 +31,7 @@ import { DisplayedUser, Group } from "@scm-manager/ui-types"; import { ErrorNotification } from "@scm-manager/ui-components"; import { getUserAutoCompleteLink } from "../../modules/indexResource"; import DeleteGroup from "./DeleteGroup"; -import { apiClient } from "@scm-manager/ui-components/src"; +import { apiClient } from "@scm-manager/ui-components"; import { compose } from "redux"; type Props = { diff --git a/scm-ui/ui-webapp/src/repos/components/form/RepositoryForm.tsx b/scm-ui/ui-webapp/src/repos/components/form/RepositoryForm.tsx index 07e0b276b7..e21ea133bc 100644 --- a/scm-ui/ui-webapp/src/repos/components/form/RepositoryForm.tsx +++ b/scm-ui/ui-webapp/src/repos/components/form/RepositoryForm.tsx @@ -26,8 +26,9 @@ import styled from "styled-components"; import { WithTranslation, withTranslation } from "react-i18next"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; import { Repository, RepositoryType } from "@scm-manager/ui-types"; -import { Checkbox, Level, InputField, Select, SubmitButton, Subtitle, Textarea } from "@scm-manager/ui-components"; +import { Checkbox, InputField, Level, Select, SubmitButton, Subtitle, Textarea } from "@scm-manager/ui-components"; import * as validator from "./repositoryValidation"; +import { CUSTOM_NAMESPACE_STRATEGY } from "../../modules/repos"; const CheckboxWrapper = styled.div` margin-top: 2em; @@ -59,8 +60,6 @@ type State = { contactValidationError: boolean; }; -const CUSTOM_NAMESPACE_STRATEGY = "CustomNamespaceStrategy"; - class RepositoryForm extends React.Component { constructor(props: Props) { super(props); @@ -108,7 +107,7 @@ class RepositoryForm extends React.Component { ); }; - submit = (event: Event) => { + submit = (event: React.FormEvent) => { event.preventDefault(); if (this.isValid()) { this.props.submitForm(this.state.repository, this.state.initRepository); diff --git a/scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx b/scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx new file mode 100644 index 0000000000..5fb14e4557 --- /dev/null +++ b/scm-ui/ui-webapp/src/repos/containers/DangerZone.tsx @@ -0,0 +1,73 @@ +/* + * 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, { FC } from "react"; +import { Repository, Links } from "@scm-manager/ui-types"; +import RenameRepository from "./RenameRepository"; +import DeleteRepo from "./DeleteRepo"; +import styled from "styled-components"; +import { Subtitle } from "@scm-manager/ui-components"; +import { useTranslation } from "react-i18next"; + +type Props = { + repository: Repository; + indexLinks: Links; +}; + +const DangerZoneContainer = styled.div` + padding: 1rem; + border: 1px solid #ff6a88; + border-radius: 5px; + > *:not(:last-child) { + padding-bottom: 1.5rem; + border-bottom: solid 2px whitesmoke; + } +`; + +const DangerZone: FC = ({ repository, indexLinks }) => { + const [t] = useTranslation("repos"); + + const dangerZone = []; + if (repository?._links?.rename || repository?._links?.renameWithNamespace) { + dangerZone.push(); + } + if (repository?._links?.delete) { + // @ts-ignore + dangerZone.push(); + } + + if (dangerZone.length === 0) { + return null; + } + + return ( + <> +
+ + {dangerZone.map(entry => entry)} + + ); +}; + +export default DangerZone; diff --git a/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx b/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx index 4b782fbcaf..8585e98466 100644 --- a/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/DeleteRepo.tsx @@ -24,23 +24,21 @@ import React from "react"; import { connect } from "react-redux"; import { compose } from "redux"; -import { withRouter } from "react-router-dom"; +import { RouteComponentProps, withRouter } from "react-router-dom"; import { WithTranslation, withTranslation } from "react-i18next"; import { History } from "history"; import { Repository } from "@scm-manager/ui-types"; -import { confirmAlert, DeleteButton, ErrorNotification, Level } from "@scm-manager/ui-components"; +import { confirmAlert, DeleteButton, ErrorNotification, Level, ButtonGroup } from "@scm-manager/ui-components"; import { deleteRepo, getDeleteRepoFailure, isDeleteRepoPending } from "../modules/repos"; -type Props = WithTranslation & { - loading: boolean; - error: Error; - repository: Repository; - confirmDialog?: boolean; - deleteRepo: (p1: Repository, p2: () => void) => void; - - // context props - history: History; -}; +type Props = RouteComponentProps & + WithTranslation & { + loading: boolean; + error: Error; + repository: Repository; + confirmDialog?: boolean; + deleteRepo: (p1: Repository, p2: () => void) => void; + }; class DeleteRepo extends React.Component { static defaultProps = { @@ -88,9 +86,16 @@ class DeleteRepo extends React.Component { return ( <> -
- } /> + + {t("deleteRepo.subtitle")} +

{t("deleteRepo.description")}

+ + } + right={} + /> ); } diff --git a/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx b/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx index a6e9874628..e4d16dcfa8 100644 --- a/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx @@ -25,17 +25,19 @@ import React from "react"; import { connect } from "react-redux"; import { withRouter } from "react-router-dom"; import RepositoryForm from "../components/form"; -import DeleteRepo from "./DeleteRepo"; -import { Repository } from "@scm-manager/ui-types"; +import { Repository, Links } from "@scm-manager/ui-types"; import { getModifyRepoFailure, isModifyRepoPending, modifyRepo, modifyRepoReset } from "../modules/repos"; import { History } from "history"; import { ErrorNotification } from "@scm-manager/ui-components"; import { ExtensionPoint } from "@scm-manager/ui-extensions"; import { compose } from "redux"; +import DangerZone from "./DangerZone"; +import { getLinks } from "../../modules/indexResource"; type Props = { loading: boolean; error: Error; + indexLinks: Links; modifyRepo: (p1: Repository, p2: () => void) => void; modifyRepoReset: (p: Repository) => void; @@ -69,7 +71,7 @@ class EditRepo extends React.Component { }; render() { - const { loading, error, repository } = this.props; + const { loading, error, repository, indexLinks } = this.props; const url = this.matchedUrl(); @@ -79,7 +81,7 @@ class EditRepo extends React.Component { }; return ( -
+ <> { }} /> - -
+ + ); } } @@ -99,9 +101,12 @@ const mapStateToProps = (state: any, ownProps: Props) => { const { namespace, name } = ownProps.repository; const loading = isModifyRepoPending(state, namespace, name); const error = getModifyRepoFailure(state, namespace, name); + const indexLinks = getLinks(state); + return { loading, - error + error, + indexLinks }; }; diff --git a/scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx b/scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx new file mode 100644 index 0000000000..ede6414029 --- /dev/null +++ b/scm-ui/ui-webapp/src/repos/containers/RenameRepository.tsx @@ -0,0 +1,178 @@ +/* + * 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, { FC, useEffect, useState } from "react"; +import { Link, Links, Repository } from "@scm-manager/ui-types"; +import { CONTENT_TYPE, CUSTOM_NAMESPACE_STRATEGY } from "../modules/repos"; +import { Button, ButtonGroup, ErrorNotification, InputField, Level, Loading, Modal } from "@scm-manager/ui-components"; +import { useTranslation } from "react-i18next"; +import { apiClient } from "@scm-manager/ui-components"; +import { useHistory } from "react-router-dom"; +import { ExtensionPoint } from "@scm-manager/ui-extensions"; +import * as validator from "../components/form/repositoryValidation"; + +type Props = { + repository: Repository; + indexLinks: Links; +}; + +const RenameRepository: FC = ({ repository, indexLinks }) => { + let history = useHistory(); + const [t] = useTranslation("repos"); + const [error, setError] = useState(undefined); + const [loading, setLoading] = useState(false); + const [showModal, setShowModal] = useState(false); + const [name, setName] = useState(repository.name); + const [namespace, setNamespace] = useState(repository.namespace); + const [nameValidationError, setNameValidationError] = useState(false); + const [namespaceValidationError, setNamespaceValidationError] = useState(false); + const [currentNamespaceStrategie, setCurrentNamespaceStrategy] = useState(""); + + useEffect(() => { + apiClient + .get((indexLinks?.namespaceStrategies as Link).href) + .then(result => result.json()) + .then(result => setCurrentNamespaceStrategy(result.current)) + .catch(setError); + }, [repository]); + + if (error) { + return ; + } + + if (loading) { + return ; + } + + const isValid = + !nameValidationError && + !namespaceValidationError && + (repository.name !== name || repository.namespace !== namespace); + + const handleNamespaceChange = (namespace: string) => { + setNamespaceValidationError(!validator.isNameValid(namespace)); + setNamespace(namespace); + }; + + const handleNameChange = (name: string) => { + setNameValidationError(!validator.isNameValid(name)); + setName(name); + }; + + const renderNamespaceField = () => { + const props = { + label: t("repository.namespace"), + helpText: t("help.namespaceHelpText"), + value: namespace, + onChange: handleNamespaceChange, + errorMessage: t("validation.namespace-invalid"), + validationError: namespaceValidationError + }; + + if (currentNamespaceStrategie === CUSTOM_NAMESPACE_STRATEGY) { + return ; + } + + return ; + }; + + const rename = () => { + setLoading(true); + const url = repository?._links?.renameWithNamespace + ? (repository?._links?.renameWithNamespace as Link).href + : (repository?._links?.rename as Link).href; + + apiClient + .post(url, { name, namespace }, CONTENT_TYPE) + .then(() => setLoading(false)) + .then(() => history.push(`/repo/${namespace}/${name}`)) + .catch(setError); + }; + + const modalBody = ( +
+ + {renderNamespaceField()} +
+ ); + + const footer = ( + <> + +