diff --git a/pom.xml b/pom.xml index 3166c6ec75..3ab3cb82a3 100644 --- a/pom.xml +++ b/pom.xml @@ -439,6 +439,13 @@ smp-maven-plugin 1.0.0-alpha-6 + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + @@ -633,7 +640,6 @@ org.apache.maven.plugins maven-deploy-plugin - 2.7 diff --git a/scm-core/src/main/java/sonia/scm/IllegalIdentifierChangeException.java b/scm-core/src/main/java/sonia/scm/IllegalIdentifierChangeException.java new file mode 100644 index 0000000000..63b9d0d4fc --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/IllegalIdentifierChangeException.java @@ -0,0 +1,21 @@ +package sonia.scm; + +import java.util.Collections; + +public class IllegalIdentifierChangeException extends BadRequestException { + + private static final String CODE = "thbsUFokjk"; + + public IllegalIdentifierChangeException(ContextEntry.ContextBuilder context, String message) { + super(context.build(), message); + } + + public IllegalIdentifierChangeException(String message) { + super(Collections.emptyList(), message); + } + + @Override + public String getCode() { + return CODE; + } +} 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 0dbd45d0a0..bddf9b378a 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 @@ -184,17 +184,19 @@ public class ModifyCommandBuilder { } } + @SuppressWarnings("UnstableApiUsage") // Files only used internal private File loadData(ByteSource data) throws IOException { File file = createTemporaryFile(); data.copyTo(Files.asByteSink(file)); return file; } + @SuppressWarnings("UnstableApiUsage") // Files and ByteStreams only used internal private File loadData(InputStream data) throws IOException { File file = createTemporaryFile(); - OutputStream out = Files.asByteSink(file).openBufferedStream(); - ByteStreams.copy(data, out); - out.close(); + try (OutputStream out = Files.asByteSink(file).openBufferedStream()) { + ByteStreams.copy(data, out); + } return file; } diff --git a/scm-ui/src/containers/Main.js b/scm-ui/src/containers/Main.js index 8c05578b6b..5e982652e8 100644 --- a/scm-ui/src/containers/Main.js +++ b/scm-ui/src/containers/Main.js @@ -1,16 +1,16 @@ //@flow import React from "react"; -import {Redirect, Route, Switch, withRouter} from "react-router-dom"; -import type {Links} from "@scm-manager/ui-types"; +import { Redirect, Route, Switch, withRouter } from "react-router-dom"; +import type { Links } from "@scm-manager/ui-types"; import Overview from "../repos/containers/Overview"; import Users from "../users/containers/Users"; import Login from "../containers/Login"; import Logout from "../containers/Logout"; -import {ProtectedRoute} from "@scm-manager/ui-components"; -import {binder, ExtensionPoint} from "@scm-manager/ui-extensions"; +import { ProtectedRoute } from "@scm-manager/ui-components"; +import { binder, ExtensionPoint } from "@scm-manager/ui-extensions"; import CreateUser from "../users/containers/CreateUser"; import SingleUser from "../users/containers/SingleUser"; @@ -34,7 +34,7 @@ class Main extends React.Component { render() { const { authenticated, links } = this.props; const redirectUrlFactory = binder.getExtension("main.redirect", this.props); - let url = "/repos"; + let url = "/repos/"; if (redirectUrlFactory) { url = redirectUrlFactory(this.props); } @@ -44,9 +44,10 @@ class Main extends React.Component { + @@ -67,9 +68,10 @@ class Main extends React.Component { component={RepositoryRoot} authenticated={authenticated} /> + @@ -89,10 +91,10 @@ class Main extends React.Component { path="/user/:name" component={SingleUser} /> - + diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java index a7b9146d00..76371a0b54 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SingleResourceManagerAdapter.java @@ -2,6 +2,7 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; import sonia.scm.ConcurrentModificationException; +import sonia.scm.IllegalIdentifierChangeException; import sonia.scm.Manager; import sonia.scm.ModelObject; import sonia.scm.NotFoundException; @@ -11,8 +12,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import static javax.ws.rs.core.Response.Status.BAD_REQUEST; - /** * Adapter from resource http endpoints to managers, for Single resources (e.g. {@code /user/name}). * @@ -55,7 +54,7 @@ class SingleResourceManagerAdapter dirs = collectPluginDirectories(pluginDirectory); + List dirs = + collectPluginDirectories(pluginDirectory) + .stream() + .filter(isPluginDirectory()) + .collect(toList()); logger.debug("process {} directories: {}", dirs.size(), dirs); @@ -194,6 +202,10 @@ public final class PluginProcessor return ImmutableSet.copyOf(wrappers); } + private Predicate isPluginDirectory() { + return dir -> Files.exists(dir.resolve(DIRECTORY_METAINF).resolve("scm").resolve("plugin.xml")); + } + /** * Method description * diff --git a/scm-webapp/src/main/resources/locales/de/plugins.json b/scm-webapp/src/main/resources/locales/de/plugins.json index 92b81c5772..bf534dc138 100644 --- a/scm-webapp/src/main/resources/locales/de/plugins.json +++ b/scm-webapp/src/main/resources/locales/de/plugins.json @@ -167,6 +167,10 @@ "CHRM7IQzo1": { "displayName": "Änderung fehlgeschlagen", "description": "Die Änderung ist fehlgeschlagen. Bitte wenden Sie sich an ihren Administrator für weitere Hinweise." + }, + "thbsUFokjk": { + "displayName": "Unerlaubte Änderung eines Schlüsselwerts", + "description": "Ein Schlüsselwert wurde unerlaubterweise geändert." } }, "namespaceStrategies": { diff --git a/scm-webapp/src/main/resources/locales/en/plugins.json b/scm-webapp/src/main/resources/locales/en/plugins.json index 3f70000624..471da10159 100644 --- a/scm-webapp/src/main/resources/locales/en/plugins.json +++ b/scm-webapp/src/main/resources/locales/en/plugins.json @@ -167,6 +167,10 @@ "CHRM7IQzo1": { "displayName": "Change failed", "description": "The change failed. Please contact your administrator for further assistance." + }, + "thbsUFokjk": { + "displayName": "Illegal change of an identifier", + "description": "A identifier value has been changed in the entity. This is not allowed." } }, "namespaceStrategies": { diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/PluginProcessorTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/PluginProcessorTest.java index 0fbf7eabbc..bb518ec731 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/PluginProcessorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/PluginProcessorTest.java @@ -134,6 +134,16 @@ public class PluginProcessorTest assertThat(plugin.getId(), is(PLUGIN_A.id)); } + @Test + public void shouldCollectPluginsAndDoNotFailOnNonPluginDirectories() throws IOException { + new File(pluginDirectory, "some-directory").mkdirs(); + + copySmp(PLUGIN_A); + InstalledPlugin plugin = collectAndGetFirst(); + + assertThat(plugin.getId(), is(PLUGIN_A.id)); + } + /** * Method description *