use tracing::debug;
use super::JiraClient;
use crate::collect::errors::{CollectError, Result};
use crate::collect::jira::model::{
transitions_from_histories, ApiChangelogHistory, ChangelogPageResponse, JiraTransition,
};
use crate::collect::jira::retry::with_retry;
const CHANGELOG_PAGE_SIZE: usize = 100;
const MAX_CHANGELOG_PAGES: usize = 200;
impl JiraClient {
pub async fn fetch_changelog(
&self,
key: &str,
expected: Option<u64>,
) -> Result<Vec<JiraTransition>> {
let mut histories = Vec::new();
let mut start_at = 0u64;
let mut reported_total = expected;
for _ in 0..MAX_CHANGELOG_PAGES {
let url = format!(
"{}/rest/api/3/issue/{}/changelog?startAt={}&maxResults={}",
self.base_url, key, start_at, CHANGELOG_PAGE_SIZE
);
debug!(url = %url, "GET (changelog fallback)");
let parsed: ChangelogPageResponse =
with_retry("fetch_changelog", &self.retry, &self.budget, || {
self.get(&url)
})
.await?;
reported_total = reported_total.max(parsed.total);
let n = parsed.values.len() as u64;
histories.extend(parsed.values);
if n == 0 {
return finish(key, histories, reported_total);
}
start_at += n;
if reported_total.is_some_and(|total| start_at >= total) {
return finish(key, histories, reported_total);
}
}
Err(CollectError::PagingBudgetExceeded {
endpoint: "changelog",
key: key.to_string(),
pages: MAX_CHANGELOG_PAGES,
})
}
}
fn finish(
key: &str,
histories: Vec<ApiChangelogHistory>,
reported_total: Option<u64>,
) -> Result<Vec<JiraTransition>> {
let retrieved = histories.len() as u64;
if let Some(expected) = reported_total {
if retrieved < expected {
return Err(CollectError::IncompleteChangelog {
key: key.to_string(),
expected,
retrieved,
});
}
}
Ok(transitions_from_histories(key, histories))
}