Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2202,7 +2202,7 @@ Name | Type | Description

Creates a commit in a git repository using the transformed worktree.<br><br>For GitHub use git.github_destination. For creating Pull Requests in GitHub, use git.github_pr_destination. For creating a Gerrit change use git.gerrit_destination.<br><br>Given that Copybara doesn't ask for user/password in the console when doing the push to remote repos, you have to use ssh protocol, have the credentials cached or use a credential manager.

`destination` `git.destination(url, push='master', tag_name=None, tag_msg=None, fetch=None, partial_fetch=False, integrates=None, primary_branch_migration=False, checker=None)`
`destination` `git.destination(url, push='master', tag_name=None, tag_msg=None, fetch=None, partial_fetch=False, integrates=None, primary_branch_migration=False, checker=None, push_options=None)`


#### Parameters:
Expand All @@ -2218,6 +2218,7 @@ partial_fetch | `bool`<br><p>This is an experimental feature that only works for
integrates | `sequence of git_integrate` or `NoneType`<br><p>Integrate changes from a url present in the migrated change label. Defaults to a semi-fake merge if COPYBARA_INTEGRATE_REVIEW label is present in the message</p>
primary_branch_migration | `bool`<br><p>When enabled, copybara will ignore the 'push' and 'fetch' params if either is 'master' or 'main' and instead try to establish the default git branch. If this fails, it will fall back to the param's declared value.<br>This is intended to help migrating to the new standard of using 'main' without breaking users relying on the legacy default.</p>
checker | `checker` or `NoneType`<br><p>A checker that can check leaks or other checks in the commit created. </p>
push_options | `sequence` or `NoneType`<br><p>A sequence of git push options that can pass into push command. Defaults to none which represents no push options.</p>



Expand Down
3 changes: 2 additions & 1 deletion java/com/google/copybara/git/GerritDestination.java
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,8 @@ static GerritDestination newGerritDestination(
gerritSubmit,
primaryBranchMigrationMode),
integrates,
checker),
checker,
ImmutableList.of()),
submit);
}

Expand Down
14 changes: 11 additions & 3 deletions java/com/google/copybara/git/GitDestination.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ static class MessageInfo {
@Nullable private String resolvedPrimary = null;
private final Iterable<GitIntegrateChanges> integrates;
private final WriteHook writerHook;
private final Iterable<String> pushOptions;
@Nullable private final Checker checker;
private final LazyResourceLoader<GitRepository> localRepo;

Expand All @@ -126,7 +127,8 @@ static class MessageInfo {
GeneralOptions generalOptions,
WriteHook writerHook,
Iterable<GitIntegrateChanges> integrates,
@Nullable Checker checker) {
@Nullable Checker checker,
Iterable<String> pushOptions) {
this.repoUrl = checkNotNull(repoUrl);
this.fetch = checkNotNull(fetch);
this.push = checkNotNull(push);
Expand All @@ -140,6 +142,7 @@ static class MessageInfo {
this.integrates = checkNotNull(integrates);
this.writerHook = checkNotNull(writerHook);
this.checker = checker;
this.pushOptions = checkNotNull(pushOptions);
this.localRepo = memoized(ignored -> destinationOptions.localGitRepo(repoUrl));
}

Expand Down Expand Up @@ -191,7 +194,8 @@ public Writer<GitRevision> newWriter(WriterContext writerContext) throws Validat
destinationOptions.rebaseWhenBaseline(),
gitOptions.visitChangePageSize,
gitOptions.gitTagOverwrite,
checker);
checker,
pushOptions);
}

/**
Expand Down Expand Up @@ -242,6 +246,7 @@ public static class WriterImpl<S extends WriterState>
private final int visitChangePageSize;
private final boolean gitTagOverwrite;
@Nullable private final Checker checker;
private final Iterable<String> pushOptions;

/** Create a new git.destination writer */
WriterImpl(
Expand All @@ -265,7 +270,8 @@ public static class WriterImpl<S extends WriterState>
boolean rebase,
int visitChangePageSize,
boolean gitTagOverwrite,
Checker checker) {
Checker checker,
Iterable<String> pushOptions) {
this.skipPush = skipPush;
this.repoUrl = checkNotNull(repoUrl);
this.remoteFetch = checkNotNull(remoteFetch);
Expand All @@ -289,6 +295,7 @@ public static class WriterImpl<S extends WriterState>
this.visitChangePageSize = visitChangePageSize;
this.gitTagOverwrite = gitTagOverwrite;
this.checker = checker;
this.pushOptions = pushOptions;
}

@Override
Expand Down Expand Up @@ -659,6 +666,7 @@ public ImmutableList<DestinationEffect> write(TransformResult transformResult,
String serverResponse = generalOptions.repoTask(
"push",
() -> scratchClone.push()
.pushOptions(pushOptions)
.withRefspecs(repoUrl,
tagName != null
? ImmutableList.of(scratchClone.createRefSpec(
Expand Down
3 changes: 2 additions & 1 deletion java/com/google/copybara/git/GitHubPrDestination.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ public Writer<GitRevision> newWriter(WriterContext writerContext) throws Validat
destinationOptions.rebaseWhenBaseline(),
gitOptions.visitChangePageSize,
gitOptions.gitTagOverwrite,
checker) {
checker,
ImmutableList.of()) {
@Override
public ImmutableList<DestinationEffect> write(
TransformResult transformResult, Glob destinationFiles, Console console)
Expand Down
20 changes: 18 additions & 2 deletions java/com/google/copybara/git/GitModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,16 @@ private boolean convertDescribeVersion(Object describeVersion) {
doc = "A checker that can check leaks or other checks in the commit created. ",
named = true,
positional = false),
@Param(
name = "push_options",
allowedTypes = {
@ParamType(type = Sequence.class),
@ParamType(type = NoneType.class),
},
defaultValue = "None",
doc = "A sequence of git push options that can pass into push command. Defaults to none which represents no push options.",
named = true,
positional = false),
},
useStarlarkThread = true)
@UsesFlags(GitDestinationOptions.class)
Expand All @@ -1352,6 +1362,7 @@ public GitDestination destination(
Object integrates,
Boolean primaryBranchMigration,
Object checker,
Object pushOptions,
StarlarkThread thread)
throws EvalException {
GitDestinationOptions destinationOptions = options.get(GitDestinationOptions.class);
Expand All @@ -1365,6 +1376,9 @@ public GitDestination destination(
"Skipping git checker for git.destination. Note that this could"
+ " cause leaks or other problems");
}
Iterable<String> resolvedPushOptions = Starlark.isNullOrNone(pushOptions)
? ImmutableList.of()
: Sequence.cast(pushOptions, String.class, "push_options");
return new GitDestination(
fixHttp(
checkNotEmpty(firstNotNull(destinationOptions.url, url), "url"),
Expand All @@ -1384,7 +1398,8 @@ public GitDestination destination(
Starlark.isNullOrNone(integrates)
? defaultGitIntegrate
: Sequence.cast(integrates, GitIntegrateChanges.class, "integrates"),
maybeChecker);
maybeChecker,
resolvedPushOptions);
}

@SuppressWarnings("unused")
Expand Down Expand Up @@ -1612,7 +1627,8 @@ public GitDestination gitHubDestination(
Starlark.isNullOrNone(integrates)
? defaultGitIntegrate
: Sequence.cast(integrates, GitIntegrateChanges.class, "integrates"),
checkerObj);
checkerObj,
ImmutableList.of());
}

@SuppressWarnings("unused")
Expand Down
22 changes: 18 additions & 4 deletions java/com/google/copybara/git/GitRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ public LogCmd log(String referenceExpr) {

@CheckReturnValue
public PushCmd push() {
return new PushCmd(this, /*url=*/null, ImmutableList.of(), /*prune=*/false);
return new PushCmd(this, /*url=*/null, ImmutableList.of(), /*prune=*/false, ImmutableList.of());
}

@CheckReturnValue
Expand Down Expand Up @@ -678,6 +678,12 @@ protected String runPush(PushCmd pushCmd) throws RepoException, ValidationExcept
cmd.add("--no-verify");
}

if(!pushCmd.pushOptions.isEmpty()) {
for(String option : pushCmd.pushOptions) {
cmd.add("--push-option=" + option);
}
}

if (pushCmd.url != null) {
cmd.add(validateUrl(pushCmd.url));
for (Refspec refspec : pushCmd.refspecs) {
Expand Down Expand Up @@ -1887,6 +1893,8 @@ public static class PushCmd {
private final ImmutableList<Refspec> refspecs;
private final boolean prune;

private final ImmutableList<String> pushOptions;

@Nullable
public String getUrl() {
return url;
Expand All @@ -1903,24 +1911,30 @@ public boolean isPrune() {

@CheckReturnValue
public PushCmd(GitRepository repo, @Nullable String url, ImmutableList<Refspec> refspecs,
boolean prune) {
boolean prune, ImmutableList<String> pushOptions) {
this.repo = checkNotNull(repo);
this.url = url;
this.refspecs = checkNotNull(refspecs);
Preconditions.checkArgument(refspecs.isEmpty() || url != null, "refspec can only be"
+ " used when a url is passed");
this.prune = prune;
this.pushOptions = pushOptions;
}

@CheckReturnValue
public PushCmd withRefspecs(String url, Iterable<Refspec> refspecs) {
return new PushCmd(repo, checkNotNull(url), ImmutableList.copyOf(refspecs),
prune);
prune, pushOptions);
}

@CheckReturnValue
public PushCmd prune(boolean prune) {
return new PushCmd(repo, url, this.refspecs, prune);
return new PushCmd(repo, url, this.refspecs, prune, pushOptions);
}

@CheckReturnValue
public PushCmd pushOptions(Iterable<String> pushOptions) {
return new PushCmd(repo, url, refspecs, prune, ImmutableList.copyOf(pushOptions));
}

/**
Expand Down
19 changes: 19 additions & 0 deletions javatests/com/google/copybara/git/GitDestinationIntegrateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,25 @@ public void testIncludeFiles() throws ValidationException, IOException, RepoExce
.isEqualTo(Lists.newArrayList(previous.getCommit().getSha1()));
}

@Test
public void testPushOptionsTrigger() throws Exception {
RepoException e = assertThrows(RepoException.class, () -> migrateOriginChange(
destination(
"url = '" + url + "'",
String.format("fetch = '%s'", primaryBranch),
String.format("push = '%s'", primaryBranch),
"integrates = []",
"push_options = ['ci.skip']"),
"Test change\n\n"
+ GitModule.DEFAULT_INTEGRATE_LABEL + "=http://should_not_be_used\n", "some content"));
assertThat(e)
.hasMessageThat()
.contains("--push-option=ci.skip");
assertThat(e)
.hasMessageThat()
.contains("the receiving end does not support push options");
}

@Test
public void testIncludeFilesOutdatedBranch() throws Exception {
Path repoPath = Files.createTempDirectory("test");
Expand Down
2 changes: 1 addition & 1 deletion javatests/com/google/copybara/git/GitRepositoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ public void doPushWithHook(GitRepository origin) throws Exception {
origin,
"file://" + remote.getGitDir(),
ImmutableList.of(repository.createRefSpec("+" + defaultBranch + ":" + defaultBranch)),
false).run();
false, ImmutableList.of()).run();
}


Expand Down