mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-17 18:51:10 +01:00
Feature Partial Diff (#1581)
With this pull request, diffs for Git are loaded in chunks. This means, that for diffs with a lot of files only a part of them are loaded. In the UI a button will be displayed to load more. In the REST API, the number of files can be specified. This only works for diffs, that are delivered as "parsed" diffs. Currently, this is only available for Git. Co-authored-by: Sebastian Sdorra <sebastian.sdorra@cloudogu.com>
This commit is contained in:
@@ -42,6 +42,7 @@ public class DiffResultDto extends HalRepresentation {
|
||||
}
|
||||
|
||||
private List<FileDto> files;
|
||||
private boolean partial;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import static de.otto.edison.hal.Link.link;
|
||||
import static de.otto.edison.hal.Link.linkBuilder;
|
||||
import static de.otto.edison.hal.Links.linkingTo;
|
||||
|
||||
@@ -55,23 +56,57 @@ class DiffResultToDiffResultDtoMapper {
|
||||
}
|
||||
|
||||
public DiffResultDto mapForIncoming(Repository repository, DiffResult result, String source, String target) {
|
||||
DiffResultDto dto = new DiffResultDto(linkingTo().self(resourceLinks.incoming().diffParsed(repository.getNamespace(), repository.getName(), source, target)).build());
|
||||
String baseLink = resourceLinks.incoming().diffParsed(repository.getNamespace(), repository.getName(), source, target);
|
||||
Links.Builder links = linkingTo().self(createSelfLink(result, baseLink));
|
||||
appendNextChunkLinkIfNeeded(links, result, baseLink);
|
||||
DiffResultDto dto = new DiffResultDto(links.build());
|
||||
setFiles(result, dto, repository, source);
|
||||
return dto;
|
||||
}
|
||||
|
||||
public DiffResultDto mapForRevision(Repository repository, DiffResult result, String revision) {
|
||||
DiffResultDto dto = new DiffResultDto(linkingTo().self(resourceLinks.diff().parsed(repository.getNamespace(), repository.getName(), revision)).build());
|
||||
String baseLink = resourceLinks.diff().parsed(repository.getNamespace(), repository.getName(), revision);
|
||||
Links.Builder links = linkingTo().self(createSelfLink(result, baseLink));
|
||||
appendNextChunkLinkIfNeeded(links, result, baseLink);
|
||||
DiffResultDto dto = new DiffResultDto(links.build());
|
||||
setFiles(result, dto, repository, revision);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private String createSelfLink(DiffResult result, String baseLink) {
|
||||
if (result.getOffset() > 0 || result.getLimit().isPresent()) {
|
||||
return createLinkWithLimitAndOffset(baseLink, result.getOffset(), result.getLimit().orElse(null));
|
||||
} else {
|
||||
return baseLink;
|
||||
}
|
||||
}
|
||||
|
||||
private void appendNextChunkLinkIfNeeded(Links.Builder links, DiffResult result, String baseLink) {
|
||||
if (result.isPartial()) {
|
||||
Optional<Integer> limit = result.getLimit();
|
||||
if (limit.isPresent()) {
|
||||
links.single(link("next", createLinkWithLimitAndOffset(baseLink, result.getOffset() + limit.get(), limit.get())));
|
||||
} else {
|
||||
throw new IllegalStateException("a result cannot be partial without a limit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String createLinkWithLimitAndOffset(String baseLink, int offset, Integer limit) {
|
||||
if (limit == null) {
|
||||
return String.format("%s?offset=%s", baseLink, offset);
|
||||
} else {
|
||||
return String.format("%s?offset=%s&limit=%s", baseLink, offset, limit);
|
||||
}
|
||||
}
|
||||
|
||||
private void setFiles(DiffResult result, DiffResultDto dto, Repository repository, String revision) {
|
||||
List<DiffResultDto.FileDto> files = new ArrayList<>();
|
||||
for (DiffFile file : result) {
|
||||
files.add(mapFile(file, repository, revision));
|
||||
}
|
||||
dto.setFiles(files);
|
||||
dto.setPartial(result.isPartial());
|
||||
}
|
||||
|
||||
private DiffResultDto.FileDto mapFile(DiffFile file, Repository repository, String revision) {
|
||||
@@ -119,7 +154,6 @@ class DiffResultToDiffResultDtoMapper {
|
||||
dto.setOldPath(oldPath);
|
||||
dto.setOldRevision(file.getOldRevision());
|
||||
|
||||
|
||||
Optional<Language> language = ContentTypeResolver.resolve(path).getLanguage();
|
||||
language.ifPresent(value -> dto.setLanguage(ProgrammingLanguages.getValue(value)));
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@@ -39,6 +39,7 @@ import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
@@ -142,10 +143,18 @@ public class DiffRootResource {
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
)
|
||||
)
|
||||
public DiffResultDto getParsed(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) throws IOException {
|
||||
public DiffResultDto getParsed(@PathParam("namespace") String namespace,
|
||||
@PathParam("name") String name,
|
||||
@PathParam("revision") String revision,
|
||||
@QueryParam("limit") @Min(1) Integer limit,
|
||||
@QueryParam("offset") @Min(0) Integer offset) throws IOException {
|
||||
HttpUtil.checkForCRLFInjection(revision);
|
||||
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
|
||||
DiffResult diffResult = repositoryService.getDiffResultCommand().setRevision(revision).getDiffResult();
|
||||
DiffResult diffResult = repositoryService.getDiffResultCommand()
|
||||
.setRevision(revision)
|
||||
.setLimit(limit)
|
||||
.setOffset(offset)
|
||||
.getDiffResult();
|
||||
return parsedDiffMapper.mapForRevision(repositoryService.getRepository(), diffResult, revision);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@@ -43,6 +43,7 @@ import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
@@ -240,15 +241,19 @@ public class IncomingRootResource {
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
public Response incomingDiffParsed(@PathParam("namespace") String namespace,
|
||||
@PathParam("name") String name,
|
||||
@PathParam("source") String source,
|
||||
@PathParam("target") String target) throws IOException {
|
||||
@PathParam("name") String name,
|
||||
@PathParam("source") String source,
|
||||
@PathParam("target") String target,
|
||||
@QueryParam("limit") @Min(1) Integer limit,
|
||||
@QueryParam("offset") @Min(0) Integer offset) throws IOException {
|
||||
HttpUtil.checkForCRLFInjection(source);
|
||||
HttpUtil.checkForCRLFInjection(target);
|
||||
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
|
||||
DiffResult diffResult = repositoryService.getDiffResultCommand()
|
||||
.setRevision(source)
|
||||
.setAncestorChangeset(target)
|
||||
.setLimit(limit)
|
||||
.setOffset(offset)
|
||||
.getDiffResult();
|
||||
return Response.ok(parsedDiffMapper.mapForIncoming(repositoryService.getRepository(), diffResult, source, target)).build();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user