Skip to content

Commit 1de5cd3

Browse files
committed
vb.toml adapter will allow changing the target branch on the workspace.
1 parent bcacbc2 commit 1de5cd3

File tree

2 files changed

+85
-25
lines changed

2 files changed

+85
-25
lines changed

crates/but-graph/src/ref_metadata_legacy.rs

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -365,38 +365,40 @@ impl RefMetadata for VirtualBranchesTomlMetadata {
365365
stack.in_workspace = false;
366366
}
367367

368+
let new_target_branch = value
369+
.target_ref
370+
.as_ref()
371+
.map(|rn| branch_from_ref_name(rn.as_ref()))
372+
.transpose()?;
368373
// We don't support initialising this yet, for now just changes.
369374
let mut changed_target = false;
370-
if let Some(target) = self.data_mut().default_target.as_mut() {
371-
if target.push_remote_name != value.push_remote {
372-
target.push_remote_name = value.push_remote.clone();
375+
match (&mut self.data_mut().default_target, new_target_branch) {
376+
(existing @ Some(_), None) => {
377+
// Have to clear everything then due to limitations of the data structure.
378+
*existing = None;
373379
changed_target = true;
374380
}
375-
if let Some((category, short_name)) = value
376-
.target_ref
377-
.as_ref()
378-
.and_then(|rn| rn.category_and_short_name())
379-
{
380-
if category == Category::RemoteBranch {
381-
// TODO: remove this as we don't handle symbolic names with slashes correctly.
382-
// At least try to not always set this value, but this test is also ambiguous.
383-
if !short_name.ends_with_str(target.branch.branch()) {
384-
let slash_pos = short_name.find_byte(b'/').context(
385-
"remote branch didn't have '/' in the name, but should be 'origin/foo'",
386-
)?;
387-
target.branch = RemoteRefname::new(
388-
short_name[..slash_pos].to_str_lossy().as_ref(),
389-
short_name[slash_pos + 1..].to_str_lossy().as_ref(),
390-
);
391-
changed_target = true;
392-
}
393-
} else {
394-
bail!(
395-
"Cannot set target branches to a branch that isn't a remote tracking branch: '{short_name}'"
396-
);
381+
(None, Some(_new)) => {
382+
bail!(
383+
"Cannot reasonably set a target in the old data structure as we don't have repo access here"
384+
)
385+
}
386+
(Some(existing), Some(new)) => {
387+
if existing.branch != new {
388+
existing.branch = new;
389+
changed_target = true;
397390
}
398391
}
392+
(None, None) => {}
399393
}
394+
395+
if let Some(target) = self.data_mut().default_target.as_mut()
396+
&& target.push_remote_name != value.push_remote
397+
{
398+
target.push_remote_name = value.push_remote.clone();
399+
changed_target = true;
400+
}
401+
400402
if changed_target {
401403
self.snapshot.changed_at = Some(Instant::now());
402404
}
@@ -515,6 +517,27 @@ impl RefMetadata for VirtualBranchesTomlMetadata {
515517
}
516518
}
517519

520+
fn branch_from_ref_name(ref_name: &FullNameRef) -> anyhow::Result<RemoteRefname> {
521+
let (category, short_name) = ref_name
522+
.category_and_short_name()
523+
.context("couldn't classify supposed remote tracking branch")?;
524+
if category != Category::RemoteBranch {
525+
bail!(
526+
"Cannot set target branches to a branch that isn't a remote tracking branch: '{short_name}'"
527+
);
528+
}
529+
530+
// TODO: remove this as we don't handle symbolic names with slashes correctly.
531+
// At least try to not always set this value, but this test is also ambiguous.
532+
let slash_pos = short_name
533+
.find_byte(b'/')
534+
.context("remote branch didn't have '/' in the name, but should be 'origin/foo'")?;
535+
Ok(RemoteRefname::new(
536+
short_name[..slash_pos].to_str_lossy().as_ref(),
537+
short_name[slash_pos + 1..].to_str_lossy().as_ref(),
538+
))
539+
}
540+
518541
impl VirtualBranchesTomlMetadata {
519542
fn workspace_from_data(data: &VirtualBranches) -> Workspace {
520543
let (target_branch, push_remote) = data

crates/but-graph/tests/graph/ref_metadata_legacy.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,43 @@ fn create_workspace_and_stacks_with_branches_from_scratch() -> anyhow::Result<()
790790
Ok(())
791791
}
792792

793+
#[test]
794+
fn target_journey() -> anyhow::Result<()> {
795+
let (mut store, _tmp) = empty_vb_store_rw()?;
796+
let ws_name = "refs/heads/gitbutler/workspace".try_into()?;
797+
let mut ws = store.workspace(ws_name)?;
798+
assert_eq!(
799+
ws.target_ref,
800+
Some("refs/remotes/origin/sub-name/main".try_into()?)
801+
);
802+
803+
let expected_target: gix::refs::FullName = "refs/remotes/origin/main".try_into()?;
804+
ws.target_ref = Some(expected_target.clone());
805+
store.set_workspace(&ws)?;
806+
807+
let mut ws = store.workspace(ws_name)?;
808+
assert_eq!(
809+
ws.target_ref,
810+
Some(expected_target.clone()),
811+
"can change the name as well"
812+
);
813+
814+
ws.target_ref = None;
815+
store.set_workspace(&ws)?;
816+
817+
let mut ws = store.workspace(ws_name)?;
818+
ws.target_ref = Some(expected_target);
819+
820+
let err = store.set_workspace(&ws).unwrap_err();
821+
assert_eq!(
822+
err.to_string(),
823+
"Cannot reasonably set a target in the old data structure as we don't have repo access here",
824+
"cannot do that as the data structures are too incompatible, can't set all values and certainly shouldn't make it up"
825+
);
826+
827+
Ok(())
828+
}
829+
793830
#[test]
794831
fn create_workspace_from_scratch_workspace_first() -> anyhow::Result<()> {
795832
let (mut store, _tmp) = empty_vb_store_rw()?;

0 commit comments

Comments
 (0)