lucide/scripts/src/repository.rs
2025-06-07 08:25:36 +00:00

139 lines
3.7 KiB
Rust

use std::{env, error::Error, path::Path};
use git2::{BranchType, Cred, IndexAddOption, PushOptions, RemoteCallbacks, Repository, Signature};
use log::info;
use semver::Version;
use crate::{GITHUB_OWNER, GITHUB_REPO, UPSTREAM_GIT_URL};
pub fn git_checkout<P: AsRef<Path>>(
path: P,
url: &str,
r#ref: &str,
) -> Result<Repository, Box<dyn Error>> {
info!(
"Cloning \"{}\" ref \"{}\" into \"{}\".",
UPSTREAM_GIT_URL,
r#ref,
path.as_ref().display()
);
let repository = Repository::clone(url, path)?;
{
let (object, reference) = repository.revparse_ext(r#ref)?;
repository.checkout_tree(&object, None)?;
match reference {
Some(reference) => {
repository.set_head(reference.name().expect("Reference name should exist."))?
}
None => repository.set_head_detached(object.id())?,
}
}
Ok(repository)
}
pub fn git_version_tags(repository: &Repository) -> Result<Vec<Version>, Box<dyn Error>> {
let tag_names = repository.tag_names(None)?;
let mut tag_names = tag_names
.into_iter()
.flat_map(|tag_name| {
tag_name.and_then(|tag_name| Version::parse(tag_name.trim_start_matches("v")).ok())
})
.collect::<Vec<_>>();
tag_names.sort();
Ok(tag_names)
}
pub fn git_has_remote_branch(repository: &Repository, branch_name: &str) -> bool {
repository
.find_branch(&format!("origin/{branch_name}"), BranchType::Remote)
.is_ok()
}
pub fn git_create_branch(repository: &Repository, branch_name: &str) -> Result<(), Box<dyn Error>> {
info!("Creating branch {branch_name}.");
let branch = repository.branch(branch_name, &repository.head()?.peel_to_commit()?, false)?;
repository.set_head(
branch
.into_reference()
.name()
.expect("Reference name should exist."),
)?;
Ok(())
}
pub fn git_commit(repository: &Repository, message: &str) -> Result<(), Box<dyn Error>> {
info!("Committing.");
repository
.index()?
.add_all(["."], IndexAddOption::DEFAULT, None)?;
repository.index()?.write()?;
let signature = Signature::now(&env::var("GIT_USER_NAME")?, &env::var("GIT_USER_EMAIL")?)?;
let tree = repository.find_tree(repository.index()?.write_tree()?)?;
let parent = repository.head()?.peel_to_commit()?;
repository.commit(
Some("HEAD"),
&signature,
&signature,
message,
&tree,
&[&parent],
)?;
Ok(())
}
pub fn git_push(repository: &Repository, branch_name: &str) -> Result<(), Box<dyn Error>> {
info!("Pushing branch {branch_name}.");
let branch = repository.find_branch(branch_name, BranchType::Local)?;
let branch_reference = branch.into_reference();
let branch_ref = branch_reference
.name()
.expect("Reference name should exist.");
let username = env::var("GITHUB_ACTOR")?;
let password = env::var("GITHUB_TOKEN")?;
let mut callbacks = RemoteCallbacks::new();
callbacks.credentials(|_, _, _| Cred::userpass_plaintext(&username, &password));
let mut options = PushOptions::new();
options.remote_callbacks(callbacks);
let mut remote = repository.find_remote("origin")?;
remote.push(&[branch_ref], Some(&mut options))?;
Ok(())
}
pub async fn github_create_pull_request(
branch_name: &str,
title: &str,
body: &str,
) -> Result<(), Box<dyn Error>> {
let octocrab = octocrab::instance();
info!("Creating pull request for branch {branch_name}.");
octocrab
.pulls(GITHUB_OWNER, GITHUB_REPO)
.create(title, branch_name, "main")
.body(body)
.send()
.await?;
Ok(())
}