gitlab/api/merge_requests/
merge_requests.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 std::collections::BTreeSet;
8use std::iter;
9
10use chrono::DateTime;
11use chrono::Utc;
12use derive_builder::Builder;
13
14use crate::api::common::{CommaSeparatedList, NameOrId, SortOrder, YesNo};
15use crate::api::endpoint_prelude::*;
16use crate::api::helpers::{Labels, ReactionEmoji};
17use crate::api::merge_requests::{
18    ApproverIds, Assignee, MergeRequestMilestone, MergeRequestOrderBy, MergeRequestScope,
19    MergeRequestSearchScope, MergeRequestState, MergeRequestView,
20};
21
22#[derive(Debug, Clone)]
23#[non_exhaustive]
24enum ApprovedByIds {
25    Any,
26    None,
27    AllOfIds(BTreeSet<u64>),
28}
29
30impl ApprovedByIds {
31    fn add_params<'a>(&'a self, params: &mut QueryParams<'a>) {
32        match self {
33            ApprovedByIds::Any => {
34                params.push("approved_by_ids", "Any");
35            },
36            ApprovedByIds::None => {
37                params.push("approved_by_ids", "None");
38            },
39            ApprovedByIds::AllOfIds(ids) => {
40                params.extend(ids.iter().map(|&id| ("approved_by_ids[]", id)));
41            },
42        }
43    }
44}
45
46/// Query for merge requests on an instance.
47///
48/// TODO: Negation (not) filters are not yet supported.
49#[derive(Debug, Builder, Clone)]
50#[builder(setter(strip_option))]
51pub struct MergeRequests<'a> {
52    /// Filter merge requests by approvals.
53    #[builder(setter(name = "_approved_by"), default, private)]
54    approved_by_ids: Option<ApprovedByIds>,
55    /// Filter merge requests by approvers.
56    #[builder(setter(name = "_approver_ids"), default, private)]
57    approver_ids: Option<ApproverIds>,
58    /// Filter merge requests by approved state.
59    #[builder(default, setter(into))]
60    approved: Option<YesNo>,
61    /// Filter merge requests by assignees.
62    #[builder(setter(name = "_assignee"), default, private)]
63    assignee: Option<Assignee>,
64    /// Filter merge requests by author.
65    #[builder(setter(into), default)]
66    author: Option<NameOrId<'a>>,
67    /// Filter merge requests created after a point in time.
68    #[builder(default)]
69    created_after: Option<DateTime<Utc>>,
70    /// Filter merge requests created before a point in time.
71    #[builder(default)]
72    created_before: Option<DateTime<Utc>>,
73    /// Filter merge requests by those deployed after a point in time.
74    #[builder(default)]
75    deployed_after: Option<DateTime<Utc>>,
76    /// Filter merge requests by those deployed before a point in time.
77    #[builder(default)]
78    deployed_before: Option<DateTime<Utc>>,
79    /// Filter merge requests by deployed environment.
80    #[builder(setter(into), default)]
81    environment: Option<Cow<'a, str>>,
82    /// Filter merge requests based on labels.
83    #[builder(setter(name = "_labels"), default, private)]
84    labels: Option<Labels<'a>>,
85    /// Filter merge requests by merge user.
86    #[builder(setter(into), default)]
87    merge_user: Option<NameOrId<'a>>,
88    /// Filter merge requests with a milestone title.
89    #[builder(setter(name = "_milestone"), default, private)]
90    milestone: Option<MergeRequestMilestone<'a>>,
91    /// Filter merge requests by the API caller's reactions.
92    #[builder(setter(name = "_my_reaction_emoji"), default, private)]
93    my_reaction_emoji: Option<ReactionEmoji<'a>>,
94    /// Filter merge requests by reviewers.
95    #[builder(setter(into), default)]
96    reviewer: Option<NameOrId<'a>>,
97    /// Filter merge requests within a scope.
98    #[builder(default)]
99    scope: Option<MergeRequestScope>,
100    /// Filter merge requests by source branch.
101    #[builder(setter(into), default)]
102    source_branch: Option<Cow<'a, str>>,
103    /// Filter merge requests based on state.
104    #[builder(default)]
105    state: Option<MergeRequestState>,
106    /// Filter merge requests by target branch.
107    #[builder(setter(into), default)]
108    target_branch: Option<Cow<'a, str>>,
109    /// Filter merge requests last updated after a point in time.
110    #[builder(default)]
111    updated_after: Option<DateTime<Utc>>,
112    /// Filter merge requests last updated before a point in time.
113    #[builder(default)]
114    updated_before: Option<DateTime<Utc>>,
115    /// The view of the merge request.
116    ///
117    /// This field can restrict the amount of data returned.
118    #[builder(default)]
119    view: Option<MergeRequestView>,
120    /// Include label details in the result.
121    #[builder(default)]
122    with_labels_details: Option<bool>,
123    /// Request that the merge status field be updated.
124    #[builder(default)]
125    with_merge_status_recheck: Option<bool>,
126    /// Filter merge requests by WIP state
127    #[builder(setter(into), default)]
128    wip: Option<YesNo>,
129
130    /// Search for merge requests using a query string.
131    ///
132    /// The search query will be escaped automatically.
133    #[builder(setter(into), default)]
134    search: Option<Cow<'a, str>>,
135    /// Which fields to use for the search query.
136    #[builder(setter(name = "_search_in"), default, private)]
137    search_in: Option<CommaSeparatedList<MergeRequestSearchScope>>,
138
139    /// Order results by a given key.
140    #[builder(default)]
141    order_by: Option<MergeRequestOrderBy>,
142    /// The sort order for returned results.
143    #[builder(default)]
144    sort: Option<SortOrder>,
145}
146
147impl<'a> MergeRequests<'a> {
148    /// Create a builder for the endpoint.
149    pub fn builder() -> MergeRequestsBuilder<'a> {
150        MergeRequestsBuilder::default()
151    }
152}
153
154impl<'a> MergeRequestsBuilder<'a> {
155    /// Filter merge requests without approvals.
156    pub fn no_approvals(&mut self) -> &mut Self {
157        self.approved_by_ids = Some(Some(ApprovedByIds::None));
158        self
159    }
160
161    /// Filter merge requests with any approvals.
162    pub fn any_approvals(&mut self) -> &mut Self {
163        self.approved_by_ids = Some(Some(ApprovedByIds::Any));
164        self
165    }
166
167    /// Filter merge requests approved by a specific user (by ID).
168    ///
169    /// Note: Mutually exclusive to querying by usernames.
170    pub fn approved_by_id(&mut self, approved_by: u64) -> &mut Self {
171        let approved_by =
172            if let Some(Some(ApprovedByIds::AllOfIds(mut set))) = self.approved_by_ids.take() {
173                set.insert(approved_by);
174                set
175            } else {
176                [approved_by].iter().copied().collect()
177            };
178        self.approved_by_ids = Some(Some(ApprovedByIds::AllOfIds(approved_by)));
179        self
180    }
181
182    /// Filter merge requests approved by a specific set of users (by ID).
183    ///
184    /// Note: Mutually exclusive to querying by usernames.
185    pub fn approved_by_ids<I>(&mut self, iter: I) -> &mut Self
186    where
187        I: Iterator<Item = u64>,
188    {
189        let approved_by_ids =
190            if let Some(Some(ApprovedByIds::AllOfIds(mut set))) = self.approved_by_ids.take() {
191                set.extend(iter);
192                set
193            } else {
194                iter.collect()
195            };
196        self.approved_by_ids = Some(Some(ApprovedByIds::AllOfIds(approved_by_ids)));
197        self
198    }
199
200    /// Filter merge requests which have no approvers.
201    pub fn no_approvers(&mut self) -> &mut Self {
202        self.approver_ids = Some(Some(ApproverIds::None));
203        self
204    }
205
206    /// Filter merge requests which have any approver(s).
207    pub fn any_approvers(&mut self) -> &mut Self {
208        self.approver_ids = Some(Some(ApproverIds::Any));
209        self
210    }
211
212    /// Filter merge requests with a specified approver (by ID).
213    pub fn approver_id(&mut self, approver: u64) -> &mut Self {
214        let approver_ids = if let Some(Some(ApproverIds::AllOf(mut set))) = self.approver_ids.take()
215        {
216            set.insert(approver);
217            set
218        } else {
219            [approver].iter().copied().collect()
220        };
221        self.approver_ids = Some(Some(ApproverIds::AllOf(approver_ids)));
222        self
223    }
224
225    /// Filter merge requests with specified approver (by ID).
226    pub fn approver_ids<I>(&mut self, iter: I) -> &mut Self
227    where
228        I: Iterator<Item = u64>,
229    {
230        let approver_ids = if let Some(Some(ApproverIds::AllOf(mut set))) = self.approver_ids.take()
231        {
232            set.extend(iter);
233            set
234        } else {
235            iter.collect()
236        };
237        self.approver_ids = Some(Some(ApproverIds::AllOf(approver_ids)));
238        self
239    }
240
241    /// Filter unassigned merge requests.
242    pub fn unassigned(&mut self) -> &mut Self {
243        self.assignee = Some(Some(Assignee::Unassigned));
244        self
245    }
246
247    /// Filter assigned merge requests.
248    pub fn assigned(&mut self) -> &mut Self {
249        self.assignee = Some(Some(Assignee::Assigned));
250        self
251    }
252
253    /// Filter merge requests assigned to a user (by ID).
254    pub fn assignee_id(&mut self, assignee: u64) -> &mut Self {
255        self.assignee = Some(Some(Assignee::Id(assignee)));
256        self
257    }
258
259    /// Filter unlabeled merge requests.
260    pub fn unlabeled(&mut self) -> &mut Self {
261        self.labels = Some(Some(Labels::None));
262        self
263    }
264
265    /// Filter merge requests with any label.
266    pub fn with_any_label(&mut self) -> &mut Self {
267        self.labels = Some(Some(Labels::Any));
268        self
269    }
270
271    /// Filter merge requests with a given label.
272    pub fn label<L>(&mut self, label: L) -> &mut Self
273    where
274        L: Into<Cow<'a, str>>,
275    {
276        let label = label.into();
277        let labels = if let Some(Some(Labels::AllOf(mut set))) = self.labels.take() {
278            set.push(label);
279            set
280        } else {
281            iter::once(label).collect()
282        };
283        self.labels = Some(Some(Labels::AllOf(labels)));
284        self
285    }
286
287    /// Filter merge requests with all of the given labels.
288    pub fn labels<I, L>(&mut self, iter: I) -> &mut Self
289    where
290        I: IntoIterator<Item = L>,
291        L: Into<Cow<'a, str>>,
292    {
293        let iter = iter.into_iter().map(Into::into);
294        let labels = if let Some(Some(Labels::AllOf(mut set))) = self.labels.take() {
295            set.extend(iter);
296            set
297        } else {
298            iter.collect()
299        };
300        self.labels = Some(Some(Labels::AllOf(labels)));
301        self
302    }
303
304    /// Filter merge requests without a milestone.
305    pub fn without_milestone(&mut self) -> &mut Self {
306        self.milestone = Some(Some(MergeRequestMilestone::None));
307        self
308    }
309
310    /// Filter merge requests with any milestone.
311    pub fn any_milestone(&mut self) -> &mut Self {
312        self.milestone = Some(Some(MergeRequestMilestone::Any));
313        self
314    }
315
316    /// Filter merge requests with a given milestone.
317    pub fn milestone<M>(&mut self, milestone: M) -> &mut Self
318    where
319        M: Into<Cow<'a, str>>,
320    {
321        self.milestone = Some(Some(MergeRequestMilestone::Named(milestone.into())));
322        self
323    }
324
325    /// Filter merge requests without a reaction by the API caller.
326    pub fn no_reaction(&mut self) -> &mut Self {
327        self.my_reaction_emoji = Some(Some(ReactionEmoji::None));
328        self
329    }
330
331    /// Filter merge requests with any reaction by the API caller.
332    pub fn any_reaction(&mut self) -> &mut Self {
333        self.my_reaction_emoji = Some(Some(ReactionEmoji::Any));
334        self
335    }
336
337    /// Filter merge requests with a specific reaction by the API caller.
338    pub fn my_reaction<E>(&mut self, emoji: E) -> &mut Self
339    where
340        E: Into<Cow<'a, str>>,
341    {
342        self.my_reaction_emoji = Some(Some(ReactionEmoji::Emoji(emoji.into())));
343        self
344    }
345
346    /// The scopes to look for search query within.
347    pub fn search_in(&mut self, scope: MergeRequestSearchScope) -> &mut Self {
348        self.search_in
349            .get_or_insert(None)
350            .get_or_insert_with(CommaSeparatedList::new)
351            .push(scope);
352        self
353    }
354}
355
356impl Endpoint for MergeRequests<'_> {
357    fn method(&self) -> Method {
358        Method::GET
359    }
360
361    fn endpoint(&self) -> Cow<'static, str> {
362        "merge_requests".into()
363    }
364
365    fn parameters(&self) -> QueryParams {
366        let mut params = QueryParams::default();
367
368        params
369            .push_opt("approved", self.approved)
370            .push_opt("created_after", self.created_after)
371            .push_opt("created_before", self.created_before)
372            .push_opt("deployed_after", self.deployed_after)
373            .push_opt("deployed_before", self.deployed_before)
374            .push_opt("environment", self.environment.as_ref())
375            .push_opt("labels", self.labels.as_ref())
376            .push_opt("milestone", self.milestone.as_ref())
377            .push_opt("my_reaction_emoji", self.my_reaction_emoji.as_ref())
378            .push_opt("scope", self.scope)
379            .push_opt("source_branch", self.source_branch.as_ref())
380            .push_opt("state", self.state)
381            .push_opt("target_branch", self.target_branch.as_ref())
382            .push_opt("updated_after", self.updated_after)
383            .push_opt("updated_before", self.updated_before)
384            .push_opt("view", self.view)
385            .push_opt("with_labels_details", self.with_labels_details)
386            .push_opt("with_merge_status_recheck", self.with_merge_status_recheck)
387            .push_opt("wip", self.wip)
388            .push_opt("search", self.search.as_ref())
389            .push_opt("in", self.search_in.as_ref())
390            .push_opt("order_by", self.order_by)
391            .push_opt("sort", self.sort);
392
393        if let Some(approved_by_ids) = self.approved_by_ids.as_ref() {
394            approved_by_ids.add_params(&mut params);
395        }
396        if let Some(approver_ids) = self.approver_ids.as_ref() {
397            approver_ids.add_params(&mut params);
398        }
399        if let Some(assignee) = self.assignee.as_ref() {
400            assignee.add_params(&mut params);
401        }
402        if let Some(author) = self.author.as_ref() {
403            match author {
404                NameOrId::Name(name) => {
405                    params.push("author_username", name);
406                },
407                NameOrId::Id(id) => {
408                    params.push("author_id", *id);
409                },
410            }
411        }
412        if let Some(merge_user) = self.merge_user.as_ref() {
413            match merge_user {
414                NameOrId::Name(name) => {
415                    params.push("merge_user_username", name);
416                },
417                NameOrId::Id(id) => {
418                    params.push("merge_user_id", *id);
419                },
420            }
421        }
422        if let Some(reviewer) = self.reviewer.as_ref() {
423            match reviewer {
424                NameOrId::Name(name) => {
425                    params.push("reviewer_username", name);
426                },
427                NameOrId::Id(id) => {
428                    params.push("reviewer_id", *id);
429                },
430            }
431        }
432
433        params
434    }
435}
436
437impl Pageable for MergeRequests<'_> {}
438
439#[cfg(test)]
440mod tests {
441    use chrono::{TimeZone, Utc};
442
443    use crate::api::common::{SortOrder, YesNo};
444    use crate::api::merge_requests::{
445        MergeRequestOrderBy, MergeRequestScope, MergeRequestSearchScope, MergeRequestView,
446        MergeRequests,
447    };
448    use crate::api::{self, Query};
449    use crate::test::client::{ExpectedUrl, SingleTestClient};
450
451    #[test]
452    fn defaults_are_sufficient() {
453        MergeRequests::builder().build().unwrap();
454    }
455
456    #[test]
457    fn endpoint() {
458        let endpoint = ExpectedUrl::builder()
459            .endpoint("merge_requests")
460            .build()
461            .unwrap();
462        let client = SingleTestClient::new_raw(endpoint, "");
463
464        let endpoint = MergeRequests::builder().build().unwrap();
465        api::ignore(endpoint).query(&client).unwrap();
466    }
467
468    #[test]
469    fn endpoint_approvals_none() {
470        let endpoint = ExpectedUrl::builder()
471            .endpoint("merge_requests")
472            .add_query_params(&[("approved_by_ids", "None")])
473            .build()
474            .unwrap();
475        let client = SingleTestClient::new_raw(endpoint, "");
476
477        let endpoint = MergeRequests::builder().no_approvals().build().unwrap();
478        api::ignore(endpoint).query(&client).unwrap();
479    }
480
481    #[test]
482    fn endpoint_approvals_any() {
483        let endpoint = ExpectedUrl::builder()
484            .endpoint("merge_requests")
485            .add_query_params(&[("approved_by_ids", "Any")])
486            .build()
487            .unwrap();
488        let client = SingleTestClient::new_raw(endpoint, "");
489
490        let endpoint = MergeRequests::builder().any_approvals().build().unwrap();
491        api::ignore(endpoint).query(&client).unwrap();
492    }
493
494    #[test]
495    fn endpoint_approved_by_id() {
496        let endpoint = ExpectedUrl::builder()
497            .endpoint("merge_requests")
498            .add_query_params(&[("approved_by_ids[]", "1")])
499            .build()
500            .unwrap();
501        let client = SingleTestClient::new_raw(endpoint, "");
502
503        let endpoint = MergeRequests::builder().approved_by_id(1).build().unwrap();
504        api::ignore(endpoint).query(&client).unwrap();
505    }
506
507    #[test]
508    fn endpoint_approved_by_ids() {
509        let endpoint = ExpectedUrl::builder()
510            .endpoint("merge_requests")
511            .add_query_params(&[("approved_by_ids[]", "1"), ("approved_by_ids[]", "2")])
512            .build()
513            .unwrap();
514        let client = SingleTestClient::new_raw(endpoint, "");
515
516        let endpoint = MergeRequests::builder()
517            .approved_by_id(1)
518            .approved_by_ids([1, 2].iter().copied())
519            .build()
520            .unwrap();
521        api::ignore(endpoint).query(&client).unwrap();
522    }
523
524    #[test]
525    fn endpoint_approvers_none() {
526        let endpoint = ExpectedUrl::builder()
527            .endpoint("merge_requests")
528            .add_query_params(&[("approver_ids", "None")])
529            .build()
530            .unwrap();
531        let client = SingleTestClient::new_raw(endpoint, "");
532
533        let endpoint = MergeRequests::builder().no_approvers().build().unwrap();
534        api::ignore(endpoint).query(&client).unwrap();
535    }
536
537    #[test]
538    fn endpoint_approvers_any() {
539        let endpoint = ExpectedUrl::builder()
540            .endpoint("merge_requests")
541            .add_query_params(&[("approver_ids", "Any")])
542            .build()
543            .unwrap();
544        let client = SingleTestClient::new_raw(endpoint, "");
545
546        let endpoint = MergeRequests::builder().any_approvers().build().unwrap();
547        api::ignore(endpoint).query(&client).unwrap();
548    }
549
550    #[test]
551    fn endpoint_approver_id() {
552        let endpoint = ExpectedUrl::builder()
553            .endpoint("merge_requests")
554            .add_query_params(&[("approver_ids[]", "1")])
555            .build()
556            .unwrap();
557        let client = SingleTestClient::new_raw(endpoint, "");
558
559        let endpoint = MergeRequests::builder().approver_id(1).build().unwrap();
560        api::ignore(endpoint).query(&client).unwrap();
561    }
562
563    #[test]
564    fn endpoint_approver_ids() {
565        let endpoint = ExpectedUrl::builder()
566            .endpoint("merge_requests")
567            .add_query_params(&[("approver_ids[]", "1"), ("approver_ids[]", "2")])
568            .build()
569            .unwrap();
570        let client = SingleTestClient::new_raw(endpoint, "");
571
572        let endpoint = MergeRequests::builder()
573            .approver_id(1)
574            .approver_ids([1, 2].iter().copied())
575            .build()
576            .unwrap();
577        api::ignore(endpoint).query(&client).unwrap();
578    }
579
580    #[test]
581    fn endpoint_approved() {
582        let endpoint = ExpectedUrl::builder()
583            .endpoint("merge_requests")
584            .add_query_params(&[("approved", "yes")])
585            .build()
586            .unwrap();
587        let client = SingleTestClient::new_raw(endpoint, "");
588
589        let endpoint = MergeRequests::builder().approved(true).build().unwrap();
590        api::ignore(endpoint).query(&client).unwrap();
591    }
592
593    #[test]
594    fn endpoint_assignee_unassigned() {
595        let endpoint = ExpectedUrl::builder()
596            .endpoint("merge_requests")
597            .add_query_params(&[("assignee_id", "None")])
598            .build()
599            .unwrap();
600        let client = SingleTestClient::new_raw(endpoint, "");
601
602        let endpoint = MergeRequests::builder().unassigned().build().unwrap();
603        api::ignore(endpoint).query(&client).unwrap();
604    }
605
606    #[test]
607    fn endpoint_assignee_assigned() {
608        let endpoint = ExpectedUrl::builder()
609            .endpoint("merge_requests")
610            .add_query_params(&[("assignee_id", "Any")])
611            .build()
612            .unwrap();
613        let client = SingleTestClient::new_raw(endpoint, "");
614
615        let endpoint = MergeRequests::builder().assigned().build().unwrap();
616        api::ignore(endpoint).query(&client).unwrap();
617    }
618
619    #[test]
620    fn endpoint_assignee_id() {
621        let endpoint = ExpectedUrl::builder()
622            .endpoint("merge_requests")
623            .add_query_params(&[("assignee_id", "1")])
624            .build()
625            .unwrap();
626        let client = SingleTestClient::new_raw(endpoint, "");
627
628        let endpoint = MergeRequests::builder().assignee_id(1).build().unwrap();
629        api::ignore(endpoint).query(&client).unwrap();
630    }
631
632    #[test]
633    fn endpoint_author() {
634        let endpoint = ExpectedUrl::builder()
635            .endpoint("merge_requests")
636            .add_query_params(&[("author_id", "1")])
637            .build()
638            .unwrap();
639        let client = SingleTestClient::new_raw(endpoint, "");
640
641        let endpoint = MergeRequests::builder().author(1).build().unwrap();
642        api::ignore(endpoint).query(&client).unwrap();
643    }
644
645    #[test]
646    fn endpoint_author_name() {
647        let endpoint = ExpectedUrl::builder()
648            .endpoint("merge_requests")
649            .add_query_params(&[("author_username", "name")])
650            .build()
651            .unwrap();
652        let client = SingleTestClient::new_raw(endpoint, "");
653
654        let endpoint = MergeRequests::builder().author("name").build().unwrap();
655        api::ignore(endpoint).query(&client).unwrap();
656    }
657
658    #[test]
659    fn endpoint_created_after() {
660        let endpoint = ExpectedUrl::builder()
661            .endpoint("merge_requests")
662            .add_query_params(&[("created_after", "2020-01-01T00:00:00Z")])
663            .build()
664            .unwrap();
665        let client = SingleTestClient::new_raw(endpoint, "");
666
667        let endpoint = MergeRequests::builder()
668            .created_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
669            .build()
670            .unwrap();
671        api::ignore(endpoint).query(&client).unwrap();
672    }
673
674    #[test]
675    fn endpoint_created_before() {
676        let endpoint = ExpectedUrl::builder()
677            .endpoint("merge_requests")
678            .add_query_params(&[("created_before", "2020-01-01T00:00:00Z")])
679            .build()
680            .unwrap();
681        let client = SingleTestClient::new_raw(endpoint, "");
682
683        let endpoint = MergeRequests::builder()
684            .created_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
685            .build()
686            .unwrap();
687        api::ignore(endpoint).query(&client).unwrap();
688    }
689
690    #[test]
691    fn endpoint_deployed_before() {
692        let endpoint = ExpectedUrl::builder()
693            .endpoint("merge_requests")
694            .add_query_params(&[("deployed_before", "2020-01-01T00:00:00Z")])
695            .build()
696            .unwrap();
697        let client = SingleTestClient::new_raw(endpoint, "");
698
699        let endpoint = MergeRequests::builder()
700            .deployed_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
701            .build()
702            .unwrap();
703        api::ignore(endpoint).query(&client).unwrap();
704    }
705
706    #[test]
707    fn endpoint_deployed_after() {
708        let endpoint = ExpectedUrl::builder()
709            .endpoint("merge_requests")
710            .add_query_params(&[("deployed_after", "2020-01-01T00:00:00Z")])
711            .build()
712            .unwrap();
713        let client = SingleTestClient::new_raw(endpoint, "");
714
715        let endpoint = MergeRequests::builder()
716            .deployed_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
717            .build()
718            .unwrap();
719        api::ignore(endpoint).query(&client).unwrap();
720    }
721
722    #[test]
723    fn endpoint_environment() {
724        let endpoint = ExpectedUrl::builder()
725            .endpoint("merge_requests")
726            .add_query_params(&[("environment", "env")])
727            .build()
728            .unwrap();
729        let client = SingleTestClient::new_raw(endpoint, "");
730
731        let endpoint = MergeRequests::builder().environment("env").build().unwrap();
732        api::ignore(endpoint).query(&client).unwrap();
733    }
734
735    #[test]
736    fn endpoint_labels() {
737        let endpoint = ExpectedUrl::builder()
738            .endpoint("merge_requests")
739            .add_query_params(&[("labels", "label,label1,label2")])
740            .build()
741            .unwrap();
742        let client = SingleTestClient::new_raw(endpoint, "");
743
744        let endpoint = MergeRequests::builder()
745            .label("label")
746            .labels(["label1", "label2"].iter().cloned())
747            .build()
748            .unwrap();
749        api::ignore(endpoint).query(&client).unwrap();
750    }
751
752    #[test]
753    fn endpoint_labels_unlabeled() {
754        let endpoint = ExpectedUrl::builder()
755            .endpoint("merge_requests")
756            .add_query_params(&[("labels", "None")])
757            .build()
758            .unwrap();
759        let client = SingleTestClient::new_raw(endpoint, "");
760
761        let endpoint = MergeRequests::builder().unlabeled().build().unwrap();
762        api::ignore(endpoint).query(&client).unwrap();
763    }
764
765    #[test]
766    fn endpoint_labels_any() {
767        let endpoint = ExpectedUrl::builder()
768            .endpoint("merge_requests")
769            .add_query_params(&[("labels", "Any")])
770            .build()
771            .unwrap();
772        let client = SingleTestClient::new_raw(endpoint, "");
773
774        let endpoint = MergeRequests::builder().with_any_label().build().unwrap();
775        api::ignore(endpoint).query(&client).unwrap();
776    }
777
778    #[test]
779    fn endpoint_merge_user() {
780        let endpoint = ExpectedUrl::builder()
781            .endpoint("merge_requests")
782            .add_query_params(&[("merge_user_id", "1")])
783            .build()
784            .unwrap();
785        let client = SingleTestClient::new_raw(endpoint, "");
786
787        let endpoint = MergeRequests::builder().merge_user(1).build().unwrap();
788        api::ignore(endpoint).query(&client).unwrap();
789    }
790
791    #[test]
792    fn endpoint_merge_user_name() {
793        let endpoint = ExpectedUrl::builder()
794            .endpoint("merge_requests")
795            .add_query_params(&[("merge_user_username", "name")])
796            .build()
797            .unwrap();
798        let client = SingleTestClient::new_raw(endpoint, "");
799
800        let endpoint = MergeRequests::builder().merge_user("name").build().unwrap();
801        api::ignore(endpoint).query(&client).unwrap();
802    }
803
804    #[test]
805    fn endpoint_milestone_none() {
806        let endpoint = ExpectedUrl::builder()
807            .endpoint("merge_requests")
808            .add_query_params(&[("milestone", "None")])
809            .build()
810            .unwrap();
811        let client = SingleTestClient::new_raw(endpoint, "");
812
813        let endpoint = MergeRequests::builder()
814            .without_milestone()
815            .build()
816            .unwrap();
817        api::ignore(endpoint).query(&client).unwrap();
818    }
819
820    #[test]
821    fn endpoint_milestone_any() {
822        let endpoint = ExpectedUrl::builder()
823            .endpoint("merge_requests")
824            .add_query_params(&[("milestone", "Any")])
825            .build()
826            .unwrap();
827        let client = SingleTestClient::new_raw(endpoint, "");
828
829        let endpoint = MergeRequests::builder().any_milestone().build().unwrap();
830        api::ignore(endpoint).query(&client).unwrap();
831    }
832
833    #[test]
834    fn endpoint_milestone() {
835        let endpoint = ExpectedUrl::builder()
836            .endpoint("merge_requests")
837            .add_query_params(&[("milestone", "1.0")])
838            .build()
839            .unwrap();
840        let client = SingleTestClient::new_raw(endpoint, "");
841
842        let endpoint = MergeRequests::builder().milestone("1.0").build().unwrap();
843        api::ignore(endpoint).query(&client).unwrap();
844    }
845
846    #[test]
847    fn endpoint_my_reaction_emoji() {
848        let endpoint = ExpectedUrl::builder()
849            .endpoint("merge_requests")
850            .add_query_params(&[("my_reaction_emoji", "tada")])
851            .build()
852            .unwrap();
853        let client = SingleTestClient::new_raw(endpoint, "");
854
855        let endpoint = MergeRequests::builder()
856            .my_reaction("tada")
857            .build()
858            .unwrap();
859        api::ignore(endpoint).query(&client).unwrap();
860    }
861
862    #[test]
863    fn endpoint_my_reaction_emoji_no_reaction() {
864        let endpoint = ExpectedUrl::builder()
865            .endpoint("merge_requests")
866            .add_query_params(&[("my_reaction_emoji", "None")])
867            .build()
868            .unwrap();
869        let client = SingleTestClient::new_raw(endpoint, "");
870
871        let endpoint = MergeRequests::builder().no_reaction().build().unwrap();
872        api::ignore(endpoint).query(&client).unwrap();
873    }
874
875    #[test]
876    fn endpoint_my_reaction_emoji_any_reaction() {
877        let endpoint = ExpectedUrl::builder()
878            .endpoint("merge_requests")
879            .add_query_params(&[("my_reaction_emoji", "Any")])
880            .build()
881            .unwrap();
882        let client = SingleTestClient::new_raw(endpoint, "");
883
884        let endpoint = MergeRequests::builder().any_reaction().build().unwrap();
885        api::ignore(endpoint).query(&client).unwrap();
886    }
887
888    #[test]
889    fn endpoint_reviewer() {
890        let endpoint = ExpectedUrl::builder()
891            .endpoint("merge_requests")
892            .add_query_params(&[("reviewer_id", "1")])
893            .build()
894            .unwrap();
895        let client = SingleTestClient::new_raw(endpoint, "");
896
897        let endpoint = MergeRequests::builder().reviewer(1).build().unwrap();
898        api::ignore(endpoint).query(&client).unwrap();
899    }
900
901    #[test]
902    fn endpoint_reviewer_name() {
903        let endpoint = ExpectedUrl::builder()
904            .endpoint("merge_requests")
905            .add_query_params(&[("reviewer_username", "name")])
906            .build()
907            .unwrap();
908        let client = SingleTestClient::new_raw(endpoint, "");
909
910        let endpoint = MergeRequests::builder().reviewer("name").build().unwrap();
911        api::ignore(endpoint).query(&client).unwrap();
912    }
913
914    #[test]
915    fn endpoint_scope() {
916        let endpoint = ExpectedUrl::builder()
917            .endpoint("merge_requests")
918            .add_query_params(&[("scope", "all")])
919            .build()
920            .unwrap();
921        let client = SingleTestClient::new_raw(endpoint, "");
922
923        let endpoint = MergeRequests::builder()
924            .scope(MergeRequestScope::All)
925            .build()
926            .unwrap();
927        api::ignore(endpoint).query(&client).unwrap();
928    }
929
930    #[test]
931    fn endpoint_updated_after() {
932        let endpoint = ExpectedUrl::builder()
933            .endpoint("merge_requests")
934            .add_query_params(&[("updated_after", "2020-01-01T00:00:00Z")])
935            .build()
936            .unwrap();
937        let client = SingleTestClient::new_raw(endpoint, "");
938
939        let endpoint = MergeRequests::builder()
940            .updated_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
941            .build()
942            .unwrap();
943        api::ignore(endpoint).query(&client).unwrap();
944    }
945
946    #[test]
947    fn endpoint_updated_before() {
948        let endpoint = ExpectedUrl::builder()
949            .endpoint("merge_requests")
950            .add_query_params(&[("updated_before", "2020-01-01T00:00:00Z")])
951            .build()
952            .unwrap();
953        let client = SingleTestClient::new_raw(endpoint, "");
954
955        let endpoint = MergeRequests::builder()
956            .updated_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
957            .build()
958            .unwrap();
959        api::ignore(endpoint).query(&client).unwrap();
960    }
961
962    #[test]
963    fn endpoint_view() {
964        let endpoint = ExpectedUrl::builder()
965            .endpoint("merge_requests")
966            .add_query_params(&[("view", "simple")])
967            .build()
968            .unwrap();
969        let client = SingleTestClient::new_raw(endpoint, "");
970
971        let endpoint = MergeRequests::builder()
972            .view(MergeRequestView::Simple)
973            .build()
974            .unwrap();
975        api::ignore(endpoint).query(&client).unwrap();
976    }
977
978    #[test]
979    fn endpoint_with_labels_details() {
980        let endpoint = ExpectedUrl::builder()
981            .endpoint("merge_requests")
982            .add_query_params(&[("with_labels_details", "true")])
983            .build()
984            .unwrap();
985        let client = SingleTestClient::new_raw(endpoint, "");
986
987        let endpoint = MergeRequests::builder()
988            .with_labels_details(true)
989            .build()
990            .unwrap();
991        api::ignore(endpoint).query(&client).unwrap();
992    }
993
994    #[test]
995    fn endpoint_with_merge_status_recheck() {
996        let endpoint = ExpectedUrl::builder()
997            .endpoint("merge_requests")
998            .add_query_params(&[("with_merge_status_recheck", "true")])
999            .build()
1000            .unwrap();
1001        let client = SingleTestClient::new_raw(endpoint, "");
1002
1003        let endpoint = MergeRequests::builder()
1004            .with_merge_status_recheck(true)
1005            .build()
1006            .unwrap();
1007        api::ignore(endpoint).query(&client).unwrap();
1008    }
1009
1010    #[test]
1011    fn endpoint_wip() {
1012        let endpoint = ExpectedUrl::builder()
1013            .endpoint("merge_requests")
1014            .add_query_params(&[("wip", "yes")])
1015            .build()
1016            .unwrap();
1017        let client = SingleTestClient::new_raw(endpoint, "");
1018
1019        let endpoint = MergeRequests::builder().wip(YesNo::Yes).build().unwrap();
1020        api::ignore(endpoint).query(&client).unwrap();
1021    }
1022
1023    #[test]
1024    fn endpoint_search() {
1025        let endpoint = ExpectedUrl::builder()
1026            .endpoint("merge_requests")
1027            .add_query_params(&[("search", "special/query")])
1028            .build()
1029            .unwrap();
1030        let client = SingleTestClient::new_raw(endpoint, "");
1031
1032        let endpoint = MergeRequests::builder()
1033            .search("special/query")
1034            .build()
1035            .unwrap();
1036        api::ignore(endpoint).query(&client).unwrap();
1037    }
1038
1039    #[test]
1040    fn endpoint_search_in() {
1041        let endpoint = ExpectedUrl::builder()
1042            .endpoint("merge_requests")
1043            .add_query_params(&[("in", "title,description")])
1044            .build()
1045            .unwrap();
1046        let client = SingleTestClient::new_raw(endpoint, "");
1047
1048        let endpoint = MergeRequests::builder()
1049            .search_in(MergeRequestSearchScope::Title)
1050            .search_in(MergeRequestSearchScope::Description)
1051            .build()
1052            .unwrap();
1053        api::ignore(endpoint).query(&client).unwrap();
1054    }
1055
1056    #[test]
1057    fn endpoint_order_by() {
1058        let endpoint = ExpectedUrl::builder()
1059            .endpoint("merge_requests")
1060            .add_query_params(&[("order_by", "title")])
1061            .build()
1062            .unwrap();
1063        let client = SingleTestClient::new_raw(endpoint, "");
1064
1065        let endpoint = MergeRequests::builder()
1066            .order_by(MergeRequestOrderBy::Title)
1067            .build()
1068            .unwrap();
1069        api::ignore(endpoint).query(&client).unwrap();
1070    }
1071
1072    #[test]
1073    fn endpoint_sort() {
1074        let endpoint = ExpectedUrl::builder()
1075            .endpoint("merge_requests")
1076            .add_query_params(&[("sort", "desc")])
1077            .build()
1078            .unwrap();
1079        let client = SingleTestClient::new_raw(endpoint, "");
1080
1081        let endpoint = MergeRequests::builder()
1082            .sort(SortOrder::Descending)
1083            .build()
1084            .unwrap();
1085        api::ignore(endpoint).query(&client).unwrap();
1086    }
1087}