JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Add ahead_behind comparison, filter and range to branches request.

erremilia - ⁨2⁩ years ago

parent: tbd commit: ⁨3aca035

Showing ⁨⁨3⁩ changed files⁩ with ⁨⁨67⁩ insertions⁩ and ⁨⁨18⁩ deletions⁩

giterated-daemon/src/backend/git.rs

View file
@@ -13,7 +13,7 @@ use giterated_models::repository::{
13 13 RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryIssue,
14 14 RepositoryIssueLabelsRequest, RepositoryIssuesCountRequest, RepositoryIssuesRequest,
15 15 RepositoryLastCommitOfFileRequest, RepositoryObjectType, RepositoryStatistics,
16 RepositoryStatisticsRequest, RepositoryTreeEntry, RepositoryVisibility, Visibility,
16 RepositoryStatisticsRequest, RepositoryTreeEntry, RepositoryVisibility, Visibility, RepositoryBranchFilter,
17 17 };
18 18
19 19 use giterated_models::user::User;
@@ -771,33 +771,63 @@ impl RepositoryBackend for GitBackend {
771 771 &mut self,
772 772 requester: &Option<AuthenticatedUser>,
773 773 repository: &Repository,
774 _request: &RepositoryBranchesRequest,
774 request: &RepositoryBranchesRequest,
775 775 ) -> Result<Vec<RepositoryBranch>, Error> {
776 776 let git = self
777 777 .open_repository_and_check_permissions(&repository.owner, &repository.name, requester)
778 778 .await?;
779 779
780 let mut branches = vec![];
781
782 for branch in git.branches(None)? {
783 let branch = branch?;
780 // Could be done better with the RepositoryBranchFilter::None check done beforehand.
781 let mut filtered_branches = git.branches(None)?.filter_map(|branch| {
782 let branch = branch.ok()?.0;
784 783
785 let Some(name) = branch.0.name().ok().flatten() else {
786 continue;
784 let Some(name) = branch.name().ok().flatten() else {
785 return None;
787 786 };
788 787
789 788 // TODO: Non UTF-8?
790 let commit =
791 GitBackend::get_last_commit_in_rev(&git, branch.0.get().name().unwrap()).ok();
789 let Some(commit) = GitBackend::get_last_commit_in_rev(&git, branch.get().name().unwrap()).ok() else {
790 return None;
791 };
792 792
793 793 // TODO: Implement stale with configurable age
794 794 let stale = false;
795 795
796 branches.push(RepositoryBranch {
797 name: name.to_string(),
798 stale,
799 last_commit: commit,
800 })
796 // Filter based on if the branch is stale or not
797 if request.filter != RepositoryBranchFilter::None {
798 #[allow(clippy::if_same_then_else)]
799 if stale && request.filter == RepositoryBranchFilter::Active {
800 return None;
801 } else if !stale && request.filter == RepositoryBranchFilter::Stale {
802 return None;
803 }
804 }
805
806 Some((name.to_string(), branch, stale, commit))
807 }).collect::<Vec<_>>();
808
809 // Sort the branches by commit date
810 filtered_branches.sort_by(|(_, _, _, c1), (_, _, _, c2)| c2.time.cmp(&c1.time));
811 // Go to the requested position
812 let mut filtered_branches = filtered_branches.iter().skip(request.range.0);
813
814 let head = git.head()?;
815 let mut branches = vec![];
816
817 // Iterate through the filtered branches using the passed range
818 for _ in request.range.0..request.range.1 {
819 let Some((name, branch, stale, commit)) = filtered_branches.next() else {
820 break;
821 };
822
823 // Get how many commits are ahead of and behind of the head
824 let ahead_behind_head = if head.target().is_some() && branch.get().target().is_some() {
825 git.graph_ahead_behind(branch.get().target().unwrap(), head.target().unwrap()).ok()
826 } else {
827 None
828 };
829
830 branches.push(RepositoryBranch { name: name.to_string(), stale: *stale, last_commit: Some(commit.clone()), ahead_behind_head })
801 831 }
802 832
803 833 Ok(branches)

giterated-models/src/repository/mod.rs

View file
@@ -163,6 +163,16 @@ pub struct RepositoryBranch {
163 163 pub stale: bool,
164 164 /// The last commit made to the branch
165 165 pub last_commit: Option<Commit>,
166 /// How many commits this branch is ahead or behind from the main branch
167 pub ahead_behind_head: Option<(usize, usize)>,
168 }
169
170 /// Filter primarily used for branch requests
171 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
172 pub enum RepositoryBranchFilter {
173 None,
174 Active,
175 Stale,
166 176 }
167 177
168 178 #[derive(Clone, Debug, Serialize, Deserialize)]

giterated-models/src/repository/operations.rs

View file
@@ -9,7 +9,7 @@ use crate::{
9 9
10 10 use super::{
11 11 Commit, IssueLabel, Repository, RepositoryBranch, RepositoryDiff, RepositoryFile,
12 RepositoryIssue, RepositoryStatistics, RepositoryTreeEntry, RepositoryView,
12 RepositoryIssue, RepositoryStatistics, RepositoryTreeEntry, RepositoryView, RepositoryBranchFilter,
13 13 };
14 14
15 15 /// A request to get a repository's information.
@@ -264,7 +264,10 @@ impl GiteratedOperation<Repository> for RepositoryStatisticsRequest {
264 264 /// - User Authorization
265 265 /// - Potential User permissions checks
266 266 #[derive(Clone, Debug, Serialize, Deserialize)]
267 pub struct RepositoryBranchesRequest;
267 pub struct RepositoryBranchesRequest {
268 pub filter: RepositoryBranchFilter,
269 pub range: (usize, usize),
270 }
268 271
269 272 impl GiteratedOperation<Repository> for RepositoryBranchesRequest {
270 273 type Success = Vec<RepositoryBranch>;
@@ -392,9 +395,15 @@ impl<S: Clone + Send + Sync, B: ObjectBackend<S> + std::fmt::Debug> Object<'_, S
392 395
393 396 pub async fn branches(
394 397 &mut self,
398 filter: RepositoryBranchFilter,
399 range_start: usize,
400 range_end: usize,
395 401 operation_state: &S,
396 402 ) -> Result<Vec<RepositoryBranch>, OperationError<RepositoryError>> {
397 self.request::<RepositoryBranchesRequest>(RepositoryBranchesRequest, operation_state)
403 self.request::<RepositoryBranchesRequest>(RepositoryBranchesRequest {
404 filter,
405 range: (range_start, range_end),
406 }, operation_state)
398 407 .await
399 408 }
400 409