use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::content_trust::ContentTrust;
use crate::paths::state::StateLayout;
pub(crate) const DEFAULT_STALE_AFTER_SECS: u64 = 24 * 60 * 60;
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct BacklogRef {
pub provider: String,
pub kind: String,
pub id: String,
pub url: String,
}
impl BacklogRef {
#[cfg_attr(not(feature = "extension-backlog"), allow(dead_code))]
pub(crate) fn key(&self) -> String {
format!("{}:{}:{}", self.provider, self.kind, self.id)
}
#[cfg_attr(not(feature = "extension-backlog"), allow(dead_code))]
pub(crate) fn is_empty(&self) -> bool {
self.provider.is_empty() || self.kind.is_empty() || self.id.is_empty()
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct WorkQueueSummary {
pub open_issues: usize,
pub queue_scoped: usize,
pub queue_candidates: usize,
pub policy_conflicts: usize,
pub metadata_invalid: usize,
pub upstream_claimed: usize,
pub auto_selectable: usize,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct WorkQueueSummaryItem {
pub ccd_id: u64,
pub github_issue_number: u64,
pub backlog_ref: BacklogRef,
pub content_trust: ContentTrust,
pub title: String,
pub url: String,
pub section: String,
pub status: String,
pub queue_state: &'static str,
pub dispatch_state: &'static str,
pub metadata_status: &'static str,
pub upstream_claim: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority_label: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub claimed_by: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority_rank: Option<u64>,
}
impl WorkQueueSummaryItem {
#[allow(dead_code)]
pub(crate) fn display_ref(&self) -> String {
if self.ccd_id != 0 {
format!("ccd#{}", self.ccd_id)
} else if self
.backlog_ref
.provider
.eq_ignore_ascii_case("github-issues")
{
format!("GH#{}", self.github_issue_number)
} else if self
.backlog_ref
.provider
.eq_ignore_ascii_case("gitlab-issues")
{
format!("GL#{}", self.github_issue_number)
} else {
format!("#{}", self.github_issue_number)
}
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct WorkQueueDispatchView {
pub status: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority_label: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub selected: Option<WorkQueueSummaryItem>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct WorkQueueCacheView {
pub path: String,
pub rendered_path: String,
pub status: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_trust: Option<ContentTrust>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub repo: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fetched_at_epoch_s: Option<u64>,
pub stale_after_s: u64,
pub queue_summary: WorkQueueSummary,
#[serde(skip_serializing_if = "Option::is_none")]
pub dispatch: Option<WorkQueueDispatchView>,
pub active_items: Vec<WorkQueueSummaryItem>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct WorkQueueSnapshotItem {
pub ccd_id: u64,
pub github_issue_number: u64,
pub backlog_ref: BacklogRef,
pub content_trust: ContentTrust,
pub title: String,
pub url: String,
pub section: String,
pub status: String,
pub queue_state: &'static str,
pub dispatch_state: &'static str,
pub metadata_status: &'static str,
pub upstream_claim: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority_label: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub claimed_by: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority_rank: Option<u64>,
pub closed: bool,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct WorkQueueSnapshot {
pub content_trust: ContentTrust,
pub provider: String,
pub repo: String,
pub fetched_at_epoch_s: u64,
pub stale_after_s: u64,
pub revalidate_on_refresh: bool,
pub queue_summary: WorkQueueSummary,
#[serde(skip_serializing_if = "Option::is_none")]
pub dispatch: Option<WorkQueueDispatchView>,
pub active_items: Vec<WorkQueueSummaryItem>,
pub items: Vec<WorkQueueSnapshotItem>,
}
#[cfg_attr(not(feature = "extension-backlog"), allow(dead_code))]
pub(crate) fn work_queue_cache_path(layout: &StateLayout) -> PathBuf {
layout.clone_profile_root().join("work_queue.json")
}
#[cfg_attr(not(feature = "extension-backlog"), allow(dead_code))]
pub(crate) fn work_queue_view_path(layout: &StateLayout) -> PathBuf {
layout.clone_profile_root().join("work_queue.md")
}
pub(crate) fn cache_view_from_snapshot(
layout: &StateLayout,
snapshot: Option<&WorkQueueSnapshot>,
limit: usize,
) -> WorkQueueCacheView {
let path = work_queue_cache_path(layout).display().to_string();
let rendered_path = work_queue_view_path(layout).display().to_string();
let Some(snapshot) = snapshot else {
return WorkQueueCacheView {
path,
rendered_path,
status: "missing",
content_trust: None,
provider: None,
repo: None,
fetched_at_epoch_s: None,
stale_after_s: DEFAULT_STALE_AFTER_SECS,
queue_summary: WorkQueueSummary::default(),
dispatch: None,
active_items: Vec::new(),
};
};
WorkQueueCacheView {
path,
rendered_path,
status: "loaded",
content_trust: Some(snapshot.content_trust),
provider: Some(snapshot.provider.clone()),
repo: Some(snapshot.repo.clone()),
fetched_at_epoch_s: Some(snapshot.fetched_at_epoch_s),
stale_after_s: snapshot.stale_after_s,
queue_summary: snapshot.queue_summary.clone(),
dispatch: snapshot.dispatch.clone(),
active_items: snapshot.active_items.iter().take(limit).cloned().collect(),
}
}