Skip to content

Commit

Permalink
feat(Release): Get linked releases of release
Browse files Browse the repository at this point in the history
  • Loading branch information
hoangnt2 committed Sep 5, 2023
1 parent 05a2760 commit 451f332
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 2 deletions.
34 changes: 34 additions & 0 deletions rest/resource-server/src/docs/asciidoc/releases.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -516,3 +516,37 @@ include::{snippets}/should_document_load_spdx_licenses_info_from_isr/http-respon

===== Example response for Component license information (CLX or CLI) type
include::{snippets}/should_document_load_spdx_licenses_info_from_clx_or_cli/http-response.adoc[]

[[resources-get-linked-releases-of-release]]
==== Get direct linked releases

A `GET` request will get direct linked releases of a single release

===== Response structure
include::{snippets}/should_document_get_direct_linked_releases/response-fields.adoc[]

===== Example request
include::{snippets}/should_document_get_direct_linked_releases/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_get_direct_linked_releases/http-response.adoc[]

===== Links
include::{snippets}/should_document_get_direct_linked_releases/links.adoc[]

[[resources-get-linked-releases-of-release-transitive]]
==== Get linked releases (transitive)

A `GET` request will get linked releases of a single release (transitive)

===== Response structure
include::{snippets}/should_document_get_linked_releases_transitively/response-fields.adoc[]

===== Example request
include::{snippets}/should_document_get_linked_releases_transitively/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_get_linked_releases_transitively/http-response.adoc[]

===== Links
include::{snippets}/should_document_get_linked_releases_transitively/links.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,18 @@ static abstract class ReleaseMixin extends Release {
"setLicenseNames",
"setAccessible",
"setId",
"setClearingReport"
"setClearingReport",
"hasSubreleases",
"accessible",
"layer",
"index",
"setIndex",
"releaseWithSameComponentSize",
"setReleaseWithSameComponent",
"setLayer",
"setDefaultValue",
"setProjectId",
"setReleaseMainLineState"

})
static abstract class ReleaseLinkMixin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.eclipse.sw360.datahandler.thrift.ProjectReleaseRelationship;
import org.eclipse.sw360.datahandler.thrift.Quadratic;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.ReleaseRelationship;
import org.eclipse.sw360.datahandler.thrift.attachments.Attachment;
import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentDTO;
import org.eclipse.sw360.datahandler.thrift.attachments.CheckStatus;
Expand Down Expand Up @@ -1311,4 +1312,15 @@ public void addEmbeddedCotsDetails(HalResource halResource, Release release) {
addEmbeddedFields("sw360:cotsDetails", cotsDetailsHalResource, halResource);
}
}

public ReleaseLink convertToReleaseLink(Release release, ReleaseRelationship relationship) {
ReleaseLink releaseLink = new ReleaseLink();
releaseLink.setId(release.getId());
releaseLink.setClearingState(release.getClearingState());
releaseLink.setLicenseIds(release.getMainLicenseIds());
releaseLink.setName(release.getName());
releaseLink.setVersion(release.getVersion());
releaseLink.setReleaseRelationship(relationship);
return releaseLink;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,33 @@ public ResponseEntity<?> loadSpdxLicensesInfo(
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}

@GetMapping(value = RELEASES_URL + "/{id}/releases")
public ResponseEntity<CollectionModel<HalResource<ReleaseLink>>> getLinkedReleases(
@PathVariable("id") String id,
@RequestParam(value = "transitive", required = false, defaultValue = "false") boolean transitive
) throws TException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
Release sw360Release = releaseService.getReleaseForUserById(id, sw360User);
Map<String, ReleaseRelationship> releaseRelationshipMap = !CommonUtils.isNullOrEmptyMap(sw360Release.getReleaseIdToRelationship())
? sw360Release.getReleaseIdToRelationship()
: new HashMap<>();
Set<String> releaseIdsInBranch = new HashSet<>();

final List<HalResource<ReleaseLink>> linkedReleaseResources = releaseRelationshipMap.entrySet().stream()
.map(item -> wrapTException(() -> {
final Release releaseById = releaseService.getReleaseForUserById(item.getKey(), sw360User);
final ReleaseLink embeddedReleaseLink = restControllerHelper.convertToReleaseLink(releaseById, item.getValue());
final HalResource<ReleaseLink> releaseResource = new HalResource<>(embeddedReleaseLink);
if (transitive) {
releaseService.addEmbeddedLinkedRelease(releaseById, sw360User, releaseResource, releaseIdsInBranch);
}
return releaseResource;
})).collect(Collectors.toList());

CollectionModel<HalResource<ReleaseLink>> collectionModel = CollectionModel.of(linkedReleaseResources);
return new ResponseEntity<>(collectionModel, HttpStatus.OK);
}

