cli: Setup tracking branch on `rad patch checkout`

Just like when opening a new patch, we setup a tracking branch on patch
checkout, so that patches can be updated via a push.
This commit is contained in:
Alexis Sellier 2023-06-21 13:09:30 +02:00
parent 1e948485be
commit b25c2e452b
No known key found for this signature in database
6 changed files with 80 additions and 54 deletions

View File

@ -107,6 +107,7 @@ Now, let's checkout the patch that we just created:
``` ```
$ rad patch checkout 077e4bb $ rad patch checkout 077e4bb
✓ Switched to branch patch/077e4bb ✓ Switched to branch patch/077e4bb
✓ Branch patch/077e4bb setup to track rad/patches/077e4bbe9a6e5546f400ef5951768c37a76f13a4
``` ```
We can also add a review verdict as such: We can also add a review verdict as such:

View File

@ -58,17 +58,20 @@ way will tell others about the corrections we needed before merging the
changes. changes.
``` ```
$ git checkout patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c $ rad patch checkout 50e29a111972f3b7d2123c5057de5bdf09bc7b1c
branch 'patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c' set up to track 'bob/patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c'. ✓ Switched to branch patch/50e29a1
✓ Branch patch/50e29a1 setup to track rad/patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c
$ git mv REQUIREMENTS REQUIREMENTS.md $ git mv REQUIREMENTS REQUIREMENTS.md
$ git commit --fixup HEAD~ $ git commit -m "Use markdown for requirements"
[patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c f6484e0] fixup! Define power requirements [patch/50e29a1 f567f69] Use markdown for requirements
1 file changed, 0 insertions(+), 0 deletions(-) 1 file changed, 0 insertions(+), 0 deletions(-)
rename REQUIREMENTS => REQUIREMENTS.md (100%) rename REQUIREMENTS => REQUIREMENTS.md (100%)
$ rad patch update --message "Define power requirements" --message "See details." 50e29a111972f3b7d2123c5057de5bdf09bc7b1c ```
Updating 27857ec -> f6484e0 ``` (stderr)
1 commit(s) ahead, 0 commit(s) behind $ git push rad -o no-sync -o patch.message="Use markdown for requirements"
✓ Patch updated to revision a3405e8e174d9660fead6eea1dea5cdd2b728488 ✓ Patch 50e29a1 updated to 744c1f0a75b1c42833c9aa32f79cd40443925d66
To rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
* [new branch] patch/50e29a1 -> patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c
``` ```
Great, all fixed up, lets merge the code. Great, all fixed up, lets merge the code.
@ -76,8 +79,8 @@ Great, all fixed up, lets merge the code.
``` ```
$ git checkout master $ git checkout master
Your branch is up to date with 'rad/master'. Your branch is up to date with 'rad/master'.
$ git merge patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c $ git merge patch/50e29a1
Updating f2de534..f6484e0 Updating f2de534..f567f69
Fast-forward Fast-forward
README.md | 0 README.md | 0
REQUIREMENTS.md | 0 REQUIREMENTS.md | 0
@ -95,20 +98,20 @@ $ rad patch show 50e29a1
│ Title Define power requirements │ │ Title Define power requirements │
│ Patch 50e29a111972f3b7d2123c5057de5bdf09bc7b1c │ │ Patch 50e29a111972f3b7d2123c5057de5bdf09bc7b1c │
│ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │ │ Author did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk │
│ Head f6484e0f43e48a8983b9b39bf9bd4cd889f1d520 │ Head f567f695d25b4e8fb63b5f5ad2a584529826e908
│ Branches master, patches/50e29a111972f3b7d2123c5057de5bdf09bc7b1c │ Branches master, patch/50e29a1
│ Commits up to date │ │ Commits up to date │
│ Status merged │ │ Status merged │
│ │ │ │
│ See details. │ │ See details. │
├──────────────────────────────────────────────────────────────────────────────┤ ├──────────────────────────────────────────────────────────────────────────────┤
│ f6484e0 fixup! Define power requirements │ f567f69 Use markdown for requirements
│ 27857ec Add README, just for the fun │ │ 27857ec Add README, just for the fun │
│ 3e674d1 Define power requirements │ │ 3e674d1 Define power requirements │
├──────────────────────────────────────────────────────────────────────────────┤ ├──────────────────────────────────────────────────────────────────────────────┤
│ ● opened by bob (z6Mkt67…v4N1tRk) [ ... ] │ │ ● opened by bob (z6Mkt67…v4N1tRk) [ ... ] │
│ ↑ updated to 3530243d46a2e7a8e4eac7afcbb17cc7c56b3d29 (27857ec) [ ... ] │ │ ↑ updated to 3530243d46a2e7a8e4eac7afcbb17cc7c56b3d29 (27857ec) [ ... ] │
│ ↑ updated to a3405e8e174d9660fead6eea1dea5cdd2b728488 (f6484e0) [ ... ] │ │ ↑ updated to 744c1f0a75b1c42833c9aa32f79cd40443925d66 (f567f69) [ ... ] │
│ ✓ merged by (you) (z6MknSL…StBU8Vi) [ ... ] │ │ ✓ merged by (you) (z6MknSL…StBU8Vi) [ ... ] │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
``` ```

View File

