diff --git a/src/main/java/org/gitlab4j/api/GitLabApi.java b/src/main/java/org/gitlab4j/api/GitLabApi.java index ecc65d3d1..c03defb7b 100644 --- a/src/main/java/org/gitlab4j/api/GitLabApi.java +++ b/src/main/java/org/gitlab4j/api/GitLabApi.java @@ -83,6 +83,7 @@ public String getApiNamespace() { private PipelineApi pipelineApi; private ProjectApi projectApi; private ProtectedBranchesApi protectedBranchesApi; + private ReleaseLinksApi releaseLinksApi; private ReleasesApi releasesApi; private RepositoryApi repositoryApi; private RepositoryFileApi repositoryFileApi; @@ -1444,6 +1445,25 @@ public ProtectedBranchesApi getProtectedBranchesApi() { return (this.protectedBranchesApi); } + /** + * Gets the ReleaseLinksApi instance owned by this GitLabApi instance. The ReleaseLinksApi is used + * to perform all Release Links related API calls. + * + * @return the ReleaseLinksApi instance owned by this GitLabApi instance + */ + public ReleaseLinksApi getReleaseLinksApi() { + + if (releaseLinksApi == null) { + synchronized (this) { + if (releaseLinksApi == null) { + releaseLinksApi = new ReleaseLinksApi(this); + } + } + } + + return releaseLinksApi; + } + /** * Gets the ReleasesApi instance owned by this GitLabApi instance. The ReleasesApi is used * to perform all release related API calls. diff --git a/src/main/java/org/gitlab4j/api/ReleaseLinksApi.java b/src/main/java/org/gitlab4j/api/ReleaseLinksApi.java new file mode 100644 index 000000000..94ee6109b --- /dev/null +++ b/src/main/java/org/gitlab4j/api/ReleaseLinksApi.java @@ -0,0 +1,170 @@ +package org.gitlab4j.api; + +import org.gitlab4j.api.models.Link; +import org.gitlab4j.api.models.ReleaseLinkParams; + +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + + +/** + * This class provides an entry point to all the GitLab ReleaseLinks API calls. + * @see ReleaseLinks API at GitLab + */ +public class ReleaseLinksApi extends AbstractApi { + + public ReleaseLinksApi(GitLabApi gitLabApi) { + super(gitLabApi); + } + + /** + * Get assets as Links from a Release. + * + *
GitLab Endpoint: GET /projects/:id/releases/:tagName/assets/links
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param tagName the tag name that the release was created from + * @return the list of assets for the specified release + * @throws GitLabApiException if any exception occurs + */ + public List getLinks(Object projectIdOrPath, String tagName) throws GitLabApiException { + return (getLinks(projectIdOrPath, tagName, getDefaultPerPage()).all()); + } + + /** + * Get assets as Links from a Release. + * + *
GitLab Endpoint: GET /projects/:id/releases/:tagName/assets/links
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param tagName the tag name that the release was created from + * @param itemsPerPage the number of Link instances that will be fetched per page + * @return the Pager of Link instances for the specified project ID + * @throws GitLabApiException if any exception occurs + */ + public Pager getLinks(Object projectIdOrPath, String tagName, int itemsPerPage) throws GitLabApiException { + return (new Pager(this, Link.class, itemsPerPage, null, "projects", getProjectIdOrPath(projectIdOrPath), "releases", urlEncode(tagName), "assets", "links")); + } + + /** + * Get a Stream of assets as Links from a Release. + * + *
GitLab Endpoint: GET /projects/:id/releases/:tagName/assets/links
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param tagName the tag name that the release was created from + * @return a Stream of Link instances for the specified project ID + * @throws GitLabApiException if any exception occurs + */ + public Stream getLinksStream(Object projectIdOrPath, String tagName) throws GitLabApiException { + return (getLinks(projectIdOrPath, tagName, getDefaultPerPage()).stream()); + } + + /** + * Get a Link for the given tag name and link id. + * + *
GitLab Endpoint: GET /projects/:id/releases/:tagName/assets/links/:linkId
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param tagName the name of the tag to fetch the Link for + * @param linkId the id of the Link to fetch for + * @return a Link instance with info on the specified tag and id + * @throws GitLabApiException if any exception occurs + */ + public Link getLink(Object projectIdOrPath, String tagName, Integer linkId) throws GitLabApiException { + Response response = get(Response.Status.OK, null, "projects", getProjectIdOrPath(projectIdOrPath), "releases", urlEncode(tagName), "assets", "links", linkId); + return (response.readEntity(Link.class)); + } + + /** + * Get an Optional instance holding a Link instance for the specific tag name and link id. + * + *
GitLab Endpoint: GET /projects/:id/releases/:tagName/assets/links/:linkId
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param tagName the name of the tag to fetch the Link for + * @param linkId the id of the Link to fetch for + * @return an Optional instance with the specified Link as the value + * @throws GitLabApiException if any exception occurs + */ + public Optional getOptionalLink(Object projectIdOrPath, String tagName, Integer linkId) throws GitLabApiException { + try { + return (Optional.ofNullable(getLink(projectIdOrPath, tagName, linkId))); + } catch (GitLabApiException glae) { + return (GitLabApi.createOptionalFromException(glae)); + } + } + + /** + * Create a Link. You need push access to the repository to create a Link. + * + *
GitLab Endpoint: POST /projects/:id/releases/:tagName/assets/links
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param params a ReleaseLinksParams instance holding the parameters for the link + * @return a Link instance containing the newly created Link info + * @throws GitLabApiException if any exception occurs + */ + public Link createLink(Object projectIdOrPath, ReleaseLinkParams params) throws GitLabApiException { + String tagName = params.getTagName(); + if (tagName == null || tagName.trim().isEmpty()) { + throw new RuntimeException("params.tagName cannot be null or empty"); + } + + String name = params.getName(); + if (name == null || name.trim().isEmpty()) { + throw new RuntimeException("params.name cannot be null or empty"); + } + + String url = params.getUrl(); + if (url == null || url.trim().isEmpty()) { + throw new RuntimeException("params.url cannot be null or empty"); + } + + Response response = post(Response.Status.CREATED, params, + "projects", getProjectIdOrPath(projectIdOrPath), "releases", urlEncode(tagName), "assets", "links"); + return (response.readEntity(Link.class)); + } + + /** + * Updates the attributes of a given Link. + * + *
GitLab Endpoint: PUT /projects/:id/releases/:tagName/assets/links/:linkId
+ * + * @param projectIdOrPath id, path of the project, or a Project instance holding the project ID or path + * @param linkId the id of the Link to fetch for + * @param params a ReleaseLinksParams instance holding the parameters for the Link + * @return a Link instance containing info on the updated Link + * @throws GitLabApiException if any exception occurs + */ + public Link updateLink(Object projectIdOrPath, Integer linkId, ReleaseLinkParams params) throws GitLabApiException { + String tagName = params.getTagName(); + if (tagName == null || tagName.trim().isEmpty()) { + throw new RuntimeException("params.tagName cannot be null or empty"); + } + + if (linkId == null) { + throw new RuntimeException("linkId cannot be null"); + } + + Response response = put(Response.Status.OK, params, + "projects", getProjectIdOrPath(projectIdOrPath), "releases", urlEncode(tagName), "assets", "links", linkId); + return (response.readEntity(Link.class)); + } + + /** + * Delete a Link. + * + *
GitLab Endpoint: DELETE /projects/:id/releases/:tagName/assets/links/:linkId
+ * + * @param projectIdOrPath the project in the form of an Integer(ID), String(path), or Project instance + * @param tagName the tag name that the link was created from + * @param linkId the id of the Link to delete + * @throws GitLabApiException if any exception occurs + */ + public void deleteLink(Object projectIdOrPath, String tagName, Integer linkId) throws GitLabApiException { + delete(Response.Status.OK, null, "projects", getProjectIdOrPath(projectIdOrPath), "releases", urlEncode(tagName), "assets", "links", linkId); + } +} diff --git a/src/main/java/org/gitlab4j/api/models/Link.java b/src/main/java/org/gitlab4j/api/models/Link.java new file mode 100644 index 000000000..f222a8cee --- /dev/null +++ b/src/main/java/org/gitlab4j/api/models/Link.java @@ -0,0 +1,72 @@ +package org.gitlab4j.api.models; + +import org.gitlab4j.api.utils.JacksonJson; + +import java.util.Date; +import java.util.List; + +public class Link { + + private Integer id; + private String name; + private String url; + /** + * @deprecated deprecated in GitLab 15.9, will be removed in GitLab 16.0. + */ + @Deprecated + private Boolean external; + private String linkType; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + /** + * @deprecated deprecated in GitLab 15.9, will be removed in GitLab 16.0. + */ + @Deprecated + public Boolean getExternal() { + return external; + } + + /** + * @deprecated deprecated in GitLab 15.9, will be removed in GitLab 16.0. + */ + @Deprecated + public void setExternal(Boolean external) { + this.external = external; + } + + public String getLinkType() { + return linkType; + } + + public void setLinkType(String linkType) { + this.linkType = linkType; + } + + @Override + public String toString() { + return (JacksonJson.toJsonString(this)); + } +} diff --git a/src/main/java/org/gitlab4j/api/models/ReleaseLinkParams.java b/src/main/java/org/gitlab4j/api/models/ReleaseLinkParams.java new file mode 100644 index 000000000..0689dbe5b --- /dev/null +++ b/src/main/java/org/gitlab4j/api/models/ReleaseLinkParams.java @@ -0,0 +1,85 @@ +package org.gitlab4j.api.models; + +import org.gitlab4j.api.utils.JacksonJson; + +import java.util.Date; +import java.util.List; + +public class ReleaseLinkParams { + + private String name; + private String tagName; + private String url; + private String filepath; + private String linkType; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ReleaseLinkParams withName(String name) { + this.name = name; + return (this); + } + + public String getTagName() { + return tagName; + } + + public void setTagName(String tagName) { + this.tagName = tagName; + } + + public ReleaseLinkParams withTagName(String tagName) { + this.tagName = tagName; + return (this); + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public ReleaseLinkParams withUrl(String url) { + this.url = url; + return (this); + } + + public String getFilepath() { + return filepath; + } + + public void setFilepath(String filepath) { + this.filepath = filepath; + } + + public ReleaseLinkParams withFilepath(String filepath) { + this.filepath = filepath; + return (this); + } + + public String getLinkType() { + return linkType; + } + + public void setLinkType(String linkType) { + this.linkType = linkType; + } + + public ReleaseLinkParams withLinkType(String linkType) { + this.linkType = linkType; + return (this); + } + + @Override + public String toString() { + return (JacksonJson.toJsonString(this)); + } +} diff --git a/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java b/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java index 0afb446e5..5afc24a75 100644 --- a/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java +++ b/src/test/java/org/gitlab4j/api/TestGitLabApiBeans.java @@ -78,6 +78,7 @@ import org.gitlab4j.api.models.Key; import org.gitlab4j.api.models.Label; import org.gitlab4j.api.models.LabelEvent; +import org.gitlab4j.api.models.Link; import org.gitlab4j.api.models.Member; import org.gitlab4j.api.models.MergeRequest; import org.gitlab4j.api.models.MergeRequestDiff; @@ -373,6 +374,12 @@ public void testLinkedIssues() throws Exception { assertTrue(compareJson(linkedIssues, "linked-issues.json")); } + @Test + public void testLinks() throws Exception { + List links = unmarshalResourceList(Link.class, "links.json"); + assertTrue(compareJson(links, "links.json")); + } + @Test public void testCommitDiscussions() throws Exception { List discussions = unmarshalResourceList(Discussion.class, "commit-discussions.json"); diff --git a/src/test/java/org/gitlab4j/api/TestReleaseLinksApi.java b/src/test/java/org/gitlab4j/api/TestReleaseLinksApi.java new file mode 100644 index 000000000..4f48f54c1 --- /dev/null +++ b/src/test/java/org/gitlab4j/api/TestReleaseLinksApi.java @@ -0,0 +1,68 @@ +package org.gitlab4j.api; + +import static org.gitlab4j.api.JsonUtils.compareJson; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.openMocks; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.ws.rs.core.MultivaluedMap; + +import org.gitlab4j.api.models.Link; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; + +public class TestReleaseLinksApi implements Constants { + + @Mock private GitLabApi gitLabApi; + @Mock private GitLabApiClient gitLabApiClient; + @Captor private ArgumentCaptor> attributeCaptor; + private MockResponse response; + + @BeforeEach + public void setUp() throws Exception { + openMocks(this); + } + + @Test + public void testGetLinks() throws Exception { + initGetLinks(); + List result = new ReleaseLinksApi(gitLabApi).getLinks(6L, "v1.0"); + assertNotNull(result); + assertTrue(compareJson(result, "links.json")); + } + + @Test + public void testGetLinksByPager() throws Exception { + initGetLinks(); + Pager pager = new ReleaseLinksApi(gitLabApi).getLinks(6L, "v1.0", 20); + assertNotNull(pager); + assertTrue(compareJson(pager.all(), "links.json")); + } + + @Test + public void testGetLinksByStream() throws Exception { + initGetLinks(); + Stream stream = new ReleaseLinksApi(gitLabApi).getLinksStream(6L, "v1.0"); + assertNotNull(stream); + List list = stream.collect(Collectors.toList()); + assertTrue(compareJson(list, "links.json")); + } + + private void initGetLinks() throws Exception, IOException { + response = new MockResponse(Link.class, null, "links.json"); + when(gitLabApi.getApiClient()).thenReturn(gitLabApiClient); + when(gitLabApiClient.validateSecretToken(any())).thenReturn(true); + when(gitLabApiClient.get(attributeCaptor.capture(), Mockito.any())).thenReturn(response); + } +} diff --git a/src/test/resources/org/gitlab4j/api/links.json b/src/test/resources/org/gitlab4j/api/links.json new file mode 100644 index 000000000..a62977ed4 --- /dev/null +++ b/src/test/resources/org/gitlab4j/api/links.json @@ -0,0 +1,16 @@ +[ + { + "id":2, + "name":"awesome-v0.2.msi", + "url":"http://192.168.10.15:3000/msi", + "external":true, + "link_type":"other" + }, + { + "id":1, + "name":"awesome-v0.2.dmg", + "url":"http://192.168.10.15:3000", + "external":true, + "link_type":"other" + } +] \ No newline at end of file