mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-12-22 00:09:47 +01:00
Merge with default
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import sonia.scm.config.ConfigurationPermissions;
|
||||
import sonia.scm.repository.GitConfig;
|
||||
import sonia.scm.repository.GitRepositoryHandler;
|
||||
import sonia.scm.web.GitVndMediaType;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
@@ -14,13 +18,15 @@ import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* RESTful Web Service Resource to manage the configuration of the git plugin.
|
||||
*/
|
||||
@OpenAPIDefinition(tags = {
|
||||
@Tag(name = "Git", description = "Configuration for the git repository type")
|
||||
})
|
||||
@Path(GitConfigResource.GIT_CONFIG_PATH_V2)
|
||||
public class GitConfigResource {
|
||||
|
||||
@@ -45,13 +51,24 @@ public class GitConfigResource {
|
||||
@GET
|
||||
@Path("")
|
||||
@Produces(GitVndMediaType.GIT_CONFIG)
|
||||
@TypeHint(GitConfigDto.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"configuration:read:git\" privilege"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Operation(summary = "Git configuration", description = "Returns the global git configuration.", tags = "Git")
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "success",
|
||||
content = @Content(
|
||||
mediaType = GitVndMediaType.GIT_CONFIG,
|
||||
schema = @Schema(implementation = GitConfigDto.class)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized, the current user does not have the \"configuration:read:git\" privilege")
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
public Response get() {
|
||||
|
||||
GitConfig config = repositoryHandler.getConfig();
|
||||
@@ -74,13 +91,20 @@ public class GitConfigResource {
|
||||
@PUT
|
||||
@Path("")
|
||||
@Consumes(GitVndMediaType.GIT_CONFIG)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "update success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"configuration:write:git\" privilege"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Operation(summary = "Modify git configuration", description = "Modifies the global git configuration.", tags = "Git")
|
||||
@ApiResponse(
|
||||
responseCode = "204",
|
||||
description = "update success"
|
||||
)
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized, the current user does not have the \"configuration:write:git\" privilege")
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
public Response update(GitConfigDto configDto) {
|
||||
|
||||
GitConfig config = dtoToConfigMapper.map(configDto);
|
||||
@@ -94,7 +118,7 @@ public class GitConfigResource {
|
||||
}
|
||||
|
||||
@Path("{namespace}/{name}")
|
||||
public GitRepositoryConfigResource getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) {
|
||||
public GitRepositoryConfigResource getRepositoryConfig() {
|
||||
return gitRepositoryConfigResource.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitRepositoryConfig;
|
||||
@@ -11,6 +13,7 @@ import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.store.ConfigurationStore;
|
||||
import sonia.scm.web.GitVndMediaType;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -42,13 +45,31 @@ public class GitRepositoryConfigResource {
|
||||
@GET
|
||||
@Path("/")
|
||||
@Produces(GitVndMediaType.GIT_REPOSITORY_CONFIG)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the repository config"),
|
||||
@ResponseCode(code = 404, condition = "not found, no repository with the specified namespace and name available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Operation(summary = "Git repository configuration", description = "Returns the repository related git configuration.", tags = "Git")
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "success",
|
||||
content = @Content(
|
||||
mediaType = GitVndMediaType.GIT_REPOSITORY_CONFIG,
|
||||
schema = @Schema(implementation = GitRepositoryConfigDto.class)
|
||||
)
|
||||
)
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized, the current user has no privileges to read the repository config")
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "not found, no repository with the specified namespace and name available",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
public Response getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) {
|
||||
Repository repository = getRepository(namespace, name);
|
||||
RepositoryPermissions.read(repository).check();
|
||||
@@ -61,13 +82,27 @@ public class GitRepositoryConfigResource {
|
||||
@PUT
|
||||
@Path("/")
|
||||
@Consumes(GitVndMediaType.GIT_REPOSITORY_CONFIG)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "update success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the privilege to change this repositories config"),
|
||||
@ResponseCode(code = 404, condition = "not found, no repository with the specified namespace and name available/name available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Operation(summary = "Modifies git repository configuration", description = "Modifies the repository related git configuration.", tags = "Git")
|
||||
@ApiResponse(
|
||||
responseCode = "204",
|
||||
description = "update success"
|
||||
)
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized, the current user does not have the privilege to change this repositories config")
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "not found, no repository with the specified namespace and name available/name available",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
public Response setRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name, GitRepositoryConfigDto dto) {
|
||||
Repository repository = getRepository(namespace, name);
|
||||
RepositoryPermissions.custom("git", repository).check();
|
||||
|
||||
@@ -88,7 +88,14 @@ abstract class GitMergeStrategy extends AbstractGitCommand.GitCloneWorker<MergeC
|
||||
}
|
||||
|
||||
MergeCommandResult analyseFailure(MergeResult result) {
|
||||
logger.info("could not merge branch {} into {} due to conflict in paths {}", branchToMerge, targetBranch, result.getConflicts().keySet());
|
||||
logger.info("could not merge branch {} into {} with merge status '{}' due to ...", branchToMerge, targetBranch, result.getMergeStatus());
|
||||
logger.info("... conflicts: {}", result.getConflicts());
|
||||
logger.info("... checkout conflicts: {}", result.getCheckoutConflicts());
|
||||
logger.info("... failing paths: {}", result.getFailingPaths());
|
||||
logger.info("... message: {}", result);
|
||||
if (result.getConflicts() == null) {
|
||||
throw new UnexpectedMergeResultException(getRepository(), result);
|
||||
}
|
||||
return MergeCommandResult.failure(targetRevision.name(), revisionToMerge.name(), result.getConflicts().keySet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import org.eclipse.jgit.api.MergeResult;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.ExceptionWithContext;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
class UnexpectedMergeResultException extends ExceptionWithContext {
|
||||
|
||||
public static final String CODE = "4GRrgkSC01";
|
||||
|
||||
public UnexpectedMergeResultException(Repository repository, MergeResult result) {
|
||||
super(ContextEntry.ContextBuilder.entity(repository).build(), createMessage(result));
|
||||
}
|
||||
|
||||
private static String createMessage(MergeResult result) {
|
||||
return "unexpected merge result: " + result
|
||||
+ "\nconflicts: " + result.getConflicts()
|
||||
+ "\ncheckout conflicts: " + result.getCheckoutConflicts()
|
||||
+ "\nfailing paths: " + result.getFailingPaths();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return CODE;
|
||||
}
|
||||
}
|
||||
@@ -113,5 +113,4 @@ public class AbstractGitCommandTestBase extends ZippedRepositoryTestBase
|
||||
|
||||
/** Field description */
|
||||
private GitContext context;
|
||||
private ScmTransportProtocol scmTransportProtocol;
|
||||
}
|
||||
|
||||
@@ -12,16 +12,23 @@ import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import sonia.scm.NoChangesMadeException;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.repository.GitWorkdirFactory;
|
||||
import sonia.scm.repository.Person;
|
||||
import sonia.scm.repository.api.MergeCommandResult;
|
||||
import sonia.scm.repository.api.MergeStrategy;
|
||||
import sonia.scm.repository.util.WorkdirProvider;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -163,11 +170,34 @@ public class GitMergeCommandTest extends AbstractGitCommandTestBase {
|
||||
assertThat(mergeCommandResult.getFilesWithConflict()).containsExactly("a.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleUnexpectedMergeResults() {
|
||||
GitMergeCommand command = createCommand(git -> {
|
||||
try {
|
||||
FileWriter fw = new FileWriter(new File(git.getRepository().getWorkTree(), "b.txt"), true);
|
||||
BufferedWriter bw = new BufferedWriter(fw);
|
||||
bw.write("change");
|
||||
bw.newLine();
|
||||
bw.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
MergeCommandRequest request = new MergeCommandRequest();
|
||||
request.setBranchToMerge("mergeable");
|
||||
request.setTargetBranch("master");
|
||||
request.setMergeStrategy(MergeStrategy.MERGE_COMMIT);
|
||||
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
|
||||
request.setMessageTemplate("simple");
|
||||
|
||||
Assertions.assertThrows(UnexpectedMergeResultException.class, () -> command.merge(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTakeAuthorFromSubjectIfNotSet() throws IOException, GitAPIException {
|
||||
SimplePrincipalCollection principals = new SimplePrincipalCollection();
|
||||
principals.add("admin", REALM);
|
||||
principals.add( new User("dirk", "Dirk Gently", "dirk@holistic.det"), REALM);
|
||||
principals.add(new User("dirk", "Dirk Gently", "dirk@holistic.det"), REALM);
|
||||
shiro.setSubject(
|
||||
new Subject.Builder()
|
||||
.principals(principals)
|
||||
@@ -364,6 +394,20 @@ public class GitMergeCommandTest extends AbstractGitCommandTestBase {
|
||||
}
|
||||
|
||||
private GitMergeCommand createCommand() {
|
||||
return new GitMergeCommand(createContext(), repository, new SimpleGitWorkdirFactory(new WorkdirProvider()));
|
||||
return createCommand(git -> {
|
||||
});
|
||||
}
|
||||
|
||||
private GitMergeCommand createCommand(Consumer<Git> interceptor) {
|
||||
return new GitMergeCommand(createContext(), repository, new SimpleGitWorkdirFactory(new WorkdirProvider())) {
|
||||
@Override
|
||||
<R, W extends GitCloneWorker<R>> R inClone(Function<Git, W> workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch) {
|
||||
Function<Git, W> interceptedWorkerSupplier = git -> {
|
||||
interceptor.accept(git);
|
||||
return workerSupplier.apply(git);
|
||||
};
|
||||
return super.inClone(interceptedWorkerSupplier, workdirFactory, initialBranch);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user