mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 08:55:44 +01:00
added diff endpoint which returns a parsed diff as json
This commit is contained in:
@@ -53,6 +53,12 @@ public abstract class DefaultChangesetToChangesetDtoMapper extends HalAppenderMa
|
||||
|
||||
Embedded.Builder embeddedBuilder = embeddedBuilder();
|
||||
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.self(resourceLinks.changeset().self(repository.getNamespace(), repository.getName(), source.getId()))
|
||||
.single(link("diff", resourceLinks.diff().self(namespace, name, source.getId())))
|
||||
.single(link("sources", resourceLinks.source().self(namespace, name, source.getId())))
|
||||
.single(link("modifications", resourceLinks.modifications().self(namespace, name, source.getId())));
|
||||
|
||||
try (RepositoryService repositoryService = serviceFactory.create(repository)) {
|
||||
if (repositoryService.isSupported(Command.TAGS)) {
|
||||
embeddedBuilder.with("tags", tagCollectionToDtoMapper.getTagDtoList(namespace, name,
|
||||
@@ -62,16 +68,13 @@ public abstract class DefaultChangesetToChangesetDtoMapper extends HalAppenderMa
|
||||
embeddedBuilder.with("branches", branchCollectionToDtoMapper.getBranchDtoList(namespace, name,
|
||||
getListOfObjects(source.getBranches(), branchName -> Branch.normalBranch(branchName, source.getId()))));
|
||||
}
|
||||
|
||||
if (repositoryService.isSupported(Command.DIFF_RESULT)) {
|
||||
linksBuilder.single(link("diffParsed", resourceLinks.diff().parsed(namespace, name, source.getId())));
|
||||
}
|
||||
}
|
||||
embeddedBuilder.with("parents", getListOfObjects(source.getParents(), parent -> changesetToParentDtoMapper.map(new Changeset(parent, 0L, null), repository)));
|
||||
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.self(resourceLinks.changeset().self(repository.getNamespace(), repository.getName(), source.getId()))
|
||||
.single(link("diff", resourceLinks.diff().self(namespace, name, source.getId())))
|
||||
.single(link("sources", resourceLinks.source().self(namespace, name, source.getId())))
|
||||
.single(link("modifications", resourceLinks.modifications().self(namespace, name, source.getId())));
|
||||
|
||||
|
||||
applyEnrichers(new EdisonHalAppender(linksBuilder, embeddedBuilder), source, repository);
|
||||
|
||||
return new ChangesetDto(linksBuilder.build(), embeddedBuilder.build());
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DiffResultDto extends HalRepresentation {
|
||||
|
||||
private List<FileDto> files;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
|
||||
public static class FileDto {
|
||||
|
||||
private String oldPath;
|
||||
private String newPath;
|
||||
private boolean oldEndingNewLine;
|
||||
private boolean newEndingNewLine;
|
||||
private String oldRevision;
|
||||
private String newRevision;
|
||||
private String newMode;
|
||||
private String oldMode;
|
||||
private String type;
|
||||
private String language;
|
||||
private List<HunkDto> hunks;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
|
||||
public static class HunkDto {
|
||||
|
||||
private String content;
|
||||
private int oldStart;
|
||||
private int newStart;
|
||||
private int oldLines;
|
||||
private int newLines;
|
||||
private List<ChangeDto> changes;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
|
||||
public static class ChangeDto {
|
||||
|
||||
private String content;
|
||||
private String type;
|
||||
@JsonProperty("isNormal")
|
||||
private boolean isNormal;
|
||||
@JsonProperty("isInsert")
|
||||
private boolean isInsert;
|
||||
@JsonProperty("isDelete")
|
||||
private boolean isDelete;
|
||||
private int lineNumber;
|
||||
private int oldLineNumber;
|
||||
private int newLineNumber;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.github.sdorra.spotter.ContentTypes;
|
||||
import com.github.sdorra.spotter.Language;
|
||||
import com.google.common.base.Strings;
|
||||
import sonia.scm.repository.api.DiffFile;
|
||||
import sonia.scm.repository.api.DiffLine;
|
||||
import sonia.scm.repository.api.DiffResult;
|
||||
import sonia.scm.repository.api.Hunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* TODO conflicts, copy and rename
|
||||
*/
|
||||
final class DiffResultToDiffResultDtoMapper {
|
||||
|
||||
static final DiffResultToDiffResultDtoMapper INSTANCE = new DiffResultToDiffResultDtoMapper();
|
||||
|
||||
private DiffResultToDiffResultDtoMapper() {
|
||||
}
|
||||
|
||||
public DiffResultDto map(DiffResult result) {
|
||||
List<DiffResultDto.FileDto> files = new ArrayList<>();
|
||||
for (DiffFile file : result) {
|
||||
files.add(mapFile(file));
|
||||
}
|
||||
DiffResultDto dto = new DiffResultDto();
|
||||
dto.setFiles(files);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private DiffResultDto.FileDto mapFile(DiffFile file) {
|
||||
DiffResultDto.FileDto dto = new DiffResultDto.FileDto();
|
||||
// ???
|
||||
dto.setOldEndingNewLine(true);
|
||||
dto.setNewEndingNewLine(true);
|
||||
|
||||
String newPath = file.getNewPath();
|
||||
String oldPath = file.getOldPath();
|
||||
|
||||
String path;
|
||||
if (isFilePath(newPath) && isFileNull(oldPath)) {
|
||||
path = newPath;
|
||||
dto.setType("add");
|
||||
} else if (isFileNull(newPath) && isFilePath(oldPath)) {
|
||||
path = oldPath;
|
||||
dto.setType("delete");
|
||||
} else if (isFilePath(newPath) && isFilePath(oldPath)) {
|
||||
path = newPath;
|
||||
dto.setType("modify");
|
||||
} else {
|
||||
// TODO copy and rename?
|
||||
throw new IllegalStateException("no file without path");
|
||||
}
|
||||
|
||||
dto.setNewPath(newPath);
|
||||
dto.setNewRevision(file.getNewRevision());
|
||||
|
||||
dto.setOldPath(oldPath);
|
||||
dto.setOldRevision(file.getOldRevision());
|
||||
|
||||
|
||||
Optional<Language> language = ContentTypes.detect(path).getLanguage();
|
||||
language.ifPresent(value -> dto.setLanguage(value.getName()));
|
||||
|
||||
List<DiffResultDto.HunkDto> hunks = new ArrayList<>();
|
||||
for (Hunk hunk : file) {
|
||||
hunks.add(mapHunk(hunk));
|
||||
}
|
||||
dto.setHunks(hunks);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private boolean isFilePath(String path) {
|
||||
return !isFileNull(path);
|
||||
}
|
||||
|
||||
private boolean isFileNull(String path) {
|
||||
return Strings.isNullOrEmpty(path) || "/dev/null".equals(path);
|
||||
}
|
||||
|
||||
private DiffResultDto.HunkDto mapHunk(Hunk hunk) {
|
||||
DiffResultDto.HunkDto dto = new DiffResultDto.HunkDto();
|
||||
dto.setContent(hunk.getRawHeader());
|
||||
|
||||
dto.setNewStart(hunk.getNewStart());
|
||||
dto.setNewLines(hunk.getNewLineCount());
|
||||
|
||||
dto.setOldStart(hunk.getOldStart());
|
||||
dto.setOldLines(hunk.getOldLineCount());
|
||||
|
||||
List<DiffResultDto.ChangeDto> changes = new ArrayList<>();
|
||||
for (DiffLine line : hunk) {
|
||||
changes.add(mapLine(line));
|
||||
}
|
||||
|
||||
dto.setChanges(changes);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private DiffResultDto.ChangeDto mapLine(DiffLine line) {
|
||||
DiffResultDto.ChangeDto dto = new DiffResultDto.ChangeDto();
|
||||
dto.setContent(line.getContent());
|
||||
|
||||
OptionalInt newLineNumber = line.getNewLineNumber();
|
||||
OptionalInt oldLineNumber = line.getOldLineNumber();
|
||||
if (newLineNumber.isPresent() && !oldLineNumber.isPresent()) {
|
||||
dto.setType("insert");
|
||||
dto.setInsert(true);
|
||||
dto.setLineNumber(newLineNumber.getAsInt());
|
||||
} else if (!newLineNumber.isPresent() && oldLineNumber.isPresent()) {
|
||||
dto.setType("delete");
|
||||
dto.setDelete(true);
|
||||
dto.setLineNumber(oldLineNumber.getAsInt());
|
||||
} else if (newLineNumber.isPresent() && oldLineNumber.isPresent()) {
|
||||
dto.setType("normal");
|
||||
dto.setNormal(true);
|
||||
dto.setNewLineNumber(newLineNumber.getAsInt());
|
||||
dto.setOldLineNumber(oldLineNumber.getAsInt());
|
||||
} else {
|
||||
throw new IllegalStateException("line without line number");
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import sonia.scm.NotFoundException;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.api.DiffCommandBuilder;
|
||||
import sonia.scm.repository.api.DiffFormat;
|
||||
import sonia.scm.repository.api.DiffResult;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
@@ -70,4 +71,23 @@ public class DiffRootResource {
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{revision}.json")
|
||||
@Produces(VndMediaType.DIFF_PARSED)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "Bad Request"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the diff"),
|
||||
@ResponseCode(code = 404, condition = "not found, no revision with the specified param for the repository available or repository not found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response getParsed(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) throws IOException {
|
||||
HttpUtil.checkForCRLFInjection(revision);
|
||||
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
|
||||
DiffResult diffResult = repositoryService.getDiffResultCommand().setRevision(revision).getDiffResult();
|
||||
return Response.ok(DiffResultToDiffResultDtoMapper.INSTANCE.map(diffResult)).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +362,10 @@ class ResourceLinks {
|
||||
return diffLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("diff").parameters().method("get").parameters(id).href();
|
||||
}
|
||||
|
||||
String parsed(String namespace, String name, String id) {
|
||||
return diffLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("diff").parameters().method("getParsed").parameters(id).href();
|
||||
}
|
||||
|
||||
String all(String namespace, String name) {
|
||||
return diffLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("diff").parameters().method("getAll").parameters().href();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user