gitlab/api/projects/protected_tags/
protect.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;
8
9use derive_builder::Builder;
10
11use crate::api::common::{NameOrId, ProtectedAccessLevel};
12use crate::api::endpoint_prelude::*;
13use crate::api::projects::protected_branches::ProtectedAccessPush;
14
15/// Protect a tag or set of tags on a project.
16#[derive(Debug, Builder, Clone)]
17#[builder(setter(strip_option))]
18pub struct ProtectTag<'a> {
19    /// The project to protect a tag within.
20    #[builder(setter(into))]
21    project: NameOrId<'a>,
22    /// The name or glob of the tag to protect.
23    #[builder(setter(into))]
24    name: Cow<'a, str>,
25    /// The minimum access level required to create the tag.
26    #[builder(default)]
27    create_access_level: Option<ProtectedAccessLevel>,
28    /// A discrete set of accesses allowed to create tags.
29    #[builder(setter(name = "_allowed_to_create"), default, private)]
30    allowed_to_create: BTreeSet<ProtectedAccessPush<ProtectedAccessLevel>>,
31}
32
33impl<'a> ProtectTag<'a> {
34    /// Create a builder for the endpoint.
35    pub fn builder() -> ProtectTagBuilder<'a> {
36        ProtectTagBuilder::default()
37    }
38}
39
40impl ProtectTagBuilder<'_> {
41    /// Add access to create tags.
42    pub fn allowed_to_create<A>(&mut self, access: A) -> &mut Self
43    where
44        A: Into<ProtectedAccessPush<ProtectedAccessLevel>>,
45    {
46        self.allowed_to_create
47            .get_or_insert_with(BTreeSet::new)
48            .insert(access.into());
49        self
50    }
51}
52
53impl Endpoint for ProtectTag<'_> {
54    fn method(&self) -> Method {
55        Method::POST
56    }
57
58    fn endpoint(&self) -> Cow<'static, str> {
59        format!("projects/{}/protected_tags", self.project).into()
60    }
61
62    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
63        let mut params = FormParams::default();
64
65        params
66            .push("name", &self.name)
67            .push_opt("create_access_level", self.create_access_level);
68
69        self.allowed_to_create
70            .iter()
71            .for_each(|value| value.add_query("allowed_to_create", &mut params));
72
73        params.into_body()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use http::Method;
80
81    use crate::api::common::ProtectedAccessLevel;
82    use crate::api::projects::protected_branches::ProtectedAccessPush;
83    use crate::api::projects::protected_tags::{
84        ProtectTag, ProtectTagBuilderError, ProtectedAccess,
85    };
86    use crate::api::{self, Query};
87    use crate::test::client::{ExpectedUrl, SingleTestClient};
88
89    #[test]
90    fn project_and_name_are_needed() {
91        let err = ProtectTag::builder().build().unwrap_err();
92        crate::test::assert_missing_field!(err, ProtectTagBuilderError, "project");
93    }
94
95    #[test]
96    fn project_is_required() {
97        let err = ProtectTag::builder().name("1.0").build().unwrap_err();
98        crate::test::assert_missing_field!(err, ProtectTagBuilderError, "project");
99    }
100
101    #[test]
102    fn name_is_required() {
103        let err = ProtectTag::builder().project(1).build().unwrap_err();
104        crate::test::assert_missing_field!(err, ProtectTagBuilderError, "name");
105    }
106
107    #[test]
108    fn project_and_name_are_sufficient() {
109        ProtectTag::builder()
110            .project(1)
111            .name("1.0")
112            .build()
113            .unwrap();
114    }
115
116    #[test]
117    fn endpoint() {
118        let endpoint = ExpectedUrl::builder()
119            .method(Method::POST)
120            .endpoint("projects/simple%2Fproject/protected_tags")
121            .content_type("application/x-www-form-urlencoded")
122            .body_str("name=1.0")
123            .build()
124            .unwrap();
125        let client = SingleTestClient::new_raw(endpoint, "");
126
127        let endpoint = ProtectTag::builder()
128            .project("simple/project")
129            .name("1.0")
130            .build()
131            .unwrap();
132        api::ignore(endpoint).query(&client).unwrap();
133    }
134
135    #[test]
136    fn endpoint_create_access_level() {
137        let endpoint = ExpectedUrl::builder()
138            .method(Method::POST)
139            .endpoint("projects/simple%2Fproject/protected_tags")
140            .content_type("application/x-www-form-urlencoded")
141            .body_str(concat!("name=1.0", "&create_access_level=40"))
142            .build()
143            .unwrap();
144        let client = SingleTestClient::new_raw(endpoint, "");
145
146        let endpoint = ProtectTag::builder()
147            .project("simple/project")
148            .name("1.0")
149            .create_access_level(ProtectedAccessLevel::Maintainer)
150            .build()
151            .unwrap();
152        api::ignore(endpoint).query(&client).unwrap();
153    }
154
155    #[test]
156    fn endpoint_allowed_to_create() {
157        let endpoint = ExpectedUrl::builder()
158            .method(Method::POST)
159            .endpoint("projects/simple%2Fproject/protected_tags")
160            .content_type("application/x-www-form-urlencoded")
161            .body_str(concat!(
162                "name=1.0",
163                "&allowed_to_create%5B%5D%5Buser_id%5D=1",
164                "&allowed_to_create%5B%5D%5Bgroup_id%5D=1",
165                "&allowed_to_create%5B%5D%5Bdeploy_key_id%5D=1",
166                "&allowed_to_create%5B%5D%5Baccess_level%5D=30",
167            ))
168            .build()
169            .unwrap();
170        let client = SingleTestClient::new_raw(endpoint, "");
171
172        let endpoint = ProtectTag::builder()
173            .project("simple/project")
174            .name("1.0")
175            .allowed_to_create(ProtectedAccess::User(1))
176            .allowed_to_create(ProtectedAccess::Group(1))
177            .allowed_to_create(ProtectedAccessPush::DeployKey(1))
178            .allowed_to_create(ProtectedAccess::Level(ProtectedAccessLevel::Developer))
179            .build()
180            .unwrap();
181        api::ignore(endpoint).query(&client).unwrap();
182    }
183}