Skip to content
Merged
60 changes: 60 additions & 0 deletions src/main/java/org/kohsuke/github/GHPullRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,66 @@ public enum MergeMethod {
REBASE
}

/**
* Request to enable auto merge for a pull request.
*
* @param authorEmail
* The email address to associate with this merge.
* @param clientMutationId
* A unique identifier for the client performing the mutation.
* @param commitBody
* Commit body to use for the commit when the PR is mergable; if omitted, a default message will be used.
* NOTE: when merging with a merge queue any input value for commit message is ignored.
* @param commitHeadline
* Commit headline to use for the commit when the PR is mergable; if omitted, a default message will be
* used. NOTE: when merging with a merge queue any input value for commit headline is ignored.
* @param expectedHeadOid
* The expected head OID of the pull request.
* @param mergeMethod
* The merge method to use. If omitted, defaults to `MERGE`. NOTE: when merging with a merge queue any
* input value for merge method is ignored.
* @throws IOException
* the io exception
*/
public void enablePullRequestAutoMerge(String authorEmail,
String clientMutationId,
String commitBody,
String commitHeadline,
String expectedHeadOid,
MergeMethod mergeMethod) throws IOException {

StringBuilder inputBuilder = new StringBuilder();
addParameter(inputBuilder, "pullRequestId", this.getNodeId());
addOptionalParameter(inputBuilder, "authorEmail", authorEmail);
addOptionalParameter(inputBuilder, "clientMutationId", clientMutationId);
addOptionalParameter(inputBuilder, "commitBody", commitBody);
addOptionalParameter(inputBuilder, "commitHeadline", commitHeadline);
addOptionalParameter(inputBuilder, "expectedHeadOid", expectedHeadOid);
addOptionalParameter(inputBuilder, "mergeMethod", mergeMethod);

String graphqlBody = "mutation EnableAutoMerge { enablePullRequestAutoMerge(input: {" + inputBuilder + "}) { "
+ "pullRequest { id } } }";

root().createGraphQLRequest(graphqlBody).sendGraphQL();

refresh();
}

private void addOptionalParameter(StringBuilder inputBuilder, String name, Object value) {
if (value != null) {
addParameter(inputBuilder, name, value);
}
}

private void addParameter(StringBuilder inputBuilder, String name, Object value) {
Objects.requireNonNull(value);
String formatString = " %s: \"%s\"";
if (value instanceof Enum) {
formatString = " %s: %s";
}

inputBuilder.append(String.format(formatString, name, value));
}
/**
* The status of auto merging a {@linkplain GHPullRequest}.
*
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/kohsuke/github/GitHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,21 @@ Requester createRequest() {
return requester;
}

/**
* Creates a request to GitHub GraphQL API.
*
* @param query
* the query for the GraphQL
* @return the requester
*/
@Nonnull
Requester createGraphQLRequest(String query) {
return createRequest().method("POST")
.rateLimit(RateLimitTarget.GRAPHQL)
.with("query", query)
.withUrlPath("/graphql");
}

/**
* Intern.
*
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/org/kohsuke/github/Requester.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.commons.io.IOUtils;
import org.kohsuke.github.connector.GitHubConnectorResponse;
import org.kohsuke.github.function.InputStreamFunction;
import org.kohsuke.github.internal.graphql.response.GHGraphQLResponse;

import java.io.ByteArrayInputStream;
import java.io.IOException;
Expand Down Expand Up @@ -103,6 +104,37 @@ public <T> T fetchInto(@Nonnull T existingInstance) throws IOException {
.body();
}

/**
* Sends a GraphQL request with no response
*
* @throws IOException
* the io exception
*/
public void sendGraphQL() throws IOException {
fetchGraphQL(GHGraphQLResponse.ObjectResponse.class);
}

/**
* Sends a request and parses the response into the given type via databinding in GraphQL response.
*
* @param <T>
* the type parameter
* @param type
* the type
* @return an instance of {@code GHGraphQLResponse<T>}
* @throws IOException
* if the server returns 4xx/5xx responses.
*/
public <T extends GHGraphQLResponse<S>, S> S fetchGraphQL(@Nonnull Class<T> type) throws IOException {
T response = fetch(type);

if (!response.isSuccessful()) {
throw new IOException("GraphQL request failed by:" + response.getErrorMessages());
}

return response.getData();
}

