diff --git a/src/main/java/org/kohsuke/github/GHMeta.java b/src/main/java/org/kohsuke/github/GHMeta.java index bfa900f7eb..25cbcb0c3c 100644 --- a/src/main/java/org/kohsuke/github/GHMeta.java +++ b/src/main/java/org/kohsuke/github/GHMeta.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; // TODO: Auto-generated Javadoc /** @@ -12,7 +13,8 @@ * * @author Paulo Miguel Almeida * @see GitHub#getMeta() GitHub#getMeta() - * @see Get Meta + * @see Get + * Meta */ public class GHMeta { @@ -24,6 +26,10 @@ public GHMeta() { @JsonProperty("verifiable_password_authentication") private boolean verifiablePasswordAuthentication; + @JsonProperty("ssh_key_fingerprints") + private Map sshKeyFingerprints; + @JsonProperty("ssh_keys") + private List sshKeys; private List hooks; private List git; private List web; @@ -43,6 +49,24 @@ public boolean isVerifiablePasswordAuthentication() { return verifiablePasswordAuthentication; } + /** + * Gets ssh key fingerprints. + * + * @return the ssh key fingerprints + */ + public Map getSshKeyFingerprints() { + return Collections.unmodifiableMap(sshKeyFingerprints); + } + + /** + * Gets ssh keys. + * + * @return the ssh keys + */ + public List getSshKeys() { + return Collections.unmodifiableList(sshKeys); + } + /** * Gets hooks. * 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. * diff --git a/src/test/java/org/kohsuke/github/GitHubTest.java b/src/test/java/org/kohsuke/github/GitHubTest.java index ada391e326..fe277899ed 100644 --- a/src/test/java/org/kohsuke/github/GitHubTest.java +++ b/src/test/java/org/kohsuke/github/GitHubTest.java @@ -283,6 +283,8 @@ public void testListMyAuthorizations() throws IOException { public void getMeta() throws IOException { GHMeta meta = gitHub.getMeta(); assertThat(meta.isVerifiablePasswordAuthentication(), is(true)); + assertThat(meta.getSshKeyFingerprints().size(), equalTo(4)); + assertThat(meta.getSshKeys().size(), equalTo(3)); assertThat(meta.getApi().size(), equalTo(19)); assertThat(meta.getGit().size(), equalTo(36)); assertThat(meta.getHooks().size(), equalTo(4)); diff --git a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/getMeta/__files/1-meta.json b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/getMeta/__files/1-meta.json index 2baa8baf32..d66ad1746e 100644 --- a/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/getMeta/__files/1-meta.json +++ b/src/test/resources/org/kohsuke/github/GitHubTest/wiremock/getMeta/__files/1-meta.json @@ -1,5 +1,16 @@ { "verifiable_password_authentication": true, + "ssh_key_fingerprints": { + "SHA256_RSA": 1234567890, + "SHA256_DSA": 1234567890, + "SHA256_ECDSA": 1234567890, + "SHA256_ED25519": 1234567890 + }, + "ssh_keys": [ + "ssh-ed25519 ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "ecdsa-sha2-nistp256 ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "ssh-rsa ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ], "hooks": [ "192.30.252.0/22", "185.199.108.0/22",