use chrono::DateTime; use thiserror::Error; use crate::gitlab::types::GitLabIssue; #[derive(Debug, Error)] pub enum TransformError { #[error("Failed to parse timestamp '{0}': {1}")] TimestampParse(String, String), } #[derive(Debug, Clone)] pub struct IssueRow { pub gitlab_id: i64, pub iid: i64, pub project_id: i64, pub title: String, pub description: Option, pub state: String, pub author_username: String, pub created_at: i64, pub updated_at: i64, pub web_url: String, pub due_date: Option, pub milestone_title: Option, } #[derive(Debug, Clone)] pub struct MilestoneRow { pub gitlab_id: i64, pub project_id: i64, pub iid: i64, pub title: String, pub description: Option, pub state: Option, pub due_date: Option, pub web_url: Option, } #[derive(Debug, Clone)] pub struct IssueWithMetadata { pub issue: IssueRow, pub label_names: Vec, pub assignee_usernames: Vec, pub milestone: Option, } fn parse_timestamp(ts: &str) -> Result { DateTime::parse_from_rfc3339(ts) .map(|dt| dt.timestamp_millis()) .map_err(|e| TransformError::TimestampParse(ts.to_string(), e.to_string())) } pub fn transform_issue(issue: &GitLabIssue) -> Result { let created_at = parse_timestamp(&issue.created_at)?; let updated_at = parse_timestamp(&issue.updated_at)?; let assignee_usernames: Vec = issue.assignees.iter().map(|a| a.username.clone()).collect(); let milestone_title = issue.milestone.as_ref().map(|m| m.title.clone()); let milestone = issue.milestone.as_ref().map(|m| MilestoneRow { gitlab_id: m.id, project_id: m.project_id.unwrap_or(issue.project_id), iid: m.iid, title: m.title.clone(), description: m.description.clone(), state: m.state.clone(), due_date: m.due_date.clone(), web_url: m.web_url.clone(), }); Ok(IssueWithMetadata { issue: IssueRow { gitlab_id: issue.id, iid: issue.iid, project_id: issue.project_id, title: issue.title.clone(), description: issue.description.clone(), state: issue.state.clone(), author_username: issue.author.username.clone(), created_at, updated_at, web_url: issue.web_url.clone(), due_date: issue.due_date.clone(), milestone_title, }, label_names: issue.labels.clone(), assignee_usernames, milestone, }) } #[cfg(test)] #[path = "issue_tests.rs"] mod tests;