Skip to main content

interprex/
issues.rs

1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4
5use crate::{Repository, Result};
6
7platform_number!(IssueNumber);
8
9#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
10#[serde(rename_all = "snake_case")]
11pub enum OpenClosed {
12    Open,
13    Closed,
14}
15
16#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17pub struct Label {
18    pub name: String,
19    pub color: String,
20    pub description: Option<String>,
21}
22
23#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
24pub struct Issue {
25    pub number: IssueNumber,
26    pub title: String,
27    pub body: Option<String>,
28    pub state: OpenClosed,
29    pub labels: Vec<Label>,
30    pub updated_at: DateTime<Utc>,
31}
32
33#[async_trait]
34pub trait IssuesProvider: Send + Sync {
35    async fn issue(&self, repository: &Repository, number: IssueNumber) -> Result<Issue>;
36    async fn labels(&self, repository: &Repository) -> Result<Vec<Label>>;
37    async fn upsert_label(&self, repository: &Repository, label: &Label) -> Result<Label>;
38}
39
40#[cfg(test)]
41mod tests {
42    use super::IssueNumber;
43    use crate::ModelError;
44
45    #[test]
46    fn platform_numbers_are_one_based() {
47        assert_eq!(IssueNumber::new(0), Err(ModelError::InvalidNumber));
48        assert_eq!(IssueNumber::new(42).expect("positive").get(), 42);
49    }
50}