1use crate::{
2 api_traits::{ApiOperation, Deploy, DeployAsset, NumberDeltaErr},
3 cmds::release::{Release, ReleaseAssetListBodyArgs, ReleaseAssetMetadata, ReleaseBodyArgs},
4 io::{HttpResponse, HttpRunner},
5 remote::query,
6 Result,
7};
8
9use super::Github;
10
11impl<R: HttpRunner<Response = HttpResponse>> Deploy for Github<R> {
12 fn list(&self, args: ReleaseBodyArgs) -> Result<Vec<Release>> {
13 let url = format!("{}/repos/{}/releases", self.rest_api_basepath, self.path);
14 query::paged(
15 &self.runner,
16 &url,
17 args.from_to_page,
18 self.request_headers(),
19 None,
20 ApiOperation::Release,
21 |value| GithubReleaseFields::from(value).into(),
22 )
23 }
24
25 fn num_pages(&self) -> Result<Option<u32>> {
26 let (url, headers) = self.resource_release_metadata_url();
27 query::num_pages(&self.runner, &url, headers, ApiOperation::Release)
28 }
29
30 fn num_resources(&self) -> Result<Option<NumberDeltaErr>> {
31 let (url, headers) = self.resource_release_metadata_url();
32 query::num_resources(&self.runner, &url, headers, ApiOperation::Release)
33 }
34}
35
36impl<R> Github<R> {
37 fn resource_release_metadata_url(&self) -> (String, crate::http::Headers) {
38 let url = format!(
39 "{}/repos/{}/releases?page=1",
40 self.rest_api_basepath, self.path
41 );
42 let headers = self.request_headers();
43 (url, headers)
44 }
45
46 fn resource_release_assets_metadata_url(&self, args: ReleaseAssetListBodyArgs) -> String {
47 let url = format!(
48 "{}/repos/{}/releases/{}/assets?page=1",
49 self.rest_api_basepath, self.path, args.id
50 );
51 url
52 }
53}
54
55impl<R: HttpRunner<Response = HttpResponse>> DeployAsset for Github<R> {
56 fn list(&self, args: ReleaseAssetListBodyArgs) -> Result<Vec<ReleaseAssetMetadata>> {
57 let url = format!(
58 "{}/repos/{}/releases/{}/assets",
59 self.rest_api_basepath, self.path, args.id
60 );
61 query::paged(
62 &self.runner,
63 &url,
64 args.list_args,
65 self.request_headers(),
66 None,
67 ApiOperation::Release,
68 |value| GithubReleaseAssetFields::from(value).into(),
69 )
70 }
71
72 fn num_pages(&self, args: ReleaseAssetListBodyArgs) -> Result<Option<u32>> {
73 let url = self.resource_release_assets_metadata_url(args);
74 query::num_pages(
75 &self.runner,
76 &url,
77 self.request_headers(),
78 ApiOperation::Release,
79 )
80 }
81
82 fn num_resources(&self, args: ReleaseAssetListBodyArgs) -> Result<Option<NumberDeltaErr>> {
83 let url = self.resource_release_assets_metadata_url(args);
84 query::num_resources(
85 &self.runner,
86 &url,
87 self.request_headers(),
88 ApiOperation::Release,
89 )
90 }
91}
92
93pub struct GithubReleaseFields {
94 release: Release,
95}
96
97impl From<&serde_json::Value> for GithubReleaseFields {
98 fn from(value: &serde_json::Value) -> Self {
99 Self {
100 release: Release::builder()
101 .id(value["id"].as_i64().unwrap().to_string())
102 .url(value["html_url"].as_str().unwrap().to_string())
103 .tag(value["tag_name"].as_str().unwrap().to_string())
104 .title(value["name"].as_str().unwrap_or_default().to_string())
105 .description(value["body"].as_str().unwrap_or_default().to_string())
106 .prerelease(value["prerelease"].as_bool().unwrap_or(false))
107 .created_at(value["created_at"].as_str().unwrap().to_string())
108 .updated_at(value["published_at"].as_str().unwrap().to_string())
109 .build()
110 .unwrap(),
111 }
112 }
113}
114
115impl From<GithubReleaseFields> for Release {
116 fn from(fields: GithubReleaseFields) -> Self {
117 fields.release
118 }
119}
120
121pub struct GithubReleaseAssetFields {
122 release_asset: ReleaseAssetMetadata,
123}
124
125impl From<&serde_json::Value> for GithubReleaseAssetFields {
126 fn from(value: &serde_json::Value) -> Self {
127 Self {
128 release_asset: ReleaseAssetMetadata::builder()
129 .id(value["id"].as_i64().unwrap().to_string())
130 .name(value["name"].as_str().unwrap().to_string())
131 .url(value["browser_download_url"].as_str().unwrap().to_string())
132 .size(value["size"].as_i64().unwrap().to_string())
133 .created_at(value["created_at"].as_str().unwrap().to_string())
134 .updated_at(value["updated_at"].as_str().unwrap().to_string())
135 .build()
136 .unwrap(),
137 }
138 }
139}
140
141impl From<GithubReleaseAssetFields> for ReleaseAssetMetadata {
142 fn from(fields: GithubReleaseAssetFields) -> Self {
143 fields.release_asset
144 }
145}
146
147#[cfg(test)]
148mod test {
149
150 use crate::{
151 api_traits::ApiOperation,
152 http::Headers,
153 setup_client,
154 test::utils::{default_github, get_contract, ContractType, ResponseContracts},
155 };
156
157 use super::*;
158
159 #[test]
160 fn test_list_releases() {
161 let contracts = ResponseContracts::new(ContractType::Github).add_contract(
162 200,
163 "list_releases.json",
164 None,
165 );
166 let (client, github) = setup_client!(contracts, default_github(), dyn Deploy);
167 let args = ReleaseBodyArgs::builder()
168 .from_to_page(None)
169 .build()
170 .unwrap();
171 let runs = github.list(args).unwrap();
172 assert_eq!(
173 "https://api.github.com/repos/jordilin/githapi/releases",
174 *client.url(),
175 );
176 assert_eq!(Some(ApiOperation::Release), *client.api_operation.borrow());
177 assert_eq!(1, runs.len());
178 }
179
180 #[test]
181 fn test_release_num_pages() {
182 let link_header = "<https://api.github.com/repos/jordilin/githapi/releases?page=2>; rel=\"next\", <https://api.github.com/repos/jordilin/githapi/releases?page=2>; rel=\"last\"";
183 let mut headers = Headers::new();
184 headers.set("link".to_string(), link_header.to_string());
185 let contracts = ResponseContracts::new(ContractType::Github).add_body::<String>(
186 200,
187 None,
188 Some(headers),
189 );
190 let (client, github) = setup_client!(contracts, default_github(), dyn Deploy);
191 let runs = github.num_pages().unwrap();
192 assert_eq!(
193 "https://api.github.com/repos/jordilin/githapi/releases?page=1",
194 *client.url(),
195 );
196 assert_eq!(Some(ApiOperation::Release), *client.api_operation.borrow());
197 assert_eq!(Some(2), runs);
198 }
199
200 #[test]
201 fn test_list_release_assets() {
202 let contracts = ResponseContracts::new(ContractType::Github).add_body(
203 200,
204 Some(format!(
205 "[{}]",
206 get_contract(ContractType::Github, "release_asset.json")
207 )),
208 None,
209 );
210 let (client, github) = setup_client!(contracts, default_github(), dyn DeployAsset);
211 let args = ReleaseAssetListBodyArgs::builder()
212 .id("123".to_string())
213 .list_args(None)
214 .build()
215 .unwrap();
216 let runs = github.list(args).unwrap();
217 assert_eq!(
218 "https://api.github.com/repos/jordilin/githapi/releases/123/assets",
219 *client.url(),
220 );
221 assert_eq!(Some(ApiOperation::Release), *client.api_operation.borrow());
222 assert_eq!(1, runs.len());
223 }
224
225 #[test]
226 fn test_query_num_release_assets_pages() {
227 let link_header = "<https://api.github.com/repos/jordilin/githapi/releases/123/assets?page=2>; rel=\"next\", <https://api.github.com/repos/jordilin/githapi/releases/123/assets?page=2>; rel=\"last\"";
228 let mut headers = Headers::new();
229 headers.set("link".to_string(), link_header.to_string());
230 let contracts = ResponseContracts::new(ContractType::Github).add_body::<String>(
231 200,
232 None,
233 Some(headers),
234 );
235 let (client, github) = setup_client!(contracts, default_github(), dyn DeployAsset);
236 let args = ReleaseAssetListBodyArgs::builder()
237 .id("123".to_string())
238 .list_args(None)
239 .build()
240 .unwrap();
241 let runs = github.num_pages(args).unwrap();
242 assert_eq!(
243 "https://api.github.com/repos/jordilin/githapi/releases/123/assets?page=1",
244 *client.url(),
245 );
246 assert_eq!(Some(ApiOperation::Release), *client.api_operation.borrow());
247 assert_eq!(Some(2), runs);
248 }
249
250 #[test]
251 fn test_query_num_release_assets_resources() {
252 let contracts = ResponseContracts::new(ContractType::Github).add_body(
253 200,
254 Some(format!(
255 "[{}]",
256 get_contract(ContractType::Github, "release_asset.json")
257 )),
258 None,
259 );
260 let (client, github) = setup_client!(contracts, default_github(), dyn DeployAsset);
261 let args = ReleaseAssetListBodyArgs::builder()
262 .id("123".to_string())
263 .list_args(None)
264 .build()
265 .unwrap();
266 github.num_resources(args).unwrap();
267 assert_eq!(
268 "https://api.github.com/repos/jordilin/githapi/releases/123/assets?page=1",
269 *client.url(),
270 );
271 assert_eq!(Some(ApiOperation::Release), *client.api_operation.borrow());
272 }
273}