mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2025-01-01 14:04:57 +03:00
Merge pull request #1930 from gitbutlerapp/refactor-delete-branch-function
support deletion of applied branches
This commit is contained in:
commit
65fc2d1cc3
@ -40,7 +40,6 @@ impl super::RunCommand for Setup {
|
||||
set_base_branch(
|
||||
&app.gb_repository(),
|
||||
&app.project_repository(),
|
||||
app.user(),
|
||||
&items[index].branch().parse()?,
|
||||
)
|
||||
.context("failed to set target branch")?;
|
||||
|
@ -5,14 +5,18 @@ use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
gb_repository,
|
||||
git::{self, diff},
|
||||
git::{
|
||||
self,
|
||||
diff::{self, Options},
|
||||
},
|
||||
keys,
|
||||
project_repository::{self, LogUntil},
|
||||
reader, sessions, users,
|
||||
virtual_branches::branch::Ownership,
|
||||
};
|
||||
|
||||
use super::{
|
||||
branch, delete_branch,
|
||||
branch,
|
||||
errors::{self, CreateVirtualBranchFromBranchError},
|
||||
integration::GITBUTLER_INTEGRATION_REFERENCE,
|
||||
iterator, target, BranchId, RemoteCommit,
|
||||
@ -51,30 +55,29 @@ pub fn get_base_branch_data(
|
||||
pub fn set_base_branch(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
user: Option<&users::User>,
|
||||
target_branch: &git::RemoteRefname,
|
||||
target_branch_ref: &git::RemoteRefname,
|
||||
) -> Result<super::BaseBranch, errors::SetBaseBranchError> {
|
||||
let repo = &project_repository.git_repository;
|
||||
|
||||
// lookup a branch by name
|
||||
let branch = match repo.find_branch(&target_branch.clone().into()) {
|
||||
let target_branch = match repo.find_branch(&target_branch_ref.clone().into()) {
|
||||
Ok(branch) => Ok(branch),
|
||||
Err(git::Error::NotFound(_)) => Err(errors::SetBaseBranchError::BranchNotFound(
|
||||
target_branch.clone(),
|
||||
target_branch_ref.clone(),
|
||||
)),
|
||||
Err(error) => Err(errors::SetBaseBranchError::Other(error.into())),
|
||||
}?;
|
||||
|
||||
let remote_name = repo
|
||||
.branch_remote_name(branch.refname().unwrap())
|
||||
.branch_remote_name(target_branch.refname().unwrap())
|
||||
.context(format!(
|
||||
"failed to get remote name for branch {}",
|
||||
branch.name().unwrap()
|
||||
target_branch.name().unwrap()
|
||||
))?;
|
||||
let remote = repo.find_remote(&remote_name).context(format!(
|
||||
"failed to find remote {} for branch {}",
|
||||
remote_name,
|
||||
branch.name().unwrap()
|
||||
target_branch.name().unwrap()
|
||||
))?;
|
||||
let remote_url = remote
|
||||
.url()
|
||||
@ -84,34 +87,30 @@ pub fn set_base_branch(
|
||||
))?
|
||||
.unwrap();
|
||||
|
||||
// get a list of currently active virtual branches
|
||||
|
||||
// if there are no applied virtual branches, calculate the sha as the merge-base between HEAD in project_repository and this target commit
|
||||
let commit = branch.peel_to_commit().context(format!(
|
||||
let target_branch_head = target_branch.peel_to_commit().context(format!(
|
||||
"failed to peel branch {} to commit",
|
||||
branch.name().unwrap()
|
||||
target_branch.name().unwrap()
|
||||
))?;
|
||||
let mut commit_oid = commit.id();
|
||||
|
||||
let head_ref = repo.head().context("Failed to get HEAD reference")?;
|
||||
let head_name: git::Refname = head_ref
|
||||
.name()
|
||||
.context("Failed to get HEAD reference name")?;
|
||||
let head_oid = head_ref
|
||||
let head_commit = head_ref
|
||||
.peel_to_commit()
|
||||
.context("Failed to peel HEAD reference to commit")?
|
||||
.id();
|
||||
.context("Failed to peel HEAD reference to commit")?;
|
||||
|
||||
if head_oid != commit_oid {
|
||||
// calculate the commit as the merge-base between HEAD in project_repository and this target commit
|
||||
commit_oid = repo.merge_base(head_oid, commit_oid).context(format!(
|
||||
// calculate the commit as the merge-base between HEAD in project_repository and this target commit
|
||||
let commit_oid = repo
|
||||
.merge_base(head_commit.id(), target_branch_head.id())
|
||||
.context(format!(
|
||||
"Failed to calculate merge base between {} and {}",
|
||||
head_oid, commit_oid
|
||||
head_commit.id(),
|
||||
target_branch_head.id()
|
||||
))?;
|
||||
}
|
||||
|
||||
let target = target::Target {
|
||||
branch: target_branch.clone(),
|
||||
branch: target_branch_ref.clone(),
|
||||
remote_url: remote_url.to_string(),
|
||||
sha: commit_oid,
|
||||
};
|
||||
@ -119,38 +118,83 @@ pub fn set_base_branch(
|
||||
let target_writer = target::Writer::new(gb_repository);
|
||||
target_writer.write_default(&target)?;
|
||||
|
||||
let current_session = gb_repository
|
||||
.get_or_create_current_session()
|
||||
.context("failed to get current session")?;
|
||||
let current_session_reader = sessions::Reader::open(gb_repository, ¤t_session)
|
||||
.context("failed to open current session for reading")?;
|
||||
|
||||
let virtual_branches = iterator::BranchIterator::new(¤t_session_reader)
|
||||
.context("failed to create branch iterator")?
|
||||
.collect::<Result<Vec<branch::Branch>, reader::Error>>()
|
||||
.context("failed to read virtual branches")?;
|
||||
|
||||
let active_virtual_branches = virtual_branches
|
||||
.iter()
|
||||
.filter(|branch| branch.applied)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if active_virtual_branches.is_empty()
|
||||
&& !head_name
|
||||
.to_string()
|
||||
.eq(&GITBUTLER_INTEGRATION_REFERENCE.to_string())
|
||||
if !head_name
|
||||
.to_string()
|
||||
.eq(&GITBUTLER_INTEGRATION_REFERENCE.to_string())
|
||||
{
|
||||
let branch = create_virtual_branch_from_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
&head_name,
|
||||
Some(true),
|
||||
user,
|
||||
)
|
||||
.context("failed to create virtual branch")?;
|
||||
if branch.ownership.is_empty() && branch.head == target.sha {
|
||||
delete_branch(gb_repository, project_repository, &branch.id)
|
||||
.context("failed to delete branch")?;
|
||||
// if there are any commits on the head branch or uncommitted changes in the working directory, we need to
|
||||
// put them into a virtual branch
|
||||
|
||||
let wd_diff = diff::workdir(repo, &head_commit.id(), &Options::default())?;
|
||||
|
||||
if !wd_diff.is_empty() || head_commit.id() != commit_oid {
|
||||
let hunks_by_filepath =
|
||||
super::virtual_hunks_by_filepath(&project_repository.project().path, &wd_diff);
|
||||
|
||||
// assign ownership to the branch
|
||||
let ownership = hunks_by_filepath.values().flatten().fold(
|
||||
Ownership::default(),
|
||||
|mut ownership, hunk| {
|
||||
ownership.put(
|
||||
&format!("{}:{}", hunk.file_path.display(), hunk.id)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
ownership
|
||||
},
|
||||
);
|
||||
|
||||
let now_ms = time::UNIX_EPOCH
|
||||
.elapsed()
|
||||
.context("failed to get elapsed time")?
|
||||
.as_millis();
|
||||
|
||||
let (upstream, upstream_head) = if let git::Refname::Local(head_name) = &head_name {
|
||||
let upstream_name = target_branch_ref.with_branch(head_name.branch());
|
||||
if upstream_name.eq(target_branch_ref) {
|
||||
(None, None)
|
||||
} else {
|
||||
match repo.find_reference(&git::Refname::from(&upstream_name)) {
|
||||
Ok(upstream) => {
|
||||
let head = upstream
|
||||
.peel_to_commit()
|
||||
.map(|commit| commit.id())
|
||||
.context(format!(
|
||||
"failed to peel upstream {} to commit",
|
||||
upstream.name().unwrap()
|
||||
))?;
|
||||
Ok((Some(upstream_name), Some(head)))
|
||||
}
|
||||
Err(git::Error::NotFound(_)) => Ok((None, None)),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
.context(format!("failed to find upstream for {}", head_name))?
|
||||
}
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let branch = branch::Branch {
|
||||
id: BranchId::generate(),
|
||||
name: head_name.to_string().replace("refs/heads/", ""),
|
||||
notes: String::new(),
|
||||
applied: true,
|
||||
upstream,
|
||||
upstream_head,
|
||||
created_timestamp_ms: now_ms,
|
||||
updated_timestamp_ms: now_ms,
|
||||
head: head_commit.id(),
|
||||
tree: super::write_tree_onto_commit(
|
||||
project_repository,
|
||||
head_commit.id(),
|
||||
&wd_diff,
|
||||
)?,
|
||||
ownership,
|
||||
order: 0,
|
||||
};
|
||||
|
||||
let branch_writer = branch::Writer::new(gb_repository);
|
||||
branch_writer.write(&branch)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,14 +565,8 @@ impl ControllerInner {
|
||||
)
|
||||
.context("failed to open gitbutler repository")?;
|
||||
|
||||
let target = super::set_base_branch(
|
||||
&gb_repository,
|
||||
&project_repository,
|
||||
user.as_ref(),
|
||||
target_branch,
|
||||
)?;
|
||||
|
||||
Ok(target)
|
||||
super::set_base_branch(&gb_repository, &project_repository, target_branch)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn merge_virtual_branch_upstream(
|
||||
|
@ -46,6 +46,8 @@ impl From<VerifyError> for crate::error::Error {
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum DeleteBranchError {
|
||||
#[error(transparent)]
|
||||
UnapplyBranch(#[from] UnapplyBranchError),
|
||||
#[error(transparent)]
|
||||
Other(#[from] anyhow::Error),
|
||||
}
|
||||
@ -414,6 +416,7 @@ impl From<IsRemoteBranchMergableError> for Error {
|
||||
impl From<DeleteBranchError> for Error {
|
||||
fn from(value: DeleteBranchError) -> Self {
|
||||
match value {
|
||||
DeleteBranchError::UnapplyBranch(error) => error.into(),
|
||||
DeleteBranchError::Other(error) => {
|
||||
tracing::error!(?error, "delete branch error");
|
||||
Error::Unknown
|
||||
|
@ -1348,7 +1348,7 @@ pub fn delete_branch(
|
||||
gb_repository: &gb_repository::Repository,
|
||||
project_repository: &project_repository::Repository,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<branch::Branch, errors::DeleteBranchError> {
|
||||
) -> Result<(), errors::DeleteBranchError> {
|
||||
let current_session = gb_repository
|
||||
.get_or_create_current_session()
|
||||
.context("failed to get or create currnt session")?;
|
||||
@ -1361,12 +1361,16 @@ pub fn delete_branch(
|
||||
.read(branch_id)
|
||||
.context("failed to read branch")?;
|
||||
|
||||
if branch.applied && unapply_branch(gb_repository, project_repository, branch_id)?.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
branch_writer
|
||||
.delete(&branch)
|
||||
.context("Failed to remove branch")?;
|
||||
|
||||
project_repository.delete_branch_reference(&branch)?;
|
||||
Ok(branch)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_ownership(
|
||||
@ -1872,6 +1876,9 @@ pub fn write_tree_onto_commit(
|
||||
let rel_path = std::path::Path::new(&filepath);
|
||||
let full_path = project_repository.path().join(rel_path);
|
||||
|
||||
let is_submodule =
|
||||
full_path.is_dir() && hunks.len() == 1 && hunks[0].diff.contains("Subproject commit");
|
||||
|
||||
// if file exists
|
||||
if full_path.exists() {
|
||||
// if file is executable, use 755, otherwise 644
|
||||
@ -1930,9 +1937,28 @@ pub fn write_tree_onto_commit(
|
||||
// upsert into the builder
|
||||
builder.upsert(rel_path, new_blob_oid, filemode);
|
||||
}
|
||||
} else if is_submodule {
|
||||
let mut blob_contents = vec![];
|
||||
|
||||
let mut hunks = hunks.clone();
|
||||
hunks.sort_by_key(|hunk| hunk.new_start);
|
||||
for hunk in hunks {
|
||||
let patch = format!("--- original\n+++ modified\n{}", hunk.diff);
|
||||
let patch_bytes = patch.as_bytes();
|
||||
let patch = Patch::from_bytes(patch_bytes)?;
|
||||
blob_contents = apply_bytes(&blob_contents, &patch)
|
||||
.context(format!("failed to apply {}", &hunk.diff))?;
|
||||
}
|
||||
|
||||
// create a blob
|
||||
let new_blob_oid = git_repository.blob(&blob_contents)?;
|
||||
// upsert into the builder
|
||||
builder.upsert(rel_path, new_blob_oid, filemode);
|
||||
} else {
|
||||
// create a git blob from a file on disk
|
||||
let blob_oid = git_repository.blob_path(&full_path)?;
|
||||
let blob_oid = git_repository
|
||||
.blob_path(&full_path)
|
||||
.context(format!("failed to create blob from path {:?}", &full_path))?;
|
||||
builder.upsert(rel_path, blob_oid, filemode);
|
||||
}
|
||||
} else if base_tree.get_path(rel_path).is_ok() {
|
||||
|
@ -70,6 +70,11 @@ impl TestProject {
|
||||
self.local_repository.workdir().unwrap()
|
||||
}
|
||||
|
||||
pub fn push_branch(&self, branch: &git::LocalRefname) {
|
||||
let mut origin = self.local_repository.find_remote("origin").unwrap();
|
||||
origin.push(&[&format!("{branch}:{branch}")], None).unwrap();
|
||||
}
|
||||
|
||||
pub fn push(&self) {
|
||||
let mut origin = self.local_repository.find_remote("origin").unwrap();
|
||||
origin
|
||||
@ -161,8 +166,36 @@ impl TestProject {
|
||||
self.local_repository.find_commit(oid)
|
||||
}
|
||||
|
||||
pub fn checkout(&self, branch: git::LocalRefname) {
|
||||
let branch: git::Refname = branch.into();
|
||||
let tree = match self.local_repository.find_branch(&branch) {
|
||||
Ok(branch) => branch.peel_to_tree(),
|
||||
Err(git::Error::NotFound(_)) => {
|
||||
let head_commit = self
|
||||
.local_repository
|
||||
.head()
|
||||
.unwrap()
|
||||
.peel_to_commit()
|
||||
.unwrap();
|
||||
self.local_repository
|
||||
.reference(&branch, head_commit.id(), false, "new branch")
|
||||
.unwrap();
|
||||
head_commit.tree()
|
||||
}
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
.unwrap();
|
||||
self.local_repository.set_head(&branch).unwrap();
|
||||
self.local_repository
|
||||
.checkout_tree(&tree)
|
||||
.force()
|
||||
.checkout()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// takes all changes in the working directory and commits them into local
|
||||
pub fn commit_all(&self, message: &str) -> git::Oid {
|
||||
let head = self.local_repository.head().unwrap();
|
||||
let mut index = self.local_repository.index().expect("failed to get index");
|
||||
index
|
||||
.add_all(["."], git2::IndexAddOption::DEFAULT, None)
|
||||
@ -172,7 +205,7 @@ impl TestProject {
|
||||
let signature = git::Signature::now("test", "test@email.com").unwrap();
|
||||
self.local_repository
|
||||
.commit(
|
||||
Some(&"refs/heads/master".parse().unwrap()),
|
||||
head.name().as_ref(),
|
||||
&signature,
|
||||
&signature,
|
||||
message,
|
||||
|
@ -315,51 +315,6 @@ mod references {
|
||||
}
|
||||
}
|
||||
|
||||
mod delete_virtual_branch {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn simple() {
|
||||
let Test {
|
||||
project_id,
|
||||
controller,
|
||||
repository,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let id = controller
|
||||
.create_virtual_branch(
|
||||
&project_id,
|
||||
&branch::BranchCreateRequest {
|
||||
name: Some("name".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
controller
|
||||
.delete_virtual_branch(&project_id, &id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 0);
|
||||
|
||||
let refnames = repository
|
||||
.references()
|
||||
.into_iter()
|
||||
.filter_map(|reference| reference.name().map(|name| name.to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
assert!(!refnames.contains(&"refs/gitbutler/name".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
mod push_virtual_branch {
|
||||
use super::*;
|
||||
|
||||
@ -519,6 +474,87 @@ mod references {
|
||||
}
|
||||
}
|
||||
|
||||
mod delete_virtual_branch {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn should_unapply_diff() {
|
||||
let Test {
|
||||
project_id,
|
||||
controller,
|
||||
repository,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// write some
|
||||
std::fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
|
||||
controller
|
||||
.delete_virtual_branch(&project_id, &branches[0].id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 0);
|
||||
assert!(!repository.path().join("file.txt").exists());
|
||||
|
||||
let refnames = repository
|
||||
.references()
|
||||
.into_iter()
|
||||
.filter_map(|reference| reference.name().map(|name| name.to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
assert!(!refnames.contains(&"refs/gitbutler/name".to_string()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn should_remove_reference() {
|
||||
let Test {
|
||||
project_id,
|
||||
controller,
|
||||
repository,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let id = controller
|
||||
.create_virtual_branch(
|
||||
&project_id,
|
||||
&branch::BranchCreateRequest {
|
||||
name: Some("name".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
controller
|
||||
.delete_virtual_branch(&project_id, &id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 0);
|
||||
|
||||
let refnames = repository
|
||||
.references()
|
||||
.into_iter()
|
||||
.filter_map(|reference| reference.name().map(|name| name.to_string()))
|
||||
.collect::<Vec<_>>();
|
||||
assert!(!refnames.contains(&"refs/gitbutler/name".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
mod set_base_branch {
|
||||
use super::*;
|
||||
|
||||
@ -3404,6 +3440,140 @@ mod init {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dirty_non_target() {
|
||||
// a situation when you initialize project while being on the local verison of the master
|
||||
// that has uncommited changes.
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
repository.checkout("refs/heads/some-feature".parse().unwrap());
|
||||
|
||||
fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 1);
|
||||
assert_eq!(branches[0].files.len(), 1);
|
||||
assert_eq!(branches[0].files[0].hunks.len(), 1);
|
||||
assert!(branches[0].upstream.is_none());
|
||||
assert_eq!(branches[0].name, "some-feature");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dirty_target() {
|
||||
// a situation when you initialize project while being on the local verison of the master
|
||||
// that has uncommited changes.
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 1);
|
||||
assert_eq!(branches[0].files.len(), 1);
|
||||
assert_eq!(branches[0].files[0].hunks.len(), 1);
|
||||
assert!(branches[0].upstream.is_none());
|
||||
assert_eq!(branches[0].name, "master");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn commit_on_non_target_local() {
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
repository.checkout("refs/heads/some-feature".parse().unwrap());
|
||||
fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
repository.commit_all("commit on target");
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
dbg!(&branches);
|
||||
assert_eq!(branches.len(), 1);
|
||||
assert!(branches[0].files.is_empty());
|
||||
assert_eq!(branches[0].commits.len(), 1);
|
||||
assert!(branches[0].upstream.is_none());
|
||||
assert_eq!(branches[0].name, "some-feature");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn commit_on_non_target_remote() {
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
repository.checkout("refs/heads/some-feature".parse().unwrap());
|
||||
fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
repository.commit_all("commit on target");
|
||||
repository.push_branch(&"refs/heads/some-feature".parse().unwrap());
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
dbg!(&branches);
|
||||
assert_eq!(branches.len(), 1);
|
||||
assert!(branches[0].files.is_empty());
|
||||
assert_eq!(branches[0].commits.len(), 1);
|
||||
assert!(branches[0].upstream.is_some());
|
||||
assert_eq!(branches[0].name, "some-feature");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn commit_on_target() {
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
repository.commit_all("commit on target");
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 1);
|
||||
assert!(branches[0].files.is_empty());
|
||||
assert_eq!(branches[0].commits.len(), 1);
|
||||
assert!(branches[0].upstream.is_none());
|
||||
assert_eq!(branches[0].name, "master");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn submodule() {
|
||||
let Test {
|
||||
@ -3431,28 +3601,6 @@ mod init {
|
||||
assert_eq!(branches[0].files.len(), 1);
|
||||
assert_eq!(branches[0].files[0].hunks.len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dirty() {
|
||||
let Test {
|
||||
repository,
|
||||
project_id,
|
||||
controller,
|
||||
..
|
||||
} = Test::default();
|
||||
|
||||
fs::write(repository.path().join("file.txt"), "content").unwrap();
|
||||
|
||||
controller
|
||||
.set_base_branch(&project_id, &"refs/remotes/origin/master".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
assert_eq!(branches.len(), 1);
|
||||
assert_eq!(branches[0].files.len(), 1);
|
||||
assert_eq!(branches[0].files[0].hunks.len(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
mod squash {
|
||||
|
@ -74,7 +74,6 @@
|
||||
<Button
|
||||
color="error"
|
||||
on:click={async () => {
|
||||
await branchController.unapplyBranch(branch.id);
|
||||
await branchController.deleteBranch(branch.id);
|
||||
}}
|
||||
>
|
||||
|
Loading…
Reference in New Issue
Block a user