mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-17 02:31:14 +01:00
Add handling when duplicated branch part cannot be created (#1692)
Add handling when duplicated branch cannot be created because a part of the name already exists as a branch
This commit is contained in:
2
gradle/changelog/create_invalid_branch_exception.yaml
Normal file
2
gradle/changelog/create_invalid_branch_exception.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: fixed
|
||||
description: Add handling when duplicated branch part cannot be created ([#1692](https://github.com/scm-manager/scm-manager/pull/1692))
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class BranchAlreadyExistsException extends ExceptionWithContext {
|
||||
|
||||
private static final String CODE = "FgSZpu9FR1";
|
||||
|
||||
public static BranchAlreadyExistsException branchAlreadyExists(ContextEntry.ContextBuilder builder) {
|
||||
return new BranchAlreadyExistsException(builder.build());
|
||||
}
|
||||
|
||||
private BranchAlreadyExistsException(List<ContextEntry> context) {
|
||||
super(context, createMessage(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
|
||||
private static String createMessage(List<ContextEntry> context) {
|
||||
return context.stream()
|
||||
.map(c -> c.getType().toLowerCase() + " with id " + c.getId())
|
||||
.collect(joining(" in ", "", " already exists"));
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
import sonia.scm.BadRequestException;
|
||||
import sonia.scm.BranchAlreadyExistsException;
|
||||
import sonia.scm.ConcurrentModificationException;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.ScmConstraintViolationException;
|
||||
@@ -91,6 +92,7 @@ public class RestDispatcher {
|
||||
public EnhanceableExceptionMapper() {
|
||||
registerException(NotFoundException.class, Status.NOT_FOUND);
|
||||
registerException(AlreadyExistsException.class, Status.CONFLICT);
|
||||
registerException(BranchAlreadyExistsException.class, Status.CONFLICT);
|
||||
registerException(ConcurrentModificationException.class, Status.CONFLICT);
|
||||
registerException(UnauthorizedException.class, Status.FORBIDDEN);
|
||||
registerException(AuthorizationException.class, Status.FORBIDDEN);
|
||||
|
||||
@@ -57,10 +57,6 @@ const CreateBranch: FC<Props> = ({ repository }) => {
|
||||
return <ErrorNotification error={errorList} />;
|
||||
}
|
||||
|
||||
if (errorCreate) {
|
||||
return <ErrorNotification error={errorCreate} />;
|
||||
}
|
||||
|
||||
if (isLoadingList || !branches) {
|
||||
return <Loading />;
|
||||
}
|
||||
@@ -68,6 +64,7 @@ const CreateBranch: FC<Props> = ({ repository }) => {
|
||||
return (
|
||||
<>
|
||||
<Subtitle subtitle={t("branches.create.title")} />
|
||||
{errorCreate ? <ErrorNotification error={errorCreate} /> : null}
|
||||
<BranchForm
|
||||
submitForm={create}
|
||||
loading={isLoadingCreate}
|
||||
|
||||
@@ -62,7 +62,7 @@ import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
import static sonia.scm.AlreadyExistsException.alreadyExists;
|
||||
import static sonia.scm.BranchAlreadyExistsException.branchAlreadyExists;
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.NotFoundException.notFound;
|
||||
|
||||
@@ -254,7 +254,7 @@ public class BranchRootResource {
|
||||
String parentName = branchRequest.getParent();
|
||||
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
|
||||
if (branchExists(branchName, repositoryService)) {
|
||||
throw alreadyExists(entity(Branch.class, branchName).in(Repository.class, namespace + "/" + name));
|
||||
throw branchAlreadyExists(entity(Branch.class, branchName).in(Repository.class, namespace + "/" + name));
|
||||
}
|
||||
Repository repository = repositoryService.getRepository();
|
||||
RepositoryPermissions.push(repository).check();
|
||||
@@ -275,7 +275,16 @@ public class BranchRootResource {
|
||||
.getBranches()
|
||||
.getBranches()
|
||||
.stream()
|
||||
.anyMatch(branch -> branchName.equals(branch.getName()));
|
||||
.anyMatch(branch -> branchName.equals(branch.getName())
|
||||
|| branchNamespaceAlreadyExistsInGitRepo(branchName, branch.getName(), repositoryService));
|
||||
}
|
||||
|
||||
private boolean branchNamespaceAlreadyExistsInGitRepo(String branchName, String branchName2, RepositoryService repositoryService) {
|
||||
if (repositoryService.getRepository().getType().equals("hg")) {
|
||||
return false;
|
||||
}
|
||||
return (branchName.contains("/") && branchName2.equals(branchName.substring(0, branchName.indexOf("/"))))
|
||||
|| (branchName2.contains("/") && branchName.equals(branchName2.substring(0, branchName2.indexOf("/"))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -193,11 +193,15 @@
|
||||
},
|
||||
"FtR7UznKU1": {
|
||||
"displayName": "Existiert bereits",
|
||||
"description": "Ein Datensatz mit den gegebenen Schlüsselwerten existiert bereits"
|
||||
"description": "Ein Datensatz mit den gegebenen Schlüsselwerten existiert bereits."
|
||||
},
|
||||
"FgSZpu9FR1": {
|
||||
"displayName": "Branch existiert bereits",
|
||||
"description": "Ein Branch oder Branchverzeichnis mit den gegebenen Schlüsselwerten existiert bereits."
|
||||
},
|
||||
"9BR7qpDAe1": {
|
||||
"displayName": "Passwortänderung nicht erlaubt",
|
||||
"description": "Sie haben nicht die Berechtigung, das Passwort zu ändern"
|
||||
"description": "Sie haben nicht die Berechtigung, das Passwort zu ändern."
|
||||
},
|
||||
"2wR7UzpPG1": {
|
||||
"displayName": "Konkurrierende Änderungen",
|
||||
|
||||
@@ -195,6 +195,10 @@
|
||||
"displayName": "Already exists",
|
||||
"description": "There is already an entity with the same key values."
|
||||
},
|
||||
"FgSZpu9FR1": {
|
||||
"displayName": "Branch already exists",
|
||||
"description": "There is already an branch or branch directory with the same key values."
|
||||
},
|
||||
"9BR7qpDAe1": {
|
||||
"displayName": "Password change not allowed",
|
||||
"description": "You do not have the permission to change the password."
|
||||
|
||||
@@ -257,6 +257,38 @@ public class BranchRootResourceTest extends RepositoryTestBase {
|
||||
verify(branchCommandBuilder, never()).branch(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCreateBranchIfDirectoryAsBranchAlreadyExists() throws Exception {
|
||||
when(branchesCommandBuilder.getBranches()).thenReturn(new Branches(createBranch("existing_branch")));
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/branches/")
|
||||
.content("{\"name\": \"existing_branch/abc\"}".getBytes())
|
||||
.contentType(VndMediaType.BRANCH_REQUEST);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertEquals(409, response.getStatus());
|
||||
verify(branchCommandBuilder, never()).branch(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCreateBranchIfBranchWithDirectoryAlreadyExists() throws Exception {
|
||||
when(branchesCommandBuilder.getBranches()).thenReturn(new Branches(createBranch("existing_branch/abc")));
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/branches/")
|
||||
.content("{\"name\": \"existing_branch\"}".getBytes())
|
||||
.contentType(VndMediaType.BRANCH_REQUEST);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertEquals(409, response.getStatus());
|
||||
verify(branchCommandBuilder, never()).branch(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailForMissingParentBranch() throws Exception {
|
||||
when(branchesCommandBuilder.getBranches()).thenReturn(new Branches(createBranch("existing_branch")));
|
||||
|
||||
Reference in New Issue
Block a user