diff --git a/src/main/java/org/gitlab4j/api/GitLabApi.java b/src/main/java/org/gitlab4j/api/GitLabApi.java index c7e765ed9..dc6450d0b 100644 --- a/src/main/java/org/gitlab4j/api/GitLabApi.java +++ b/src/main/java/org/gitlab4j/api/GitLabApi.java @@ -72,6 +72,7 @@ public String getApiNamespace() { private NotesApi notesApi; private EventsApi eventsApi; private SnippetsApi snippetsApi; + private WikisApi wikisApi; /** * Get the GitLab4J shared Logger instance. @@ -1295,4 +1296,22 @@ public SnippetsApi getSnippetApi() { return snippetsApi; } + + /** + * Gets the WikisApi instance owned by this GitLabApi instance. The WikisApi is used to perform all wiki related API calls. + * + * @return the WikisApi instance owned by this GitLabApi instance + */ + public WikisApi getWikisApi() { + if (wikisApi == null) { + synchronized (this) { + if (wikisApi == null) { + wikisApi = new WikisApi(this); + } + } + } + + return wikisApi; + } + } diff --git a/src/main/java/org/gitlab4j/api/WikisApi.java b/src/main/java/org/gitlab4j/api/WikisApi.java new file mode 100644 index 000000000..7c6f2c620 --- /dev/null +++ b/src/main/java/org/gitlab4j/api/WikisApi.java @@ -0,0 +1,177 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Greg Messner + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.gitlab4j.api; + +import org.gitlab4j.api.models.WikiPage; + +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Optional; + +/** + * @author shuklaalok7 (alok@clay.fish) + * @since v4.8.21 2018-06-5 1:26 AM IST + */ +public class WikisApi extends AbstractApi { + + + public WikisApi(GitLabApi gitLabApi) { + super(gitLabApi); + } + + /** + * Get a list of pages in project wiki. This only returns the first page of wiki-pages. + * + * GET /projects/:id/wikis + * + * @param projectId the project ID to get the wiki-pages for + * @return a list of pages in the project's wiki + * @throws GitLabApiException if any exception occurs + */ + public List getPages(Integer projectId) throws GitLabApiException { + return getPages(projectId, 1, this.getDefaultPerPage()); + } + + /** + * Get a list of project snippets. This only returns the first page of snippets. + * + * GET /projects/:id/wikis + * + * @param projectId the project ID to get the wiki pages for + * @param page the page to get + * @param perPage the number of wiki-pages per page + * @return a list of pages in project's wiki for the specified range + * @throws GitLabApiException if any exception occurs + */ + public List getPages(Integer projectId, int page, int perPage) throws GitLabApiException { + Response response = get(Response.Status.OK, getPageQueryParams(page, perPage), "projects", projectId, "wikis"); + return response.readEntity(new GenericType>() {}); + } + + /** + * Get a Pager of project's wiki pages. + * + * GET /projects/:id/wikis + * + * @param projectId the project ID to get the wiki-pages for + * @param itemsPerPage the number of wiki-pages per page + * @return the Pager of wiki-pages + * @throws GitLabApiException if any exception occurs + */ + public Pager getPages(Integer projectId, int itemsPerPage) throws GitLabApiException { + return (new Pager<>(this, WikiPage.class, itemsPerPage, null, "projects", projectId, "wikis")); + } + + /** + * Get a single page of project wiki. + * + * GET /projects/:id/wikis/:slug + * + * @param projectId the project ID to get the wiki page for + * @param slug the slug of the project's wiki page + * @return the specified project Snippet + * @throws GitLabApiException if any exception occurs + */ + public WikiPage getPage(Integer projectId, String slug) throws GitLabApiException { + Response response = get(Response.Status.OK, null, "projects", projectId, "wikis", slug); + return (response.readEntity(WikiPage.class)); + } + + /** + * Get a single page of project wiki as an Optional instance. + * + * GET /projects/:id/wikis/:slug + * + * @param projectId the project ID to get the snippet for + * @param slug the slug of the project's wiki page + * @return the specified project Snippet as an Optional instance + */ + public Optional getOptionalPage(Integer projectId, String slug) { + try { + return (Optional.ofNullable(getPage(projectId, slug))); + } catch (GitLabApiException glae) { + return (GitLabApi.createOptionalFromException(glae)); + } + } + + /** + * Creates a new project wiki page. The user must have permission to create new wiki page. + * + * POST /projects/:id/wikis + * + * @param projectId the ID of the project owned by the authenticated user, required + * @param title the title of a snippet, required + * @param content the content of a wiki page, required + * @return a WikiPage instance with info on the created page + * @throws GitLabApiException if any exception occurs + */ + public WikiPage createPage(Integer projectId, String title, String content) throws GitLabApiException { + // one of title or content is required + GitLabApiForm formData = new GitLabApiForm() + .withParam("title", title) + .withParam("content", content); + + Response response = post(Response.Status.CREATED, formData, "projects", projectId, "wikis"); + return (response.readEntity(WikiPage.class)); + } + + /** + * Updates an existing project wiki page. The user must have permission to change an existing wiki page. + * + * PUT /projects/:id/wikis/:slug + * + * @param projectId the ID of the project owned by the authenticated user, required + * @param slug the slug of the project's wiki page, required + * @param title the title of a snippet, optional + * @param content the content of a page, optional. Either title or content must be supplied. + * @return a WikiPage instance with info on the updated page + * @throws GitLabApiException if any exception occurs + */ + public WikiPage updatePage(Integer projectId, String slug, String title, String content) throws GitLabApiException { + + GitLabApiForm formData = new GitLabApiForm() + .withParam("title", title) + .withParam("slug", slug, true) + .withParam("content", content); + + Response response = put(Response.Status.OK, formData.asMap(), "projects", projectId, "wikis", slug); + return (response.readEntity(WikiPage.class)); + } + + /** + * Deletes an existing project wiki page. This is an idempotent function and deleting a non-existent page does + * not cause an error. + * + * DELETE /projects/:id/wikis/:slug + * + * @param projectId the project ID + * @param slug the slug of the project's wiki page + * @throws GitLabApiException if any exception occurs + */ + public void deletePage(Integer projectId, String slug) throws GitLabApiException { + delete(Response.Status.NO_CONTENT, null, "projects", projectId, "wikis", slug); + } + +} diff --git a/src/main/java/org/gitlab4j/api/models/WikiPage.java b/src/main/java/org/gitlab4j/api/models/WikiPage.java new file mode 100644 index 000000000..686d01a52 --- /dev/null +++ b/src/main/java/org/gitlab4j/api/models/WikiPage.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Greg Messner + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.gitlab4j.api.models; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class WikiPage { + + private String title; + private String content; + private String slug; + private String format; + + public WikiPage() { + } + + public WikiPage(String title, String slug, String content) { + this.title = title; + this.slug = slug; + this.content = content; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getSlug() { + return slug; + } + + public void setSlug(String slug) { + this.slug = slug; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } +} diff --git a/src/test/java/org/gitlab4j/api/TestWikisApi.java b/src/test/java/org/gitlab4j/api/TestWikisApi.java new file mode 100644 index 000000000..b159da730 --- /dev/null +++ b/src/test/java/org/gitlab4j/api/TestWikisApi.java @@ -0,0 +1,190 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Greg Messner + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.gitlab4j.api; + +import org.gitlab4j.api.GitLabApi.ApiVersion; +import org.gitlab4j.api.models.Project; +import org.gitlab4j.api.models.WikiPage; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; +import static org.junit.Assume.assumeTrue; + +/** + * In order for these tests to run you must set the following properties in ~/test-gitlab4j.properties + *

+ * TEST_NAMESPACE + * TEST_PROJECT_NAME + * TEST_HOST_URL + * TEST_PRIVATE_TOKEN + *

+ * If any of the above are NULL, all tests in this class will be skipped. + */ +public class TestWikisApi { + + // The following needs to be set to your test repository + private static final String TEST_NAMESPACE; + private static final String TEST_PROJECT_NAME; + private static final String TEST_HOST_URL; + private static final String TEST_PRIVATE_TOKEN; + private static final String TEST_WIKI_TITLE_PREFIX = "Test Wiki: "; + private static GitLabApi gitLabApi; + private static Integer testProjectId; + private static String testContent; + + static { + TEST_NAMESPACE = TestUtils.getProperty("TEST_NAMESPACE"); + TEST_PROJECT_NAME = TestUtils.getProperty("TEST_PROJECT_NAME"); + TEST_HOST_URL = TestUtils.getProperty("TEST_HOST_URL"); + TEST_PRIVATE_TOKEN = TestUtils.getProperty("TEST_PRIVATE_TOKEN"); + } + + public TestWikisApi() { + super(); + } + + @BeforeClass + public static void setup() { + + String problems = ""; + if (TEST_NAMESPACE == null || TEST_NAMESPACE.trim().isEmpty()) { + problems += "TEST_NAMESPACE cannot be empty\n"; + } + + if (TEST_HOST_URL == null || TEST_HOST_URL.trim().isEmpty()) { + problems += "TEST_HOST_URL cannot be empty\n"; + } + + if (TEST_PRIVATE_TOKEN == null || TEST_PRIVATE_TOKEN.trim().isEmpty()) { + problems += "TEST_PRIVATE_TOKEN cannot be empty\n"; + } + + if (problems.isEmpty()) { + gitLabApi = new GitLabApi(ApiVersion.V4, TEST_HOST_URL, TEST_PRIVATE_TOKEN); + } else { + System.err.print(problems); + } + + if (gitLabApi != null) { + try { + Project project = gitLabApi.getProjectApi().getProject(TEST_NAMESPACE, TEST_PROJECT_NAME); + testProjectId = project.getId(); + } catch (Exception e) { + System.err.print(e.getMessage()); + gitLabApi = null; + } + } + + testContent = "This is a test content and must be deleted after testing."; + + deleteAllTestWikiPages(); + } + + @AfterClass + public static void teardown() throws GitLabApiException { + deleteAllTestWikiPages(); + } + + private static void deleteAllTestWikiPages() { + if (gitLabApi != null) { + try { + List wikiPages = gitLabApi.getWikisApi().getPages(testProjectId); + wikiPages.stream().filter(wp -> wp.getTitle().startsWith(TEST_WIKI_TITLE_PREFIX)).map(WikiPage::getSlug).forEach(slug -> { + try { + gitLabApi.getWikisApi().deletePage(testProjectId, slug); + } catch (GitLabApiException ignored) { + } + }); + } catch (GitLabApiException ignore) { + + } + } + } + + @Before + public void beforeMethod() { + assumeTrue(gitLabApi != null); + } + + private WikiPage createWikiPage(String title, String content) throws GitLabApiException { + return (gitLabApi.getWikisApi().createPage(testProjectId, title, content)); + } + + @Test + public void testCreate() throws GitLabApiException { + String title = TEST_WIKI_TITLE_PREFIX + "Test createWikiPage()"; + WikiPage wikiPage = createWikiPage(title, testContent); + assertNotNull(wikiPage); + assertEquals(title, wikiPage.getTitle()); + assertEquals(testContent, wikiPage.getContent()); + } + + @Test + public void testUpdate() throws GitLabApiException { + String title = TEST_WIKI_TITLE_PREFIX + "Test createWikiPage()"; + WikiPage wikiPage = createWikiPage(title, testContent); + assertNotNull(wikiPage); + + title = TEST_WIKI_TITLE_PREFIX + "Test updateWikiPage()"; + wikiPage = gitLabApi.getWikisApi().updatePage(testProjectId, wikiPage.getSlug(), title, "some content"); + assertEquals(title, wikiPage.getTitle()); + assertEquals("some content", wikiPage.getContent()); + } + + @Test + public void testListWikiPages() throws GitLabApiException { + String title = TEST_WIKI_TITLE_PREFIX + "Test listWikiPages()"; + WikiPage newWikiPage = createWikiPage(title, testContent); + assertNotNull(newWikiPage); + + String wikiPageSlug = newWikiPage.getSlug(); + List wikiPages = gitLabApi.getWikisApi().getPages(testProjectId); + assertNotNull(wikiPages); + + wikiPages.stream().filter(wp -> wp.getSlug().equals(wikiPageSlug)).forEach(wp -> { + assertEquals(title, wp.getTitle()); + assertEquals(wikiPageSlug, wp.getSlug()); + }); + } + + @Test + public void testDeleteWikiPage() throws GitLabApiException { + String title = TEST_WIKI_TITLE_PREFIX + "Test listWikiPages()"; + WikiPage createdWikiPage = createWikiPage(title, testContent); + assertNotNull(createdWikiPage); + + String wikiPageSlug = createdWikiPage.getSlug(); + gitLabApi.getWikisApi().deletePage(testProjectId, wikiPageSlug); + List wikiPages = gitLabApi.getWikisApi().getPages(testProjectId); + if (wikiPages.stream().anyMatch(wp -> wp.getSlug().equals(wikiPageSlug))) { + fail("WikiPage was not deleted."); + } + } + +}