use std::collections::HashSet;
use std::sync::OnceLock;
use regex::Regex;
use rusqlite::{params, Connection};
use crate::collect::azdo::pr_fetcher::types::{AdoPrReviewer, AdoPullRequest};
use crate::core::errors::{Result as CoreResult, TgaError};
fn merged_pr_re() -> &'static Regex {
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| {
Regex::new(r"(?i)Merged PR (\d+):").expect("MERGED_PR_RE is a static valid pattern")
})
}
pub fn extract_pr_ids<I, S>(messages: I) -> Vec<i64>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let mut seen: HashSet<i64> = HashSet::new();
let re = merged_pr_re();
for msg in messages {
for cap in re.captures_iter(msg.as_ref()) {
if let Some(m) = cap.get(1) {
if let Ok(id) = m.as_str().parse::<i64>() {
seen.insert(id);
}
}
}
}
let mut out: Vec<i64> = seen.into_iter().collect();
out.sort_unstable();
out
}
pub fn get_existing_pr_numbers(
conn: &Connection,
provider: &str,
repository: &str,
) -> CoreResult<HashSet<i64>> {
let mut stmt = conn
.prepare("SELECT pr_number FROM pull_requests WHERE provider = ?1 AND repository = ?2")?;
let rows = stmt
.query_map(params![provider, repository], |row| row.get::<_, i64>(0))
.map_err(TgaError::from)?;
let mut out = HashSet::new();
for r in rows {
out.insert(r.map_err(TgaError::from)?);
}
Ok(out)
}
pub fn upsert_pr(conn: &Connection, pr: &AdoPullRequest, repository: &str) -> CoreResult<i64> {
let state = match pr.status.to_ascii_lowercase().as_str() {
"completed" => "merged",
"abandoned" => "closed",
_ => "open",
};
let commit_shas = match &pr.merge_commit_sha {
Some(sha) => serde_json::to_string(&[sha.as_str()])?,
None => "[]".to_string(),
};
conn.execute(
"INSERT OR REPLACE INTO pull_requests \
(provider, repository, pr_number, title, author, state, created_at, merged_at, commit_shas) \
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
params![
"azdo",
repository,
pr.pr_number,
pr.title,
pr.author,
state,
pr.created_at.to_rfc3339(),
pr.closed_at.map(|t| t.to_rfc3339()),
commit_shas,
],
)?;
let id: i64 = conn
.query_row(
"SELECT id FROM pull_requests WHERE provider = ?1 AND repository = ?2 AND pr_number = ?3",
params!["azdo", repository, pr.pr_number],
|row| row.get(0),
)
.map_err(TgaError::from)?;
Ok(id)
}
pub fn upsert_pr_reviewer(
conn: &Connection,
pr_db_id: i64,
reviewer: &AdoPrReviewer,
) -> CoreResult<()> {
conn.execute(
"INSERT OR REPLACE INTO pr_reviewers \
(pr_id, provider, reviewer_id, display_name, vote, is_required, is_container) \
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
params![
pr_db_id,
"azdo",
reviewer.reviewer_id,
reviewer.display_name,
reviewer.vote,
reviewer.is_required as i32,
reviewer.is_container as i32,
],
)?;
Ok(())
}