@ -18,22 +18,19 @@ Now let's checkout `master` and pull the maintainer's changes:
``` ```
$ git checkout master $ git checkout master
Your branch is up to date with 'rad/master'. Your branch is up to date with 'rad/master'.
```
``` (stderr)
$ git pull --all --ff $ git pull --all --ff
Fetching rad From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji
Fetching z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi f2de534..f567f69 master -> rad/master
Updating f2de534..f6484e0 From rad://z42hL2jL4XNk6K8oHQaSWfMgCL7ji/z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
Fast-forward f2de534..f567f69 master -> z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master
README.md | 0
REQUIREMENTS.md | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
create mode 100644 REQUIREMENTS.md
``` ```
Now our master branch is up to date with the maintainer's master: Now our master branch is up to date with the maintainer's master:
``` ```
$ git rev-parse master $ git rev-parse master
f6484e0f43e48a8983b9b39bf9bd4cd889f1d520 f567f695d25b4e8fb63b5f5ad2a584529826e908
$ git diff master..z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master $ git diff master..z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master
``` ```

View File

@ -2,10 +2,10 @@ use anyhow::anyhow;
use radicle::cob::patch; use radicle::cob::patch;
use radicle::cob::patch::{Patch, PatchId}; use radicle::cob::patch::{Patch, PatchId};
use radicle::git;
use radicle::git::RefString; use radicle::git::RefString;
use radicle::storage::git::Repository; use radicle::storage::git::Repository;
use radicle::storage::ReadRepository; use radicle::storage::ReadRepository;
use radicle::{git, rad};
use crate::terminal as term; use crate::terminal as term;
@ -32,10 +32,20 @@ pub fn run(
spinner.message(format!( spinner.message(format!(
"Switched to branch {}", "Switched to branch {}",
term::format::highlight(patch_branch.as_str()) term::format::highlight(&patch_branch)
)); ));
spinner.finish(); spinner.finish();
if let Some(branch) = rad::setup_patch_upstream(patch_id, *patch.head(), working)? {
let tracking = branch
.name()?
.ok_or_else(|| anyhow!("failed to create tracking branch: invalid name"))?;
term::success!(
"Branch {} setup to track {}",
term::format::highlight(patch_branch),
term::format::tertiary(tracking)
);
}
Ok(()) Ok(())
} }
@ -52,7 +62,6 @@ fn find_patch_commit<'a>(
match working.find_commit(patch_head.into()) { match working.find_commit(patch_head.into()) {
Ok(commit) => Ok(commit), Ok(commit) => Ok(commit),
Err(e) if git::ext::is_not_found_err(&e) => { Err(e) if git::ext::is_not_found_err(&e) => {
// TODO: Handle case of concurrent revisions.
let (_, rev) = patch.latest(); let (_, rev) = patch.latest();
let author = *rev.author().id(); let author = *rev.author().id();
let remote = stored.remote(&author)?; let remote = stored.remote(&author)?;

View File

@ -325,34 +325,9 @@ fn patch_open<G: Signer>(
"Create reference for patch head", "Create reference for patch head",
)?; )?;
let head = working.head()?; // Setup current branch so that pushing updates the patch.
if head.peel_to_commit()?.id() == commit.id() { rad::setup_patch_upstream(&patch, commit.id().into(), working)?;
if let Ok(r) = head.resolve() {
let branch = git::raw::Branch::wrap(r);
let name: Option<git::RefString> =
branch.name()?.and_then(|b| b.try_into().ok());
working.reference(
&git::refs::workdir::patch_upstream(&patch),
commit.id(),
// The patch shouldn't exist yet, and so neither should
// this ref.
false,
"Create remote tracking branch for patch",
)?;
if let Some(name) = name {
if branch.upstream().is_err() {
git::set_upstream(
working,
&*radicle::rad::REMOTE_NAME,
name.as_str(),
git::refs::workdir::patch(&patch),
)?;
}
}
}
}
Ok(()) Ok(())
} }
Err(e) => Err(e), Err(e) => Err(e),

View File

@ -6,6 +6,7 @@ use std::str::FromStr;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use thiserror::Error; use thiserror::Error;
use crate::cob::ObjectId;
use crate::crypto::{Signer, Verified}; use crate::crypto::{Signer, Verified};
use crate::git; use crate::git;
use crate::identity::doc::{DocError, Id}; use crate::identity::doc::{DocError, Id};
@ -317,6 +318,46 @@ pub fn repo(path: impl AsRef<Path>) -> Result<(git2::Repository, Id), RemoteErro
Ok((repo, id)) Ok((repo, id))
} }
/// Setup patch upstream branch such that `git push` updates the patch.
pub fn setup_patch_upstream<'a>(
patch: &ObjectId,
patch_head: git::Oid,
working: &'a git::raw::Repository,
) -> Result<Option<git::raw::Branch<'a>>, git::ext::Error> {
let head = working.head()?;
// Don't do anything in case we're not on the patch branch.
if head.peel_to_commit()?.id() != *patch_head {
return Ok(None);
}
let Ok(r) = head.resolve() else {
return Ok(None);
};
let branch = git::raw::Branch::wrap(r);
let name: Option<git::RefString> = branch.name()?.and_then(|b| b.try_into().ok());
let remote_branch = git::refs::workdir::patch_upstream(patch);
let remote_branch = working.reference(
&remote_branch,
*patch_head,
true,
"Create remote tracking branch for patch",
)?;
assert!(remote_branch.is_remote());
if let Some(name) = name {
if branch.upstream().is_err() {
git::set_upstream(
working,
&*REMOTE_NAME,
name.as_str(),
git::refs::workdir::patch(patch),
)?;
}
}
Ok(Some(git::raw::Branch::wrap(remote_branch)))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::collections::HashMap; use std::collections::HashMap;