diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index ab60eafb86..4859eac77d 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1455,26 +1455,14 @@ public PagedIterable listForks(final ForkSort sort) { /** * Forks this repository as your repository. * - * @return Newly forked repository that belong to you. + * @return Newly forked repository that belongs to you. * @throws IOException * the io exception + * @deprecated Use {@link #createFork(String, String, boolean)} instead */ + @Deprecated(forRemoval = true) public GHRepository fork() throws IOException { - root().createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).send(); - - // this API is asynchronous. we need to wait for a bit - for (int i = 0; i < 10; i++) { - GHRepository r = root().getMyself().getRepository(name); - if (r != null) { - return r; - } - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - throw (IOException) new InterruptedIOException().initCause(e); - } - } - throw new IOException(this + " was forked but can't find the new repository"); + return createFork(null, null, false); } /** @@ -1500,20 +1488,61 @@ public GHBranchSync sync(String branch) throws IOException { * * @param org * the org - * @return Newly forked repository that belong to you. + * @return Newly forked repository that belongs to you. * @throws IOException * the io exception + * @deprecated Use {@link #createFork(String, String, boolean)} instead */ + @Deprecated(forRemoval = true) public GHRepository forkTo(GHOrganization org) throws IOException { - root().createRequest() - .method("POST") - .with("organization", org.getLogin()) - .withUrlPath(getApiTailUrl("forks")) - .send(); + return createFork(org.getLogin(), null, false); + } + + /** + * Creates a fork of this repository with optional parameters. + * + * @param organization + * the organization to fork to, or null to fork to the authenticated user's account + * @param name + * the name of the new repository, or null to use the same name as the original repository + * @param defaultBranchOnly + * whether to fork only the default branch + * @return the newly forked repository + * @throws IOException + * if an I/O error occurs + */ + public GHRepository createFork(@Nullable String organization, @Nullable String name, boolean defaultBranchOnly) + throws IOException { + + if (organization != null && organization.isEmpty()) { + throw new IllegalArgumentException("Organization cannot be empty. Pass null for default value."); + } + if (name != null && name.isEmpty()) { + throw new IllegalArgumentException("Name cannot be empty. Pass null for default value."); + } + if (name != null && !name.matches("^[a-zA-Z0-9._-]+$")) { + throw new IllegalArgumentException("Repository name contains invalid characters"); + } + Requester requester = root().createRequest().method("POST").withUrlPath(getApiTailUrl("forks")); + + requester.with("organization", organization); + requester.with("name", name); + if (defaultBranchOnly) { + requester.with("default_branch_only", true); + } + + requester.send(); // this API is asynchronous. we need to wait for a bit for (int i = 0; i < 10; i++) { - GHRepository r = org.getRepository(name); + organization = organization != null ? organization : root().getMyself().getLogin(); + name = name != null ? name : this.name; + GHRepository r; + try { + r = GHRepository.read(root(), root().getMyself().getLogin(), name); + } catch (FileNotFoundException e) { + r = null; + } if (r != null) { return r; } @@ -1523,7 +1552,31 @@ public GHRepository forkTo(GHOrganization org) throws IOException { throw (IOException) new InterruptedIOException().initCause(e); } } - throw new IOException(this + " was forked into " + org.getLogin() + " but can't find the new repository"); + throw new IOException(this + " was forked but can't find the new repository"); + } + + /** + * Creates a fork of this repository. + * + * @param defaultBranchOnly + * if true, only the default branch will be forked + * @return the newly forked repository + * @throws IOException + * if an I/O error occurs + */ + public GHRepository createFork(boolean defaultBranchOnly) throws IOException { + return createFork(null, null, defaultBranchOnly); + } + + /** + * Creates a fork of this repository with the default branch only. + * + * @return the newly forked repository + * @throws IOException + * if an I/O error occurs + */ + public GHRepository createFork() throws IOException { + return createFork(true); } /** diff --git a/src/test/java/org/kohsuke/github/GHRepositoryTest.java b/src/test/java/org/kohsuke/github/GHRepositoryTest.java index 4a339571a3..bc63b74e36 100644 --- a/src/test/java/org/kohsuke/github/GHRepositoryTest.java +++ b/src/test/java/org/kohsuke/github/GHRepositoryTest.java @@ -823,6 +823,36 @@ public void ghRepositorySearchBuilderForkDefaultResetForksSearchTerms() { assertThat(ghRepositorySearchBuilder.terms.stream().filter(item -> item.contains("fork:")).count(), is(0L)); } + /** + * Test createFork method with valid parameters. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + @Test + public void testCreateForkWithValidParameters() throws IOException { + String repositoryName = "rubywm"; + String upstreamRepositoryOrganization = "kohsuke"; + cleanupRepository(GITHUB_API_TEST_ORG + "/" + repositoryName); + GHRepository forkedRepository = gitHub.getRepository(upstreamRepositoryOrganization + "/" + repositoryName) + .createFork(gitHub.getOrganization(GITHUB_API_TEST_ORG).name, repositoryName, true); + assertThat(forkedRepository, notNullValue()); + assertThat(forkedRepository.getOwnerName(), equalTo("new-owner")); + assertThat(forkedRepository.getName(), equalTo("new-repo")); + } + + /** + * Test createFork method with invalid parameters. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + @Test(expected = IllegalArgumentException.class) + public void testCreateForkWithInvalidParameters() throws IOException { + GHRepository repository = getRepository(); + repository.createFork(null, "", true); + } + /** * List commit comments some comments. *