gitlab/api/runners/
edit.rs1use derive_builder::Builder;
8
9use crate::api::common::CommaSeparatedList;
10use crate::api::endpoint_prelude::*;
11use crate::api::ParamValue;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum RunnerAccessLevel {
17 NotProtected,
19 RefProtected,
21}
22
23impl RunnerAccessLevel {
24 fn as_str(self) -> &'static str {
26 match self {
27 Self::NotProtected => "not_protected",
28 Self::RefProtected => "ref_protected",
29 }
30 }
31}
32
33impl ParamValue<'static> for RunnerAccessLevel {
34 fn as_value(&self) -> Cow<'static, str> {
35 self.as_str().into()
36 }
37}
38
39#[derive(Debug, Builder, Clone)]
41#[builder(setter(strip_option), build_fn(validate = "Self::validate"))]
42pub struct EditRunner<'a> {
43 runner: u64,
45
46 #[builder(setter(into), default)]
48 description: Option<Cow<'a, str>>,
49 #[builder(default)]
51 paused: Option<bool>,
52 #[builder(setter(name = "_tag_list"), default, private)]
54 tag_list: Option<CommaSeparatedList<Cow<'a, str>>>,
55 #[builder(default)]
57 run_untagged: Option<bool>,
58 #[builder(default)]
60 locked: Option<bool>,
61 #[builder(default)]
63 access_level: Option<RunnerAccessLevel>,
64 #[builder(default)]
66 maximum_timeout: Option<u64>,
67 #[builder(setter(into), default)]
71 maintenance_note: Option<Cow<'a, str>>,
72}
73
74impl<'a> EditRunner<'a> {
75 pub fn builder() -> EditRunnerBuilder<'a> {
77 EditRunnerBuilder::default()
78 }
79}
80
81impl<'a> EditRunnerBuilder<'a> {
82 pub fn tag<T>(&mut self, tag: T) -> &mut Self
84 where
85 T: Into<Cow<'a, str>>,
86 {
87 self.tag_list
88 .get_or_insert(None)
89 .get_or_insert_with(CommaSeparatedList::new)
90 .push(tag.into());
91 self
92 }
93
94 pub fn tags<I, T>(&mut self, iter: I) -> &mut Self
96 where
97 I: Iterator<Item = T>,
98 T: Into<Cow<'a, str>>,
99 {
100 self.tag_list
101 .get_or_insert(None)
102 .get_or_insert_with(CommaSeparatedList::new)
103 .extend(iter.map(|t| t.into()));
104 self
105 }
106
107 fn validate(&self) -> Result<(), EditRunnerBuilderError> {
108 if let Some(Some(maintenance_note)) = self.maintenance_note.as_ref() {
109 if maintenance_note.len() > super::MAX_MAINTENANCE_NOTE_LENGTH {
110 return Err(format!(
111 "`maintenance_note` may be at most {} bytes",
112 super::MAX_MAINTENANCE_NOTE_LENGTH,
113 )
114 .into());
115 }
116 }
117
118 Ok(())
119 }
120}
121
122impl Endpoint for EditRunner<'_> {
123 fn method(&self) -> Method {
124 Method::PUT
125 }
126
127 fn endpoint(&self) -> Cow<'static, str> {
128 format!("runners/{}", self.runner).into()
129 }
130
131 fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
132 let mut params = FormParams::default();
133
134 params
135 .push_opt("description", self.description.as_ref())
136 .push_opt("paused", self.paused)
137 .push_opt("tag_list", self.tag_list.as_ref())
138 .push_opt("run_untagged", self.run_untagged)
139 .push_opt("locked", self.locked)
140 .push_opt("access_level", self.access_level)
141 .push_opt("maximum_timeout", self.maximum_timeout)
142 .push_opt("maintenance_note", self.maintenance_note.as_ref());
143
144 params.into_body()
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use http::Method;
151
152 use crate::api::runners::{EditRunner, EditRunnerBuilderError, RunnerAccessLevel};
153 use crate::api::{self, Query};
154 use crate::test::client::{ExpectedUrl, SingleTestClient};
155
156 #[test]
157 fn runner_access_level_as_str() {
158 let items = &[
159 (RunnerAccessLevel::NotProtected, "not_protected"),
160 (RunnerAccessLevel::RefProtected, "ref_protected"),
161 ];
162
163 for (i, s) in items {
164 assert_eq!(i.as_str(), *s);
165 }
166 }
167
168 #[test]
169 fn runner_is_required() {
170 let err = EditRunner::builder().build().unwrap_err();
171 crate::test::assert_missing_field!(err, EditRunnerBuilderError, "runner");
172 }
173
174 #[test]
175 fn runner_is_sufficient() {
176 EditRunner::builder().runner(1).build().unwrap();
177 }
178
179 #[test]
180 fn maintenance_note_length() {
181 use crate::api::runners::MAX_MAINTENANCE_NOTE_LENGTH;
182
183 let too_long = format!("{:width$}", "note", width = MAX_MAINTENANCE_NOTE_LENGTH + 1);
184 let err = EditRunner::builder()
185 .runner(1)
186 .maintenance_note(too_long)
187 .build()
188 .unwrap_err();
189 if let EditRunnerBuilderError::ValidationError(message) = err {
190 assert_eq!(
191 message,
192 format!("`maintenance_note` may be at most {MAX_MAINTENANCE_NOTE_LENGTH} bytes"),
193 );
194 } else {
195 panic!("unexpected error: {:?}", err);
196 }
197 }
198
199 #[test]
200 fn endpoint() {
201 let endpoint = ExpectedUrl::builder()
202 .method(Method::PUT)
203 .endpoint("runners/1")
204 .content_type("application/x-www-form-urlencoded")
205 .build()
206 .unwrap();
207 let client = SingleTestClient::new_raw(endpoint, "");
208
209 let endpoint = EditRunner::builder().runner(1).build().unwrap();
210 api::ignore(endpoint).query(&client).unwrap();
211 }
212
213 #[test]
214 fn endpoint_description() {
215 let endpoint = ExpectedUrl::builder()
216 .method(Method::PUT)
217 .endpoint("runners/1")
218 .content_type("application/x-www-form-urlencoded")
219 .body_str("description=desc")
220 .build()
221 .unwrap();
222 let client = SingleTestClient::new_raw(endpoint, "");
223
224 let endpoint = EditRunner::builder()
225 .runner(1)
226 .description("desc")
227 .build()
228 .unwrap();
229 api::ignore(endpoint).query(&client).unwrap();
230 }
231
232 #[test]
233 fn endpoint_paused() {
234 let endpoint = ExpectedUrl::builder()
235 .method(Method::PUT)
236 .endpoint("runners/1")
237 .content_type("application/x-www-form-urlencoded")
238 .body_str("paused=true")
239 .build()
240 .unwrap();
241 let client = SingleTestClient::new_raw(endpoint, "");
242
243 let endpoint = EditRunner::builder()
244 .runner(1)
245 .paused(true)
246 .build()
247 .unwrap();
248 api::ignore(endpoint).query(&client).unwrap();
249 }
250
251 #[test]
252 fn endpoint_tag_list() {
253 let endpoint = ExpectedUrl::builder()
254 .method(Method::PUT)
255 .endpoint("runners/1")
256 .content_type("application/x-www-form-urlencoded")
257 .body_str("tag_list=tag2%2Ctag1%2Ctag3")
258 .build()
259 .unwrap();
260 let client = SingleTestClient::new_raw(endpoint, "");
261
262 let endpoint = EditRunner::builder()
263 .runner(1)
264 .tag("tag2")
265 .tags(["tag1", "tag3"].iter().cloned())
266 .build()
267 .unwrap();
268 api::ignore(endpoint).query(&client).unwrap();
269 }
270
271 #[test]
272 fn endpoint_run_untagged() {
273 let endpoint = ExpectedUrl::builder()
274 .method(Method::PUT)
275 .endpoint("runners/1")
276 .content_type("application/x-www-form-urlencoded")
277 .body_str("run_untagged=false")
278 .build()
279 .unwrap();
280 let client = SingleTestClient::new_raw(endpoint, "");
281
282 let endpoint = EditRunner::builder()
283 .runner(1)
284 .run_untagged(false)
285 .build()
286 .unwrap();
287 api::ignore(endpoint).query(&client).unwrap();
288 }
289
290 #[test]
291 fn endpoint_locked() {
292 let endpoint = ExpectedUrl::builder()
293 .method(Method::PUT)
294 .endpoint("runners/1")
295 .content_type("application/x-www-form-urlencoded")
296 .body_str("locked=false")
297 .build()
298 .unwrap();
299 let client = SingleTestClient::new_raw(endpoint, "");
300
301 let endpoint = EditRunner::builder()
302 .runner(1)
303 .locked(false)
304 .build()
305 .unwrap();
306 api::ignore(endpoint).query(&client).unwrap();
307 }
308
309 #[test]
310 fn endpoint_access_level() {
311 let endpoint = ExpectedUrl::builder()
312 .method(Method::PUT)
313 .endpoint("runners/1")
314 .content_type("application/x-www-form-urlencoded")
315 .body_str("access_level=ref_protected")
316 .build()
317 .unwrap();
318 let client = SingleTestClient::new_raw(endpoint, "");
319
320 let endpoint = EditRunner::builder()
321 .runner(1)
322 .access_level(RunnerAccessLevel::RefProtected)
323 .build()
324 .unwrap();
325 api::ignore(endpoint).query(&client).unwrap();
326 }
327
328 #[test]
329 fn endpoint_maximum_timeout() {
330 let endpoint = ExpectedUrl::builder()
331 .method(Method::PUT)
332 .endpoint("runners/1")
333 .content_type("application/x-www-form-urlencoded")
334 .body_str("maximum_timeout=3600")
335 .build()
336 .unwrap();
337 let client = SingleTestClient::new_raw(endpoint, "");
338
339 let endpoint = EditRunner::builder()
340 .runner(1)
341 .maximum_timeout(3600)
342 .build()
343 .unwrap();
344 api::ignore(endpoint).query(&client).unwrap();
345 }
346
347 #[test]
348 fn endpoint_maintenance_note() {
349 let endpoint = ExpectedUrl::builder()
350 .method(Method::PUT)
351 .endpoint("runners/1")
352 .content_type("application/x-www-form-urlencoded")
353 .body_str("maintenance_note=note")
354 .build()
355 .unwrap();
356 let client = SingleTestClient::new_raw(endpoint, "");
357
358 let endpoint = EditRunner::builder()
359 .runner(1)
360 .maintenance_note("note")
361 .build()
362 .unwrap();
363 api::ignore(endpoint).query(&client).unwrap();
364 }
365}