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",