gitlab/api/projects/milestones/
create.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 derive_builder::Builder;
8
9use chrono::NaiveDate;
10
11use crate::api::common::NameOrId;
12use crate::api::endpoint_prelude::*;
13
14/// Create a new milestone on a project.
15#[derive(Debug, Builder, Clone)]
16#[builder(setter(strip_option))]
17pub struct CreateProjectMilestone<'a> {
18    /// The project to create a new milestone within.
19    #[builder(setter(into))]
20    project: NameOrId<'a>,
21    /// The title of the milestone.
22    #[builder(setter(into))]
23    title: Cow<'a, str>,
24
25    /// A short description for the milestone.
26    #[builder(setter(into), default)]
27    description: Option<Cow<'a, str>>,
28    /// When the milestone is due.
29    #[builder(default)]
30    due_date: Option<NaiveDate>,
31    /// When the milestone starts.
32    #[builder(default)]
33    start_date: Option<NaiveDate>,
34}
35
36impl<'a> CreateProjectMilestone<'a> {
37    /// Create a builder for the endpoint.
38    pub fn builder() -> CreateProjectMilestoneBuilder<'a> {
39        CreateProjectMilestoneBuilder::default()
40    }
41}
42
43impl Endpoint for CreateProjectMilestone<'_> {
44    fn method(&self) -> Method {
45        Method::POST
46    }
47
48    fn endpoint(&self) -> Cow<'static, str> {
49        format!("projects/{}/milestones", self.project).into()
50    }
51
52    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
53        let mut params = FormParams::default();
54
55        params
56            .push("title", &self.title)
57            .push_opt("description", self.description.as_ref())
58            .push_opt("due_date", self.due_date)
59            .push_opt("start_date", self.start_date);
60
61        params.into_body()
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use chrono::NaiveDate;
68    use http::Method;
69
70    use crate::api::projects::milestones::{
71        CreateProjectMilestone, CreateProjectMilestoneBuilderError,
72    };
73    use crate::api::{self, Query};
74    use crate::test::client::{ExpectedUrl, SingleTestClient};
75
76    #[test]
77    fn project_and_title_are_necessary() {
78        let err = CreateProjectMilestone::builder().build().unwrap_err();
79        crate::test::assert_missing_field!(err, CreateProjectMilestoneBuilderError, "project");
80    }
81
82    #[test]
83    fn project_is_necessary() {
84        let err = CreateProjectMilestone::builder()
85            .title("title")
86            .build()
87            .unwrap_err();
88        crate::test::assert_missing_field!(err, CreateProjectMilestoneBuilderError, "project");
89    }
90
91    #[test]
92    fn title_is_necessary() {
93        let err = CreateProjectMilestone::builder()
94            .project("project")
95            .build()
96            .unwrap_err();
97        crate::test::assert_missing_field!(err, CreateProjectMilestoneBuilderError, "title");
98    }
99
100    #[test]
101    fn project_and_title_are_sufficient() {
102        CreateProjectMilestone::builder()
103            .project("project")
104            .title("title")
105            .build()
106            .unwrap();
107    }
108
109    #[test]
110    fn endpoint() {
111        let endpoint = ExpectedUrl::builder()
112            .method(Method::POST)
113            .endpoint("projects/simple%2Fproject/milestones")
114            .content_type("application/x-www-form-urlencoded")
115            .body_str("title=title")
116            .build()
117            .unwrap();
118        let client = SingleTestClient::new_raw(endpoint, "");
119
120        let endpoint = CreateProjectMilestone::builder()
121            .project("simple/project")
122            .title("title")
123            .build()
124            .unwrap();
125        api::ignore(endpoint).query(&client).unwrap();
126    }
127
128    #[test]
129    fn endpoint_description() {
130        let endpoint = ExpectedUrl::builder()
131            .method(Method::POST)
132            .endpoint("projects/simple%2Fproject/milestones")
133            .content_type("application/x-www-form-urlencoded")
134            .body_str(concat!("title=title", "&description=description"))
135            .build()
136            .unwrap();
137        let client = SingleTestClient::new_raw(endpoint, "");
138
139        let endpoint = CreateProjectMilestone::builder()
140            .project("simple/project")
141            .title("title")
142            .description("description")
143            .build()
144            .unwrap();
145        api::ignore(endpoint).query(&client).unwrap();
146    }
147
148    #[test]
149    fn endpoint_due_date() {
150        let endpoint = ExpectedUrl::builder()
151            .method(Method::POST)
152            .endpoint("projects/simple%2Fproject/milestones")
153            .content_type("application/x-www-form-urlencoded")
154            .body_str(concat!("title=title", "&due_date=2020-01-01"))
155            .build()
156            .unwrap();
157        let client = SingleTestClient::new_raw(endpoint, "");
158
159        let endpoint = CreateProjectMilestone::builder()
160            .project("simple/project")
161            .title("title")
162            .due_date(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap())
163            .build()
164            .unwrap();
165        api::ignore(endpoint).query(&client).unwrap();
166    }
167
168    #[test]
169    fn endpoint_start_date() {
170        let endpoint = ExpectedUrl::builder()
171            .method(Method::POST)
172            .endpoint("projects/simple%2Fproject/milestones")
173            .content_type("application/x-www-form-urlencoded")
174            .body_str(concat!("title=title", "&start_date=2020-01-01"))
175            .build()
176            .unwrap();
177        let client = SingleTestClient::new_raw(endpoint, "");
178
179        let endpoint = CreateProjectMilestone::builder()
180            .project("simple/project")
181            .title("title")
182            .start_date(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap())
183            .build()
184            .unwrap();
185        api::ignore(endpoint).query(&client).unwrap();
186    }
187}