1use chrono::{DateTime, Utc};
2use octocrab::models::repos::Asset;
3use reqwest::Url;
4use serde::*;
5
6use crate::*;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub struct Release {
12 pub url: Url,
13 pub html_url: Url,
14 pub assets_url: Url,
15 pub upload_url: Url,
16 pub tarball_url: Option<Url>,
17 pub zipball_url: Option<Url>,
18 pub id: i64,
19 pub node_id: String,
20 pub tag_name: String,
21 pub target_commitish: String,
22 pub name: Option<String>,
23 pub body: Option<String>,
24 pub draft: bool,
25 pub prerelease: bool,
26 pub created_at: DateTime<Utc>,
27 pub published_at: Option<DateTime<Utc>>,
28 pub author: Option<octocrab::models::User>,
29 pub assets: Vec<Asset>,
30}
31
32#[derive(Serialize, Debug)]
33pub struct ReleaseRec {
34 pub url: Url,
35 pub html_url: Url,
36 pub assets_url: Url,
37 pub upload_url: Url,
38 pub tarball_url: Option<Url>,
39 pub zipball_url: Option<Url>,
40 pub id: i64,
41 pub node_id: String,
42 pub tag_name: String,
43 pub target_commitish: String,
44 pub name: Option<String>,
45 pub body: Option<String>,
46 pub draft: bool,
47 pub prerelease: bool,
48 pub created_at: DateTime<Utc>,
49 pub published_at: Option<DateTime<Utc>>,
50 pub author_id: Option<i64>,
51 pub assets: String,
52
53 pub sdc_repository: String,
54}
55
56impl From<Release> for ReleaseRec {
57 fn from(from: Release) -> Self {
58 Self {
59 url: from.url,
60 html_url: from.html_url,
61 assets_url: from.assets_url,
62 upload_url: from.upload_url,
63 tarball_url: from.tarball_url,
64 zipball_url: from.zipball_url,
65 id: from.id,
66 node_id: from.node_id,
67 tag_name: from.tag_name,
68 target_commitish: from.target_commitish,
69 name: from.name,
70 body: from.body,
71 draft: from.draft,
72 prerelease: from.prerelease,
73 created_at: from.created_at,
74 published_at: from.published_at,
75 author_id: from.author.map(|u| u.id),
76 assets: from
77 .assets
78 .iter()
79 .map(|v| format!("{};{};{}", v.id, v.name, v.browser_download_url))
80 .collect::<Vec<String>>()
81 .join(","),
82
83 sdc_repository: String::default(),
84 }
85 }
86}
87
88impl RepositryAware for ReleaseRec {
89 fn set_repository(&mut self, name: String) {
90 self.sdc_repository = name;
91 }
92}
93
94pub struct ReleaseFetcher {
95 owner: String,
96 name: String,
97 octocrab: octocrab::Octocrab,
98}
99
100impl ReleaseFetcher {
101 pub fn new(owner: String, name: String, octocrab: octocrab::Octocrab) -> Self {
102 Self {
103 owner,
104 name,
105 octocrab,
106 }
107 }
108}
109
110impl UrlConstructor for ReleaseFetcher {
111 fn reponame(&self) -> String {
112 format!("{}/{}", self.owner, self.name)
113 }
114
115 fn entrypoint(&self) -> Option<Url> {
116 let param = Params::default();
117
118 let route = format!(
119 "repos/{owner}/{repo}/releases?{query}",
120 owner = &self.owner,
121 repo = &self.name,
122 query = param.to_query(),
123 );
124 self.octocrab.absolute_url(route).ok()
125 }
126}
127
128impl LoopWriter for ReleaseFetcher {
129 type Model = Release;
130 type Record = ReleaseRec;
131}
132
133impl ReleaseFetcher {
134 pub async fn fetch<T: std::io::Write>(&self, mut wtr: csv::Writer<T>) -> octocrab::Result<()> {
135 let mut next: Option<Url> = self.entrypoint();
136
137 while let Some(page) = self.octocrab.get_page(&next).await? {
138 next = self.write_and_continue(page, &mut wtr);
139 }
140
141 Ok(())
142 }
143}