Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 17 additions & 40 deletions src/utils/sort_queue.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,40 @@
use crate::bors::RollupMode;
use crate::database::{BuildStatus, MergeableState, PullRequestModel};
use crate::database::{MergeableState, PullRequestModel, QueueStatus};

/// Sorts pull requests according to merge queue priority rules.
/// Ordered by pending builds > success builds > approval > mergeability > priority value > rollup > age.
/// Ordered by: ready for merge > pending builds > approved > stalled > not approved > mergeability
/// > priority > rollup > age.
pub fn sort_queue_prs(mut prs: Vec<PullRequestModel>) -> Vec<PullRequestModel> {
prs.sort_by(|a, b| {
// 1. Pending builds come first (to block merge queue)
get_queue_blocking_priority(a)
.cmp(&get_queue_blocking_priority(b))
// 2. Compare approval status (approved PRs should come first)
.then_with(|| a.is_approved().cmp(&b.is_approved()).reverse())
// 3. Compare build status within approval groups
.then_with(|| get_status_priority(a).cmp(&get_status_priority(b)))
// 4. Compare mergeability state (0 = mergeable, 1 = conflicts/unknown)
// 1. Compare queue status (ready for merge > pending > approved > stalled > not approved)
get_queue_status_priority(&a.queue_status())
.cmp(&get_queue_status_priority(&b.queue_status()))
// 2. Compare mergeability state (0 = mergeable, 1 = conflicts/unknown)
.then_with(|| get_mergeable_priority(a).cmp(&get_mergeable_priority(b)))
// 5. Compare priority numbers (higher priority should come first)
// 3. Compare priority numbers (higher priority should come first)
.then_with(|| {
a.priority
.unwrap_or(0)
.cmp(&b.priority.unwrap_or(0))
.reverse()
})
// 6. Compare rollup mode (-1 = never/iffy, 0 = maybe, 1 = always)
// 4. Compare rollup mode (always > maybe > iffy > never)
.then_with(|| {
get_rollup_priority(a.rollup.as_ref()).cmp(&get_rollup_priority(b.rollup.as_ref()))
})
// 7. Compare PR numbers (older first)
// 5. Compare PR numbers (older first)
.then_with(|| a.number.cmp(&b.number))
});
prs
}

fn get_queue_blocking_priority(pr: &PullRequestModel) -> u32 {
match &pr.auto_build {
Some(build) => match build.status {
// Pending builds must come first to block the merge queue
BuildStatus::Pending => 0,
// All other statuses come after
_ => 1,
},
None => 1, // No build - can potentially start new build
}
}

fn get_status_priority(pr: &PullRequestModel) -> u32 {
match &pr.auto_build {
Some(build) => match build.status {
BuildStatus::Success => 0,
BuildStatus::Pending => 1,
BuildStatus::Failure => 3,
BuildStatus::Cancelled | BuildStatus::Timeouted => 2,
},
None => {
if pr.is_approved() {
1 // Approved but no build - should be prioritized
} else {
2 // No status
}
}
fn get_queue_status_priority(status: &QueueStatus) -> u32 {
match status {
QueueStatus::ReadyForMerge(_, _) => 0,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this function, I wonder if we should add the mergeability status into QueueStatus, and have something like QueueStatus::Unmergeable. Not sure if that would help with anything though, and definitely not for this PR anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wouldn't be able to use that variant in the merge queue itself since it filters out un-mergeable PRs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not really different from NotApproved or Stalled, which should already never be returned from the SQL query, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. I guess there's no use for that variant (at least now).

QueueStatus::Pending(_, _) => 1,
QueueStatus::Approved(_) => 2,
QueueStatus::Stalled(_, _) => 3,
QueueStatus::NotApproved => 4,
}
}

Expand Down