cli: Allow setting a different patch base on push

Using `-o patch.base=<oid>`, users can specify a different patch base,
when creating or updating a patch.
This commit is contained in:
Alexis Sellier 2023-06-13 13:14:52 +02:00
parent a6782ac2d6
commit cb576cf8c3
No known key found for this signature in database
4 changed files with 72 additions and 19 deletions

View File

@ -115,6 +115,40 @@ $ rad patch show -v 57cb9b2758518e547de324456ac967fda456c6c1
│ 7f63fcb Add Mel │
│ 5c88a79 Add Alan │
├────────────────────────────────────────────────────────────────────┤
│ ● opened by (you) (z6MknSL…StBU8Vi) 5 months ago │
│ ● opened by (you) (z6MknSL…StBU8Vi) [ ... ] │
╰────────────────────────────────────────────────────────────────────╯
```
If we want to instead create a "stacked" patch, we can do so with the
`patch.base` push option:
``` (stderr)
$ git push -o patch.message="Add Mel #2" -o patch.base=5c88a79d75f5c2b4cc51ee6f163d2db91ee198d7 rad HEAD:refs/patches
✓ Patch 395221c5b75fa9bc2de7909d03e69dfd606611c6 opened
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
* [new reference] HEAD -> refs/patches
```
As you'll notice, using the previous patch as the base, we only see commit
`7f63fcb` listed for this new patch.
However, since the patch is still intended to be merged into `master`, we see
that it is still two commits ahead and one behind from `master`.
```
$ rad patch show -v 395221c5b75fa9bc2de7909d03e69dfd606611c6
╭────────────────────────────────────────────────────────────────────╮
│ Title Add Mel #2
│ Patch 395221c5b75fa9bc2de7909d03e69dfd606611c6 │
│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
│ Head 7f63fcbcf23fc39eea784c091ad3d20d7e4bd005 │
│ Base 5c88a79d75f5c2b4cc51ee6f163d2db91ee198d7 │
│ Branches feature/2 │
│ Commits ahead 2, behind 1 │
│ Status open │
├────────────────────────────────────────────────────────────────────┤
│ 7f63fcb Add Mel │
├────────────────────────────────────────────────────────────────────┤
│ ● opened by (you) (z6MknSL…StBU8Vi) [ ... ] │
╰────────────────────────────────────────────────────────────────────╯
```

View File

@ -60,6 +60,8 @@ pub struct Options {
no_sync: bool,
/// Open patch in draft mode.
draft: bool,
/// Patch base to use, when opening or updating a patch.
base: Option<git::Oid>,
/// Patch message.
message: cli::patch::Message,
}
@ -115,8 +117,18 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
let args = args.join(" ");
if let Some((key, val)) = args.split_once('=') {
if key == "patch.message" {
opts.message.append(val);
match key {
"patch.message" => {
opts.message.append(val);
}
"patch.base" => {
let base = val.parse()?;
opts.base = Some(base);
}
_ => {
println!("unsupported");
continue;
}
}
} else {
println!("unsupported");

View File

@ -50,6 +50,9 @@ pub enum Error {
/// Git error.
#[error("git: {0}")]
Git(#[from] git::raw::Error),
/// Git extension error.
#[error("git: {0}")]
GitExt(#[from] git::ext::Error),
/// Storage error.
#[error(transparent)]
Storage(#[from] radicle::storage::Error),
@ -261,16 +264,17 @@ fn patch_open<G: Signer>(
push_ref(src, &dst, false, working, stored.raw())?;
let (_, target) = stored.canonical_head()?;
let base = stored.backend.merge_base(*target, commit.id())?;
if base == commit.id() {
let head = commit.id().into();
let base = if let Some(base) = opts.base {
base
} else {
stored.merge_base(&target, &head)?
};
if base == head {
return Err(Error::EmptyPatch);
}
let (title, description) = cli::patch::get_create_message(
opts.message,
&stored.backend,
&base.into(),
&commit.id().into(),
)?;
let (title, description) =
cli::patch::get_create_message(opts.message, &stored.backend, &base, &head)?;
let mut patches = patch::Patches::open(stored)?;
let patch = if opts.draft {
@ -401,8 +405,16 @@ fn patch_update<G: Signer>(
)?;
let (_, target) = stored.canonical_head()?;
let base = stored.backend.merge_base(*target, commit.id())?;
let revision = patch.update(message, base, commit.id(), signer)?;
let head: git::Oid = commit.id().into();
let base = if let Some(base) = opts.base {
base
} else {
stored.merge_base(&target, &head)?
};
if base == head {
return Err(Error::EmptyPatch);
}
let revision = patch.update(message, base, head, signer)?;
eprintln!(
"{} Patch {} updated to {}",

View File

@ -305,12 +305,7 @@ impl Patch {
/// Get the merge base of this patch.
pub fn merge_base<R: ReadRepository>(&self, repo: &R) -> Result<git::Oid, git::ext::Error> {
let target = self.target().head(repo).map_err(|_| {
git::ext::Error::NotFound(git::ext::NotFound::NoSuchBranch(String::from("HEAD")))
})?;
let base = repo.merge_base(&target, self.head())?;
Ok(base)
repo.merge_base(self.base(), self.head())
}
/// Get the commit range of this patch.