Skip to content

Commit 3f87086

Browse files
committed
Support GitHub Enterprise
GitHub can be hosted by companies for their own usage (under their own URL). This changset removes the hard-coded url to `github.com` and makes it confligurable for a user, which GitHub-instances shall be supported. Closes #134
1 parent 73e23e1 commit 3f87086

19 files changed

+192
-87
lines changed

docs/reference.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,6 +3356,7 @@ Parameter | Description
33563356
Name | Type | Description
33573357
---- | ---- | -----------
33583358
<span style="white-space: nowrap;">`--allstar-app-ids`</span> | *list* | Flag used to set AllStar GitHub app id aliases. See https://github.com/ossf/allstar.
3359+
<span style="white-space: nowrap;">`--github-allowed-hosts`</span> | *list* | If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported.
33593360
<span style="white-space: nowrap;">`--github-api-bearer-auth`</span> | *boolean* | If using a token for GitHub access, bearer auth might be required
33603361
<span style="white-space: nowrap;">`--github-destination-delete-pr-branch`</span> | *boolean* | Overwrite git.github_destination delete_pr_branch field
33613362
<span style="white-space: nowrap;">`--gql-commit-history-override`</span> | *list* | Flag used to target GraphQL params 'first' arguments in the event the defaults are over or underusing the api ratelimit. The flag value should be semicolon separated. This should be rarely used for repos that don't fit well in our defaults. E.g. '50;5;5' represent 50 commits, 5 PRs for each commit, 5 reviews per PR
@@ -3404,6 +3405,7 @@ Name | Type | Description
34043405
<span style="white-space: nowrap;">`--git-destination-push`</span> | *string* | If set, overrides the git destination push reference.
34053406
<span style="white-space: nowrap;">`--git-destination-url`</span> | *string* | If set, overrides the git destination URL.
34063407
<span style="white-space: nowrap;">`--git-skip-checker`</span> | *boolean* | If true and git.destination has a configured checker, it will not be used in the migration.
3408+
<span style="white-space: nowrap;">`--github-allowed-hosts`</span> | *list* | If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported.
34073409
<span style="white-space: nowrap;">`--github-api-bearer-auth`</span> | *boolean* | If using a token for GitHub access, bearer auth might be required
34083410
<span style="white-space: nowrap;">`--github-destination-delete-pr-branch`</span> | *boolean* | Overwrite git.github_destination delete_pr_branch field
34093411
<span style="white-space: nowrap;">`--gql-commit-history-override`</span> | *list* | Flag used to target GraphQL params 'first' arguments in the event the defaults are over or underusing the api ratelimit. The flag value should be semicolon separated. This should be rarely used for repos that don't fit well in our defaults. E.g. '50;5;5' represent 50 commits, 5 PRs for each commit, 5 reviews per PR
@@ -3444,6 +3446,7 @@ Name | Type | Description
34443446
<span style="white-space: nowrap;">`--git-fuzzy-last-rev`</span> | *boolean* | By default Copybara will try to migrate the revision listed as the version in the metadata file from github. This flag tells Copybara to first find the git tag which most closely matches the metadata version, and use that for the migration.
34453447
<span style="white-space: nowrap;">`--git-origin-log-batch`</span> | *int* | Read the origin git log in batches of n commits. Might be needed for large migrations resulting in git logs of more than 1 GB.
34463448
<span style="white-space: nowrap;">`--git-origin-rebase-ref`</span> | *string* | When importing a change from a Git origin ref, it will be rebased to this ref, if set. A common use case: importing a Github PR, rebase it to the main branch (usually 'master'). Note that, if the repo uses submodules, they won't be rebased.
3449+
<span style="white-space: nowrap;">`--github-allowed-hosts`</span> | *list* | If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported.
34473450
<span style="white-space: nowrap;">`--github-api-bearer-auth`</span> | *boolean* | If using a token for GitHub access, bearer auth might be required
34483451
<span style="white-space: nowrap;">`--github-destination-delete-pr-branch`</span> | *boolean* | Overwrite git.github_destination delete_pr_branch field
34493452
<span style="white-space: nowrap;">`--gql-commit-history-override`</span> | *list* | Flag used to target GraphQL params 'first' arguments in the event the defaults are over or underusing the api ratelimit. The flag value should be semicolon separated. This should be rarely used for repos that don't fit well in our defaults. E.g. '50;5;5' represent 50 commits, 5 PRs for each commit, 5 reviews per PR
@@ -3539,6 +3542,7 @@ Name | Type | Description
35393542
<span style="white-space: nowrap;">`--git-destination-push`</span> | *string* | If set, overrides the git destination push reference.
35403543
<span style="white-space: nowrap;">`--git-destination-url`</span> | *string* | If set, overrides the git destination URL.
35413544
<span style="white-space: nowrap;">`--git-skip-checker`</span> | *boolean* | If true and git.destination has a configured checker, it will not be used in the migration.
3545+
<span style="white-space: nowrap;">`--github-allowed-hosts`</span> | *list* | If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported.
35423546
<span style="white-space: nowrap;">`--github-api-bearer-auth`</span> | *boolean* | If using a token for GitHub access, bearer auth might be required
35433547
<span style="white-space: nowrap;">`--github-destination-delete-pr-branch`</span> | *boolean* | Overwrite git.github_destination delete_pr_branch field
35443548
<span style="white-space: nowrap;">`--github-destination-pr-branch`</span> | *string* | If set, uses this branch for creating the pull request instead of using a generated one
@@ -3605,6 +3609,7 @@ Name | Type | Description
36053609
<span style="white-space: nowrap;">`--git-fuzzy-last-rev`</span> | *boolean* | By default Copybara will try to migrate the revision listed as the version in the metadata file from github. This flag tells Copybara to first find the git tag which most closely matches the metadata version, and use that for the migration.
36063610
<span style="white-space: nowrap;">`--git-origin-log-batch`</span> | *int* | Read the origin git log in batches of n commits. Might be needed for large migrations resulting in git logs of more than 1 GB.
36073611
<span style="white-space: nowrap;">`--git-origin-rebase-ref`</span> | *string* | When importing a change from a Git origin ref, it will be rebased to this ref, if set. A common use case: importing a Github PR, rebase it to the main branch (usually 'master'). Note that, if the repo uses submodules, they won't be rebased.
3612+
<span style="white-space: nowrap;">`--github-allowed-hosts`</span> | *list* | If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported.
36083613
<span style="white-space: nowrap;">`--github-api-bearer-auth`</span> | *boolean* | If using a token for GitHub access, bearer auth might be required
36093614
<span style="white-space: nowrap;">`--github-destination-delete-pr-branch`</span> | *boolean* | Overwrite git.github_destination delete_pr_branch field
36103615
<span style="white-space: nowrap;">`--github-force-import`</span> | *boolean* | Force import regardless of the state of the PR
@@ -3644,6 +3649,7 @@ Parameter | Description
36443649
Name | Type | Description
36453650
---- | ---- | -----------
36463651
<span style="white-space: nowrap;">`--allstar-app-ids`</span> | *list* | Flag used to set AllStar GitHub app id aliases. See https://github.com/ossf/allstar.
3652+
<span style="white-space: nowrap;">`--github-allowed-hosts`</span> | *list* | If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported.
36473653
<span style="white-space: nowrap;">`--github-api-bearer-auth`</span> | *boolean* | If using a token for GitHub access, bearer auth might be required
36483654
<span style="white-space: nowrap;">`--github-destination-delete-pr-branch`</span> | *boolean* | Overwrite git.github_destination delete_pr_branch field
36493655
<span style="white-space: nowrap;">`--gql-commit-history-override`</span> | *list* | Flag used to target GraphQL params 'first' arguments in the event the defaults are over or underusing the api ratelimit. The flag value should be semicolon separated. This should be rarely used for repos that don't fit well in our defaults. E.g. '50;5;5' represent 50 commits, 5 PRs for each commit, 5 reviews per PR

