implement modification api in git, svn and hg. implement the endpoint

This commit is contained in:
Mohamed Karray
2018-09-13 11:57:10 +02:00
parent 6b6b558823
commit 4697c55f96
52 changed files with 1231 additions and 426 deletions

View File

@@ -45,7 +45,8 @@ import javax.ws.rs.ext.Provider;
* @author Sebastian Sdorra
* @since 1.36
*/
@Provider @Slf4j
@Provider
@Slf4j
public class IllegalArgumentExceptionMapper
implements ExceptionMapper<IllegalArgumentException>
{

View File

@@ -65,7 +65,8 @@ public abstract class ChangesetToChangesetDtoMapper extends BaseMapper<Changeset
Links.Builder linksBuilder = linkingTo()
.self(resourceLinks.changeset().self(repository.getNamespace(), repository.getName(), target.getId()))
.single(link("diff", resourceLinks.diff().self(namespace, name, target.getId())));
.single(link("diff", resourceLinks.diff().self(namespace, name, target.getId())))
.single(link("modifications", resourceLinks.modifications().self(namespace, name, target.getId())));
target.add(linksBuilder.build());
}

View File

@@ -0,0 +1,15 @@
package sonia.scm.api.v2.resources;
import sonia.scm.api.rest.StatusExceptionMapper;
import sonia.scm.repository.InternalRepositoryException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
@Provider
public class InternalRepositoryExceptionMapper extends StatusExceptionMapper<InternalRepositoryException> {
public InternalRepositoryExceptionMapper() {
super(InternalRepositoryException.class, Response.Status.INTERNAL_SERVER_ERROR);
}
}

View File

@@ -34,6 +34,7 @@ public class MapperModule extends AbstractModule {
bind(TagToTagDtoMapper.class).to(Mappers.getMapper(TagToTagDtoMapper.class).getClass());
bind(FileObjectToFileObjectDtoMapper.class).to(Mappers.getMapper(FileObjectToFileObjectDtoMapper.class).getClass());
bind(ModificationsToDtoMapper.class).to(Mappers.getMapper(ModificationsToDtoMapper.class).getClass());
// no mapstruct required
bind(UIPluginDtoMapper.class);

View File

@@ -0,0 +1,45 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import de.otto.edison.hal.Links;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
public class ModificationsDto extends HalRepresentation {
private String revision;
/**
* list of added files
*/
private List<String> added;
/**
* list of modified files
*/
private List<String> modified;
/**
* list of removed files
*/
private List<String> removed;
@Override
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
protected HalRepresentation add(Links links) {
return super.add(links);
}
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
protected HalRepresentation withEmbedded(String rel, List<? extends HalRepresentation> halRepresentations) {
return super.withEmbedded(rel, halRepresentations);
}
}

View File

@@ -0,0 +1,70 @@
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 sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.io.IOException;
public class ModificationsRootResource {
private final RepositoryServiceFactory serviceFactory;
private final ModificationsToDtoMapper modificationsToDtoMapper;
@Inject
public ModificationsRootResource(RepositoryServiceFactory serviceFactory, ModificationsToDtoMapper modificationsToDtoMapper) {
this.serviceFactory = serviceFactory;
this.modificationsToDtoMapper = modificationsToDtoMapper;
}
/**
* Get the file modifications related to a revision.
* file modifications are for example: Modified, Added or Removed.
*
* @param namespace
* @param name
* @param revision
* @return
* @throws IOException
* @throws RevisionNotFoundException
* @throws RepositoryNotFoundException
*/
@GET
@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 changeset"),
@ResponseCode(code = 404, condition = "not found, no changeset with the specified id is available in the repository"),
@ResponseCode(code = 500, condition = "internal server error")
})
@Produces(VndMediaType.MODIFICATIONS)
@TypeHint(ModificationsDto.class)
@Path("{revision}")
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) throws IOException, RevisionNotFoundException, RepositoryNotFoundException , InternalRepositoryException {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Modifications modifications = repositoryService.getModificationsCommand()
.revision(revision)
.getModifications();
ModificationsDto output = modificationsToDtoMapper.map(modifications, repositoryService.getRepository());
if (modifications != null ) {
return Response.ok(output).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
}
}

View File

@@ -0,0 +1,31 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.Links;
import org.mapstruct.AfterMapping;
import org.mapstruct.Context;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.Repository;
import javax.inject.Inject;
import static de.otto.edison.hal.Links.linkingTo;
@Mapper
public abstract class ModificationsToDtoMapper extends BaseMapper<Modifications, ModificationsDto> {
@Inject
private ResourceLinks resourceLinks;
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
public abstract ModificationsDto map(Modifications modifications, @Context Repository repository);
@AfterMapping
void appendLinks(@MappingTarget ModificationsDto target, @Context Repository repository) {
Links.Builder linksBuilder = linkingTo()
.self(resourceLinks.modifications().self(repository.getNamespace(), repository.getName(), target.getRevision()));
target.add(linksBuilder.build());
}
}

View File

@@ -40,6 +40,7 @@ public class RepositoryResource {
private final Provider<ContentResource> contentResource;
private final Provider<PermissionRootResource> permissionRootResource;
private final Provider<DiffRootResource> diffRootResource;
private final Provider<ModificationsRootResource> modificationsRootResource;
@Inject
public RepositoryResource(
@@ -50,7 +51,7 @@ public class RepositoryResource {
Provider<ChangesetRootResource> changesetRootResource,
Provider<SourceRootResource> sourceRootResource, Provider<ContentResource> contentResource,
Provider<PermissionRootResource> permissionRootResource,
Provider<DiffRootResource> diffRootResource) {
Provider<DiffRootResource> diffRootResource, Provider<ModificationsRootResource> modificationsRootResource) {
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
this.manager = manager;
this.repositoryToDtoMapper = repositoryToDtoMapper;
@@ -62,6 +63,7 @@ public class RepositoryResource {
this.contentResource = contentResource;
this.permissionRootResource = permissionRootResource;
this.diffRootResource = diffRootResource;
this.modificationsRootResource = modificationsRootResource;
}
/**
@@ -180,6 +182,9 @@ public class RepositoryResource {
return permissionRootResource.get();
}
@Path("modifications/")
public ModificationsRootResource modifications() {return modificationsRootResource.get(); }
private Optional<Response> handleNotArchived(Throwable throwable) {
if (throwable instanceof RepositoryIsNotArchivedException) {
return Optional.of(Response.status(Response.Status.PRECONDITION_FAILED).build());

View File

@@ -307,6 +307,21 @@ class ResourceLinks {
}
}
public ModificationsLinks modifications() {
return new ModificationsLinks(uriInfoStore.get());
}
static class ModificationsLinks {
private final LinkBuilder modificationsLinkBuilder;
ModificationsLinks(UriInfo uriInfo) {
modificationsLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ModificationsRootResource.class);
}
String self(String namespace, String name, String revision) {
return modificationsLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("modifications").parameters().method("get").parameters(revision).href();
}
}
public SourceLinks source() {
return new SourceLinks(uriInfoStore.get());
}