5 Commits

Author SHA1 Message Date
d73314cefb tmp: tests 2022-06-13 22:38:43 +02:00
239e587cbc Use new cargo fmt 2022-06-13 22:38:43 +02:00
742c8587ce Enable output in rust unit tests 2022-06-13 22:38:27 +02:00
Hannes Körber
fb45087477 Update handling of branches on worktree setup 2022-06-13 22:37:58 +02:00
Hannes Körber
a3dc2df37d Quote branch name on output 2022-06-13 22:37:44 +02:00
4 changed files with 175 additions and 46 deletions

View File

@@ -40,8 +40,8 @@ build-static:
test: test-unit test-integration test-e2e test: test-unit test-integration test-e2e
test-unit: test-unit +tests="":
cargo test --lib --bins cargo test --lib --bins -- --show-output {{tests}}
test-integration: test-integration:
cargo test --test "*" cargo test --test "*"

View File

@@ -9,8 +9,8 @@ pub mod gitlab;
pub use github::Github; pub use github::Github;
pub use gitlab::Gitlab; pub use gitlab::Gitlab;
use super::repo;
use super::auth; use super::auth;
use super::repo;
use std::collections::HashMap; use std::collections::HashMap;
@@ -166,7 +166,11 @@ pub trait Provider {
.header("accept", accept_header.unwrap_or("application/json")) .header("accept", accept_header.unwrap_or("application/json"))
.header( .header(
"authorization", "authorization",
format!("{} {}", Self::auth_header_key(), &self.secret_token().access()), format!(
"{} {}",
Self::auth_header_key(),
&self.secret_token().access()
),
) )
.body(()) .body(())
.map_err(|error| error.to_string())?; .map_err(|error| error.to_string())?;

View File

@@ -1184,7 +1184,7 @@ impl RepoHandle {
&& !branch_name.ends_with(&format!("{}{}", super::BRANCH_NAMESPACE_SEPARATOR, name)) && !branch_name.ends_with(&format!("{}{}", super::BRANCH_NAMESPACE_SEPARATOR, name))
{ {
return Err(WorktreeRemoveFailureReason::Error(format!( return Err(WorktreeRemoveFailureReason::Error(format!(
"Branch {} is checked out in worktree, this does not look correct", "Branch \"{}\" is checked out in worktree, this does not look correct",
&branch_name &branch_name
))); )));
} }

View File

@@ -1,9 +1,112 @@
use std::path::Path; use std::path::Path;
use super::output::*;
use super::repo; use super::repo;
pub const GIT_MAIN_WORKTREE_DIRECTORY: &str = ".git-main-working-tree"; pub const GIT_MAIN_WORKTREE_DIRECTORY: &str = ".git-main-working-tree";
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
use std::process::Command;
use tempdir::TempDir;
fn init_empty_repo() -> PathBuf {
let directory = TempDir::new("grm-worktree").unwrap();
Command::new("git")
.args(["init", "."])
.current_dir(directory.path())
.output()
.unwrap();
Command::new("touch")
.args(["test"])
.current_dir(directory.path())
.output()
.unwrap();
Command::new("git")
.args(["add", "test"])
.current_dir(directory.path())
.output()
.unwrap();
Command::new("git")
.args(["commit", "-m", "Initial commit"])
.current_dir(directory.path())
.output()
.unwrap();
Command::new("bash")
.args(["-c", "git ls-files | xargs rm -rf"])
.current_dir(directory.path())
.output()
.unwrap();
Command::new("mv")
.args([".git", GIT_MAIN_WORKTREE_DIRECTORY])
.current_dir(directory.path())
.output()
.unwrap();
Command::new("git")
.args([
"--git-dir",
GIT_MAIN_WORKTREE_DIRECTORY,
"config",
"core.bare",
"true",
])
.current_dir(directory.path())
.output()
.unwrap();
directory.into_path()
}
#[test]
fn add_new_worktree() {
let repo_path = init_empty_repo();
let out = add_worktree(&repo_path, "test", None, None, true);
assert!(out.is_ok());
let repo = git2::Repository::open(repo_path.join("test")).unwrap();
assert_eq!(repo.head().unwrap().shorthand().unwrap(), "test");
assert!(repo
.find_branch("test", git2::BranchType::Local)
.unwrap()
.upstream()
.is_err());
}
#[test]
fn add_new_worktree_with_remote_track() {
let repo_path = init_empty_repo();
let out = add_worktree(&repo_path, "test", None, Some(("origin", "test")), true);
assert!(out.is_ok());
let repo = git2::Repository::open(repo_path.join("test")).unwrap();
assert_eq!(repo.head().unwrap().shorthand().unwrap(), "test");
assert_eq!(
repo.find_branch("test", git2::BranchType::Local)
.unwrap()
.upstream()
.unwrap()
.name()
.unwrap()
.unwrap(),
"test"
);
}
}
// The logic about the base branch and the tracking branch is as follows:
//
// * If a branch with the same name does not exist and no track is given, use the default
// branch
//
// * If a branch with the same name exists and no track is given, use that
//
// * If a branch with the same name does not exist and track is given, use the
// local branch that tracks that branch
//
// * If a branch with the same name exists and track is given, use the locally
// existing branch. If the locally existing branch is not the local branch to
// the remote tracking branch, issue a warning
pub fn add_worktree( pub fn add_worktree(
directory: &Path, directory: &Path,
name: &str, name: &str,
@@ -31,55 +134,77 @@ pub fn add_worktree(
let mut remote_branch_exists = false; let mut remote_branch_exists = false;
let default_checkout = || repo.default_branch()?.to_commit(); let mut target_branch = match repo.find_local_branch(name) {
Ok(branchref) => {
let checkout_commit; if !no_track {
if no_track { if let Some((remote_name, remote_branch_name)) = track {
checkout_commit = default_checkout()?; let remote_branch = repo.find_remote_branch(remote_name, remote_branch_name);
} else { if let Ok(remote_branch) = remote_branch {
match track {
Some((remote_name, remote_branch_name)) => {
let remote_branch = repo.find_remote_branch(remote_name, remote_branch_name);
match remote_branch {
Ok(branch) => {
remote_branch_exists = true; remote_branch_exists = true;
checkout_commit = branch.to_commit()?; if let Ok(local_upstream_branch) = branchref.upstream() {
} if remote_branch.name()? != local_upstream_branch.name()? {
Err(_) => { print_warning(&format!(
remote_branch_exists = false; "You specified a tracking branch ({}) for an existing branch ({}), but \
checkout_commit = default_checkout()?; it differs from the current upstream ({}). Will keep current upstream"
, format!("{}/{}", remote_name, remote_branch_name), branchref.name()?, local_upstream_branch.name()?))
}
}
} }
} }
} }
None => match &config { branchref
None => checkout_commit = default_checkout()?, }
Some(config) => match &config.track { Err(_) => {
None => checkout_commit = default_checkout()?, let default_checkout = || repo.default_branch()?.to_commit();
Some(track_config) => {
if track_config.default { let checkout_commit;
let remote_branch =
repo.find_remote_branch(&track_config.default_remote, name); if no_track {
match remote_branch { checkout_commit = default_checkout()?;
Ok(branch) => { } else {
remote_branch_exists = true; match track {
checkout_commit = branch.to_commit()?; Some((remote_name, remote_branch_name)) => {
} let remote_branch =
Err(_) => { repo.find_remote_branch(remote_name, remote_branch_name);
match remote_branch {
Ok(branch) => {
remote_branch_exists = true;
checkout_commit = branch.to_commit()?;
}
Err(_) => {
remote_branch_exists = false;
checkout_commit = default_checkout()?;
}
}
}
None => match &config {
None => checkout_commit = default_checkout()?,
Some(config) => match &config.track {
None => checkout_commit = default_checkout()?,
Some(track_config) => {
if track_config.default {
let remote_branch =
repo.find_remote_branch(&track_config.default_remote, name);
match remote_branch {
Ok(branch) => {
remote_branch_exists = true;
checkout_commit = branch.to_commit()?;
}
Err(_) => {
checkout_commit = default_checkout()?;
}
}
} else {
checkout_commit = default_checkout()?; checkout_commit = default_checkout()?;
} }
} }
} else { },
checkout_commit = default_checkout()?; },
} };
} }
},
},
};
}
let mut target_branch = match repo.find_local_branch(name) { repo.create_branch(name, &checkout_commit)?
Ok(branchref) => branchref, }
Err(_) => repo.create_branch(name, &checkout_commit)?,
}; };
fn push( fn push(