Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
cli: Add `rad patch archive --undo`
Merged did:key:z6MkkfM3...sVz5 opened 2 years ago

Allows archived patches to be reverted to open state.

3 files changed +45 -9 ea31040e 0581c017
modified radicle-cli/src/commands/patch.rs
@@ -57,7 +57,7 @@ Usage
    rad patch list [--all|--merged|--open|--archived|--draft|--authored] [--author <did>]... [<option>...]
    rad patch show <patch-id> [<option>...]
    rad patch diff <patch-id> [<option>...]
-
    rad patch archive <patch-id> [<option>...]
+
    rad patch archive <patch-id> [--undo] [<option>...]
    rad patch update <patch-id> [<option>...]
    rad patch checkout <patch-id> [<option>...]
    rad patch review <patch-id> [--accept | --reject] [-m [<string>]] [-d | --delete] [<option>...]
@@ -109,6 +109,10 @@ Assign options
    -d, --delete <did>         Delete an assignee from the patch (may be specified multiple times).
                               Note: --add will take precedence over --delete

+
Archive options
+

+
        --undo                 Unarchive a patch
+

Label options

    -a, --add    <label>       Add a label to the patch (may be specified multiple times).
@@ -204,6 +208,7 @@ pub enum Operation {
    },
    Archive {
        patch_id: Rev,
+
        undo: bool,
    },
    Ready {
        patch_id: Rev,
@@ -347,6 +352,11 @@ impl Args for Options {
                    undo = true;
                }

+
                // Archive options.
+
                Long("undo") if op == Some(OperationName::Archive) => {
+
                    undo = true;
+
                }
+

                // Update options.
                Short('b') | Long("base") if op == Some(OperationName::Update) => {
                    let val = parser.value()?;
@@ -591,6 +601,7 @@ impl Args for Options {
            },
            OperationName::Archive => Operation::Archive {
                patch_id: patch_id.ok_or_else(|| anyhow!("a patch id must be provided"))?,
+
                undo,
            },
            OperationName::Checkout => Operation::Checkout {
                patch_id: patch_id.ok_or_else(|| anyhow!("a patch must be provided"))?,
@@ -726,9 +737,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
                &workdir,
            )?;
        }
-
        Operation::Archive { ref patch_id } => {
+
        Operation::Archive { ref patch_id, undo } => {
            let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
-
            archive::run(&patch_id, &profile, &repository)?;
+
            archive::run(&patch_id, undo, &profile, &repository)?;
        }
        Operation::Ready { ref patch_id, undo } => {
            let patch_id = patch_id.resolve::<PatchId>(&repository.backend)?;
modified radicle-cli/src/commands/patch/archive.rs
@@ -3,13 +3,23 @@ use super::*;
use radicle::prelude::*;
use radicle::storage::git::Repository;

-
pub fn run(patch_id: &PatchId, profile: &Profile, repository: &Repository) -> anyhow::Result<()> {
+
pub fn run(
+
    patch_id: &PatchId,
+
    undo: bool,
+
    profile: &Profile,
+
    repository: &Repository,
+
) -> anyhow::Result<()> {
    let signer = term::signer(profile)?;
    let mut patches = profile.patches_mut(repository)?;
    let Ok(mut patch) = patches.get_mut(patch_id) else {
        anyhow::bail!("Patch `{patch_id}` not found");
    };
-
    patch.archive(&signer)?;
+

+
    if undo {
+
        patch.unarchive(&signer)?;
+
    } else {
+
        patch.archive(&signer)?;
+
    }

    Ok(())
}
modified radicle/src/cob/patch.rs
@@ -2242,11 +2242,25 @@ where
    }

    /// Archive a patch.
-
    pub fn archive<G: Signer>(&mut self, signer: &G) -> Result<EntryId, Error> {
-
        self.lifecycle(Lifecycle::Archived, signer)
+
    pub fn archive<G: Signer>(&mut self, signer: &G) -> Result<bool, Error> {
+
        self.lifecycle(Lifecycle::Archived, signer)?;
+

+
        Ok(true)
+
    }
+

+
    /// Mark an archived patch as ready to be reviewed again.
+
    /// Returns `false` if the patch was not archived.
+
    pub fn unarchive<G: Signer>(&mut self, signer: &G) -> Result<bool, Error> {
+
        if !self.is_archived() {
+
            return Ok(false);
+
        }
+
        self.lifecycle(Lifecycle::Open, signer)?;
+

+
        Ok(true)
    }

-
    /// Mark a patch as ready to be reviewed. Returns `false` if the patch was not a draft.
+
    /// 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.is_draft() {
            return Ok(false);
@@ -2256,7 +2270,8 @@ where
        Ok(true)
    }

-
    /// Mark an open patch as a draft. Returns `false` if the patch was not open and free of merges.
+
    /// Mark an open patch as a draft.
+
    /// Returns `false` if the patch was not open and free of merges.
    pub fn unready<G: Signer>(&mut self, signer: &G) -> Result<bool, Error> {
        if !matches!(self.state(), State::Open { conflicts } if conflicts.is_empty()) {
            return Ok(false);