diff --git a/Cargo.lock b/Cargo.lock
index 0dbae51f..4f7b1ba9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1494,9 +1494,9 @@ dependencies = [
[[package]]
name = "octocrab"
-version = "0.45.0"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9142159757f166a7b20e3dcd410a5af008a63747c73e836a01fa4f7af84d2c4"
+checksum = "a1620cb765b304c2828fe3cc1c6510cad7354cbeb519561f415fd3b07aae0ef5"
dependencies = [
"arc-swap",
"async-trait",
diff --git a/src/templates.rs b/src/templates.rs
index 9e2c1be8..478d5752 100644
--- a/src/templates.rs
+++ b/src/templates.rs
@@ -1,8 +1,23 @@
-use crate::database::{MergeableState::*, PullRequestModel, QueueStatus::*, TreeState};
+use crate::database::{MergeableState::*, PullRequestModel, QueueStatus, TreeState};
use askama::Template;
use axum::response::{Html, IntoResponse, Response};
use http::StatusCode;
+/// Build status to display on the queue page.
+pub fn status_text(pr: &PullRequestModel) -> String {
+ if let Some(try_build) = &pr.try_build {
+ try_build.status.to_string()
+ } else {
+ match pr.queue_status() {
+ QueueStatus::Approved(_) => "approved".to_string(),
+ QueueStatus::ReadyForMerge(_, _) => "ready for merge".to_string(),
+ QueueStatus::Pending(_, _) => "pending".to_string(),
+ QueueStatus::Stalled(_, _) => "stalled".to_string(),
+ QueueStatus::NotApproved => String::new(),
+ }
+ }
+}
+
pub struct HtmlTemplate(pub T);
impl IntoResponse for HtmlTemplate
diff --git a/src/utils/sort_queue.rs b/src/utils/sort_queue.rs
index 164be611..e40985ac 100644
--- a/src/utils/sort_queue.rs
+++ b/src/utils/sort_queue.rs
@@ -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) -> Vec {
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,
+ QueueStatus::Pending(_, _) => 1,
+ QueueStatus::Approved(_) => 2,
+ QueueStatus::Stalled(_, _) => 3,
+ QueueStatus::NotApproved => 4,
}
}
diff --git a/templates/queue.html b/templates/queue.html
index cef5d70d..a6dc753f 100644
--- a/templates/queue.html
+++ b/templates/queue.html
@@ -3,12 +3,29 @@
{% block title %}Bors queue - {{ repo_name }} {% if tree_state.is_closed() %} [TREECLOSED] {% endif %}{% endblock %}
{% block head %}
+
+
{% endblock %}
@@ -32,72 +49,144 @@
{{ stats.failed_count }} failed, {{ stats.rolled_up_count }} rolled up
-
-
- # |
- Status |
- Mergeable |
- Title |
- Author |
- Assignees |
- Approved by |
- Priority |
- Rollup |
-
-
-
- {% for pr in prs %}
-
-
- {{ pr.number.0 }}
- |
-
- {% if let Some(try_build) = pr.try_build %}
- {{ try_build.status }} (try)
- {% else %}
- {% match pr.queue_status() %}
- {% when Approved(_) %}
- approved
- {% when ReadyForMerge(_, _) %}
- ready for merge
- {% when Pending(_, _) %}
- pending
- {% when Stalled(_, _) %}
- stalled
- {% when NotApproved %}
- {% endmatch %}
- {% endif %}
- |
-
- {% match pr.mergeable_state %}
- {% when Mergeable %}
- yes
- {% when HasConflicts %}
- no
- {% when Unknown %}
- {% endmatch %}
- |
- {{ pr.title }} |
- {{ pr.author }} |
- {{ pr.assignees|join(", ") }} |
-
- {% if let Some(approver) = pr.approver() %}
- {{ approver }}
- {% endif %}
- |
- {{ pr.priority.unwrap_or(0) }} |
-
- {% if let Some(rollup) = pr.rollup %}
- {{ rollup }}
- {% endif %}
- |
-
- {% endfor %}
-
-
+
+
+
+
+
+
+
+
+
+ # |
+ Status |
+ Mergeable |
+ Title |
+ Author |
+ Assignees |
+ Approved by |
+ Priority |
+ Rollup |
+
+
+
+
+ {% for pr in prs %}
+
+
+ {{ pr.number.0 }}
+ |
+
+ {% if let Some(try_build) = pr.try_build %}
+ {{ crate::templates::status_text(pr) }} (try)
+ {% else %}
+ {{ crate::templates::status_text(pr) }}
+ {% endif %}
+ |
+
+ {% match pr.mergeable_state %}
+ {% when Mergeable %}
+ yes
+ {% when HasConflicts %}
+ no
+ {% when Unknown %}
+ {% endmatch %}
+ |
+ {{ pr.title }} |
+ {{ pr.author }} |
+ {{ pr.assignees|join(", ") }} |
+
+ {% if let Some(approver) = pr.approver() %}
+ {{ approver }}
+ {% endif %}
+ |
+ {{ pr.priority.unwrap_or(0) }} |
+
+ {% if let Some(rollup) = pr.rollup %}
+ {{ rollup }}
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
{% endblock %}