12 Commits

Author SHA1 Message Date
Hannes Körber
0f45708e81 Improve default branch guessing 2022-06-13 22:37:36 +02:00
Hannes Körber
d036b53037 Print ok-ish stuff to stdout 2022-06-13 22:37:27 +02:00
2be1dec818 Add some comments about repo syncing 2022-06-13 22:37:19 +02:00
f89c9c2ca5 Do not fail on empty clone target 2022-06-13 22:37:11 +02:00
62c2fc24cd Initialize local branches on clone 2022-06-13 22:37:06 +02:00
d0425e2fdb Add function to get all remote branches 2022-06-13 22:37:03 +02:00
a8665ae741 Add function to get basename of branch 2022-06-13 22:36:54 +02:00
d26b6e799c Refactor default_branch() for readability 2022-06-13 22:36:47 +02:00
60eb059f60 providers: Use references for field access 2022-06-13 22:32:31 +02:00
d9f416018d Use opaque type for auth token
So we cannot accidentially output it, as it does not implement
`Display`.
2022-06-13 22:32:31 +02:00
Max Volk
461c69dacb Reword some of the documentation and spelling fixes 2022-06-13 22:32:26 +02:00
ef21f9cad4 Remove accidentially added file 2022-06-13 22:32:26 +02:00
8 changed files with 98 additions and 123 deletions

45
Cargo.lock generated
View File