private RequestStatus linkOrUnlinkPackages(String id, Set<String> packagesInRequestBody, boolean link)
throws URISyntaxException, TException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.ThriftClients;
import org.eclipse.sw360.datahandler.thrift.ReleaseRelationship;
import org.eclipse.sw360.datahandler.thrift.attachments.Attachment;
import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentType;
import org.eclipse.sw360.datahandler.thrift.components.*;
Expand All @@ -38,6 +39,7 @@
import org.eclipse.sw360.rest.resourceserver.Sw360ResourceServer;
import org.eclipse.sw360.rest.resourceserver.attachment.Sw360AttachmentService;
import org.eclipse.sw360.rest.resourceserver.core.AwareOfRestServices;
import org.eclipse.sw360.rest.resourceserver.core.HalResource;
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
import org.eclipse.sw360.rest.resourceserver.project.Sw360ProjectService;
import org.eclipse.sw360.rest.resourceserver.license.Sw360LicenseService;
Expand All @@ -47,6 +49,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.Link;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
Expand All @@ -55,6 +58,7 @@
import static org.eclipse.sw360.datahandler.common.CommonUtils.isNullEmptyOrWhitespace;
import static org.eclipse.sw360.datahandler.common.CommonUtils.nullToEmptyString;
import static org.eclipse.sw360.datahandler.common.WrappedException.wrapTException;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand Down Expand Up @@ -683,4 +687,27 @@ public RequestStatus triggerReportGenerationFossology(String releaseId, User use
FossologyService.Iface fossologyClient = getThriftFossologyClient();
return fossologyClient.triggerReportGenerationFossology(releaseId, user);
}

public void addEmbeddedLinkedRelease(Release sw360Release, User sw360User, HalResource<ReleaseLink> releaseResource, Set<String> releaseIdsInBranch) {
releaseIdsInBranch.add(sw360Release.getId());
Map<String, ReleaseRelationship> releaseIdToRelationship = sw360Release.getReleaseIdToRelationship();
if (releaseIdToRelationship != null) {
releaseIdToRelationship.forEach((key, value) -> wrapTException(() -> {
if (releaseIdsInBranch.contains(key)) {
return;
}

Release linkedRelease = getReleaseForUserById(key, sw360User);
ReleaseLink embeddedLinkedRelease = convertToEmbeddedLinkedRelease(linkedRelease, value);
HalResource<ReleaseLink> halLinkedRelease = new HalResource<>(embeddedLinkedRelease);
addEmbeddedLinkedRelease(linkedRelease, sw360User, halLinkedRelease, releaseIdsInBranch);
releaseResource.addEmbeddedResource("sw360:releaseLinks", halLinkedRelease);
}));
}
releaseIdsInBranch.remove(sw360Release.getId());
}

