mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-10-05 16:37:44 +03:00
add push method
This commit is contained in:
parent
4cf7c384b1
commit
70acaac3af
@ -566,4 +566,41 @@ impl<E: GitExecutor + 'static> crate::Repository for Repository<E> {
|
||||
})?
|
||||
}
|
||||
}
|
||||
|
||||
async fn push(
|
||||
&self,
|
||||
remote: &str,
|
||||
refspec: RefSpec,
|
||||
authorization: &Authorization,
|
||||
) -> Result<(), crate::Error<Self::Error>> {
|
||||
let mut args = vec!["-C", &self.path, "push", "--quiet"];
|
||||
|
||||
let refspec_string = refspec.to_string();
|
||||
|
||||
args.push(remote);
|
||||
args.push(&refspec_string);
|
||||
|
||||
let (status, stdout, stderr) = self
|
||||
.execute_with_auth_harness(&args, None, authorization)
|
||||
.await?;
|
||||
|
||||
if status == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
// Did the ref not match?
|
||||
if stderr.to_lowercase().contains("does not match any") {
|
||||
// FIXME(qix-): this fallback doesn't make much sense; might need to be reworked.
|
||||
Err(crate::Error::RefNotFound(
|
||||
refspec.source.unwrap_or(refspec_string),
|
||||
))?
|
||||
} else {
|
||||
Err(Error::<E>::Failed {
|
||||
status,
|
||||
args: args.into_iter().map(Into::into).collect(),
|
||||
stdout,
|
||||
stderr,
|
||||
})?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -325,4 +325,78 @@ impl<R: ThreadedResource> crate::Repository for Repository<R> {
|
||||
.await
|
||||
.await
|
||||
}
|
||||
|
||||
async fn push(
|
||||
&self,
|
||||
remote: &str,
|
||||
refspec: RefSpec,
|
||||
authorization: &Authorization,
|
||||
) -> Result<(), crate::Error<Self::Error>> {
|
||||
let remote = remote.to_owned();
|
||||
let authorization = authorization.clone();
|
||||
|
||||
self.repo
|
||||
.with(move |repo| {
|
||||
let mut remote = repo.find_remote(&remote)?;
|
||||
|
||||
let mut callbacks = git2::RemoteCallbacks::new();
|
||||
|
||||
callbacks.credentials(|_url, username, _allowed| {
|
||||
let auth = match &authorization {
|
||||
Authorization::Auto => {
|
||||
let cred = git2::Cred::default()?;
|
||||
Ok(cred)
|
||||
}
|
||||
Authorization::Basic { username, password } => {
|
||||
let username = username.as_deref().unwrap_or_default();
|
||||
let password = password.as_deref().unwrap_or_default();
|
||||
|
||||
git2::Cred::userpass_plaintext(username, password)
|
||||
}
|
||||
Authorization::Ssh {
|
||||
passphrase,
|
||||
private_key,
|
||||
} => {
|
||||
let private_key =
|
||||
private_key.as_ref().map(PathBuf::from).unwrap_or_else(|| {
|
||||
let mut path = dirs::home_dir().unwrap();
|
||||
path.push(".ssh");
|
||||
path.push("id_rsa");
|
||||
path
|
||||
});
|
||||
|
||||
let username = username
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| std::env::var("USER").unwrap_or_default());
|
||||
|
||||
git2::Cred::ssh_key(
|
||||
&username,
|
||||
None,
|
||||
&private_key,
|
||||
passphrase.clone().as_deref(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
auth
|
||||
});
|
||||
|
||||
let mut push_options = git2::PushOptions::new();
|
||||
push_options.remote_callbacks(callbacks);
|
||||
|
||||
let refspec = refspec.to_string();
|
||||
|
||||
let r = remote.push(&[&refspec], Some(&mut push_options));
|
||||
|
||||
r.map_err(|e| {
|
||||
if e.code() == git2::ErrorCode::NotFound {
|
||||
crate::Error::RefNotFound(refspec)
|
||||
} else {
|
||||
e.into()
|
||||
}
|
||||
})
|
||||
})
|
||||
.await
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,36 @@ macro_rules! gitbutler_git_integration_tests {
|
||||
}
|
||||
}).await
|
||||
}
|
||||
|
||||
async fn push_with_ssh_basic_no_master(repo, server, server_repo) {
|
||||
use crate::*;
|
||||
|
||||
let auth = Authorization::Basic {
|
||||
username: Some("my_username".to_owned()),
|
||||
password: Some("my_password".to_owned()),
|
||||
};
|
||||
server.allow_authorization(auth.clone());
|
||||
|
||||
server.run_with_server(async move |port| {
|
||||
repo.create_remote("origin", &format!("[my_username@localhost:{port}]:test.git")).await.unwrap();
|
||||
|
||||
let err = repo.push(
|
||||
"origin",
|
||||
RefSpec{
|
||||
source: Some("refs/heads/master".to_owned()),
|
||||
destination: Some("refs/heads/master".to_owned()),
|
||||
..Default::default()
|
||||
},
|
||||
&auth
|
||||
).await.unwrap_err();
|
||||
|
||||
if let Error::RefNotFound(refname) = err {
|
||||
assert_eq!(refname, "refs/heads/master");
|
||||
} else {
|
||||
panic!("expected RefNotFound, got {:?}", err);
|
||||
}
|
||||
}).await
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -115,6 +115,17 @@ pub trait Repository {
|
||||
|
||||
/// Gets the URI for a remote.
|
||||
async fn remote(&self, remote: &str) -> Result<String, Error<Self::Error>>;
|
||||
|
||||
/// Pushes the given refspec to the given remote.
|
||||
///
|
||||
/// This is an authorized operation; the given authorization
|
||||
/// credentials will be used to authenticate with the remote.
|
||||
async fn push(
|
||||
&self,
|
||||
remote: &str,
|
||||
refspec: RefSpec,
|
||||
authorization: &Authorization,
|
||||
) -> Result<(), Error<Self::Error>>;
|
||||
}
|
||||
|
||||
/// Provides authentication credentials when performing
|
||||
|
Loading…
Reference in New Issue
Block a user