cli: Add `--repo` option to `issue` and `patch`

Allows users to operate on a repo without a checkout.
This commit is contained in:
cloudhead 2024-02-23 18:16:52 +01:00
parent 449790e252
commit 0726754b0e
No known key found for this signature in database
5 changed files with 58 additions and 15 deletions

View File

@ -13,7 +13,7 @@ use radicle::cob::issue::{CloseReason, State};
use radicle::cob::thread;
use radicle::crypto::Signer;
use radicle::issue::cache::Issues as _;
use radicle::prelude::Did;
use radicle::prelude::{Did, RepoId};
use radicle::profile;
use radicle::storage;
use radicle::storage::{ReadRepository, WriteRepository, WriteStorage};
@ -69,6 +69,7 @@ Show options
Options
--repo <rid> Operate on the given repository (default: cwd)
--no-announce Don't announce issue to peers
--header Show only the issue header, hiding the comments
-q, --quiet Don't print anything
@ -167,6 +168,7 @@ pub struct LabelOptions {
#[derive(Debug)]
pub struct Options {
pub op: Operation,
pub repo: Option<RepoId>,
pub announce: bool,
pub quiet: bool,
}
@ -194,6 +196,7 @@ impl Args for Options {
let mut debug = false;
let mut assign_opts = AssignOptions::default();
let mut label_opts = LabelOptions::default();
let mut repo = None;
while let Some(arg) = parser.next()? {
match arg {
@ -337,6 +340,12 @@ impl Args for Options {
Long("quiet") | Short('q') => {
quiet = true;
}
Long("repo") => {
let val = parser.value()?;
let rid = term::args::rid(&val)?;
repo = Some(rid);
}
Value(val) if op.is_none() => match val.to_string_lossy().as_ref() {
"c" | "comment" => op = Some(OperationName::Comment),
@ -412,6 +421,7 @@ impl Args for Options {
Ok((
Options {
op,
repo,
announce,
quiet,
},
@ -423,7 +433,11 @@ impl Args for Options {
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let profile = ctx.profile()?;
let signer = term::signer(&profile)?;
let (_, rid) = radicle::rad::cwd()?;
let rid = if let Some(rid) = options.repo {
rid
} else {
radicle::rad::cwd().map(|(_, rid)| rid)?
};
let repo = profile.storage.repository_mut(rid)?;
let announce = options.announce
&& matches!(

View File

@ -16,10 +16,13 @@ pub fn run(id: Option<IssueId>, repository: &Repository, profile: &Profile) -> a
}
None => issues.write_all(|result, progress| {
match result {
Ok((id, _)) => term::success!("Successfully cached issue `{id}`"),
Ok((id, _)) => term::success!(
"Successfully cached issue {id} ({}/{})",
progress.seen(),
progress.total()
),
Err(e) => term::warning(format!("Failed to retrieve issue: {e}")),
};
term::info!("Cached {} of {}", progress.seen(), progress.total());
ControlFlow::Continue(())
})?,
}

View File

@ -145,6 +145,7 @@ Checkout options
Other options
--repo <rid> Operate on the given repository (default: cwd)
--[no-]announce Announce changes made to the network
-q, --quiet Quiet output
--help Print help
@ -278,6 +279,7 @@ impl Operation {
#[derive(Debug)]
pub struct Options {
pub op: Operation,
pub repo: Option<RepoId>,
pub announce: bool,
pub verbose: bool,
pub quiet: bool,
@ -309,6 +311,7 @@ impl Args for Options {
let mut label_opts = LabelOptions::default();
let mut review_op = review::Operation::default();
let mut base_id = None;
let mut repo = None;
while let Some(arg) = parser.next()? {
match arg {
@ -503,6 +506,12 @@ impl Args for Options {
Long("quiet") | Short('q') => {
quiet = true;
}
Long("repo") => {
let val = parser.value()?;
let rid = term::args::rid(&val)?;
repo = Some(rid);
}
Long("help") => {
return Err(Error::HelpManual { name: "rad-patch" }.into());
}
@ -631,6 +640,7 @@ impl Args for Options {
Ok((
Options {
op,
repo,
verbose,
quiet,
announce,
@ -643,11 +653,16 @@ impl Args for Options {
}
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let (workdir, id) = radicle::rad::cwd()
.map_err(|_| anyhow!("this command must be run in the context of a repository"))?;
let (workdir, rid) = if let Some(rid) = options.repo {
(None, rid)
} else {
radicle::rad::cwd()
.map(|(workdir, rid)| (Some(workdir), rid))
.map_err(|_| anyhow!("this command must be run in the context of a repository"))?
};
let profile = ctx.profile()?;
let repository = profile.storage.repository(id)?;
let repository = profile.storage.repository(rid)?;
let announce = options.announce && options.op.is_announce();
transport::local::register(profile.storage.clone());
@ -673,7 +688,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
options.verbose,
&profile,
&repository,
&workdir,
workdir.as_ref(),
)?;
}
Operation::Diff {
@ -697,6 +712,10 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
.as_ref()
.map(|base| base.resolve(&repository.backend))
.transpose()?;
let workdir = workdir.ok_or(anyhow!(
"this command must be run from a repository checkout"
))?;
update::run(
patch_id,
base_id,
@ -728,6 +747,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
.transpose()?
.map(patch::RevisionId::from);
let workdir = workdir.ok_or(anyhow!(
"this command must be run from a repository checkout"
))?;
checkout::run(
&patch::PatchId::from(patch_id),
revision_id,
@ -798,7 +820,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let patch = patches
.get(&patch_id)?
.ok_or_else(|| anyhow!("patch {patch_id} not found"))?;
let workdir = workdir.ok_or(anyhow!(
"this command must be run from a repository checkout"
))?;
radicle::rad::setup_patch_upstream(&patch_id, *patch.head(), &workdir, true)?;
}
Operation::Cache { patch_id } => {
@ -811,7 +835,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
if announce {
let mut node = Node::new(profile.socket());
node::announce(id, &mut node)?;
node::announce(rid, &mut node)?;
}
Ok(())
}

View File

@ -16,10 +16,13 @@ pub fn run(id: Option<PatchId>, repository: &Repository, profile: &Profile) -> a
}
None => patches.write_all(|result, progress| {
match result {
Ok((id, _)) => term::success!("Successfully cached patch `{id}`"),
Ok((id, _)) => term::success!(
"Successfully cached patch {id} ({}/{})",
progress.seen(),
progress.total()
),
Err(e) => term::warning(format!("Failed to retrieve patch: {e}")),
};
term::info!("Cached {} of {}", progress.seen(), progress.total());
ControlFlow::Continue(())
})?,
}

View File

@ -30,8 +30,7 @@ pub fn run(
verbose: bool,
profile: &Profile,
stored: &Repository,
// TODO: Should be optional.
workdir: &git::raw::Repository,
workdir: Option<&git::raw::Repository>,
) -> anyhow::Result<()> {
let patches = profile.patches(stored)?;
let Some(patch) = patches.get(patch_id)? else {
@ -42,7 +41,7 @@ pub fn run(
println!("{:#?}", patch);
return Ok(());
}
term::patch::show(&patch, patch_id, verbose, stored, Some(workdir), profile)?;
term::patch::show(&patch, patch_id, verbose, stored, workdir, profile)?;
if diff {
term::blank();