Skip to content

Commit

Permalink
Add option to fork default branch only (#1995)
Browse files Browse the repository at this point in the history
* add only fork default branch

* Remove owner validation in fork builder tests

* update fork tests from personal to org account

* improve test coverage

* remove mockito test

* improve more test coverage

* mvn spotless:apply

* change sleep method scope

* Update src/test/java/org/kohsuke/github/GHRepositoryForkBuilderTest.java

* Update src/test/java/org/kohsuke/github/GHRepositoryForkBuilderTest.java

* Update src/test/java/org/kohsuke/github/GHRepositoryForkBuilderTest.java

* Update src/test/java/org/kohsuke/github/GHRepositoryForkBuilderTest.java

* Cleanup extra test files

---------

Co-authored-by: Liam Newman <[email protected]>
  • Loading branch information
Alaurant and bitwiseman authored Jan 21, 2025
1 parent 8714d1b commit d37839b
Show file tree
Hide file tree
Showing 80 changed files with 9,386 additions and 36 deletions.
51 changes: 16 additions & 35 deletions src/main/java/org/kohsuke/github/GHRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.Reader;
import java.net.URL;
import java.util.Arrays;
Expand Down Expand Up @@ -1458,23 +1457,11 @@ public PagedIterable<GHRepository> listForks(final ForkSort sort) {
* @return Newly forked repository that belong to you.
* @throws IOException
* the io exception
* @deprecated Use {@link #createFork()}
*/
@Deprecated
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 this.createFork().create();
}

/**
Expand Down Expand Up @@ -1503,27 +1490,11 @@ public GHBranchSync sync(String branch) throws IOException {
* @return Newly forked repository that belong to you.
* @throws IOException
* the io exception
* @deprecated Use {@link #createFork()}
*/
@Deprecated
public GHRepository forkTo(GHOrganization org) throws IOException {
root().createRequest()
.method("POST")
.with("organization", org.getLogin())
.withUrlPath(getApiTailUrl("forks"))
.send();

// this API is asynchronous. we need to wait for a bit
for (int i = 0; i < 10; i++) {
GHRepository r = org.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 into " + org.getLogin() + " but can't find the new repository");
return this.createFork().organization(org).create();
}

/**
Expand Down Expand Up @@ -3453,4 +3424,14 @@ public void deleteAutolink(int autolinkId) throws IOException {
.send();
}

/**
* Create fork gh repository fork builder.
* (https://docs.github.com/en/rest/repos/forks?apiVersion=2022-11-28#create-a-fork)
*
* @return the gh repository fork builder
*/
public GHRepositoryForkBuilder createFork() {
return new GHRepositoryForkBuilder(this);
}

}
144 changes: 144 additions & 0 deletions src/main/java/org/kohsuke/github/GHRepositoryForkBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package org.kohsuke.github;

import java.io.IOException;
import java.io.InterruptedIOException;

/**
* A builder pattern object for creating a fork of a repository.
*
* @see GHRepository#createFork() GHRepository#createFork()GHRepository#createFork()
* @see <a href="https://docs.github.com/en/rest/repos/forks#create-a-fork">Repository fork API</a>
*/
public class GHRepositoryForkBuilder {
private final GHRepository repo;
private final Requester req;
private String organization;
private String name;
private Boolean defaultBranchOnly;

static int FORK_RETRY_INTERVAL = 3000;

/**
* Instantiates a new Gh repository fork builder.
*
* @param repo
* the repository
*/
GHRepositoryForkBuilder(GHRepository repo) {
this.repo = repo;
this.req = repo.root().createRequest();
}

/**
* Sets whether to fork only the default branch.
*
* @param defaultBranchOnly
* the default branch only
* @return the gh repository fork builder
*/
public GHRepositoryForkBuilder defaultBranchOnly(boolean defaultBranchOnly) {
this.defaultBranchOnly = defaultBranchOnly;
return this;
}

/**
* Specifies the target organization for the fork.
*
* @param organization
* the organization
* @return the gh repository fork builder
*/
public GHRepositoryForkBuilder organization(GHOrganization organization) {
this.organization = organization.getLogin();
return this;
}

/**
* Sets a custom name for the forked repository.
*
* @param name
* the desired repository name
* @return the builder
*/
public GHRepositoryForkBuilder name(String name) {
this.name = name;
return this;
}

/**
* Creates the fork with the specified parameters.
*
* @return the gh repository
* @throws IOException
* the io exception
*/
public GHRepository create() throws IOException {
if (defaultBranchOnly != null) {
req.with("default_branch_only", defaultBranchOnly);
}
if (organization != null) {
req.with("organization", organization);
}
if (name != null) {
req.with("name", name);
}

req.method("POST").withUrlPath(repo.getApiTailUrl("forks")).send();

// this API is asynchronous. we need to wait for a bit
for (int i = 0; i < 10; i++) {
GHRepository r = lookupForkedRepository();
if (r != null) {
return r;
}
sleep(FORK_RETRY_INTERVAL);
}
throw new IOException(createTimeoutMessage());
}

private GHRepository lookupForkedRepository() throws IOException {
String repoName = name != null ? name : repo.getName();

if (organization != null) {
return repo.root().getOrganization(organization).getRepository(repoName);
}
return repo.root().getMyself().getRepository(repoName);
}

/**
* Sleep.
*
* @param millis
* the millis
* @throws IOException
* the io exception
*/
void sleep(int millis) throws IOException {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw (IOException) new InterruptedIOException().initCause(e);
}
}

/**
* Create timeout message string.
*
* @return the string
*/
String createTimeoutMessage() {
StringBuilder message = new StringBuilder(repo.getFullName());
message.append(" was forked");

if (organization != null) {
message.append(" into ").append(organization);
}

if (name != null) {
message.append(" with name ").append(name);
}

message.append(" but can't find the new repository");
return message.toString();
}
}
Loading

0 comments on commit d37839b

Please sign in to comment.