public ReleaseLink convertToEmbeddedLinkedRelease(Release release, ReleaseRelationship relationship) {
return rch.convertToReleaseLink(release, relationship);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doCallRealMethod;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
Expand Down Expand Up @@ -54,6 +55,7 @@
import org.eclipse.sw360.datahandler.thrift.components.ExternalToolProcessStatus;
import org.eclipse.sw360.datahandler.thrift.components.ExternalToolProcessStep;
import org.eclipse.sw360.datahandler.thrift.components.Release;
import org.eclipse.sw360.datahandler.thrift.components.ReleaseLink;
import org.eclipse.sw360.datahandler.thrift.licenses.License;
import org.eclipse.sw360.datahandler.thrift.packages.Package;
import org.eclipse.sw360.datahandler.thrift.packages.PackageManager;
Expand All @@ -68,6 +70,7 @@
import org.eclipse.sw360.rest.resourceserver.TestHelper;
import org.eclipse.sw360.rest.resourceserver.attachment.AttachmentInfo;
import org.eclipse.sw360.rest.resourceserver.attachment.Sw360AttachmentService;
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
import org.eclipse.sw360.rest.resourceserver.license.Sw360LicenseService;
import org.eclipse.sw360.rest.resourceserver.packages.SW360PackageService;
import org.eclipse.sw360.rest.resourceserver.licenseinfo.Sw360LicenseInfoService;
Expand Down Expand Up @@ -130,7 +133,7 @@ public class ReleaseSpecTest extends TestRestDocsSpecBase {
@MockBean
private Sw360LicenseInfoService licenseInfoMockService;

private Release release, release3, releaseTest;
private Release release, release3, releaseTest, release5;
private Attachment attachment;
Component component;
private Project project;
Expand Down Expand Up @@ -325,6 +328,8 @@ public void before() throws TException, IOException {
release2.setClearingInformation(clearingInfo);
release2.setCotsDetails(cotsDetails);
release2.setEccInformation(eccInformation);
release2.setMainLicenseIds(Set.of("MIT", "GPL"));
release2.setOtherLicenseIds(Set.of("MIT"));
releaseList.add(release2);

Package package2 = new Package()
Expand Down Expand Up @@ -355,6 +360,31 @@ public void before() throws TException, IOException {
release3.setCreatedOn("2016-12-18");
release3.setCreatedBy("[email protected]");
release3.setComponentId("1234");
release3.setMainLicenseIds(Set.of("MIT", "GPL 2+"));
release3.setClearingState(ClearingState.APPROVED);
release3.setMainlineState(MainlineState.MAINLINE);
release3.setOtherLicenseIds(Set.of("MIT"));

Release release4 = new Release();
release4.setId("90876");
release4.setName("Numpy");
release4.setVersion("1.19.5");
release4.setMainLicenseIds(Set.of("MIT"));
release4.setClearingState(ClearingState.APPROVED);
release4.setOtherLicenseIds(Collections.emptySet());

ReleaseLink releaseLink4 = new ReleaseLink();
releaseLink4.setId(release4.getId());
releaseLink4.setName(release4.getName());
releaseLink4.setVersion(release4.getVersion());
releaseLink4.setLicenseIds(release4.getMainLicenseIds());
releaseLink4.setClearingState(release4.getClearingState());
releaseLink4.setReleaseRelationship(ReleaseRelationship.CODE_SNIPPET);

release5 = new Release();
release5.setId("3333333");
release5.setReleaseIdToRelationship(Map.of(release2.getId(), ReleaseRelationship.DYNAMICALLY_LINKED, release3.getId(), ReleaseRelationship.CODE_SNIPPET));

Attachment attachment3 = new Attachment(attachment);
attachment3.setAttachmentContentId("34535345");
attachment3.setAttachmentType(AttachmentType.SOURCE);
Expand Down Expand Up @@ -402,6 +432,8 @@ public void before() throws TException, IOException {
given(this.releaseServiceMock.getRecentReleases(any())).willReturn(releaseList);
given(this.releaseServiceMock.getReleaseSubscriptions(any())).willReturn(releaseList);
given(this.releaseServiceMock.getReleaseForUserById(eq(release.getId()), any())).willReturn(release);
given(this.releaseServiceMock.getReleaseForUserById(eq(release2.getId()), any())).willReturn(release2);
given(this.releaseServiceMock.getReleaseForUserById(eq(release5.getId()), any())).willReturn(release5);
given(this.releaseServiceMock.getReleaseForUserById(eq(testRelease.getId()), any())).willReturn(testRelease);
given(this.releaseServiceMock.getProjectsByRelease(eq(release.getId()), any())).willReturn(projectList);
given(this.releaseServiceMock.getUsingComponentsForRelease(eq(release.getId()), any())).willReturn(usedByComponent);
Expand All @@ -418,6 +450,9 @@ public void before() throws TException, IOException {
when(this.releaseServiceMock.createRelease(any(), any())).then(invocation ->
new Release("Test Release", "1.0", component.getId())
.setId("1234567890"));
doCallRealMethod().when(this.releaseServiceMock).addEmbeddedLinkedRelease(any(), any(), any(), any());
given(this.releaseServiceMock.getReleaseForUserById(eq("90876"), any())).willReturn(release4);
given(this.releaseServiceMock.convertToEmbeddedLinkedRelease(any(), any())).willReturn(releaseLink4);

given(this.userServiceMock.getUserByEmailOrExternalId("[email protected]")).willReturn(
new User("[email protected]", "sw360").setId("123456789"));
Expand Down Expand Up @@ -1237,6 +1272,48 @@ public void should_document_load_spdx_licenses_info_from_clx_or_cli() throws Exc
.andExpect(status().isOk());
}

@Test
public void should_document_get_direct_linked_releases() throws Exception {
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);
mockMvc.perform(get("/api/releases/" + release5.getId() + "/releases")
.header("Authorization", "Bearer " + accessToken)
.param("transitive", "false")
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk())
.andDo(this.documentationHandler.document(
requestParameters(
parameterWithName("transitive").description("Get the transitive releases")
),
links(
linkWithRel("curies").description("Curies are used for online documentation")
),
responseFields(
subsectionWithPath("_embedded.sw360:releaseLinks").description("An array of <<resources-releases, Releases resources>>"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}

@Test
public void should_document_get_linked_releases_transitively() throws Exception {
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);
mockMvc.perform(get("/api/releases/" + release5.getId() + "/releases")
.header("Authorization", "Bearer " + accessToken)
.param("transitive", "true")
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk())
.andDo(this.documentationHandler.document(
requestParameters(
parameterWithName("transitive").description("Get the transitive releases")
),
links(
linkWithRel("curies").description("Curies are used for online documentation")
),
responseFields(
subsectionWithPath("_embedded.sw360:releaseLinks").description("An array of <<resources-releases, Releases resources>>"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}

public void mockLicensesInfo(AttachmentType attachmentType) throws TException{
Set<Attachment> listAttachment = new HashSet<>();
Attachment attachmentTest = new Attachment();
Expand Down

0 comments on commit 451f332

Please sign in to comment.