gitlab/api/projects/deployments/
deployments.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use chrono::{DateTime, Utc};
8use derive_builder::Builder;
9
10use crate::api::common::{NameOrId, SortOrder};
11use crate::api::endpoint_prelude::*;
12use crate::api::projects::deployments::DeploymentStatus;
13use crate::api::ParamValue;
14
15/// Sort orderings for deployments.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[non_exhaustive]
18pub enum DeploymentOrderBy {
19    /// Order deployments by ID.
20    Id,
21    /// Order deployments by project-specific ID.
22    Iid,
23    /// Order deployments by creation date.
24    CreatedAt,
25    /// Order deployments by last update date.
26    UpdatedAt,
27    /// Order deployments by completion date.
28    FinishedAt,
29    /// Order deployments by the ref deployed.
30    Ref,
31}
32
33impl DeploymentOrderBy {
34    /// The scope as a query parameter.
35    pub(crate) fn as_str(self) -> &'static str {
36        match self {
37            Self::Id => "id",
38            Self::Iid => "iid",
39            Self::CreatedAt => "created_at",
40            Self::UpdatedAt => "updated_at",
41            Self::FinishedAt => "finished_at",
42            Self::Ref => "ref",
43        }
44    }
45}
46
47impl ParamValue<'static> for DeploymentOrderBy {
48    fn as_value(&self) -> Cow<'static, str> {
49        self.as_str().into()
50    }
51}
52
53/// Statuses deployments can be filtered by.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55#[non_exhaustive]
56pub enum DeploymentStatusFilter {
57    /// Only consider created deployments.
58    Created,
59    /// Only consider running deployments.
60    Running,
61    /// Only consider successful deployments.
62    Success,
63    /// Only consider failed deployments.
64    Failed,
65    /// Only consider canceled deployments.
66    Canceled,
67    /// Only consider blocked deployments.
68    Blocked,
69}
70
71impl DeploymentStatusFilter {
72    /// The status as a query parameter.
73    pub(crate) fn as_str(self) -> &'static str {
74        match self {
75            Self::Created => "created",
76            Self::Running => "running",
77            Self::Success => "success",
78            Self::Failed => "failed",
79            Self::Canceled => "canceled",
80            Self::Blocked => "blocked",
81        }
82    }
83}
84
85impl From<DeploymentStatus> for DeploymentStatusFilter {
86    fn from(status: DeploymentStatus) -> Self {
87        match status {
88            DeploymentStatus::Running => Self::Running,
89            DeploymentStatus::Success => Self::Success,
90            DeploymentStatus::Failed => Self::Failed,
91            DeploymentStatus::Canceled => Self::Canceled,
92        }
93    }
94}
95
96impl ParamValue<'static> for DeploymentStatusFilter {
97    fn as_value(&self) -> Cow<'static, str> {
98        self.as_str().into()
99    }
100}
101
102/// Query for deployments within a project.
103#[derive(Debug, Builder, Clone)]
104#[builder(setter(strip_option))]
105pub struct Deployments<'a> {
106    /// The project to query for deployments.
107    #[builder(setter(into))]
108    project: NameOrId<'a>,
109
110    /// The order to use for returned results.
111    #[builder(default)]
112    order_by: Option<DeploymentOrderBy>,
113    /// The sort direction for returned results.
114    #[builder(default)]
115    sort: Option<SortOrder>,
116    /// Only include deployments updated after a date.
117    #[builder(default)]
118    updated_after: Option<DateTime<Utc>>,
119    /// Only include deployments updated before a date.
120    #[builder(default)]
121    updated_before: Option<DateTime<Utc>>,
122    /// Only include deployments finished after a date.
123    #[builder(default)]
124    finished_after: Option<DateTime<Utc>>,
125    /// Only include deployments finished before a date.
126    #[builder(default)]
127    finished_before: Option<DateTime<Utc>>,
128    /// Only include deployments to a named environment.
129    #[builder(setter(into), default)]
130    environment: Option<Cow<'a, str>>,
131    /// Only include deployments of a specific status.
132    #[builder(setter(into), default)]
133    status: Option<DeploymentStatusFilter>,
134}
135
136impl<'a> Deployments<'a> {
137    /// Create a builder for the endpoint.
138    pub fn builder() -> DeploymentsBuilder<'a> {
139        DeploymentsBuilder::default()
140    }
141}
142
143impl Endpoint for Deployments<'_> {
144    fn method(&self) -> Method {
145        Method::GET
146    }
147
148    fn endpoint(&self) -> Cow<'static, str> {
149        format!("projects/{}/deployments", self.project).into()
150    }
151
152    fn parameters(&self) -> QueryParams {
153        let mut params = QueryParams::default();
154
155        params
156            .push_opt("order_by", self.order_by)
157            .push_opt("sort", self.sort)
158            .push_opt("updated_after", self.updated_after)
159            .push_opt("updated_before", self.updated_before)
160            .push_opt("finished_after", self.finished_after)
161            .push_opt("finished_before", self.finished_before)
162            .push_opt("environment", self.environment.as_ref())
163            .push_opt("status", self.status);
164
165        params
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use chrono::{TimeZone, Utc};
172
173    use crate::api::common::SortOrder;
174    use crate::api::projects::deployments::{
175        DeploymentOrderBy, DeploymentStatus, DeploymentStatusFilter, Deployments,
176        DeploymentsBuilderError,
177    };
178    use crate::api::{self, Query};
179    use crate::test::client::{ExpectedUrl, SingleTestClient};
180
181    #[test]
182    fn deployment_order_by_as_str() {
183        let items = &[
184            (DeploymentOrderBy::Id, "id"),
185            (DeploymentOrderBy::Iid, "iid"),
186            (DeploymentOrderBy::CreatedAt, "created_at"),
187            (DeploymentOrderBy::UpdatedAt, "updated_at"),
188            (DeploymentOrderBy::FinishedAt, "finished_at"),
189            (DeploymentOrderBy::Ref, "ref"),
190        ];
191
192        for (i, s) in items {
193            assert_eq!(i.as_str(), *s);
194        }
195    }
196
197    #[test]
198    fn deployment_status_filter_as_str() {
199        let items = &[
200            (DeploymentStatusFilter::Created, "created"),
201            (DeploymentStatusFilter::Running, "running"),
202            (DeploymentStatusFilter::Success, "success"),
203            (DeploymentStatusFilter::Failed, "failed"),
204            (DeploymentStatusFilter::Canceled, "canceled"),
205            (DeploymentStatusFilter::Blocked, "blocked"),
206        ];
207
208        for (i, s) in items {
209            assert_eq!(i.as_str(), *s);
210        }
211    }
212
213    #[test]
214    fn deployment_status_filter_from_deployment_status() {
215        let items = &[
216            (DeploymentStatus::Running, DeploymentStatusFilter::Running),
217            (DeploymentStatus::Success, DeploymentStatusFilter::Success),
218            (DeploymentStatus::Failed, DeploymentStatusFilter::Failed),
219            (DeploymentStatus::Canceled, DeploymentStatusFilter::Canceled),
220        ];
221
222        for (i, f) in items {
223            assert_eq!(DeploymentStatusFilter::from(*i), *f);
224        }
225    }
226
227    #[test]
228    fn project_is_needed() {
229        let err = Deployments::builder().build().unwrap_err();
230        crate::test::assert_missing_field!(err, DeploymentsBuilderError, "project");
231    }
232
233    #[test]
234    fn project_is_sufficient() {
235        Deployments::builder().project(1).build().unwrap();
236    }
237
238    #[test]
239    fn endpoint() {
240        let endpoint = ExpectedUrl::builder()
241            .endpoint("projects/simple%2Fproject/deployments")
242            .build()
243            .unwrap();
244        let client = SingleTestClient::new_raw(endpoint, "");
245
246        let endpoint = Deployments::builder()
247            .project("simple/project")
248            .build()
249            .unwrap();
250        api::ignore(endpoint).query(&client).unwrap();
251    }
252
253    #[test]
254    fn endpoint_order_by() {
255        let endpoint = ExpectedUrl::builder()
256            .endpoint("projects/1/deployments")
257            .add_query_params(&[("order_by", "ref")])
258            .build()
259            .unwrap();
260        let client = SingleTestClient::new_raw(endpoint, "");
261
262        let endpoint = Deployments::builder()
263            .project(1)
264            .order_by(DeploymentOrderBy::Ref)
265            .build()
266            .unwrap();
267        api::ignore(endpoint).query(&client).unwrap();
268    }
269
270    #[test]
271    fn endpoint_sort() {
272        let endpoint = ExpectedUrl::builder()
273            .endpoint("projects/1/deployments")
274            .add_query_params(&[("sort", "desc")])
275            .build()
276            .unwrap();
277        let client = SingleTestClient::new_raw(endpoint, "");
278
279        let endpoint = Deployments::builder()
280            .project(1)
281            .sort(SortOrder::Descending)
282            .build()
283            .unwrap();
284        api::ignore(endpoint).query(&client).unwrap();
285    }
286
287    #[test]
288    fn endpoint_updated_after() {
289        let endpoint = ExpectedUrl::builder()
290            .endpoint("projects/1/deployments")
291            .add_query_params(&[("updated_after", "2024-01-01T00:00:00Z")])
292            .build()
293            .unwrap();
294        let client = SingleTestClient::new_raw(endpoint, "");
295
296        let endpoint = Deployments::builder()
297            .project(1)
298            .updated_after(Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap())
299            .build()
300            .unwrap();
301        api::ignore(endpoint).query(&client).unwrap();
302    }
303
304    #[test]
305    fn endpoint_updated_before() {
306        let endpoint = ExpectedUrl::builder()
307            .endpoint("projects/1/deployments")
308            .add_query_params(&[("updated_before", "2024-01-01T00:00:00Z")])
309            .build()
310            .unwrap();
311        let client = SingleTestClient::new_raw(endpoint, "");
312
313        let endpoint = Deployments::builder()
314            .project(1)
315            .updated_before(Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap())
316            .build()
317            .unwrap();
318        api::ignore(endpoint).query(&client).unwrap();
319    }
320
321    #[test]
322    fn endpoint_finished_after() {
323        let endpoint = ExpectedUrl::builder()
324            .endpoint("projects/1/deployments")
325            .add_query_params(&[("finished_after", "2024-01-01T00:00:00Z")])
326            .build()
327            .unwrap();
328        let client = SingleTestClient::new_raw(endpoint, "");
329
330        let endpoint = Deployments::builder()
331            .project(1)
332            .finished_after(Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap())
333            .build()
334            .unwrap();
335        api::ignore(endpoint).query(&client).unwrap();
336    }
337
338    #[test]
339    fn endpoint_finished_before() {
340        let endpoint = ExpectedUrl::builder()
341            .endpoint("projects/1/deployments")
342            .add_query_params(&[("finished_before", "2024-01-01T00:00:00Z")])
343            .build()
344            .unwrap();
345        let client = SingleTestClient::new_raw(endpoint, "");
346
347        let endpoint = Deployments::builder()
348            .project(1)
349            .finished_before(Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap())
350            .build()
351            .unwrap();
352        api::ignore(endpoint).query(&client).unwrap();
353    }
354
355    #[test]
356    fn endpoint_environment() {
357        let endpoint = ExpectedUrl::builder()
358            .endpoint("projects/1/deployments")
359            .add_query_params(&[("environment", "env")])
360            .build()
361            .unwrap();
362        let client = SingleTestClient::new_raw(endpoint, "");
363
364        let endpoint = Deployments::builder()
365            .project(1)
366            .environment("env")
367            .build()
368            .unwrap();
369        api::ignore(endpoint).query(&client).unwrap();
370    }
371
372    #[test]
373    fn endpoint_status() {
374        let endpoint = ExpectedUrl::builder()
375            .endpoint("projects/1/deployments")
376            .add_query_params(&[("status", "failed")])
377            .build()
378            .unwrap();
379        let client = SingleTestClient::new_raw(endpoint, "");
380
381        let endpoint = Deployments::builder()
382            .project(1)
383            .status(DeploymentStatus::Failed)
384            .build()
385            .unwrap();
386        api::ignore(endpoint).query(&client).unwrap();
387    }
388}