java/com/google/copybara/git/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ java_library(
7373
"//java/com/google/copybara/monitor",
7474
"//java/com/google/copybara/profiler",
7575
"//java/com/google/copybara/revision",
76+
"//java/com/google/copybara/starlark",
7677
"//java/com/google/copybara/templatetoken",
7778
"//java/com/google/copybara/transform",
7879
"//java/com/google/copybara/transform/patch",

java/com/google/copybara/git/GitHubOptions.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
import com.google.copybara.jcommander.DurationConverter;
4040
import com.google.copybara.jcommander.GreaterThanZeroListValidator;
4141
import com.google.copybara.jcommander.SemicolonSeparatedListSplitter;
42+
import com.google.copybara.starlark.StarlarkUtil;
4243
import com.google.copybara.util.console.Console;
44+
import net.starlark.java.eval.EvalException;
45+
4346
import java.io.IOException;
4447
import java.time.Duration;
4548
import java.util.List;
@@ -86,6 +89,27 @@ public class GitHubOptions implements Option {
8689
arity = 1)
8790
public boolean gitHubApiBearerAuth = false;
8891

92+
@Parameter(
93+
names = "--github-allowed-hosts",
94+
description = "If using GitHub Enterprise, one needs to specify valid hosts. By default only `github.com` is supported."
95+
)
96+
public List<String> gitHubAllowedHosts = ImmutableList.of("github.com");
97+
98+
public GitHubHost getGitHubHost(String url) throws EvalException {
99+
GitHubHost host = GitHubHost.fromUrl(url);
100+
StarlarkUtil.check(gitHubAllowedHosts.contains(host.getHost()), "'%s' is not a valid GitHub url", host.getHost());
101+
return host;
102+
}
103+
104+
public boolean isGithubUrl(String url)
105+
{
106+
GitHubHost host = GitHubHost.fromUrl(url);
107+
if(gitHubAllowedHosts.contains(host.getHost())){
108+
return host.isGitHubUrl(url);
109+
}
110+
111+
return false;
112+
}
89113

90114
public GitHubOptions(GeneralOptions generalOptions, GitOptions gitOptions) {
91115
this.generalOptions = Preconditions.checkNotNull(generalOptions);
@@ -100,7 +124,7 @@ public LazyResourceLoader<GitHubApi> newGitHubApiSupplier(
100124
GitHubHost ghHost) {
101125
return (console) -> {
102126
String project = ghHost.getProjectNameFromUrl(url);
103-
return newGitHubRestApi(project, checker, credentials, console);
127+
return newGitHubRestApi(ghHost, project, checker, credentials, console);
104128
};
105129
}
106130

@@ -112,7 +136,7 @@ public LazyResourceLoader<GitHubGraphQLApi> newGitHubGraphQLApiSupplier(
112136
GitHubHost ghHost) {
113137
return (console) -> {
114138
String project = ghHost.getProjectNameFromUrl(url);
115-
return newGitHubGraphQLApi(project, checker, credentials, console);
139+
return newGitHubGraphQLApi(ghHost, project, checker, credentials, console);
116140
};
117141
}
118142

@@ -121,9 +145,9 @@ public LazyResourceLoader<GitHubGraphQLApi> newGitHubGraphQLApiSupplier(
121145
*
122146
* <p>The project for 'https://github.com/foo/bar' is 'foo/bar'.
123147
*/
124-
public GitHubApi newGitHubRestApi(
148+
public GitHubApi newGitHubRestApi(GitHubHost ghHost,
125149
String gitHubProject, @Nullable CredentialFileHandler credentials) throws RepoException {
126-
return newGitHubRestApi(
150+
return newGitHubRestApi(ghHost,
127151
gitHubProject, /* checker= */ null, credentials, generalOptions.console());
128152
}
129153

@@ -134,6 +158,7 @@ public GitHubApi newGitHubRestApi(
134158
* <p>The project for 'https://github.com/foo/bar' is 'foo/bar'.
135159
*/
136160
public GitHubApi newGitHubRestApi(
161+
GitHubHost ghHost,
137162
String gitHubProject,
138163
@Nullable Checker checker,
139164
@Nullable CredentialFileHandler credentials,
@@ -144,7 +169,7 @@ public GitHubApi newGitHubRestApi(
144169
if (storePath == null) {
145170
storePath = "~/.git-credentials";
146171
}
147-
GitHubApiTransport transport = newTransport(repo, storePath, console);
172+
GitHubApiTransport transport = newTransport(ghHost, repo, storePath, console);
148173
if (checker != null) {
149174
transport = new GitHubApiTransportWithChecker(transport, new ApiChecker(checker, console));
150175
}
@@ -156,9 +181,9 @@ public GitHubApi newGitHubRestApi(
156181
*
157182
* <p>The project for 'https://github.com/foo/bar' is 'foo/bar'.
158183
*/
159-
public GitHubGraphQLApi newGitHubGraphQLApi(
184+
public GitHubGraphQLApi newGitHubGraphQLApi(GitHubHost ghHost,
160185
String gitHubProject, @Nullable CredentialFileHandler credentials) throws RepoException {
161-
return newGitHubGraphQLApi(
186+
return newGitHubGraphQLApi(ghHost,
162187
gitHubProject, /* checker= */ null, credentials, generalOptions.console());
163188
}
164189

@@ -169,6 +194,7 @@ public GitHubGraphQLApi newGitHubGraphQLApi(
169194
* <p>The project for 'https://github.com/foo/bar' is 'foo/bar'.
170195
*/
171196
public GitHubGraphQLApi newGitHubGraphQLApi(
197+
GitHubHost ghHost,
172198
String gitHubProject,
173199
@Nullable Checker checker,
174200
@Nullable CredentialFileHandler credentials,
@@ -180,7 +206,7 @@ public GitHubGraphQLApi newGitHubGraphQLApi(
180206
if (storePath == null) {
181207
storePath = "~/.git-credentials";
182208
}
183-
GitHubApiTransport transport = newTransport(repo, storePath, console);
209+
GitHubApiTransport transport = newTransport(ghHost, repo, storePath, console);
184210
if (checker != null) {
185211
transport = new GitHubApiTransportWithChecker(transport, new ApiChecker(checker, console));
186212
}
@@ -210,9 +236,9 @@ public void validateEndpointChecker(@Nullable Checker checker) throws Validation
210236
// Accept any by default
211237
}
212238

213-
private GitHubApiTransport newTransport(
239+
private GitHubApiTransport newTransport(GitHubHost ghHost,
214240
GitRepository repo, String storePath, Console console) {
215-
return new GitHubApiTransportImpl(
241+
return new GitHubApiTransportImpl(ghHost,
216242
repo, newHttpTransport(), storePath, gitHubApiBearerAuth, console);
217243
}
218244

java/com/google/copybara/git/GitHubPrDestination.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public ImmutableList<DestinationEffect> write(
234234
return result.build();
235235
}
236236

237-
GitHubApi api = gitHubOptions.newGitHubRestApi(getProjectName(), credentials);
237+
GitHubApi api = gitHubOptions.newGitHubRestApi(ghHost, getProjectName(), credentials);
238238

239239
ImmutableList<PullRequest> pullRequests =
240240
api.getPullRequests(
@@ -346,7 +346,7 @@ public Endpoint getFeedbackEndPoint(Console console) throws ValidationException
346346
}
347347

348348
private String asHttpsUrl() throws ValidationException {
349-
return "https://github.com/" + getProjectName();
349+
return ghHost.projectAsUrl(getProjectName());
350350
}
351351

352352
@VisibleForTesting

java/com/google/copybara/git/GitHubPrOrigin.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ public String showDiff(GitRevision revisionFrom, GitRevision revisionTo) throws
269269
/** Given a commit SHA, use the GitHub API to (try to) look up info for a corresponding PR. */
270270
private PullRequest getPrFromSha(String project, String sha)
271271
throws RepoException, ValidationException {
272-
GitHubApi gitHubApi = gitHubOptions.newGitHubRestApi(project, credentials);
272+
GitHubApi gitHubApi = gitHubOptions.newGitHubRestApi(ghHost, project, credentials);
273273
IssuesAndPullRequestsSearchResults searchResults =
274274
gitHubApi.getIssuesOrPullRequestsSearchResults(
275275
new IssuesAndPullRequestsSearchRequestParams(
@@ -299,13 +299,13 @@ private PullRequest getPrFromSha(String project, String sha)
299299
private PullRequest getPrFromNumber(String project, long prNumber)
300300
throws RepoException, ValidationException {
301301
try (ProfilerTask ignore = generalOptions.profiler().start("github_api_get_pr")) {
302-
return gitHubOptions.newGitHubRestApi(project, credentials).getPullRequest(project, prNumber);
302+
return gitHubOptions.newGitHubRestApi(ghHost, project, credentials).getPullRequest(project, prNumber);
303303
}
304304
}
305305

306306
private GitRevision getRevisionForPR(String project, PullRequest prData)
307307
throws RepoException, ValidationException {
308-
GitHubApi api = gitHubOptions.newGitHubRestApi(project, credentials);
308+
GitHubApi api = gitHubOptions.newGitHubRestApi(ghHost, project, credentials);
309309
int prNumber = (int) prData.getNumber();
310310
boolean actuallyUseMerge = this.useMerge;
311311
ImmutableListMultimap.Builder<String, String> labels = ImmutableListMultimap.builder();

java/com/google/copybara/git/GitHubPrWriteHook.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void beforePush(
9595
}
9696
for (Change<?> originalChange : originChanges) {
9797
String projectName = ghHost.getProjectNameFromUrl(repoUrl);
98-
GitHubApi api = gitHubOptions.newGitHubRestApi(projectName, creds);
98+
GitHubApi api = gitHubOptions.newGitHubRestApi(ghHost, projectName, creds);
9999

100100
try {
101101
ImmutableList<PullRequest> pullRequests =

java/com/google/copybara/git/GitHubPreSubmitApprovalsProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public ImmutableList<ChangeWithApprovals> tryPresubmitUserValidation(
202202
ImmutableList.builder();
203203
ImmutableList<Review> reviews = null;
204204
try {
205-
reviews = this.githubOptions.newGitHubRestApi(projectId, creds)
205+
reviews = this.githubOptions.newGitHubRestApi(githubHost, projectId, creds)
206206
.getReviews(projectId, prNumber);
207207
} catch (RepoException | ValidationException e) {
208208
console.warnFmt(

java/com/google/copybara/git/GitHubWriteHook.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public class GitHubWriteHook extends DefaultWriteHook {
9292
private PullRequest getPrFromNumber(String project, long prNumber)
9393
throws RepoException, ValidationException {
9494
try (ProfilerTask ignore = generalOptions.profiler().start("github_api_get_pr")) {
95-
return gitHubOptions.newGitHubRestApi(project, creds).getPullRequest(project, prNumber);
95+
return gitHubOptions.newGitHubRestApi(ghHost, project, creds).getPullRequest(project, prNumber);
9696
}
9797
}
9898

@@ -106,7 +106,7 @@ public void beforePush(
106106
throws ValidationException, RepoException {
107107

108108
String configProjectName = ghHost.getProjectNameFromUrl(repoUrl);
109-
GitHubApi api = gitHubOptions.newGitHubRestApi(configProjectName, creds);
109+
GitHubApi api = gitHubOptions.newGitHubRestApi(ghHost, configProjectName, creds);
110110

111111

112112
// TODO(joshgoldman): add credentials to the GitRepository object for pushing to the fork
@@ -204,7 +204,7 @@ public ImmutableList<DestinationEffect> afterPush(String serverResponse, Message
204204
return baseEffects.build();
205205
}
206206
String projectId = ghHost.getProjectNameFromUrl(repoUrl);
207-
GitHubApi api = gitHubOptions.newGitHubRestApi(projectId, creds);
207+
GitHubApi api = gitHubOptions.newGitHubRestApi(ghHost, projectId, creds);
208208

209209
if (!originChanges.isEmpty()) {
210210
if (gitHubOptions.githubPrBranchDeletionDelay != null) {

0 commit comments

Comments
 (0)