@@ -101,7 +101,7 @@ version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
dependencies = [ dependencies = [
"heck", "heck 0.4.0",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -119,9 +119,9 @@ dependencies = [
[[package]] [[package]]
name = "comfy-table" name = "comfy-table"
version = "6.0.0" version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121d8a5b0346092c18a4b2fd6f620d7a06f0eb7ac0a45860939a0884bc579c56" checksum = "b103d85ca6e209388771bfb7aa6b68a7aeec4afbf6f0a0264bfbf50360e5212e"
dependencies = [ dependencies = [
"crossterm", "crossterm",
"strum", "strum",
@@ -332,7 +332,7 @@ dependencies = [
[[package]] [[package]]
name = "git-repo-manager" name = "git-repo-manager"
version = "0.7.2" version = "0.7.1"
dependencies = [ dependencies = [
"clap", "clap",
"comfy-table", "comfy-table",
@@ -371,6 +371,15 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.4.0"
@@ -523,9 +532,9 @@ dependencies = [
[[package]] [[package]]
name = "libz-sys" name = "libz-sys"
version = "1.1.8" version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" checksum = "92e7e15d7610cce1d9752e137625f14e61a28cd45929b6e12e47b50fe154ee2e"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -611,9 +620,9 @@ dependencies = [
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.74" version = "0.9.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cc", "cc",
@@ -637,9 +646,9 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
dependencies = [ dependencies = [
"lock_api", "lock_api",
"parking_lot_core", "parking_lot_core",
@@ -996,17 +1005,17 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.24.1" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.24.1" version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9550962e7cf70d9980392878dfaf1dcc3ece024f4cf3bf3c46b978d0bad61d6c" checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
dependencies = [ dependencies = [
"heck", "heck 0.3.3",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
@@ -1167,6 +1176,12 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.9" version = "0.1.9"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "git-repo-manager" name = "git-repo-manager"
version = "0.7.2" version = "0.7.1"
edition = "2021" edition = "2021"
authors = [ authors = [
@@ -64,7 +64,7 @@ version = "=0.15.0"
version = "=1.5.6" version = "=1.5.6"
[dependencies.comfy-table] [dependencies.comfy-table]
version = "=6.0.0" version = "=5.0.1"
[dependencies.serde_yaml] [dependencies.serde_yaml]
version = "=0.8.24" version = "=0.8.24"

View File

@@ -2,7 +2,7 @@ set positional-arguments
target := "x86_64-unknown-linux-musl" target := "x86_64-unknown-linux-musl"
check: fmt-check lint test check: test
cargo check cargo check
cargo fmt --check cargo fmt --check
cargo clippy --no-deps -- -Dwarnings cargo clippy --no-deps -- -Dwarnings
@@ -11,12 +11,8 @@ fmt:
cargo fmt cargo fmt
git ls-files | grep '\.py$' | xargs black git ls-files | grep '\.py$' | xargs black
fmt-check:
cargo fmt --check
git ls-files | grep '\.py$' | xargs black --check
lint: lint:
cargo clippy --no-deps -- -Dwarnings cargo clippy --no-deps
lint-fix: lint-fix:
cargo clippy --no-deps --fix cargo clippy --no-deps --fix
@@ -44,8 +40,8 @@ build-static:
test: test-unit test-integration test-e2e test: test-unit test-integration test-e2e
test-unit +tests="": test-unit:
cargo test --lib --bins -- --show-output {{tests}} cargo test --lib --bins
test-integration: test-integration:
cargo test --test "*" cargo test --test "*"

View File

@@ -136,8 +136,8 @@ impl Provider for Github {
fn get_current_user(&self) -> Result<String, ApiErrorResponse<GithubApiErrorResponse>> { fn get_current_user(&self) -> Result<String, ApiErrorResponse<GithubApiErrorResponse>> {
Ok(super::call::<GithubUser, GithubApiErrorResponse>( Ok(super::call::<GithubUser, GithubApiErrorResponse>(
&format!("{GITHUB_API_BASEURL}/user"), &format!("{GITHUB_API_BASEURL}/user"),
Self::auth_header_key(), &Self::auth_header_key(),
self.secret_token(), &self.secret_token(),
Some(ACCEPT_HEADER_JSON), Some(ACCEPT_HEADER_JSON),
)? )?
.username) .username)

View File

@@ -157,8 +157,8 @@ impl Provider for Gitlab {
fn get_current_user(&self) -> Result<String, ApiErrorResponse<GitlabApiErrorResponse>> { fn get_current_user(&self) -> Result<String, ApiErrorResponse<GitlabApiErrorResponse>> {
Ok(super::call::<GitlabUser, GitlabApiErrorResponse>( Ok(super::call::<GitlabUser, GitlabApiErrorResponse>(
&format!("{}/api/v4/user", self.api_url()), &format!("{}/api/v4/user", self.api_url()),
Self::auth_header_key(), &Self::auth_header_key(),
self.secret_token(), &self.secret_token(),
Some(ACCEPT_HEADER_JSON), Some(ACCEPT_HEADER_JSON),
)? )?
.username) .username)

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::auth;
use super::repo; use super::repo;
use super::auth;
use std::collections::HashMap; use std::collections::HashMap;
@@ -166,11 +166,7 @@ pub trait Provider {
.header("accept", accept_header.unwrap_or("application/json")) .header("accept", accept_header.unwrap_or("application/json"))
.header( .header(
"authorization", "authorization",
format!( format!("{} {}", Self::auth_header_key(), &self.secret_token().access()),
"{} {}",
Self::auth_header_key(),
&self.secret_token().access()
),
) )
.body(()) .body(())
.map_err(|error| error.to_string())?; .map_err(|error| error.to_string())?;
@@ -295,7 +291,7 @@ pub trait Provider {
for repo in repos { for repo in repos {
let namespace = repo.namespace(); let namespace = repo.namespace();
let mut repo = repo.into_repo_config(self.name(), worktree_setup, force_ssh); let mut repo = repo.into_repo_config(&self.name(), worktree_setup, force_ssh);
// Namespace is already part of the hashmap key. I'm not too happy // Namespace is already part of the hashmap key. I'm not too happy
// about the data exchange format here. // about the data exchange format here.

View File

@@ -1056,12 +1056,12 @@ impl RepoHandle {
// Note that <remote>/HEAD only exists after a normal clone, there is no way to get the // Note that <remote>/HEAD only exists after a normal clone, there is no way to get the
// remote HEAD afterwards. So this is a "best effort" approach. // remote HEAD afterwards. So this is a "best effort" approach.
if let Ok(remote_head) = self.find_remote_branch(remote_name, "HEAD") { if let Ok(remote_head) = self.find_remote_branch(&remote_name, "HEAD") {
if let Some(pointer_name) = remote_head.as_reference().symbolic_target() { if let Some(pointer_name) = remote_head.as_reference().symbolic_target() {
if let Some(local_branch_name) = if let Some(local_branch_name) =
pointer_name.strip_prefix(&format!("refs/remotes/{}/", remote_name)) pointer_name.strip_prefix(&format!("refs/remotes/{}/", remote_name))
{ {
return Ok(Some(self.find_local_branch(local_branch_name)?)); return Ok(Some(self.find_local_branch(&local_branch_name)?));
} else { } else {
eprintln!("Remote HEAD ({}) pointer is invalid", pointer_name); eprintln!("Remote HEAD ({}) pointer is invalid", pointer_name);
} }
@@ -1088,7 +1088,7 @@ impl RepoHandle {
if remotes.len() == 1 { if remotes.len() == 1 {
let remote_name = &remotes[0]; let remote_name = &remotes[0];
if let Some(default_branch) = self.get_remote_default_branch(remote_name)? { if let Some(default_branch) = self.get_remote_default_branch(&remote_name)? {
return Ok(default_branch); return Ok(default_branch);
} }
} else { } else {
@@ -1099,13 +1099,17 @@ impl RepoHandle {
} }
} }
if !default_branches.is_empty() if !default_branches.is_empty() {
&& (default_branches.len() == 1 if default_branches.len() == 1 {
|| default_branches return Ok(default_branches.remove(0));
} else {
if default_branches
.windows(2) .windows(2)
.all(|w| w[0].name() == w[1].name())) .all(|w| w[0].name() == w[1].name())
{ {
return Ok(default_branches.remove(0)); return Ok(default_branches.remove(0));
}
}
} }
} }
@@ -1180,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,23 +1,9 @@
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";
// 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,
@@ -45,77 +31,55 @@ pub fn add_worktree(
let mut remote_branch_exists = false; let mut remote_branch_exists = false;
let mut target_branch = match repo.find_local_branch(name) { let default_checkout = || repo.default_branch()?.to_commit();
Ok(branchref) => {
if !no_track { let checkout_commit;
if let Some((remote_name, remote_branch_name)) = track { if no_track {
let remote_branch = repo.find_remote_branch(remote_name, remote_branch_name); checkout_commit = default_checkout()?;
if let Ok(remote_branch) = remote_branch { } else {
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;
if let Ok(local_upstream_branch) = branchref.upstream() { checkout_commit = branch.to_commit()?;
if remote_branch.name()? != local_upstream_branch.name()? { }
print_warning(&format!( Err(_) => {
"You specified a tracking branch ({}/{}) for an existing branch ({}), but \ remote_branch_exists = false;
it differs from the current upstream ({}). Will keep current upstream" checkout_commit = default_checkout()?;
, remote_name, remote_branch_name, branchref.name()?, local_upstream_branch.name()?))
}
}
} }
} }
} }
branchref None => match &config {
} None => checkout_commit = default_checkout()?,
Err(_) => { Some(config) => match &config.track {
let default_checkout = || repo.default_branch()?.to_commit(); None => checkout_commit = default_checkout()?,
Some(track_config) => {
let checkout_commit; if track_config.default {
let remote_branch =
if no_track { repo.find_remote_branch(&track_config.default_remote, name);
checkout_commit = default_checkout()?; match remote_branch {
} else { Ok(branch) => {
match track { remote_branch_exists = true;
Some((remote_name, remote_branch_name)) => { checkout_commit = branch.to_commit()?;
let remote_branch = }
repo.find_remote_branch(remote_name, remote_branch_name); Err(_) => {
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()?;
}; }
} }
},
},
};
}
repo.create_branch(name, &checkout_commit)? let mut target_branch = match repo.find_local_branch(name) {
} Ok(branchref) => branchref,
Err(_) => repo.create_branch(name, &checkout_commit)?,
}; };
fn push( fn push(