/**
* Makes a request and just obtains the HTTP status code. Method does not throw exceptions for many status codes
* that would otherwise throw.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.kohsuke.github.internal.graphql.response;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
* A response of GraphQL.
* <p>
* This class is used to parse the response of GraphQL.
* </p>
*
* @param <T>
* the type of data
*/
public class GHGraphQLResponse<T> {

private final T data;

private final List<GraphQLError> errors;

/**
* @param data
* GraphQL success response
* @param errors
* GraphQL failure response, This will be empty if not fail
*/
@JsonCreator
@SuppressFBWarnings(value = { "EI_EXPOSE_REP2" }, justification = "Spotbugs also doesn't like this")
public GHGraphQLResponse(@JsonProperty("data") T data, @JsonProperty("errors") List<GraphQLError> errors) {
if (errors == null) {
errors = Collections.emptyList();
}
this.data = data;
this.errors = Collections.unmodifiableList(errors);
}

/**
* @return request is succeeded. True when error list is empty.
*/
public boolean isSuccessful() {
return errors.isEmpty();
}

/**
* @return GraphQL success response
*/
public T getData() {
if (!isSuccessful()) {
throw new RuntimeException("Response not successful, data invalid");
}

return data;
}

/**
* @return GraphQL error messages from Github Response. Empty list when no errors occurred.
*/
public List<String> getErrorMessages() {
return errors.stream().map(GraphQLError::getMessage).collect(Collectors.toList());
}

/**
* A error of GraphQL response. Minimum implementation for GraphQL error.
*/
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_FIELD", "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" },
justification = "JSON API")
private static class GraphQLError {
private String message;

public String getMessage() {
return message;
}
}

/**
* A GraphQL response with basic Object data type.
*/
public static class ObjectResponse extends GHGraphQLResponse<Object> {
/**
* {@inheritDoc}
*/
@JsonCreator
@SuppressFBWarnings(value = { "EI_EXPOSE_REP2" }, justification = "Spotbugs also doesn't like this")
public ObjectResponse(@JsonProperty("data") Object data, @JsonProperty("errors") List<GraphQLError> errors) {
super(data, errors);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6703,5 +6703,95 @@
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
},
{
"name": "org.kohsuke.github.GHPullRequest$EnablePullRequestAutoMergeResponse",
"allPublicFields": true,
"allDeclaredFields": true,
"queryAllPublicConstructors": true,
"queryAllDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
},
{
"name": "org.kohsuke.github.GHPullRequest$EnablePullRequestAutoMergeResponse$EnablePullRequestAutoMerge",
"allPublicFields": true,
"allDeclaredFields": true,
"queryAllPublicConstructors": true,
"queryAllDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
},
{
"name": "org.kohsuke.github.GHPullRequest$EnablePullRequestAutoMergeResponse$EnablePullRequestAutoMerge$EnablePullRequestAutoMergePullRequest",
"allPublicFields": true,
"allDeclaredFields": true,
"queryAllPublicConstructors": true,
"queryAllDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
},
{
"name": "org.kohsuke.github.internal.graphql.response.GHGraphQLResponse",
"allPublicFields": true,
"allDeclaredFields": true,
"queryAllPublicConstructors": true,
"queryAllDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
},
{
"name": "org.kohsuke.github.internal.graphql.response.GHGraphQLResponse$GraphQLError",
"allPublicFields": true,
"allDeclaredFields": true,
"queryAllPublicConstructors": true,
"queryAllDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
},
{
"name": "org.kohsuke.github.internal.graphql.response.GHGraphQLResponse$ObjectResponse",
"allPublicFields": true,
"allDeclaredFields": true,
"queryAllPublicConstructors": true,
"queryAllDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredConstructors": true,
"queryAllPublicMethods": true,
"queryAllDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredMethods": true,
"allPublicClasses": true,
"allDeclaredClasses": true
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -1342,5 +1342,23 @@
},
{
"name": "org.kohsuke.github.SkipFromToString"
},
{
"name": "org.kohsuke.github.GHPullRequest$EnablePullRequestAutoMergeResponse"
},
{
"name": "org.kohsuke.github.GHPullRequest$EnablePullRequestAutoMergeResponse$EnablePullRequestAutoMerge"
},
{
"name": "org.kohsuke.github.GHPullRequest$EnablePullRequestAutoMergeResponse$EnablePullRequestAutoMerge$EnablePullRequestAutoMergePullRequest"
},
{
"name": "org.kohsuke.github.internal.graphql.response.GHGraphQLResponse"
},
{
"name": "org.kohsuke.github.internal.graphql.response.GHGraphQLResponse$GraphQLError"
},
{
"name": "org.kohsuke.github.internal.graphql.response.GHGraphQLResponse$ObjectResponse"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,4 @@ public void shouldMockGHPullRequest() throws IOException {

assertThat("Mock should return true", pullRequest.isDraft());
}

}
Loading