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