cli: Create `rad patch ready` command
Allows for converting patches to and from draft mode.
This commit is contained in:
parent
f111681dd6
commit
12a91bd0ae
|
|
@ -0,0 +1,69 @@
|
||||||
|
Let's say we have some changes in a branch:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git checkout -b cloudhead/draft
|
||||||
|
$ git commit -a -m "Nothing to see here.." -q --allow-empty
|
||||||
|
```
|
||||||
|
|
||||||
|
To open a patch in draft mode, we use the `--draft` option:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rad patch open --draft -m "Nothing yet" --quiet
|
||||||
|
3bdbfc4f85b942293ba7adb8e47bf3202a602e8b
|
||||||
|
```
|
||||||
|
|
||||||
|
We can confirm it's a draft by running `show`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rad patch show 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b
|
||||||
|
╭─────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ Title Nothing yet │
|
||||||
|
│ Patch 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b │
|
||||||
|
│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
|
||||||
|
│ Head 2a465832b5a76abe25be44a3a5d224bbd7741ba7 │
|
||||||
|
│ Branches cloudhead/draft │
|
||||||
|
│ Commits ahead 1, behind 0 │
|
||||||
|
│ Status draft │
|
||||||
|
├─────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ● opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [ ... ] │
|
||||||
|
╰─────────────────────────────────────────────────────────────────────────────────────────╯
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the patch is ready for review, we can use the `ready` command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rad patch ready 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rad patch show 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b
|
||||||
|
╭─────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ Title Nothing yet │
|
||||||
|
│ Patch 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b │
|
||||||
|
│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
|
||||||
|
│ Head 2a465832b5a76abe25be44a3a5d224bbd7741ba7 │
|
||||||
|
│ Branches cloudhead/draft │
|
||||||
|
│ Commits ahead 1, behind 0 │
|
||||||
|
│ Status open │
|
||||||
|
├─────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ● opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [ ... ] │
|
||||||
|
╰─────────────────────────────────────────────────────────────────────────────────────────╯
|
||||||
|
```
|
||||||
|
|
||||||
|
If for whatever reason, it needed to go back into draft mode, we could use
|
||||||
|
the `--undo` flag:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ rad patch ready --undo 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b
|
||||||
|
$ rad patch show 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b
|
||||||
|
╭─────────────────────────────────────────────────────────────────────────────────────────╮
|
||||||
|
│ Title Nothing yet │
|
||||||
|
│ Patch 3bdbfc4f85b942293ba7adb8e47bf3202a602e8b │
|
||||||
|
│ Author did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi │
|
||||||
|
│ Head 2a465832b5a76abe25be44a3a5d224bbd7741ba7 │
|
||||||
|
│ Branches cloudhead/draft │
|
||||||
|
│ Commits ahead 1, behind 0 │
|
||||||
|
│ Status draft │
|
||||||
|
├─────────────────────────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ ● opened by did:key:z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi (you) [ ... ] │
|
||||||
|
╰─────────────────────────────────────────────────────────────────────────────────────────╯
|
||||||
|
|
@ -10,6 +10,8 @@ mod create;
|
||||||
mod delete;
|
mod delete;
|
||||||
#[path = "patch/list.rs"]
|
#[path = "patch/list.rs"]
|
||||||
mod list;
|
mod list;
|
||||||
|
#[path = "patch/ready.rs"]
|
||||||
|
mod ready;
|
||||||
#[path = "patch/show.rs"]
|
#[path = "patch/show.rs"]
|
||||||
mod show;
|
mod show;
|
||||||
#[path = "patch/update.rs"]
|
#[path = "patch/update.rs"]
|
||||||
|
|
@ -45,6 +47,7 @@ Usage
|
||||||
rad patch update <patch-id> [<option>...]
|
rad patch update <patch-id> [<option>...]
|
||||||
rad patch checkout <patch-id> [<option>...]
|
rad patch checkout <patch-id> [<option>...]
|
||||||
rad patch delete <patch-id> [<option>...]
|
rad patch delete <patch-id> [<option>...]
|
||||||
|
rad patch ready <patch-id> [--undo] [<option>...]
|
||||||
|
|
||||||
Show options
|
Show options
|
||||||
|
|
||||||
|
|
@ -66,6 +69,10 @@ List options
|
||||||
--merged Show only merged patches
|
--merged Show only merged patches
|
||||||
--open Show only open patches (default)
|
--open Show only open patches (default)
|
||||||
|
|
||||||
|
Ready options
|
||||||
|
|
||||||
|
--undo Convert a patch back to a draft
|
||||||
|
|
||||||
Other options
|
Other options
|
||||||
|
|
||||||
--help Print help
|
--help Print help
|
||||||
|
|
@ -80,6 +87,7 @@ pub enum OperationName {
|
||||||
Archive,
|
Archive,
|
||||||
Delete,
|
Delete,
|
||||||
Checkout,
|
Checkout,
|
||||||
|
Ready,
|
||||||
#[default]
|
#[default]
|
||||||
List,
|
List,
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +111,10 @@ pub enum Operation {
|
||||||
Archive {
|
Archive {
|
||||||
patch_id: Rev,
|
patch_id: Rev,
|
||||||
},
|
},
|
||||||
|
Ready {
|
||||||
|
patch_id: Rev,
|
||||||
|
undo: bool,
|
||||||
|
},
|
||||||
Delete {
|
Delete {
|
||||||
patch_id: Rev,
|
patch_id: Rev,
|
||||||
},
|
},
|
||||||
|
|
@ -138,6 +150,7 @@ impl Args for Options {
|
||||||
let mut filter = Some(patch::State::Open);
|
let mut filter = Some(patch::State::Open);
|
||||||
let mut diff = false;
|
let mut diff = false;
|
||||||
let mut draft = false;
|
let mut draft = false;
|
||||||
|
let mut undo = false;
|
||||||
let mut quiet = false;
|
let mut quiet = false;
|
||||||
|
|
||||||
while let Some(arg) = parser.next()? {
|
while let Some(arg) = parser.next()? {
|
||||||
|
|
@ -187,6 +200,11 @@ impl Args for Options {
|
||||||
diff = true;
|
diff = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ready options.
|
||||||
|
Long("undo") if op == Some(OperationName::Ready) => {
|
||||||
|
undo = true;
|
||||||
|
}
|
||||||
|
|
||||||
// List options.
|
// List options.
|
||||||
Long("all") => {
|
Long("all") => {
|
||||||
filter = None;
|
filter = None;
|
||||||
|
|
@ -217,6 +235,7 @@ impl Args for Options {
|
||||||
"d" | "delete" => op = Some(OperationName::Delete),
|
"d" | "delete" => op = Some(OperationName::Delete),
|
||||||
"c" | "checkout" => op = Some(OperationName::Checkout),
|
"c" | "checkout" => op = Some(OperationName::Checkout),
|
||||||
"a" | "archive" => op = Some(OperationName::Archive),
|
"a" | "archive" => op = Some(OperationName::Archive),
|
||||||
|
"y" | "ready" => op = Some(OperationName::Ready),
|
||||||
unknown => anyhow::bail!("unknown operation '{}'", unknown),
|
unknown => anyhow::bail!("unknown operation '{}'", unknown),
|
||||||
},
|
},
|
||||||
Value(val)
|
Value(val)
|
||||||
|
|
@ -226,6 +245,7 @@ impl Args for Options {
|
||||||
Some(OperationName::Update),
|
Some(OperationName::Update),
|
||||||
Some(OperationName::Delete),
|
Some(OperationName::Delete),
|
||||||
Some(OperationName::Archive),
|
Some(OperationName::Archive),
|
||||||
|
Some(OperationName::Ready),
|
||||||
Some(OperationName::Checkout),
|
Some(OperationName::Checkout),
|
||||||
]
|
]
|
||||||
.contains(&op) =>
|
.contains(&op) =>
|
||||||
|
|
@ -262,6 +282,10 @@ impl Args for Options {
|
||||||
OperationName::Checkout => Operation::Checkout {
|
OperationName::Checkout => Operation::Checkout {
|
||||||
patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
|
patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
|
||||||
},
|
},
|
||||||
|
OperationName::Ready => Operation::Ready {
|
||||||
|
patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
|
||||||
|
undo,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
|
|
@ -336,6 +360,10 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
|
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
|
||||||
archive::run(&repository, &profile, &patch_id)?;
|
archive::run(&repository, &profile, &patch_id)?;
|
||||||
}
|
}
|
||||||
|
Operation::Ready { ref patch_id, undo } => {
|
||||||
|
let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
|
||||||
|
ready::run(&repository, &profile, &patch_id, undo)?;
|
||||||
|
}
|
||||||
Operation::Delete { patch_id } => {
|
Operation::Delete { patch_id } => {
|
||||||
let patch_id = patch_id.resolve(&repository.backend)?;
|
let patch_id = patch_id.resolve(&repository.backend)?;
|
||||||
delete::run(&repository, &profile, &patch_id)?;
|
delete::run(&repository, &profile, &patch_id)?;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use radicle::cob::patch;
|
||||||
|
use radicle::prelude::*;
|
||||||
|
use radicle::storage::git::Repository;
|
||||||
|
|
||||||
|
pub fn run(
|
||||||
|
repository: &Repository,
|
||||||
|
profile: &Profile,
|
||||||
|
patch_id: &PatchId,
|
||||||
|
undo: bool,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let signer = term::signer(profile)?;
|
||||||
|
let mut patches = patch::Patches::open(repository)?;
|
||||||
|
let Ok(mut patch) = patches.get_mut(patch_id) else {
|
||||||
|
anyhow::bail!("Patch `{patch_id}` not found");
|
||||||
|
};
|
||||||
|
|
||||||
|
if undo {
|
||||||
|
patch.unready(&signer)?;
|
||||||
|
} else {
|
||||||
|
patch.ready(&signer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -271,6 +271,26 @@ fn rad_patch() {
|
||||||
test("examples/rad-patch.md", working.path(), Some(home), []).unwrap();
|
test("examples/rad-patch.md", working.path(), Some(home), []).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rad_patch_draft() {
|
||||||
|
let mut environment = Environment::new();
|
||||||
|
let profile = environment.profile("alice");
|
||||||
|
let working = tempfile::tempdir().unwrap();
|
||||||
|
let home = &profile.home;
|
||||||
|
|
||||||
|
// Setup a test repository.
|
||||||
|
fixtures::repository(working.path());
|
||||||
|
|
||||||
|
test("examples/rad-init.md", working.path(), Some(home), []).unwrap();
|
||||||
|
test(
|
||||||
|
"examples/rad-patch-draft.md",
|
||||||
|
working.path(),
|
||||||
|
Some(home),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rad_rm() {
|
fn rad_rm() {
|
||||||
let mut environment = Environment::new();
|
let mut environment = Environment::new();
|
||||||
|
|
|
||||||
|
|
@ -980,6 +980,26 @@ impl<'a, 'g> PatchMut<'a, 'g> {
|
||||||
self.lifecycle(State::Archived, signer)
|
self.lifecycle(State::Archived, signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark a patch as ready to be reviewed. Returns `false` if the patch was not a draft.
|
||||||
|
pub fn ready<G: Signer>(&mut self, signer: &G) -> Result<bool, Error> {
|
||||||
|
if self.state() != State::Draft {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
self.lifecycle(State::Open, signer)?;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark an open patch as a draft. Returns `false` if the patch was not open.
|
||||||
|
pub fn unready<G: Signer>(&mut self, signer: &G) -> Result<bool, Error> {
|
||||||
|
if self.state() != State::Open {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
self.lifecycle(State::Draft, signer)?;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
/// Tag a patch.
|
/// Tag a patch.
|
||||||
pub fn tag<G: Signer>(
|
pub fn tag<G: Signer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue