cli: add support for push options
Previously, if you tried to run `jj rebase -s 'roots(mutable())' -d main@origin, you would suddenly get divergent changes because it had also rebased old versions of current commits.
Checklist
If applicable:
- [x] I have updated
CHANGELOG.md - [x] I have updated the documentation (
README.md,docs/,demos/) - [x] I have updated the config schema (
cli/src/config-schema.json) - [x] I have added/updated tests to cover my changes
We don't use conventional commits here
Do we have that documented somewhere? I personally don't care much about the style as long as it's easy to understand. If we do have some rules or guidelines about the style, I think we should document them (again, maybe we have and I just don't remember where).
so if you'd touch the library it'd be
lib:etc.
And I find this too coarse-grained, btw. It doesn't tell me much about the topic the commit affects.
We don't use conventional commits here
Do we have that documented somewhere? I personally don't care much about the style as long as it's easy to understand. If we do have some rules or guidelines about the style, I think we should document them (again, maybe we have and I just don't remember where).
We don't have them documented somewhere, just about a rough analysis from me in the Discord here. Which I think implies this. I don't consider it a hard blocker, but I think uniformity is nice.
so if you'd touch the library it'd be
lib:etc.And I find this too coarse-grained, btw. It doesn't tell me much about the topic the commit affects.
It was a quick example, so that's my bad.
I explored gitoxide, the Git server implementation used in tests, but couldn't found any functionality for handling push options. So far, I struggled to find a straightforward method for testing this feature.
I don't have a good testing strategy either. Fake ssh command or something could be inserted to capture the wire protocol, but doing that wouldn't be simple.
Maybe okay to leave this option untested?
Can you test by pushing to another folder?
Hi, I would like to offer a test suggestion: setup a hook on the source repo that echos back the received options and capture the output through the callbacks.
- I only got it to work with the git subprocess setting.
- If this is an acceptable approach I could either create a new PR based on this one or let @shikanime finish this PR
Setup hooks
std::process::Command::new("git")
.arg("--git-dir")
.arg(&setup.source_repo_dir)
.args(["config", "receive.advertisePushOptions", "true"])
.output()
.unwrap();
let hooks_dir = setup.source_repo_dir.join("hooks");
fs::create_dir_all(&hooks_dir).unwrap();
let hook_path = hooks_dir.join("pre-receive");
let hook_content = r#"#!/bin/sh
if [ -n "$GIT_PUSH_OPTION_COUNT" ] && [ "$GIT_PUSH_OPTION_COUNT" -gt 0 ]; then
i=0
while [ $i -lt "$GIT_PUSH_OPTION_COUNT" ]; do
eval "option_value=\$GIT_PUSH_OPTION_$i"
echo "Push-Option: $option_value"
i=$((i + 1))
done
fi
"#;
fs::write(&hook_path, hook_content).unwrap();
let mut perms = fs::metadata(&hook_path).unwrap().permissions();
perms.set_mode(perms.mode() | 0o111);
fs::set_permissions(&hook_path, perms).unwrap();
Configure callbacks and assert output
let remote_output = Arc::new(std::sync::Mutex::new(Vec::new()));
let output_clone = remote_output.clone();
let mut sideband_closure = |data: &[u8]| {
if let Ok(mut output) = output_clone.lock() {
output.extend_from_slice(data);
}
};
let mut callbacks = git::RemoteCallbacks::default();
callbacks.sideband_progress = Some(&mut sideband_closure);
let result = git::push_updates(
setup.jj_repo.as_ref(),
&git_settings,
"origin".as_ref(),
&[GitRefUpdate {
qualified_name: "refs/heads/main".into(),
expected_current_target: Some(setup.main_commit.id().clone()),
new_target: Some(setup.child_of_main_commit.id().clone()),
}],
&["merge_request.create", "merge_request.draft"],
callbacks,
);
let captured_bytes = remote_output.lock().unwrap();
let captured_string = String::from_utf8_lossy(&captured_bytes);
if subprocess {
assert!(captured_string.contains("Push-Option: merge_request.create"));
assert!(captured_string.contains("Push-Option: merge_request.draft"));
}
setup a hook on the source repo that echos back the received options and capture the output through the callbacks.
That sounds good to me. We're going to delete/deprecate the libgit2 code path soon.
Configure callbacks and assert output
I think we can just snapshot the remote: outputs.
Sounds like a reasonable approach ദ്ദി(• ˕ •
needs a rebase
I think this should be extended to gerrit as well, it uses push options for different flags/votes https://gerrit-review.googlesource.com/Documentation/user-upload.html#push_options
I won't keep this PR rebased yearly unless we decide to merge it or actively reject it.
To give some additional input. It works well and is very convenient for creating gitlab merge requests.
The only thing to be aware of is that jj is capable of pushing multiple bookmarks at once, but it's not possible to specify options per bookmark.
This would create two draft merge requests, which is fine
jj git push --option merge_request.create --option merge_request.draft -c @- -c @--
But something like this is not possible
jj git push --option merge_request.create --option merge_request.draft -c @- --option merge_request.title="The title I want" -c @-- --option merge_request.title="Another title"
This is of course easily solved by pushing independently.
I won't keep this PR rebased yearly unless we decide to merge it or actively reject it.
Sorry, I didn't realize that this was waiting for a review. The messages before today didn't make it clear to me that it was ready for a review. I just reviewed it and it looks good to me, thanks.
@bertwin Yes, I thought about this a while ago too, but it would require a lot of unusual things, such as changes to the revset, named options or the ordering of flags. For now, we should keep things simple and consider a UX specifically designed for multi-branch workflows, including GHStack, Gerrit and Stack PR, when necessary. For now, pushing branches individually looks fine to me, as it is pretty similar to other tools.
Hi @shikanime, given that Martin has approved, would you give it one last rebase to resolve the conflicts? It should be fine to merge then, in time for the 0.36 release (scheduled Dec 3).
I was just considering to implement push-options myself when I found this PR. :)