use anyhow::Result; use git2::{ Cred, CredentialType, Direction, FetchOptions, PushOptions, RemoteCallbacks, Repository, Signature, }; use std::path::Path; pub const TAGS: &'static [&'static str] = &["refs/tags/*:refs/tags/*"]; pub fn pull(repo: &Repository, token: String, what: &[&str]) -> Result<()> { let mut remote = repo.find_remote("origin")?; let mut fo = FetchOptions::new(); remote.connect_auth(Direction::Fetch, Some(callbacks(token.clone())), None)?; fo.remote_callbacks(callbacks(token)); remote.fetch(what, Some(&mut fo), None)?; Ok(()) } fn callbacks<'a>(token: String) -> RemoteCallbacks<'a> { let mut callbacks = RemoteCallbacks::new(); callbacks.credentials(move |_u, _username, allowed_types| { if allowed_types.contains(CredentialType::SSH_KEY) { let user = "git"; Cred::ssh_key_from_agent(user) } else { Cred::userpass_plaintext(&token, "x-oauth-basic") } }); callbacks } pub fn push(repo: &Repository, token: String, what: &[&str]) -> Result<()> { let mut remote = repo.find_remote("origin")?; remote.connect_auth(Direction::Push, Some(callbacks(token.clone())), None)?; let mut po = PushOptions::new(); po.remote_callbacks(callbacks(token)); remote.push(what, Some(&mut po))?; Ok(()) } pub fn commit(repo: &Repository, sig: &Signature, msg: &str, files: &[&str]) -> Result<()> { let mut index = repo.index()?; for file in files { index.add_path(Path::new(file))?; } let oid = index.write_tree()?; let tree = repo.find_tree(oid)?; repo.commit(Some("HEAD"), &sig, &sig, &msg, &tree, &[])?; Ok(()) } pub fn tag_version(repo: &Repository, sig: &Signature, tag: String, desc: String) -> Result<()> { let obj = repo.revparse_single("HEAD")?; repo.tag(&tag, &obj, &sig, &desc, false)?; Ok(()) } pub fn has_tag(repo: &Repository, tag: String) -> Result { let tags = repo.tag_names(Some(&tag))?; for tag_obj in tags.iter() { if tag_obj.is_none() { continue; } let tag_name = tag_obj.unwrap(); log::debug!("tag: {}", tag_name.to_string()); if tag == tag_name.to_string() { return Ok(true); } } Ok(false) } #[cfg(test)] mod tests { use anyhow::Result; use git2::*; use std::{fs::File, io::Write}; use tempfile::tempdir; #[test] fn has_tag() -> Result<()> { const TAG: &'static str = "0.1.0"; let dir = tempdir()?; let repo = Repository::init(&dir)?; let mut fout = File::create(&dir.path().join("VERSION"))?; write!(fout, "{}", TAG)?; drop(fout); let sig = &Signature::now("Gitea Release Tool", "gitea-release@tulpa.dev")?; super::commit(&repo, &sig, "test commit please ignore", &["VERSION"])?; super::tag_version(&repo, &sig, TAG.into(), format!("version {}", TAG))?; assert!(super::has_tag(&repo, TAG.into())?); Ok(()) } }