use anyhow::Error; use giterated_models::{ object::Object, repository::{ Commit, DefaultBranch, Repository, RepositoryCommitBeforeRequest, RepositoryCommitFromIdRequest, }, }; use giterated_stack::{AuthenticatedUser, GiteratedStack, OperationState, StackOperationState}; use super::{GitBackend, GitBackendError}; impl GitBackend { /// Gets the total amount of commits using revwalk pub fn get_total_commit_count( git: &git2::Repository, start_commit: &git2::Commit, ) -> anyhow::Result { // TODO: There must be a better way let mut revwalk = git.revwalk()?; revwalk.set_sorting(git2::Sort::TIME)?; revwalk.push(start_commit.id())?; Ok(revwalk.count()) } /// Gets the last commit in a rev pub fn get_last_commit_in_rev( git: &git2::Repository, rev: &str, default_branch: &DefaultBranch, ) -> anyhow::Result { let oid = Self::get_oid_from_reference(git, Some(rev), default_branch)?; // Walk through the repository commit graph starting at our rev let mut revwalk = git.revwalk()?; revwalk.set_sorting(git2::Sort::TIME)?; revwalk.push(oid)?; if let Some(Ok(commit_oid)) = revwalk.next() { if let Ok(commit) = git .find_commit(commit_oid) .map_err(|_| GitBackendError::CommitNotFound(commit_oid.to_string())) { return Ok(Commit::from(commit)); } } Err(GitBackendError::RefNotFound(oid.to_string()).into()) } pub async fn handle_repository_commit_from_id( &mut self, requester: &Option, repository_object: &mut Object<'_, StackOperationState, Repository, GiteratedStack>, OperationState(_operation_state): OperationState, request: &RepositoryCommitFromIdRequest, ) -> Result { let repository = repository_object.object(); let git = self .open_repository_and_check_permissions(&repository.owner, &repository.name, requester) .await?; // Parse the passed object ids let oid = git2::Oid::from_str(request.0.as_str()) .map_err(|_| GitBackendError::InvalidObjectId(request.0.clone()))?; // Get the commit from the oid let commit = git .find_commit(oid) .map_err(|_| GitBackendError::CommitNotFound(oid.to_string()))?; Ok(Commit::from(commit)) } pub async fn handle_repository_commit_before( &mut self, requester: &Option, repository_object: &mut Object<'_, StackOperationState, Repository, GiteratedStack>, OperationState(_operation_state): OperationState, request: &RepositoryCommitBeforeRequest, ) -> Result { let repository = repository_object.object(); let git = self .open_repository_and_check_permissions(&repository.owner, &repository.name, requester) .await?; // Parse the passed object id let oid = match git2::Oid::from_str(request.0.as_str()) { Ok(oid) => oid, Err(_) => { return Err(Box::new(GitBackendError::InvalidObjectId(request.0.clone())).into()) } }; // Find the commit using the parsed oid let commit = match git.find_commit(oid) { Ok(commit) => commit, Err(_) => return Err(Box::new(GitBackendError::CommitNotFound(oid.to_string())).into()), }; // Get the first parent it has let parent = commit.parent(0); if let Ok(parent) = parent { return Ok(Commit::from(parent)); } else { // TODO: See if can be done better // Walk through the repository commit graph starting at our current commit let mut revwalk = git.revwalk()?; revwalk.set_sorting(git2::Sort::TIME)?; revwalk.push(commit.id())?; if let Some(Ok(before_commit_oid)) = revwalk.next() { // Find the commit using the parsed oid if let Ok(before_commit) = git.find_commit(before_commit_oid) { return Ok(Commit::from(before_commit)); } } Err(Box::new(GitBackendError::CommitParentNotFound(oid.to_string())).into()) } } }