Skip to content

Commit

Permalink
Expose GitHub create issue in starlark
Browse files Browse the repository at this point in the history
To create issues in feedback.

BUG=197664009
PiperOrigin-RevId: 392933907
Change-Id: I9ff303b733f90c519589c9be070871cd001dc8be
  • Loading branch information
hsudhof committed Aug 26, 2021
1 parent 10d3222 commit 323e89b
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 12 deletions.
17 changes: 17 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
- [git_merge_result](#git_merge_result)
- [github_api_obj](#github_api_obj)
- [github_api_obj.add_label](#github_api_objadd_label)
- [github_api_obj.create_issue](#github_api_objcreate_issue)
- [github_api_obj.create_status](#github_api_objcreate_status)
- [github_api_obj.delete_reference](#github_api_objdelete_reference)
- [github_api_obj.get_authenticated_user](#github_api_objget_authenticated_user)
Expand Down Expand Up @@ -2718,6 +2719,22 @@ Parameter | Description
number | `int`<br><p>Pull Request number</p>
labels | `sequence of string`<br><p>List of labels to add.</p>
<a id="github_api_obj.create_issue" aria-hidden="true"></a>
### github_api_obj.create_issue
Create a new issue.
`Issue github_api_obj.create_issue(title, body, assignees)`
#### Parameters:
Parameter | Description
--------- | -----------
title | `string`<br><p>Title of the issue</p>
body | `string`<br><p>Body of the issue.</p>
assignees | `sequence`<br><p>GitHub users to whom the issue will be assigned.</p>
<a id="github_api_obj.create_status" aria-hidden="true"></a>
### github_api_obj.create_status
Expand Down
30 changes: 30 additions & 0 deletions java/com/google/copybara/git/GitHubEndPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.flogger.FluentLogger;
import com.google.copybara.Endpoint;
import com.google.copybara.LazyResourceLoader;
import com.google.copybara.config.SkylarkUtil;
Expand All @@ -41,6 +43,8 @@
import com.google.copybara.git.github.api.GitHubApiException;
import com.google.copybara.git.github.api.GitHubApiException.ResponseCode;
import com.google.copybara.git.github.api.GitHubCommit;
import com.google.copybara.git.github.api.Issue;
import com.google.copybara.git.github.api.Issue.CreateIssueRequest;
import com.google.copybara.git.github.api.PullRequest;
import com.google.copybara.git.github.api.PullRequestComment;
import com.google.copybara.git.github.api.Ref;
Expand Down Expand Up @@ -72,6 +76,8 @@
doc = "GitHub API endpoint implementation for feedback migrations and after migration hooks.")
public class GitHubEndPoint implements Endpoint, StarlarkValue {

private static final FluentLogger logger = FluentLogger.forEnclosingClass();

private final LazyResourceLoader<GitHubApi> apiSupplier;
private final String url;
private final Console console;
Expand Down Expand Up @@ -539,6 +545,30 @@ public void addLabels(StarlarkInt prNumber, Sequence<?> labels)
}
}

@StarlarkMethod(
name = "create_issue",
doc = "Create a new issue.",
parameters = {
@Param(name = "title", named = true, doc = "Title of the issue"),
@Param(name = "body", named = true, doc = "Body of the issue."),
@Param(name = "assignees", named = true,
doc = "GitHub users to whom the issue will be assigned."),
})
public Issue createIssue(String title, String body, StarlarkList<?> assignees)
throws EvalException, RepoException {
try {
String project = ghHost.getProjectNameFromUrl(url);
return apiSupplier.load(console)
.createIssue(project, new CreateIssueRequest(title, body,
SkylarkUtil.convertStringList(assignees,
"Expected assignees to be a list of string.")));
} catch (ValidationException | RuntimeException e) {
throw Starlark.errorf(
"Error calling create_issue: %s - %s",
e.getMessage(), Throwables.getRootCause(e).getMessage());
}
}

@StarlarkMethod(
name = "post_issue_comment",
doc = "Post a comment on a issue.",
Expand Down
12 changes: 12 additions & 0 deletions java/com/google/copybara/git/github/api/GitHubApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.copybara.exception.RepoException;
import com.google.copybara.exception.ValidationException;
import com.google.copybara.git.github.api.GitHubApiException.ResponseCode;
import com.google.copybara.git.github.api.Issue.CreateIssueRequest;
import com.google.copybara.profiler.Profiler;
import com.google.copybara.profiler.Profiler.ProfilerTask;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -298,6 +299,17 @@ public Issue getIssue(String projectId, long number)
}
}

/**
* Create a issue
*/
public Issue createIssue(String projectId, CreateIssueRequest request)
throws RepoException, ValidationException {
try (ProfilerTask ignore = profiler.start("github_api_create_issue")) {
return transport.post(
String.format("repos/%s/issues", projectId), request, Issue.class);
}
}

/**
* Get all the refs for a repo (git ls-remote)
* @param projectId a project in the form of "google/copybara"
Expand Down
38 changes: 32 additions & 6 deletions java/com/google/copybara/git/github/api/Issue.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
package com.google.copybara.git.github.api;

import com.google.api.client.util.Key;
import com.google.common.collect.ImmutableList;
import java.util.List;
import net.starlark.java.eval.StarlarkValue;

/**
* Represents an issue returned by https://api.github.com/repos/REPO_ID/issues/NUMBER
*/
public class Issue extends PullRequestOrIssue {

@Key
private List<Label> labels;
public class Issue extends PullRequestOrIssue implements StarlarkValue {

@Key private List<Label> labels;


public List<Label> getLabels() {
return labels;
Expand All @@ -37,9 +40,32 @@ public void setLabels(List<Label> labels) {

@Override
public String toString() {
return getToStringHelper()
.add("labels", labels)
.toString();
return super.toString() + getToStringHelper();
}

/** Represents https://docs.github.com/en/rest/reference/issues#create-an-issue--parameters */
public static class CreateIssueRequest {
@Key private String title;
@Key private String body;
@Key private List<String> assignees;

public CreateIssueRequest(String title, String body, List<String> assignees) {
this.title = title;
this.body = body;
this.assignees = ImmutableList.copyOf(assignees);
}

public String getTitle() {
return title;
}

public String getBody() {
return body;
}

public ImmutableList<String> getAssignees() {
return ImmutableList.copyOf(assignees);
}
}

}
11 changes: 5 additions & 6 deletions java/com/google/copybara/git/github/api/PullRequestOrIssue.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import java.time.ZonedDateTime;
import java.util.List;
import javax.annotation.Nullable;
import net.starlark.java.annot.StarlarkMethod;
import net.starlark.java.eval.StarlarkInt;
import net.starlark.java.eval.StarlarkValue;

/**
Expand All @@ -44,16 +44,15 @@ public class PullRequestOrIssue implements StarlarkValue {
@Key private User assignee;
@Key private List<User> assignees;

@StarlarkMethod(name = "number", doc = "Pull Request number", structField = true)
public int getNumberForStarlark() {
// Sadly Starlark doesn't support long.
return Ints.saturatedCast(number);
}

public long getNumber() {
return number;
}

@StarlarkMethod(name = "number", doc = "Pull Request number", structField = true)
public StarlarkInt getNumberForSkylark() {
return StarlarkInt.of(number);
}
public String getState() {
return state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.google.copybara.git.github.api.GitHubApiTransport;
import com.google.copybara.git.github.api.GitHubCommit;
import com.google.copybara.git.github.api.Issue;
import com.google.copybara.git.github.api.Issue.CreateIssueRequest;
import com.google.copybara.git.github.api.Label;
import com.google.copybara.git.github.api.PullRequest;
import com.google.copybara.git.github.api.PullRequestComment;
Expand Down Expand Up @@ -365,6 +366,25 @@ public void testGetIssue() throws Exception {
.containsExactly("cla: yes");
}

@Test
public void testCreateIssue() throws Exception {
trainMockPost(
"/repos/example/project/issues", createValidator(TestCreateIssueRequest.class,
(ci) ->
ci.getTitle().equals("[TEST] example pull request one")
&& ci.getBody().equals("Example body.\n")
&& ci.getAssignees().equals(ImmutableList.of("foo", "bar"))),

getResource("issues_12345_testdata.json"));
Issue issue = api.createIssue("example/project",
new CreateIssueRequest("[TEST] example pull request one", "Example body.\n",
ImmutableList.of("foo", "bar")));

assertThat(issue.getNumber()).isEqualTo(12345);
assertThat(issue.getState()).isEqualTo("open");
assertThat(issue.getTitle()).isEqualTo("[TEST] example pull request one");
assertThat(issue.getBody()).isEqualTo("Example body.\r\n");
}

@Test
public void testCreateStatus() throws Exception {
Expand Down Expand Up @@ -670,6 +690,15 @@ public TestCreatePullRequest() {
}
}

/**
* We don't want CreateIssueRequest to be instantiable, this subclass sidesteps the issue.
**/
public static class TestCreateIssueRequest extends CreateIssueRequest {
public TestCreateIssueRequest() {
super("invalid", "invalid", ImmutableList.of("foo", "bar"));
}
}

/**
* We don't want CreatePullRequest to be instantiable, this subclass sidesteps the issue.
**/
Expand Down
17 changes: 17 additions & 0 deletions javatests/com/google/copybara/git/GitHubEndpointTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,23 @@ public void testPostComment() throws Exception {
.buildRequest(eq("POST"), contains("google/example/issues/12345/comments"));
}

@Test
public void testCreateIssue() throws Exception {
gitUtil.mockApi(eq("POST"), contains("/issues"), mockResponse(toJson(
ImmutableMap.of(
"number", 123456,
"title", "This is an issue"
))));
runFeedback(ImmutableList.<String>builder()
.add("res = ctx.destination.create_issue("
+ "title='This is an issue', body='body', assignees=['foo'])")
.addAll(checkFieldStarLark("res", "number", "123456"))
.addAll(checkFieldStarLark("res", "title", "'This is an issue'"))
.build());
verify(gitUtil.httpTransport())
.buildRequest(eq("POST"), contains("google/example/issues"));
}

private String toJson(Object obj) throws IOException {
return GsonFactory.getDefaultInstance().toPrettyString(obj);
}
Expand Down

0 comments on commit 323e89b

Please sign in to comment.