cli: Add `--repo` option to `issue` and `patch`
Allows users to operate on a repo without a checkout.
This commit is contained in:
parent
449790e252
commit
0726754b0e
|
|
@ -13,7 +13,7 @@ use radicle::cob::issue::{CloseReason, State};
|
||||||
use radicle::cob::thread;
|
use radicle::cob::thread;
|
||||||
use radicle::crypto::Signer;
|
use radicle::crypto::Signer;
|
||||||
use radicle::issue::cache::Issues as _;
|
use radicle::issue::cache::Issues as _;
|
||||||
use radicle::prelude::Did;
|
use radicle::prelude::{Did, RepoId};
|
||||||
use radicle::profile;
|
use radicle::profile;
|
||||||
use radicle::storage;
|
use radicle::storage;
|
||||||
use radicle::storage::{ReadRepository, WriteRepository, WriteStorage};
|
use radicle::storage::{ReadRepository, WriteRepository, WriteStorage};
|
||||||
|
|
@ -69,6 +69,7 @@ Show options
|
||||||
|
|
||||||
Options
|
Options
|
||||||
|
|
||||||
|
--repo <rid> Operate on the given repository (default: cwd)
|
||||||
--no-announce Don't announce issue to peers
|
--no-announce Don't announce issue to peers
|
||||||
--header Show only the issue header, hiding the comments
|
--header Show only the issue header, hiding the comments
|
||||||
-q, --quiet Don't print anything
|
-q, --quiet Don't print anything
|
||||||
|
|
@ -167,6 +168,7 @@ pub struct LabelOptions {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub op: Operation,
|
pub op: Operation,
|
||||||
|
pub repo: Option<RepoId>,
|
||||||
pub announce: bool,
|
pub announce: bool,
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -194,6 +196,7 @@ impl Args for Options {
|
||||||
let mut debug = false;
|
let mut debug = false;
|
||||||
let mut assign_opts = AssignOptions::default();
|
let mut assign_opts = AssignOptions::default();
|
||||||
let mut label_opts = LabelOptions::default();
|
let mut label_opts = LabelOptions::default();
|
||||||
|
let mut repo = None;
|
||||||
|
|
||||||
while let Some(arg) = parser.next()? {
|
while let Some(arg) = parser.next()? {
|
||||||
match arg {
|
match arg {
|
||||||
|
|
@ -337,6 +340,12 @@ impl Args for Options {
|
||||||
Long("quiet") | Short('q') => {
|
Long("quiet") | Short('q') => {
|
||||||
quiet = true;
|
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() {
|
Value(val) if op.is_none() => match val.to_string_lossy().as_ref() {
|
||||||
"c" | "comment" => op = Some(OperationName::Comment),
|
"c" | "comment" => op = Some(OperationName::Comment),
|
||||||
|
|
@ -412,6 +421,7 @@ impl Args for Options {
|
||||||
Ok((
|
Ok((
|
||||||
Options {
|
Options {
|
||||||
op,
|
op,
|
||||||
|
repo,
|
||||||
announce,
|
announce,
|
||||||
quiet,
|
quiet,
|
||||||
},
|
},
|
||||||
|
|
@ -423,7 +433,11 @@ impl Args for Options {
|
||||||
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let profile = ctx.profile()?;
|
let profile = ctx.profile()?;
|
||||||
let signer = term::signer(&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 repo = profile.storage.repository_mut(rid)?;
|
||||||
let announce = options.announce
|
let announce = options.announce
|
||||||
&& matches!(
|
&& matches!(
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,13 @@ pub fn run(id: Option<IssueId>, repository: &Repository, profile: &Profile) -> a
|
||||||
}
|
}
|
||||||
None => issues.write_all(|result, progress| {
|
None => issues.write_all(|result, progress| {
|
||||||
match result {
|
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}")),
|
Err(e) => term::warning(format!("Failed to retrieve issue: {e}")),
|
||||||
};
|
};
|
||||||
term::info!("Cached {} of {}", progress.seen(), progress.total());
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
})?,
|
})?,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@ Checkout options
|
||||||
|
|
||||||
Other options
|
Other options
|
||||||
|
|
||||||
|
--repo <rid> Operate on the given repository (default: cwd)
|
||||||
--[no-]announce Announce changes made to the network
|
--[no-]announce Announce changes made to the network
|
||||||
-q, --quiet Quiet output
|
-q, --quiet Quiet output
|
||||||
--help Print help
|
--help Print help
|
||||||
|
|
@ -278,6 +279,7 @@ impl Operation {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub op: Operation,
|
pub op: Operation,
|
||||||
|
pub repo: Option<RepoId>,
|
||||||
pub announce: bool,
|
pub announce: bool,
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
|
|
@ -309,6 +311,7 @@ impl Args for Options {
|
||||||
let mut label_opts = LabelOptions::default();
|
let mut label_opts = LabelOptions::default();
|
||||||
let mut review_op = review::Operation::default();
|
let mut review_op = review::Operation::default();
|
||||||
let mut base_id = None;
|
let mut base_id = None;
|
||||||
|
let mut repo = None;
|
||||||
|
|
||||||
while let Some(arg) = parser.next()? {
|
while let Some(arg) = parser.next()? {
|
||||||
match arg {
|
match arg {
|
||||||
|
|
@ -503,6 +506,12 @@ impl Args for Options {
|
||||||
Long("quiet") | Short('q') => {
|
Long("quiet") | Short('q') => {
|
||||||
quiet = true;
|
quiet = true;
|
||||||
}
|
}
|
||||||
|
Long("repo") => {
|
||||||
|
let val = parser.value()?;
|
||||||
|
let rid = term::args::rid(&val)?;
|
||||||
|
|
||||||
|
repo = Some(rid);
|
||||||
|
}
|
||||||
Long("help") => {
|
Long("help") => {
|
||||||
return Err(Error::HelpManual { name: "rad-patch" }.into());
|
return Err(Error::HelpManual { name: "rad-patch" }.into());
|
||||||
}
|
}
|
||||||
|
|
@ -631,6 +640,7 @@ impl Args for Options {
|
||||||
Ok((
|
Ok((
|
||||||
Options {
|
Options {
|
||||||
op,
|
op,
|
||||||
|
repo,
|
||||||
verbose,
|
verbose,
|
||||||
quiet,
|
quiet,
|
||||||
announce,
|
announce,
|
||||||
|
|
@ -643,11 +653,16 @@ impl Args for Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let (workdir, id) = radicle::rad::cwd()
|
let (workdir, rid) = if let Some(rid) = options.repo {
|
||||||
.map_err(|_| anyhow!("this command must be run in the context of a repository"))?;
|
(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 profile = ctx.profile()?;
|
||||||
let repository = profile.storage.repository(id)?;
|
let repository = profile.storage.repository(rid)?;
|
||||||
let announce = options.announce && options.op.is_announce();
|
let announce = options.announce && options.op.is_announce();
|
||||||
|
|
||||||
transport::local::register(profile.storage.clone());
|
transport::local::register(profile.storage.clone());
|
||||||
|
|
@ -673,7 +688,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
options.verbose,
|
options.verbose,
|
||||||
&profile,
|
&profile,
|
||||||
&repository,
|
&repository,
|
||||||
&workdir,
|
workdir.as_ref(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Operation::Diff {
|
Operation::Diff {
|
||||||
|
|
@ -697,6 +712,10 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|base| base.resolve(&repository.backend))
|
.map(|base| base.resolve(&repository.backend))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
let workdir = workdir.ok_or(anyhow!(
|
||||||
|
"this command must be run from a repository checkout"
|
||||||
|
))?;
|
||||||
|
|
||||||
update::run(
|
update::run(
|
||||||
patch_id,
|
patch_id,
|
||||||
base_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))
|
.map(|rev| rev.resolve::<radicle::git::Oid>(&repository.backend))
|
||||||
.transpose()?
|
.transpose()?
|
||||||
.map(patch::RevisionId::from);
|
.map(patch::RevisionId::from);
|
||||||
|
let workdir = workdir.ok_or(anyhow!(
|
||||||
|
"this command must be run from a repository checkout"
|
||||||
|
))?;
|
||||||
checkout::run(
|
checkout::run(
|
||||||
&patch::PatchId::from(patch_id),
|
&patch::PatchId::from(patch_id),
|
||||||
revision_id,
|
revision_id,
|
||||||
|
|
@ -798,7 +820,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let patch = patches
|
let patch = patches
|
||||||
.get(&patch_id)?
|
.get(&patch_id)?
|
||||||
.ok_or_else(|| anyhow!("patch {patch_id} not found"))?;
|
.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)?;
|
radicle::rad::setup_patch_upstream(&patch_id, *patch.head(), &workdir, true)?;
|
||||||
}
|
}
|
||||||
Operation::Cache { patch_id } => {
|
Operation::Cache { patch_id } => {
|
||||||
|
|
@ -811,7 +835,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
|
||||||
if announce {
|
if announce {
|
||||||
let mut node = Node::new(profile.socket());
|
let mut node = Node::new(profile.socket());
|
||||||
node::announce(id, &mut node)?;
|
node::announce(rid, &mut node)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,13 @@ pub fn run(id: Option<PatchId>, repository: &Repository, profile: &Profile) -> a
|
||||||
}
|
}
|
||||||
None => patches.write_all(|result, progress| {
|
None => patches.write_all(|result, progress| {
|
||||||
match result {
|
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}")),
|
Err(e) => term::warning(format!("Failed to retrieve patch: {e}")),
|
||||||
};
|
};
|
||||||
term::info!("Cached {} of {}", progress.seen(), progress.total());
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
})?,
|
})?,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ pub fn run(
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
profile: &Profile,
|
profile: &Profile,
|
||||||
stored: &Repository,
|
stored: &Repository,
|
||||||
// TODO: Should be optional.
|
workdir: Option<&git::raw::Repository>,
|
||||||
workdir: &git::raw::Repository,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let patches = profile.patches(stored)?;
|
let patches = profile.patches(stored)?;
|
||||||
let Some(patch) = patches.get(patch_id)? else {
|
let Some(patch) = patches.get(patch_id)? else {
|
||||||
|
|
@ -42,7 +41,7 @@ pub fn run(
|
||||||
println!("{:#?}", patch);
|
println!("{:#?}", patch);
|
||||||
return Ok(());
|
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 {
|
if diff {
|
||||||
term::blank();
|
term::blank();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue