Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fork): Fork default branch only #1994

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
101 changes: 77 additions & 24 deletions src/main/java/org/kohsuke/github/GHRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -1455,26 +1455,14 @@ public PagedIterable<GHRepository> 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);
}

/**
Expand All @@ -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 {
Comment on lines +1501 to +1515
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You did basically exactly what I ask for with the deprecations, thanks!
Did you leave out the public GHRepository createFork() intentionally or just WIP?
If you still plan to provide the method overload with few parameters, the right signature is public GHRepository createFork(boolean defaultBranchOnly) instead of no parameters. What are your thoughts?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WiP, definitely. I'll work on it, thanks!


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;
}
Expand All @@ -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);
}

/**
Expand Down
30 changes: 30 additions & 0 deletions src/test/java/org/kohsuke/github/GHRepositoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Member

@bitwiseman bitwiseman Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at the test for forkTo():

@Test
public void testOrgFork() throws Exception {
cleanupRepository(GITHUB_API_TEST_ORG + "/rubywm");
gitHub.getRepository("kohsuke/rubywm").forkTo(gitHub.getOrganization(GITHUB_API_TEST_ORG));
}

That might help.

Note, it uses GITHUB_API_TEST_ORG but you can you a different org while you're trying things out. When you're basically ready, we can re-record the using GITHUB_API_TEST_ORG .

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.
*
Expand Down
Loading