cli: Use library for opening patch
Instead of calling `rad patch open`, use `patch::create` directly. Also outputs the patch id for the user.
This commit is contained in:
parent
39239fea51
commit
51dced4808
|
|
@ -2092,6 +2092,7 @@ name = "radicle-remote-helper"
|
|||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"radicle",
|
||||
"radicle-cli",
|
||||
"radicle-crypto",
|
||||
"radicle-git-ext",
|
||||
"thiserror",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ $ git checkout -b feature/1
|
|||
Switched to a new branch 'feature/1'
|
||||
$ git commit -a -m "Add things" -q --allow-empty
|
||||
$ git push rad HEAD:refs/patches
|
||||
✓ Patch 8f0e8ecb47a17e8f3219f33150a4092d645e4875 opened
|
||||
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
* [new reference] HEAD -> refs/patches
|
||||
```
|
||||
|
|
@ -72,6 +73,7 @@ simpler:
|
|||
$ git checkout -b feature/2 -q
|
||||
$ git commit -a -m "Add more things" -q --allow-empty
|
||||
$ git push rad/patches
|
||||
✓ Patch 8678aafff1d1e28430952abf431e60b87e28023c opened
|
||||
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||
* [new reference] HEAD -> refs/patches
|
||||
```
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ pub fn run(
|
|||
let (target_ref, target_oid) = get_merge_target(storage, &head_branch)?;
|
||||
|
||||
if head_branch.upstream().is_err() {
|
||||
// TODO(cloudhead): Disable this when invoked from remote helper.
|
||||
radicle::git::set_upstream(
|
||||
workdir,
|
||||
&*radicle::rad::REMOTE_NAME,
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ pub mod format;
|
|||
pub mod io;
|
||||
pub use io::{proposal, signer};
|
||||
pub mod patch;
|
||||
pub use radicle_term::*;
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::process;
|
||||
|
||||
pub use radicle_term::*;
|
||||
|
||||
use radicle::profile::Profile;
|
||||
|
||||
use crate::terminal;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::io;
|
||||
|
||||
use radicle::git;
|
||||
|
||||
use crate::terminal as term;
|
||||
|
|
@ -18,7 +20,13 @@ impl Message {
|
|||
/// Get the `Message` as a string according to the method.
|
||||
pub fn get(self, help: &str) -> std::io::Result<String> {
|
||||
let comment = match self {
|
||||
Message::Edit => term::Editor::new().extension("markdown").edit(help)?,
|
||||
Message::Edit => {
|
||||
if term::is_terminal(&io::stderr()) {
|
||||
term::Editor::new().extension("markdown").edit(help)?
|
||||
} else {
|
||||
Some(help.to_owned())
|
||||
}
|
||||
}
|
||||
Message::Blank => None,
|
||||
Message::Text(c) => Some(c),
|
||||
};
|
||||
|
|
@ -68,7 +76,7 @@ pub fn message(title: &str, description: &str) -> String {
|
|||
pub fn get_message(
|
||||
message: term::patch::Message,
|
||||
default_msg: &str,
|
||||
) -> anyhow::Result<(String, String)> {
|
||||
) -> io::Result<(String, String)> {
|
||||
let display_msg = default_msg.trim_end();
|
||||
|
||||
let message = message.get(&format!("{display_msg}\n{PATCH_MSG}"))?;
|
||||
|
|
@ -78,7 +86,10 @@ pub fn get_message(
|
|||
let (title, description) = (title.trim().to_string(), description.trim().to_string());
|
||||
|
||||
if title.is_empty() {
|
||||
anyhow::bail!("a patch title must be provided");
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"a patch title must be provided",
|
||||
));
|
||||
}
|
||||
|
||||
Ok((title, description))
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ version = "0"
|
|||
path = "../radicle-crypto"
|
||||
version = "0"
|
||||
|
||||
[dependencies.radicle-cli]
|
||||
path = "../radicle-cli"
|
||||
version = "0"
|
||||
|
||||
[[bin]]
|
||||
name = "git-remote-rad"
|
||||
path = "src/git-remote-rad.rs"
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ pub fn run(profile: radicle::Profile) -> Result<(), Error> {
|
|||
vec![refspec.to_string()],
|
||||
&working,
|
||||
url,
|
||||
stored,
|
||||
&stored,
|
||||
&profile,
|
||||
&stdin,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,12 +8,15 @@ use std::{io, process};
|
|||
use radicle::storage::git::cob::object::ParseObjectId;
|
||||
use thiserror::Error;
|
||||
|
||||
use radicle::crypto::PublicKey;
|
||||
use radicle::cob::patch;
|
||||
use radicle::crypto::{PublicKey, Signer};
|
||||
use radicle::node::{Handle, NodeId};
|
||||
use radicle::storage::git::transport::local::Url;
|
||||
use radicle::storage::WriteRepository;
|
||||
use radicle::storage::{self, ReadRepository};
|
||||
use radicle::Profile;
|
||||
use radicle::{git, rad};
|
||||
use radicle_cli::terminal as cli;
|
||||
|
||||
use crate::read_line;
|
||||
|
||||
|
|
@ -52,6 +55,9 @@ pub enum Error {
|
|||
/// Parse error for object IDs.
|
||||
#[error(transparent)]
|
||||
ParseObjectId(#[from] ParseObjectId),
|
||||
/// Patch COB error.
|
||||
#[error(transparent)]
|
||||
Patch(#[from] radicle::cob::patch::Error),
|
||||
}
|
||||
|
||||
enum Command {
|
||||
|
|
@ -94,11 +100,11 @@ impl FromStr for Command {
|
|||
}
|
||||
|
||||
/// Run a git push command.
|
||||
pub fn run<R: WriteRepository>(
|
||||
pub fn run(
|
||||
mut specs: Vec<String>,
|
||||
working: &Path,
|
||||
url: Url,
|
||||
stored: R,
|
||||
stored: &storage::git::Repository,
|
||||
profile: &Profile,
|
||||
stdin: &io::Stdin,
|
||||
) -> Result<(), Error> {
|
||||
|
|
@ -148,16 +154,15 @@ pub fn run<R: WriteRepository>(
|
|||
}
|
||||
Command::Push(git::Refspec { src, dst, force }) => {
|
||||
let working = git::raw::Repository::open(working)?;
|
||||
let stored = stored.raw();
|
||||
|
||||
if let Some(oid) = dst.strip_prefix(git::refname!("refs/heads/patches")) {
|
||||
let oid = git::Oid::from_str(oid)?;
|
||||
|
||||
patch_update(src, dst, *force, &oid, &nid, &working, stored)
|
||||
patch_update(src, dst, *force, &oid, &nid, &working, stored.raw())
|
||||
} else if dst == &*rad::PATCHES_REFNAME {
|
||||
patch_open(src, &nid, &working, stored)
|
||||
patch_open(src, &nid, &working, stored, &signer)
|
||||
} else {
|
||||
push_ref(src, dst, *force, &nid, &working, stored)
|
||||
push_ref(src, dst, *force, &nid, &working, stored.raw())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -182,7 +187,7 @@ pub fn run<R: WriteRepository>(
|
|||
// If our node is not running, we simply skip this step, as the
|
||||
// refs will be announced eventually, when the node restarts.
|
||||
if radicle::Node::new(profile.socket()).is_running() {
|
||||
let rid = stored.id().to_string();
|
||||
let rid = stored.id.to_string();
|
||||
let stderr = io::stderr().as_raw_fd();
|
||||
// Nb. allow this to fail. The push to local storage was still successful.
|
||||
execute("rad", ["sync", &rid, "--verbose"], unsafe {
|
||||
|
|
@ -199,11 +204,12 @@ pub fn run<R: WriteRepository>(
|
|||
}
|
||||
|
||||
/// Open a new patch.
|
||||
fn patch_open(
|
||||
fn patch_open<G: Signer>(
|
||||
src: &git::RefStr,
|
||||
nid: &NodeId,
|
||||
working: &git::raw::Repository,
|
||||
stored: &git::raw::Repository,
|
||||
stored: &storage::git::Repository,
|
||||
signer: &G,
|
||||
) -> Result<(), Error> {
|
||||
let reference = working.find_reference(src.as_str())?;
|
||||
let commit = reference.peel_to_commit()?;
|
||||
|
|
@ -216,23 +222,37 @@ fn patch_open(
|
|||
//
|
||||
// In case the reference is not properly deleted, the next attempt to open a patch should
|
||||
// not fail, since the reference will already exist with the correct OID.
|
||||
push_ref(src, dst, false, nid, working, stored)?;
|
||||
push_ref(src, dst, false, nid, working, stored.raw())?;
|
||||
|
||||
let result = match execute(
|
||||
"rad",
|
||||
["patch", "open", "--quiet", "--no-push"],
|
||||
process::Stdio::piped(),
|
||||
let mut patches = patch::Patches::open(stored).unwrap();
|
||||
let message = commit.message().unwrap_or_default();
|
||||
let (title, description) = cli::patch::get_message(cli::patch::Message::Edit, message)?;
|
||||
let (_, target) = stored.canonical_head()?;
|
||||
let base = stored.backend.merge_base(*target, commit.id())?;
|
||||
let result = match patches.create(
|
||||
title,
|
||||
&description,
|
||||
patch::MergeTarget::default(),
|
||||
base,
|
||||
commit.id(),
|
||||
&[],
|
||||
signer,
|
||||
) {
|
||||
Ok(patch) => {
|
||||
let patch = patch.trim();
|
||||
let patch = radicle::cob::ObjectId::from_str(patch)?;
|
||||
let patch = patch.id;
|
||||
|
||||
eprintln!(
|
||||
"{} Patch {} opened",
|
||||
cli::format::positive("✓"),
|
||||
cli::format::tertiary(patch)
|
||||
);
|
||||
|
||||
// Create long-lived patch head reference, now that we know the Patch ID.
|
||||
//
|
||||
// refs/namespaces/<nid>/refs/heads/patches/<patch-id>
|
||||
//
|
||||
let refname = git::refs::storage::patch(nid, &patch);
|
||||
let _ = stored.reference(
|
||||
let _ = stored.raw().reference(
|
||||
refname.as_str(),
|
||||
commit.id(),
|
||||
true,
|
||||
|
|
@ -271,10 +291,15 @@ fn patch_open(
|
|||
}
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
// Delete short-lived patch head reference.
|
||||
stored.find_reference(dst).map(|mut r| r.delete()).ok();
|
||||
|
||||
result
|
||||
// Delete short-lived patch head reference.
|
||||
stored
|
||||
.raw()
|
||||
.find_reference(dst)
|
||||
.map(|mut r| r.delete())
|
||||
.ok();
|
||||
|
||||
result.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Update an existing patch.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub use element::{Element, Line, Max, Size};
|
|||
pub use hstack::HStack;
|
||||
pub use inquire::ui::Styled;
|
||||
pub use io::*;
|
||||
pub use is_terminal::is_terminal;
|
||||
pub use label::{label, Label};
|
||||
pub use spinner::{spinner, Spinner};
|
||||
pub use table::Table;
|
||||
|
|
|
|||
Loading…
Reference in New Issue