pub use crate::context::facade::GitContext; pub use crate::handler::RepoPath; pub use crate::service::GitService; pub use crate::service::commits::{CommitStatusDto, CommitStatusDtoState}; pub use crate::service::diffs::{ChangedPathDiffDto, DiffOptionsDto}; pub use crate::service::merge::{ExecuteMergeCmd, MergeCommitDto, MergePlanDto, MergeResultDto}; pub use crate::share::access::authorize_repo_access; pub use crate::share::errors::GitError; use models::repo::repos; use sea_orm::{ActiveModelTrait, ConnectionTrait, EntityTrait, QuerySelect, Set}; use uuid::Uuid; pub struct RepositoryInfo { pub lower_name: String, pub is_private: bool, } impl GitService { pub async fn repository(&self, id: Uuid) -> Result, GitError> { let Some(repo) = repos::Entity::find_by_id(id) .one(self.database.read()) .await? else { return Ok(None); }; Ok(Some(RepositoryInfo { lower_name: repo.lower_name, is_private: repo.is_private, })) } pub async fn repository_visible_from_space( &self, id: Uuid, space_id: Uuid, ) -> Result { let Some(repo) = repos::Entity::find_by_id(id) .one(self.database.read()) .await? else { return Ok(false); }; if !repo.is_private { return Ok(true); } Ok(self .access .for_dir(repo.dir_id) .await? .is_some_and(|space| space.id() == space_id)) } pub async fn merge_requirements( &self, repository: Uuid, branch: &str, caller: i64, ) -> Result, GitError> { let policies = crate::share::policy::match_branch_policies(self.database.read(), repository, branch) .await?; if policies.is_empty() { return Ok(None); } let whitelists = crate::share::policy::branch_policy_whitelists(self.database.read(), &policies).await?; Ok(Some(MergeRequirements { required_approvals: policies .iter() .map(|policy| policy.required_approvals) .max() .unwrap_or(0), dismiss_stale_approvals: policies.iter().any(|policy| policy.dismiss_stale_approvals), whitelist_bypass: policies.iter().any(|policy| policy.enable_merge_whitelist) && whitelists.merge_allowed.contains(&caller), block_on_rejected_reviews: policies .iter() .any(|policy| policy.block_on_rejected_reviews), block_on_change_requested_reviews: policies .iter() .any(|policy| policy.block_on_change_requested_reviews), block_on_outdated_branch: policies .iter() .any(|policy| policy.block_on_outdated_branch), require_signed_commits: policies.iter().any(|policy| policy.require_signed_commits), required_status_contexts: policies .iter() .flat_map(|policy| { policy .required_status_contexts .split(['\n', ',']) .map(str::trim) .filter(|value| !value.is_empty()) .map(str::to_owned) }) .collect(), protected_file_patterns: policies .iter() .map(|policy| policy.protected_file_patterns.as_str()) .collect::>() .join(","), unprotected_file_patterns: policies .iter() .map(|policy| policy.unprotected_file_patterns.as_str()) .collect::>() .join(","), })) } pub async fn lock_repository( &self, tx: &impl ConnectionTrait, id: Uuid, ) -> Result<(), GitError> { repos::Entity::find_by_id(id) .lock_exclusive() .one(tx) .await? .ok_or(GitError::NotFound)?; Ok(()) } pub async fn set_pull_count(&self, id: Uuid, count: i32) -> Result<(), GitError> { repos::ActiveModel { id: Set(id), nums_pr: Set(count), ..Default::default() } .update(self.database.write()) .await?; Ok(()) } } pub struct MergeRequirements { pub required_approvals: i32, pub dismiss_stale_approvals: bool, pub whitelist_bypass: bool, pub block_on_rejected_reviews: bool, pub block_on_change_requested_reviews: bool, pub block_on_outdated_branch: bool, pub require_signed_commits: bool, pub required_status_contexts: Vec, pub protected_file_patterns: String, pub unprotected_file_patterns: String, }