Skip to content

Commit

Permalink
Export of internal change
Browse files Browse the repository at this point in the history
  • Loading branch information
Yannic committed Feb 29, 2020
1 parent ae02df7 commit fe276db
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 23 deletions.
3 changes: 2 additions & 1 deletion docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2131,7 +2131,7 @@ version_selector | `latestVersionSelector`<br><p>Select a custom version (tag)to

Creates changes in a new pull request in the destination.

`gitHubPrDestination git.github_pr_destination(url, destination_ref="master", pr_branch=None, title=None, body=None, integrates=None, api_checker=None, update_description=False)`
`gitHubPrDestination git.github_pr_destination(url, destination_ref="master", pr_destination_url=None, pr_branch=None, title=None, body=None, integrates=None, api_checker=None, update_description=False)`


#### Parameters:
Expand All @@ -2140,6 +2140,7 @@ Parameter | Description
--------- | -----------
url | `string`<br><p>Url of the GitHub project. For example "https://github.com/google/copybara'"</p>
destination_ref | `string`<br><p>Destination reference for the change. By default 'master'</p>
pr_destination_url | `string`<br><p>Url of the GitHub project to create the PullRequest on. Set this if you want to push to a personal fork and create the PullRequest on the upstream project (e.g. because you don't have write access to the upstream repo).By default, `pr_destination_url` is the same as `url`.</p>
pr_branch | `string`<br><p>Customize the pull request branch. Any variable present in the message in the form of ${CONTEXT_REFERENCE} will be replaced by the corresponding stable reference (head, PR number, Gerrit change number, etc.).</p>
title | `string`<br><p>When creating (or updating if `update_description` is set) a pull request, use this title. By default it uses the change first line. This field accepts a template with labels. For example: `"Change ${CONTEXT_REFERENCE}"`</p>
body | `string`<br><p>When creating (or updating if `update_description` is set) a pull request, use this body. By default it uses the change summary. This field accepts a template with labels. For example: `"Change ${CONTEXT_REFERENCE}"`</p>
Expand Down
26 changes: 22 additions & 4 deletions java/com/google/copybara/git/GitHubPrDestination.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import com.google.copybara.util.Identity;
import com.google.copybara.util.console.Console;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;

Expand All @@ -64,6 +65,7 @@ public class GitHubPrDestination implements Destination<GitRevision> {

private final String url;
private final String destinationRef;
private final Optional<String> prDestinationUrl;
private final String prBranch;
private final GeneralOptions generalOptions;
private final GitHubOptions gitHubOptions;
Expand All @@ -82,6 +84,7 @@ public class GitHubPrDestination implements Destination<GitRevision> {
GitHubPrDestination(
String url,
String destinationRef,
Optional<String> prDestinationUrl,
@Nullable String prBranch,
GeneralOptions generalOptions,
GitHubOptions gitHubOptions,
Expand All @@ -97,6 +100,7 @@ public class GitHubPrDestination implements Destination<GitRevision> {
boolean updateDescription) {
this.url = Preconditions.checkNotNull(url);
this.destinationRef = Preconditions.checkNotNull(destinationRef);
this.prDestinationUrl = Preconditions.checkNotNull(prDestinationUrl);
this.prBranch = prBranch;
this.generalOptions = Preconditions.checkNotNull(generalOptions);
this.gitHubOptions = Preconditions.checkNotNull(gitHubOptions);
Expand Down Expand Up @@ -176,6 +180,12 @@ public ImmutableList<DestinationEffect> write(
return result.build();
}

String prBranch =
getQualifiedPullRequestBranchName(
writerContext.getOriginalRevision(),
writerContext.getWorkflowName(),
writerContext.getWorkflowIdentityUser());

if (!gitHubDestinationOptions.createPullRequest) {
console.infoFmt(
"Please create a PR manually following this link: %s/compare/%s...%s"
Expand All @@ -188,9 +198,7 @@ public ImmutableList<DestinationEffect> write(
GitHubApi api = gitHubOptions.newGitHubApi(getProjectName());

ImmutableList<PullRequest> pullRequests = api.getPullRequests(
getProjectName(),
PullRequestListParams.DEFAULT
.withHead(String.format("%s:%s", getUserNameFromUrl(url), prBranch)));
getProjectName(), PullRequestListParams.DEFAULT.withHead(prBranch));

ChangeMessage msg = ChangeMessage.parseMessage(transformResult.getSummary().trim());

Expand Down Expand Up @@ -275,7 +283,7 @@ private String asHttpsUrl() throws ValidationException {

@VisibleForTesting
String getProjectName() throws ValidationException {
return GitHubUtil.getProjectNameFromUrl(url);
return GitHubUtil.getProjectNameFromUrl(prDestinationUrl.orElse(url));
}

@VisibleForTesting
Expand All @@ -288,6 +296,16 @@ public Iterable<GitIntegrateChanges> getIntegrates() {
return integrates;
}

private String getQualifiedPullRequestBranchName(
@Nullable Revision changeRevision, String workflowName, String workflowIdentityUser)
throws ValidationException {
String branch = getPullRequestBranchName(changeRevision, workflowName, workflowIdentityUser);
if (prDestinationUrl.isPresent()) {
return String.format("%s:%s", getUserNameFromUrl(url), branch);
}
return branch;
}

private String getPullRequestBranchName(
@Nullable Revision changeRevision, String workflowName, String workflowIdentityUser)
throws ValidationException {
Expand Down
22 changes: 22 additions & 0 deletions java/com/google/copybara/git/GitModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -1199,6 +1200,18 @@ public GitDestination gitHubDestination(
named = true,
doc = "Destination reference for the change. By default 'master'",
defaultValue = "\"master\""),
@Param(
name = "pr_destination_url",
type = String.class,
defaultValue = "None",
noneable = true,
named = true,
positional = false,
doc =
"Url of the GitHub project to create the PullRequest on. Set this if you want to "
+ "push to a personal fork and create the PullRequest on the upstream project "
+ "(e.g. because you don't have write access to the upstream repo)."
+ "By default, `pr_destination_url` is the same as `url`."),
@Param(
name = "pr_branch",
type = String.class,
Expand Down Expand Up @@ -1297,6 +1310,7 @@ public GitDestination gitHubDestination(
public GitHubPrDestination githubPrDestination(
String url,
String destinationRef,
Object prDestinationUrl,
Object prBranch,
Object title,
Object body,
Expand All @@ -1309,12 +1323,20 @@ public GitHubPrDestination githubPrDestination(
// This restricts to github.com, we will have to revisit this to support setups like GitHub
// Enterprise.
check(GitHubUtil.isGitHubUrl(url), "'%s' is not a valid GitHub url", url);
check(prDestinationUrl == Starlark.NONE || GitHubUtil.isGitHubUrl((String)prDestinationUrl),
"'%s' is not a valid GitHub url", prDestinationUrl);
GitDestinationOptions destinationOptions = options.get(GitDestinationOptions.class);
return new GitHubPrDestination(
fixHttp(
checkNotEmpty(firstNotNull(destinationOptions.url, url), "url"),
thread.getCallerLocation()),
destinationRef,
Optional.ofNullable(
prDestinationUrl == Starlark.NONE ?
null :
fixHttp(
checkNotEmpty((String)prDestinationUrl, "pr_destination_url"),
thread.getCallerLocation())),
convertFromNoneable(prBranch, null),
generalOptions,
options.get(GitHubOptions.class),
Expand Down
104 changes: 95 additions & 9 deletions javatests/com/google/copybara/git/GitHubPrDestinationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,45 @@ public void testFindProject() throws ValidationException {
.onceInLog(MessageType.ERROR, ".*'https://github.com' is not a valid GitHub url.*");
}

private void checkFindProject(String url, String project) throws ValidationException {
GitHubPrDestination d = skylark.eval("r", "r = git.github_pr_destination("
+ " url = '" + url + "',"
+ " destination_ref = 'other',"
+ ")");

assertThat(d.getProjectName()).isEqualTo(project);
}

@Test
public void testFindUpstreamProject() throws ValidationException {
checkFindProjectFromUpstreamUrl("https://github.com/foo", "foo");
checkFindProjectFromUpstreamUrl("https://github.com/foo/bar", "foo/bar");
checkFindProjectFromUpstreamUrl("https://github.com/foo.git", "foo");
checkFindProjectFromUpstreamUrl("https://github.com/foo/", "foo");
checkFindProjectFromUpstreamUrl("git+https://github.com/foo", "foo");
checkFindProjectFromUpstreamUrl("[email protected]/foo", "foo");
checkFindProjectFromUpstreamUrl(
"[email protected]:org/internal_repo_name.git", "org/internal_repo_name");
ValidationException e =
assertThrows(
ValidationException.class,
() -> checkFindProjectFromUpstreamUrl("https://github.com", "foo"));
console
.assertThat()
.onceInLog(MessageType.ERROR, ".*'https://github.com' is not a valid GitHub url.*");
}

private void checkFindProjectFromUpstreamUrl(
String url, String project) throws ValidationException {
GitHubPrDestination d = skylark.eval("r", "r = git.github_pr_destination("
+ " url = 'https://github.com/google/copybara',"
+ " pr_destination_url = '" + url + "',"
+ " destination_ref = 'other',"
+ ")");

assertThat(d.getProjectName()).isEqualTo(project);
}

@Test
public void testIntegratesCanBeRemoved() throws Exception {
GitHubPrDestination d = skylark.eval("r", "r = git.github_pr_destination("
Expand All @@ -464,15 +503,6 @@ public void testIntegratesCanBeRemoved() throws Exception {
assertThat(d.getIntegrates()).isEmpty();
}

private void checkFindProject(String url, String project) throws ValidationException {
GitHubPrDestination d = skylark.eval("r", "r = git.github_pr_destination("
+ " url = '" + url + "',"
+ " destination_ref = 'other',"
+ ")");

assertThat(d.getProjectName()).isEqualTo(project);
}

@Test
public void testWriteNoMaster() throws ValidationException, IOException, RepoException {
GitHubPrDestination d = skylark.eval("r", "r = git.github_pr_destination("
Expand Down Expand Up @@ -530,6 +560,62 @@ public void testWriteNoMaster() throws ValidationException, IOException, RepoExc
+ "DummyOrigin-RevId: one\n");
}

@Test
public void testPrDestinationUrl() throws ValidationException, IOException, RepoException {
GitHubPrDestination d = skylark.eval("r", "r = git.github_pr_destination("
+ " url = 'https://github.com/foo',"
+ " pr_destination_url = 'https://github.com/bar',"
+ ")");
DummyRevision dummyRevision = new DummyRevision("dummyReference", "feature");
WriterContext writerContext =
new WriterContext("piper_to_github_pr", "TEST", false, dummyRevision,
Glob.ALL_FILES.roots());
String branchName =
Identity.computeIdentity(
"OriginGroupIdentity",
dummyRevision.contextReference(),
writerContext.getWorkflowName(),
"copy.bara.sky",
writerContext.getWorkflowIdentityUser());

gitUtil.mockApi(
"GET",
"https://api.github.com/repos/bar/pulls?per_page=100&head=foo:" + branchName,
mockResponse("[]"));
gitUtil.mockApi(
"POST",
"https://api.github.com/repos/bar/pulls",
mockResponseAndValidateRequest(
"{\n"
+ " \"id\": 1,\n"
+ " \"number\": 12345,\n"
+ " \"state\": \"open\",\n"
+ " \"title\": \"test summary\",\n"
+ " \"body\": \"test summary\""
+ "}",
req ->
req.equals(
"{\"base\":\"master\",\"body\":\"test summary\\n\",\"head\":\""
+ branchName
+ "\",\"title\":\"test summary\"}")));

Writer<GitRevision> writer = d.newWriter(writerContext);
GitRepository remote = gitUtil.mockRemoteRepo("github.com/foo");
addFiles(remote, "master", "first change", ImmutableMap.<String, String>builder()
.put("foo.txt", "").build());

writeFile(this.workdir, "test.txt", "some content");
writer.write(
TransformResults.of(this.workdir, new DummyRevision("one")), Glob.ALL_FILES, console);

assertThat(remote.refExists(branchName)).isTrue();
assertThat(Iterables.transform(remote.log(branchName).run(), GitLogEntry::getBody))
.containsExactly("first change\n",
"test summary\n"
+ "\n"
+ "DummyOrigin-RevId: one\n");
}

@Test
public void testBranchNameFromUserWithLabel() throws ValidationException, IOException, RepoException {
testBranchNameFromUser("test${CONTEXT_REFERENCE}", "test_feature", "&feature");
Expand Down
16 changes: 7 additions & 9 deletions third_party/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ package(
java_library(
name = "guava",
exports = [
"@maven//:com_google_guava_failureaccess",
"@maven//:com_google_guava_failureaccess",
"@maven//:com_google_guava_guava",
],
)
Expand Down Expand Up @@ -95,18 +95,18 @@ java_library(
name = "truth",
testonly = 1,
exports = [
"@maven//:com_googlecode_java_diff_utils_diffutils",
"@maven//:com_google_truth_truth",
"@maven//:com_googlecode_java_diff_utils_diffutils",
],
)

java_library(
name = "google_http_client",
exports = [
"@maven//:com_google_code_gson_gson",
"@maven//:com_google_http_client_google_http_client",
"@maven//:com_google_http_client_google_http_client_gson",
"@maven//:com_google_code_gson_gson",
"@maven//:commons_codec_commons_codec",
"@maven//:commons_codec_commons_codec",
],
)

Expand Down Expand Up @@ -152,20 +152,18 @@ java_library(
"@maven//:com_google_flogger_flogger",
],
runtime_deps = [
"@maven//:com_google_flogger_flogger_system_backend"
]
"@maven//:com_google_flogger_flogger_system_backend",
],
)

java_library(
name = "hg_testing",
testonly = 1,
exports = [
"//java/com/google/copybara/hg/testing",
]
],
)

# Required temporarily until @io_bazel//src/main/java/com/google/devtools/build/lib/syntax/...
# is fixed
exports_files(["bazel.patch"])


0 comments on commit fe276db

Please sign in to comment.