diff --git a/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java b/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java index 972ed95a2d..51ff906b8f 100644 --- a/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java +++ b/scm-core/src/test/java/sonia/scm/util/ValidationUtilTest.java @@ -147,6 +147,10 @@ public class ValidationUtilTest public void testIsRepositoryNameValid() { String[] validPaths = { "scm", + "scm-", + "scm_", + "s_cm", + "s-cm", "s", "sc", ".hiddenrepo", @@ -206,7 +210,8 @@ public class ValidationUtilTest "a/..b", "scm/main", "scm/plugins/git-plugin", - "scm/plugins/git-plugin" + "_scm", + "-scm" }; for (String path : validPaths) { diff --git a/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java b/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java index 66c1006d4f..cd5f640c7b 100644 --- a/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java @@ -10,6 +10,7 @@ import sonia.scm.event.ScmEventBus; import sonia.scm.update.repository.MigrationStrategy; import sonia.scm.update.repository.MigrationStrategyDao; import sonia.scm.update.repository.XmlRepositoryV1UpdateStep; +import sonia.scm.util.ValidationUtil; import javax.inject.Inject; import javax.inject.Singleton; @@ -18,13 +19,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; + +import static java.util.Comparator.comparing; @Singleton class MigrationWizardServlet extends HttpServlet { @@ -46,16 +47,20 @@ class MigrationWizardServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) { - List repositoriesWithoutMigrationStrategies = - new ArrayList<>(repositoryV1UpdateStep.getRepositoriesWithoutMigrationStrategies()); - repositoriesWithoutMigrationStrategies.sort(Comparator.comparing(XmlRepositoryV1UpdateStep.V1Repository::getPath)); + List repositoryLineEntries = getRepositoryLineEntries(); + doGet(req, resp, repositoryLineEntries); + } + protected void doGet(HttpServletRequest req, HttpServletResponse resp, List repositoryLineEntries) { HashMap model = new HashMap<>(); model.put("contextPath", req.getContextPath()); model.put("submitUrl", req.getRequestURI()); - model.put("repositories", repositoriesWithoutMigrationStrategies); + model.put("repositories", repositoryLineEntries); model.put("strategies", getMigrationStrategies()); + model.put("validationErrorsFound", repositoryLineEntries + .stream() + .anyMatch(entry -> entry.isNamespaceInvalid() || entry.isNameInvalid())); MustacheFactory mf = new DefaultMustacheFactory(); Mustache template = mf.compile("templates/repository-migration.mustache"); @@ -64,16 +69,41 @@ class MigrationWizardServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { - resp.setStatus(200); + List repositoryLineEntries = getRepositoryLineEntries(); - Arrays.stream(req.getParameterValues("ids")).forEach( - id -> { - String strategy = req.getParameter("strategy-" + id); - String namespace = req.getParameter("namespace-" + id); - String name = req.getParameter("name-" + id); - migrationStrategyDao.set(id, MigrationStrategy.valueOf(strategy), namespace, name); + boolean validationErrorFound = false; + for (RepositoryLineEntry repositoryLineEntry : repositoryLineEntries) { + String id = repositoryLineEntry.getId(); + String namespace = req.getParameter("namespace-" + id); + String name = req.getParameter("name-" + id); + repositoryLineEntry.setNamespace(namespace); + repositoryLineEntry.setName(name); + + if (!ValidationUtil.isRepositoryNameValid(namespace)) { + repositoryLineEntry.setNamespaceValid(false); + validationErrorFound = true; } - ); + if (!ValidationUtil.isRepositoryNameValid(name)) { + repositoryLineEntry.setNameValid(false); + validationErrorFound = true; + } + } + + if (validationErrorFound) { + doGet(req, resp, repositoryLineEntries); + return; + } + + repositoryLineEntries.stream() + .map(RepositoryLineEntry::getId) + .forEach( + id -> { + String strategy = req.getParameter("strategy-" + id); + String namespace = req.getParameter("namespace-" + id); + String name = req.getParameter("name-" + id); + migrationStrategyDao.set(id, MigrationStrategy.valueOf(strategy), namespace, name); + } + ); MustacheFactory mf = new DefaultMustacheFactory(); Mustache template = mf.compile("templates/repository-migration-restart.mustache"); @@ -81,9 +111,20 @@ class MigrationWizardServlet extends HttpServlet { respondWithTemplate(resp, model, template); + resp.setStatus(200); + ScmEventBus.getInstance().post(new RestartEvent(MigrationWizardServlet.class, "wrote migration data")); } + private List getRepositoryLineEntries() { + List repositoriesWithoutMigrationStrategies = + repositoryV1UpdateStep.getRepositoriesWithoutMigrationStrategies(); + return repositoriesWithoutMigrationStrategies.stream() + .map(RepositoryLineEntry::new) + .sorted(comparing(RepositoryLineEntry::getPath)) + .collect(Collectors.toList()); + } + private MigrationStrategy[] getMigrationStrategies() { return MigrationStrategy.values(); } @@ -101,4 +142,66 @@ class MigrationWizardServlet extends HttpServlet { writer.flush(); resp.setStatus(200); } + + private static class RepositoryLineEntry { + private final String id; + private final String type; + private final String path; + private String namespace; + private String name; + private boolean namespaceValid = true; + private boolean nameValid = true; + + public RepositoryLineEntry(XmlRepositoryV1UpdateStep.V1Repository repository) { + this.id = repository.getId(); + this.type = repository.getType(); + this.path = repository.getPath(); + this.namespace = repository.getNewNamespace(); + this.name = repository.getNewName(); + } + + public String getId() { + return id; + } + + public String getType() { + return type; + } + + public String getPath() { + return path; + } + + public String getNamespace() { + return namespace; + } + + public String getName() { + return name; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public void setName(String name) { + this.name = name; + } + + public void setNamespaceValid(boolean namespaceValid) { + this.namespaceValid = namespaceValid; + } + + public void setNameValid(boolean nameValid) { + this.nameValid = nameValid; + } + + public boolean isNamespaceInvalid() { + return !namespaceValid; + } + + public boolean isNameInvalid() { + return !nameValid; + } + } } diff --git a/scm-webapp/src/main/resources/templates/repository-migration.mustache b/scm-webapp/src/main/resources/templates/repository-migration.mustache index 5a9085fb4b..9d7e5e0a0b 100644 --- a/scm-webapp/src/main/resources/templates/repository-migration.mustache +++ b/scm-webapp/src/main/resources/templates/repository-migration.mustache @@ -41,14 +41,24 @@


+ {{#validationErrorsFound}} +
Please correct the invalid namespaces or names below and try again.
+
+ {{/validationErrorsFound}}
- - - + + + {{#repositories}} @@ -59,10 +69,10 @@ {{type}} {{/repositories}}
Original name TypeNew namespaceNew nameStrategyNew namespace + + New name + + Strategy + +
- + - +
@@ -78,9 +88,6 @@
- {{#repositories}} - - {{/repositories}}