1use std::collections::BTreeSet;
8use std::time::Duration;
9
10use derive_builder::Builder;
11
12use crate::api::common::{CommaSeparatedList, NameOrId, VisibilityLevel};
13use crate::api::endpoint_prelude::*;
14use crate::api::groups::{
15 BranchProtectionDefaults, DuoAvailability, GitAccessProtocol, GroupProjectCreationAccessLevel,
16 SharedRunnersMinutesLimit, SubgroupCreationAccessLevel,
17};
18use crate::api::projects::FeatureAccessLevel;
19use crate::api::ParamValue;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23#[non_exhaustive]
24pub enum SharedRunnersSetting {
25 Enabled,
27 DisabledWithOverride,
29 DisableAndUnoverridable,
31}
32
33impl SharedRunnersSetting {
34 fn as_str(self) -> &'static str {
35 match self {
36 SharedRunnersSetting::Enabled => "enabled",
37 SharedRunnersSetting::DisabledWithOverride => "disabled_with_override",
38 SharedRunnersSetting::DisableAndUnoverridable => "disabled_and_unoverridable",
39 }
40 }
41}
42
43impl ParamValue<'static> for SharedRunnersSetting {
44 fn as_value(&self) -> Cow<'static, str> {
45 self.as_str().into()
46 }
47}
48
49#[derive(Debug, Builder, Clone)]
51#[builder(setter(strip_option))]
52pub struct EditGroup<'a> {
53 #[builder(setter(into))]
55 group: NameOrId<'a>,
56
57 #[builder(setter(into), default)]
59 name: Option<Cow<'a, str>>,
60 #[builder(setter(into), default)]
62 path: Option<Cow<'a, str>>,
63 #[builder(setter(into), default)]
65 description: Option<Cow<'a, str>>,
66 #[builder(default)]
68 membership_lock: Option<bool>,
69 #[builder(default)]
71 visibility: Option<VisibilityLevel>,
72 #[builder(default)]
74 share_with_group_lock: Option<bool>,
75 #[builder(default)]
77 require_two_factor_authentication: Option<bool>,
78 #[builder(default)]
80 two_factor_grace_period: Option<u64>,
81 #[builder(default)]
83 project_creation_level: Option<GroupProjectCreationAccessLevel>,
84 #[builder(default)]
86 auto_devops_enabled: Option<bool>,
87 #[builder(default)]
89 subgroup_creation_level: Option<SubgroupCreationAccessLevel>,
90 #[builder(default)]
92 emails_enabled: Option<bool>,
93 #[builder(default)]
98 mentions_disabled: Option<bool>,
99 #[builder(default)]
103 prevent_sharing_groups_outside_hierarchy: Option<bool>,
104 #[builder(default)]
106 lfs_enabled: Option<bool>,
107 #[builder(default)]
109 request_access_enabled: Option<bool>,
110 #[builder(default)]
112 parent_id: Option<u64>,
113 #[builder(setter(into), default)]
115 default_branch: Option<Cow<'a, str>>,
116 #[builder(default)]
118 enabled_git_access_protocol: Option<GitAccessProtocol>,
119 #[builder(default)]
121 default_branch_protection_defaults: Option<BranchProtectionDefaults>,
122 #[builder(default)]
124 shared_runners_setting: Option<SharedRunnersSetting>,
125 #[builder(setter(into), default)]
127 shared_runners_minutes_limit: Option<SharedRunnersMinutesLimit>,
128 #[builder(default)]
130 extra_shared_runners_minutes_limit: Option<u64>,
131 #[builder(default)]
133 file_template_project_id: Option<u64>,
134 #[builder(default)]
136 prevent_forking_outside_group: Option<bool>,
137 #[builder(setter(name = "_ip_restriction_ranges"), default, private)]
139 ip_restriction_ranges: Option<CommaSeparatedList<Cow<'a, str>>>,
140 #[builder(setter(name = "_allowed_email_domains_list"), default, private)]
142 allowed_email_domains_list: Option<CommaSeparatedList<Cow<'a, str>>>,
143 #[builder(default)]
145 wiki_access_level: Option<FeatureAccessLevel>,
146 #[builder(default)]
148 duo_availability: Option<DuoAvailability>,
149 #[builder(default)]
151 experiment_features_enabled: Option<bool>,
152 #[builder(default)]
154 math_rendering_limits_enabled: Option<bool>,
155 #[builder(default)]
157 lock_math_rendering_limits_enabled: Option<bool>,
158 #[builder(default)]
160 duo_features_enabled: Option<bool>,
161 #[builder(default)]
163 max_artifacts_size: Option<u64>,
164
165 #[builder(default)]
169 unique_project_download_limit: Option<u64>,
170 #[builder(default)]
174 unique_project_download_limit_interval: Option<Duration>,
175 #[builder(
179 setter(name = "_unique_project_download_limit_allowlist"),
180 default,
181 private
182 )]
183 unique_project_download_limit_allowlist: BTreeSet<Cow<'a, str>>,
184 #[builder(
188 setter(name = "_unique_project_download_limit_alertlist"),
189 default,
190 private
191 )]
192 unique_project_download_limit_alertlist: BTreeSet<u64>,
193 #[builder(default)]
197 auto_ban_user_on_excessive_projects_download: Option<bool>,
198}
199
200impl<'a> EditGroup<'a> {
201 pub fn builder() -> EditGroupBuilder<'a> {
203 EditGroupBuilder::default()
204 }
205}
206
207impl<'a> EditGroupBuilder<'a> {
208 pub fn ip_restriction_range<R>(&mut self, range: R) -> &mut Self
210 where
211 R: Into<Cow<'a, str>>,
212 {
213 self.ip_restriction_ranges
214 .get_or_insert(None)
215 .get_or_insert_with(CommaSeparatedList::new)
216 .push(range.into());
217 self
218 }
219
220 pub fn ip_restriction_ranges<I, R>(&mut self, iter: I) -> &mut Self
222 where
223 I: Iterator<Item = R>,
224 R: Into<Cow<'a, str>>,
225 {
226 self.ip_restriction_ranges
227 .get_or_insert(None)
228 .get_or_insert_with(CommaSeparatedList::new)
229 .extend(iter.map(Into::into));
230 self
231 }
232
233 pub fn allowed_email_domain<D>(&mut self, domain: D) -> &mut Self
235 where
236 D: Into<Cow<'a, str>>,
237 {
238 self.allowed_email_domains_list
239 .get_or_insert(None)
240 .get_or_insert_with(CommaSeparatedList::new)
241 .push(domain.into());
242 self
243 }
244
245 pub fn allowed_email_domains<I, D>(&mut self, iter: I) -> &mut Self
247 where
248 I: Iterator<Item = D>,
249 D: Into<Cow<'a, str>>,
250 {
251 self.allowed_email_domains_list
252 .get_or_insert(None)
253 .get_or_insert_with(CommaSeparatedList::new)
254 .extend(iter.map(Into::into));
255 self
256 }
257
258 pub fn unique_project_download_limit_allow<A>(&mut self, allow: A) -> &mut Self
260 where
261 A: Into<Cow<'a, str>>,
262 {
263 self.unique_project_download_limit_allowlist
264 .get_or_insert_with(BTreeSet::new)
265 .insert(allow.into());
266 self
267 }
268
269 pub fn unique_project_download_limit_allow_users<I, A>(&mut self, iter: I) -> &mut Self
271 where
272 I: Iterator<Item = A>,
273 A: Into<Cow<'a, str>>,
274 {
275 self.unique_project_download_limit_allowlist
276 .get_or_insert_with(BTreeSet::new)
277 .extend(iter.map(Into::into));
278 self
279 }
280
281 pub fn unique_project_download_limit_alert(&mut self, alert: u64) -> &mut Self {
283 self.unique_project_download_limit_alertlist
284 .get_or_insert_with(BTreeSet::new)
285 .insert(alert);
286 self
287 }
288
289 pub fn unique_project_download_limit_alert_users<I>(&mut self, iter: I) -> &mut Self
291 where
292 I: Iterator<Item = u64>,
293 {
294 self.unique_project_download_limit_alertlist
295 .get_or_insert_with(BTreeSet::new)
296 .extend(iter);
297 self
298 }
299}
300
301impl Endpoint for EditGroup<'_> {
302 fn method(&self) -> Method {
303 Method::PUT
304 }
305
306 fn endpoint(&self) -> Cow<'static, str> {
307 format!("groups/{}", self.group).into()
308 }
309
310 fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
311 let mut params = FormParams::default();
312
313 params
314 .push_opt("name", self.name.as_ref())
315 .push_opt("path", self.path.as_ref())
316 .push_opt("description", self.description.as_ref())
317 .push_opt("membership_lock", self.membership_lock)
318 .push_opt("visibility", self.visibility)
319 .push_opt("share_with_group_lock", self.share_with_group_lock)
320 .push_opt(
321 "require_two_factor_authentication",
322 self.require_two_factor_authentication,
323 )
324 .push_opt("two_factor_grace_period", self.two_factor_grace_period)
325 .push_opt("project_creation_level", self.project_creation_level)
326 .push_opt("auto_devops_enabled", self.auto_devops_enabled)
327 .push_opt("subgroup_creation_level", self.subgroup_creation_level)
328 .push_opt("emails_enabled", self.emails_enabled)
329 .push_opt("mentions_disabled", self.mentions_disabled)
330 .push_opt(
331 "prevent_sharing_groups_outside_hierarchy",
332 self.prevent_sharing_groups_outside_hierarchy,
333 )
334 .push_opt("lfs_enabled", self.lfs_enabled)
335 .push_opt("request_access_enabled", self.request_access_enabled)
336 .push_opt("parent_id", self.parent_id)
337 .push_opt("default_branch", self.default_branch.as_ref())
338 .push_opt(
339 "enabled_git_access_protocol",
340 self.enabled_git_access_protocol,
341 )
342 .push_opt("shared_runners_setting", self.shared_runners_setting)
343 .push_opt(
344 "shared_runners_minutes_limit",
345 self.shared_runners_minutes_limit,
346 )
347 .push_opt(
348 "extra_shared_runners_minutes_limit",
349 self.extra_shared_runners_minutes_limit,
350 )
351 .push_opt("file_template_project_id", self.file_template_project_id)
352 .push_opt(
353 "prevent_forking_outside_group",
354 self.prevent_forking_outside_group,
355 )
356 .push_opt("ip_restriction_ranges", self.ip_restriction_ranges.as_ref())
357 .push_opt(
358 "allowed_email_domains",
359 self.allowed_email_domains_list.as_ref(),
360 )
361 .push_opt("wiki_access_level", self.wiki_access_level)
362 .push_opt("duo_availability", self.duo_availability)
363 .push_opt(
364 "experiment_features_enabled",
365 self.experiment_features_enabled,
366 )
367 .push_opt(
368 "math_rendering_limits_enabled",
369 self.math_rendering_limits_enabled,
370 )
371 .push_opt(
372 "lock_math_rendering_limits_enabled",
373 self.lock_math_rendering_limits_enabled,
374 )
375 .push_opt("duo_features_enabled", self.duo_features_enabled)
376 .push_opt("max_artifacts_size", self.max_artifacts_size)
377 .push_opt(
378 "unique_project_download_limit",
379 self.unique_project_download_limit,
380 )
381 .push_opt(
382 "unique_project_download_limit_interval_in_seconds",
383 self.unique_project_download_limit_interval
384 .map(|interval| interval.as_secs()),
385 )
386 .extend(
387 self.unique_project_download_limit_allowlist
388 .iter()
389 .map(|value| ("unique_project_download_limit_allowlist[]", value)),
390 )
391 .extend(
392 self.unique_project_download_limit_alertlist
393 .iter()
394 .map(|&value| ("unique_project_download_limit_alertlist[]", value)),
395 )
396 .push_opt(
397 "auto_ban_user_on_excessive_projects_download",
398 self.auto_ban_user_on_excessive_projects_download,
399 );
400
401 if let Some(defaults) = self.default_branch_protection_defaults.as_ref() {
402 defaults.add_query(&mut params);
403 }
404
405 params.into_body()
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use std::time::Duration;
412
413 use http::Method;
414
415 use crate::api::common::VisibilityLevel;
416 use crate::api::groups::{
417 BranchProtectionAccessLevel, BranchProtectionDefaults, DuoAvailability, EditGroup,
418 EditGroupBuilderError, GitAccessProtocol, GroupProjectCreationAccessLevel,
419 SharedRunnersMinutesLimit, SharedRunnersSetting, SubgroupCreationAccessLevel,
420 };
421 use crate::api::projects::FeatureAccessLevel;
422 use crate::api::{self, Query};
423 use crate::test::client::{ExpectedUrl, SingleTestClient};
424
425 #[test]
426 fn shared_runners_setting_as_str() {
427 let items = &[
428 (SharedRunnersSetting::Enabled, "enabled"),
429 (
430 SharedRunnersSetting::DisabledWithOverride,
431 "disabled_with_override",
432 ),
433 (
434 SharedRunnersSetting::DisableAndUnoverridable,
435 "disabled_and_unoverridable",
436 ),
437 ];
438
439 for (i, s) in items {
440 assert_eq!(i.as_str(), *s);
441 }
442 }
443
444 #[test]
445 fn group_is_necessary() {
446 let err = EditGroup::builder().build().unwrap_err();
447 crate::test::assert_missing_field!(err, EditGroupBuilderError, "group");
448 }
449
450 #[test]
451 fn group_is_sufficient() {
452 EditGroup::builder().group("group").build().unwrap();
453 }
454
455 #[test]
456 fn endpoint() {
457 let endpoint = ExpectedUrl::builder()
458 .method(Method::PUT)
459 .endpoint("groups/simple%2Fgroup")
460 .content_type("application/x-www-form-urlencoded")
461 .build()
462 .unwrap();
463 let client = SingleTestClient::new_raw(endpoint, "");
464
465 let endpoint = EditGroup::builder().group("simple/group").build().unwrap();
466 api::ignore(endpoint).query(&client).unwrap();
467 }
468
469 #[test]
470 fn endpoint_name() {
471 let endpoint = ExpectedUrl::builder()
472 .method(Method::PUT)
473 .endpoint("groups/simple%2Fgroup")
474 .content_type("application/x-www-form-urlencoded")
475 .body_str("name=name")
476 .build()
477 .unwrap();
478 let client = SingleTestClient::new_raw(endpoint, "");
479
480 let endpoint = EditGroup::builder()
481 .group("simple/group")
482 .name("name")
483 .build()
484 .unwrap();
485 api::ignore(endpoint).query(&client).unwrap();
486 }
487
488 #[test]
489 fn endpoint_path() {
490 let endpoint = ExpectedUrl::builder()
491 .method(Method::PUT)
492 .endpoint("groups/simple%2Fgroup")
493 .content_type("application/x-www-form-urlencoded")
494 .body_str("path=path")
495 .build()
496 .unwrap();
497 let client = SingleTestClient::new_raw(endpoint, "");
498
499 let endpoint = EditGroup::builder()
500 .group("simple/group")
501 .path("path")
502 .build()
503 .unwrap();
504 api::ignore(endpoint).query(&client).unwrap();
505 }
506
507 #[test]
508 fn endpoint_description() {
509 let endpoint = ExpectedUrl::builder()
510 .method(Method::PUT)
511 .endpoint("groups/simple%2Fgroup")
512 .content_type("application/x-www-form-urlencoded")
513 .body_str("description=description")
514 .build()
515 .unwrap();
516 let client = SingleTestClient::new_raw(endpoint, "");
517
518 let endpoint = EditGroup::builder()
519 .group("simple/group")
520 .description("description")
521 .build()
522 .unwrap();
523 api::ignore(endpoint).query(&client).unwrap();
524 }
525
526 #[test]
527 fn endpoint_membership_lock() {
528 let endpoint = ExpectedUrl::builder()
529 .method(Method::PUT)
530 .endpoint("groups/simple%2Fgroup")
531 .content_type("application/x-www-form-urlencoded")
532 .body_str("membership_lock=true")
533 .build()
534 .unwrap();
535 let client = SingleTestClient::new_raw(endpoint, "");
536
537 let endpoint = EditGroup::builder()
538 .group("simple/group")
539 .membership_lock(true)
540 .build()
541 .unwrap();
542 api::ignore(endpoint).query(&client).unwrap();
543 }
544
545 #[test]
546 fn endpoint_visibility() {
547 let endpoint = ExpectedUrl::builder()
548 .method(Method::PUT)
549 .endpoint("groups/simple%2Fgroup")
550 .content_type("application/x-www-form-urlencoded")
551 .body_str("visibility=internal")
552 .build()
553 .unwrap();
554 let client = SingleTestClient::new_raw(endpoint, "");
555
556 let endpoint = EditGroup::builder()
557 .group("simple/group")
558 .visibility(VisibilityLevel::Internal)
559 .build()
560 .unwrap();
561 api::ignore(endpoint).query(&client).unwrap();
562 }
563
564 #[test]
565 fn endpoint_share_with_group_lock() {
566 let endpoint = ExpectedUrl::builder()
567 .method(Method::PUT)
568 .endpoint("groups/simple%2Fgroup")
569 .content_type("application/x-www-form-urlencoded")
570 .body_str("share_with_group_lock=true")
571 .build()
572 .unwrap();
573 let client = SingleTestClient::new_raw(endpoint, "");
574
575 let endpoint = EditGroup::builder()
576 .group("simple/group")
577 .share_with_group_lock(true)
578 .build()
579 .unwrap();
580 api::ignore(endpoint).query(&client).unwrap();
581 }
582
583 #[test]
584 fn endpoint_require_two_factor_authentication() {
585 let endpoint = ExpectedUrl::builder()
586 .method(Method::PUT)
587 .endpoint("groups/simple%2Fgroup")
588 .content_type("application/x-www-form-urlencoded")
589 .body_str("require_two_factor_authentication=true")
590 .build()
591 .unwrap();
592 let client = SingleTestClient::new_raw(endpoint, "");
593
594 let endpoint = EditGroup::builder()
595 .group("simple/group")
596 .require_two_factor_authentication(true)
597 .build()
598 .unwrap();
599 api::ignore(endpoint).query(&client).unwrap();
600 }
601
602 #[test]
603 fn endpoint_two_factor_grace_period() {
604 let endpoint = ExpectedUrl::builder()
605 .method(Method::PUT)
606 .endpoint("groups/simple%2Fgroup")
607 .content_type("application/x-www-form-urlencoded")
608 .body_str("two_factor_grace_period=1")
609 .build()
610 .unwrap();
611 let client = SingleTestClient::new_raw(endpoint, "");
612
613 let endpoint = EditGroup::builder()
614 .group("simple/group")
615 .two_factor_grace_period(1)
616 .build()
617 .unwrap();
618 api::ignore(endpoint).query(&client).unwrap();
619 }
620
621 #[test]
622 fn endpoint_project_creation_level() {
623 let endpoint = ExpectedUrl::builder()
624 .method(Method::PUT)
625 .endpoint("groups/simple%2Fgroup")
626 .content_type("application/x-www-form-urlencoded")
627 .body_str("project_creation_level=maintainer")
628 .build()
629 .unwrap();
630 let client = SingleTestClient::new_raw(endpoint, "");
631
632 let endpoint = EditGroup::builder()
633 .group("simple/group")
634 .project_creation_level(GroupProjectCreationAccessLevel::Maintainer)
635 .build()
636 .unwrap();
637 api::ignore(endpoint).query(&client).unwrap();
638 }
639
640 #[test]
641 fn endpoint_auto_devops_enabled() {
642 let endpoint = ExpectedUrl::builder()
643 .method(Method::PUT)
644 .endpoint("groups/simple%2Fgroup")
645 .content_type("application/x-www-form-urlencoded")
646 .body_str("auto_devops_enabled=false")
647 .build()
648 .unwrap();
649 let client = SingleTestClient::new_raw(endpoint, "");
650
651 let endpoint = EditGroup::builder()
652 .group("simple/group")
653 .auto_devops_enabled(false)
654 .build()
655 .unwrap();
656 api::ignore(endpoint).query(&client).unwrap();
657 }
658
659 #[test]
660 fn endpoint_subgroup_creation_level() {
661 let endpoint = ExpectedUrl::builder()
662 .method(Method::PUT)
663 .endpoint("groups/simple%2Fgroup")
664 .content_type("application/x-www-form-urlencoded")
665 .body_str("subgroup_creation_level=owner")
666 .build()
667 .unwrap();
668 let client = SingleTestClient::new_raw(endpoint, "");
669
670 let endpoint = EditGroup::builder()
671 .group("simple/group")
672 .subgroup_creation_level(SubgroupCreationAccessLevel::Owner)
673 .build()
674 .unwrap();
675 api::ignore(endpoint).query(&client).unwrap();
676 }
677
678 #[test]
679 fn endpoint_emails_enabled() {
680 let endpoint = ExpectedUrl::builder()
681 .method(Method::PUT)
682 .endpoint("groups/simple%2Fgroup")
683 .content_type("application/x-www-form-urlencoded")
684 .body_str("emails_enabled=false")
685 .build()
686 .unwrap();
687 let client = SingleTestClient::new_raw(endpoint, "");
688
689 let endpoint = EditGroup::builder()
690 .group("simple/group")
691 .emails_enabled(false)
692 .build()
693 .unwrap();
694 api::ignore(endpoint).query(&client).unwrap();
695 }
696
697 #[test]
698 fn endpoint_mentions_disabled() {
699 let endpoint = ExpectedUrl::builder()
700 .method(Method::PUT)
701 .endpoint("groups/simple%2Fgroup")
702 .content_type("application/x-www-form-urlencoded")
703 .body_str("mentions_disabled=true")
704 .build()
705 .unwrap();
706 let client = SingleTestClient::new_raw(endpoint, "");
707
708 let endpoint = EditGroup::builder()
709 .group("simple/group")
710 .mentions_disabled(true)
711 .build()
712 .unwrap();
713 api::ignore(endpoint).query(&client).unwrap();
714 }
715
716 #[test]
717 fn endpoint_prevent_sharing_groups_outside_hierarchy() {
718 let endpoint = ExpectedUrl::builder()
719 .method(Method::PUT)
720 .endpoint("groups/simple%2Fgroup")
721 .content_type("application/x-www-form-urlencoded")
722 .body_str("prevent_sharing_groups_outside_hierarchy=true")
723 .build()
724 .unwrap();
725 let client = SingleTestClient::new_raw(endpoint, "");
726
727 let endpoint = EditGroup::builder()
728 .group("simple/group")
729 .prevent_sharing_groups_outside_hierarchy(true)
730 .build()
731 .unwrap();
732 api::ignore(endpoint).query(&client).unwrap();
733 }
734
735 #[test]
736 fn endpoint_lfs_enabled() {
737 let endpoint = ExpectedUrl::builder()
738 .method(Method::PUT)
739 .endpoint("groups/simple%2Fgroup")
740 .content_type("application/x-www-form-urlencoded")
741 .body_str("lfs_enabled=true")
742 .build()
743 .unwrap();
744 let client = SingleTestClient::new_raw(endpoint, "");
745
746 let endpoint = EditGroup::builder()
747 .group("simple/group")
748 .lfs_enabled(true)
749 .build()
750 .unwrap();
751 api::ignore(endpoint).query(&client).unwrap();
752 }
753
754 #[test]
755 fn endpoint_request_access_enabled() {
756 let endpoint = ExpectedUrl::builder()
757 .method(Method::PUT)
758 .endpoint("groups/simple%2Fgroup")
759 .content_type("application/x-www-form-urlencoded")
760 .body_str("request_access_enabled=true")
761 .build()
762 .unwrap();
763 let client = SingleTestClient::new_raw(endpoint, "");
764
765 let endpoint = EditGroup::builder()
766 .group("simple/group")
767 .request_access_enabled(true)
768 .build()
769 .unwrap();
770 api::ignore(endpoint).query(&client).unwrap();
771 }
772
773 #[test]
774 fn endpoint_parent_id() {
775 let endpoint = ExpectedUrl::builder()
776 .method(Method::PUT)
777 .endpoint("groups/simple%2Fgroup")
778 .content_type("application/x-www-form-urlencoded")
779 .body_str("parent_id=1")
780 .build()
781 .unwrap();
782 let client = SingleTestClient::new_raw(endpoint, "");
783
784 let endpoint = EditGroup::builder()
785 .group("simple/group")
786 .parent_id(1)
787 .build()
788 .unwrap();
789 api::ignore(endpoint).query(&client).unwrap();
790 }
791
792 #[test]
793 fn endpoint_default_branch() {
794 let endpoint = ExpectedUrl::builder()
795 .method(Method::PUT)
796 .endpoint("groups/simple%2Fgroup")
797 .content_type("application/x-www-form-urlencoded")
798 .body_str("default_branch=main")
799 .build()
800 .unwrap();
801 let client = SingleTestClient::new_raw(endpoint, "");
802
803 let endpoint = EditGroup::builder()
804 .group("simple/group")
805 .default_branch("main")
806 .build()
807 .unwrap();
808 api::ignore(endpoint).query(&client).unwrap();
809 }
810
811 #[test]
812 fn endpoint_enabled_git_access_protocol() {
813 let endpoint = ExpectedUrl::builder()
814 .method(Method::PUT)
815 .endpoint("groups/simple%2Fgroup")
816 .content_type("application/x-www-form-urlencoded")
817 .body_str("enabled_git_access_protocol=http")
818 .build()
819 .unwrap();
820 let client = SingleTestClient::new_raw(endpoint, "");
821
822 let endpoint = EditGroup::builder()
823 .group("simple/group")
824 .enabled_git_access_protocol(GitAccessProtocol::Http)
825 .build()
826 .unwrap();
827 api::ignore(endpoint).query(&client).unwrap();
828 }
829
830 #[test]
831 fn endpoint_default_branch_protection_defaults_allowed_to_push() {
832 let endpoint = ExpectedUrl::builder()
833 .method(Method::PUT)
834 .endpoint("groups/simple%2Fgroup")
835 .content_type("application/x-www-form-urlencoded")
836 .body_str("default_branch_protection_defaults%5Ballowed_to_push%5D%5B%5D=30")
837 .build()
838 .unwrap();
839 let client = SingleTestClient::new_raw(endpoint, "");
840
841 let endpoint = EditGroup::builder()
842 .group("simple/group")
843 .default_branch_protection_defaults(
844 BranchProtectionDefaults::builder()
845 .allowed_to_push(BranchProtectionAccessLevel::Developer)
846 .allowed_to_push(BranchProtectionAccessLevel::Maintainer)
847 .not_allowed_to_push(BranchProtectionAccessLevel::Maintainer)
848 .build()
849 .unwrap(),
850 )
851 .build()
852 .unwrap();
853 api::ignore(endpoint).query(&client).unwrap();
854 }
855
856 #[test]
857 fn endpoint_default_branch_protection_defaults_allow_force_push() {
858 let endpoint = ExpectedUrl::builder()
859 .method(Method::PUT)
860 .endpoint("groups/simple%2Fgroup")
861 .content_type("application/x-www-form-urlencoded")
862 .body_str("default_branch_protection_defaults%5Ballow_force_push%5D=true")
863 .build()
864 .unwrap();
865 let client = SingleTestClient::new_raw(endpoint, "");
866
867 let endpoint = EditGroup::builder()
868 .group("simple/group")
869 .default_branch_protection_defaults(
870 BranchProtectionDefaults::builder()
871 .allow_force_push(true)
872 .build()
873 .unwrap(),
874 )
875 .build()
876 .unwrap();
877 api::ignore(endpoint).query(&client).unwrap();
878 }
879
880 #[test]
881 fn endpoint_default_branch_protection_defaults_allowed_to_merge() {
882 let endpoint = ExpectedUrl::builder()
883 .method(Method::PUT)
884 .endpoint("groups/simple%2Fgroup")
885 .content_type("application/x-www-form-urlencoded")
886 .body_str("default_branch_protection_defaults%5Ballowed_to_merge%5D%5B%5D=30")
887 .build()
888 .unwrap();
889 let client = SingleTestClient::new_raw(endpoint, "");
890
891 let endpoint = EditGroup::builder()
892 .group("simple/group")
893 .default_branch_protection_defaults(
894 BranchProtectionDefaults::builder()
895 .allowed_to_merge(BranchProtectionAccessLevel::Developer)
896 .allowed_to_merge(BranchProtectionAccessLevel::Maintainer)
897 .not_allowed_to_merge(BranchProtectionAccessLevel::Maintainer)
898 .build()
899 .unwrap(),
900 )
901 .build()
902 .unwrap();
903 api::ignore(endpoint).query(&client).unwrap();
904 }
905
906 #[test]
907 fn endpoint_default_branch_protection_defaults_developer_can_initial_push() {
908 let endpoint = ExpectedUrl::builder()
909 .method(Method::PUT)
910 .endpoint("groups/simple%2Fgroup")
911 .content_type("application/x-www-form-urlencoded")
912 .body_str("default_branch_protection_defaults%5Bdeveloper_can_initial_push%5D=true")
913 .build()
914 .unwrap();
915 let client = SingleTestClient::new_raw(endpoint, "");
916
917 let endpoint = EditGroup::builder()
918 .group("simple/group")
919 .default_branch_protection_defaults(
920 BranchProtectionDefaults::builder()
921 .developer_can_initial_push(true)
922 .build()
923 .unwrap(),
924 )
925 .build()
926 .unwrap();
927 api::ignore(endpoint).query(&client).unwrap();
928 }
929
930 #[test]
931 fn endpoint_shared_runners_setting() {
932 let endpoint = ExpectedUrl::builder()
933 .method(Method::PUT)
934 .endpoint("groups/simple%2Fgroup")
935 .content_type("application/x-www-form-urlencoded")
936 .body_str("shared_runners_setting=disabled_with_override")
937 .build()
938 .unwrap();
939 let client = SingleTestClient::new_raw(endpoint, "");
940
941 let endpoint = EditGroup::builder()
942 .group("simple/group")
943 .shared_runners_setting(SharedRunnersSetting::DisabledWithOverride)
944 .build()
945 .unwrap();
946 api::ignore(endpoint).query(&client).unwrap();
947 }
948
949 #[test]
950 fn endpoint_shared_runners_minutes_limit() {
951 let endpoint = ExpectedUrl::builder()
952 .method(Method::PUT)
953 .endpoint("groups/simple%2Fgroup")
954 .content_type("application/x-www-form-urlencoded")
955 .body_str("shared_runners_minutes_limit=0")
956 .build()
957 .unwrap();
958 let client = SingleTestClient::new_raw(endpoint, "");
959
960 let endpoint = EditGroup::builder()
961 .group("simple/group")
962 .shared_runners_minutes_limit(SharedRunnersMinutesLimit::Unlimited)
963 .build()
964 .unwrap();
965 api::ignore(endpoint).query(&client).unwrap();
966 }
967
968 #[test]
969 fn endpoint_shared_runners_minutes_limit_into() {
970 let endpoint = ExpectedUrl::builder()
971 .method(Method::PUT)
972 .endpoint("groups/simple%2Fgroup")
973 .content_type("application/x-www-form-urlencoded")
974 .body_str("shared_runners_minutes_limit=1")
975 .build()
976 .unwrap();
977 let client = SingleTestClient::new_raw(endpoint, "");
978
979 let endpoint = EditGroup::builder()
980 .group("simple/group")
981 .shared_runners_minutes_limit(1)
982 .build()
983 .unwrap();
984 api::ignore(endpoint).query(&client).unwrap();
985 }
986
987 #[test]
988 fn endpoint_extra_shared_runners_minutes_limit() {
989 let endpoint = ExpectedUrl::builder()
990 .method(Method::PUT)
991 .endpoint("groups/simple%2Fgroup")
992 .content_type("application/x-www-form-urlencoded")
993 .body_str("extra_shared_runners_minutes_limit=1")
994 .build()
995 .unwrap();
996 let client = SingleTestClient::new_raw(endpoint, "");
997
998 let endpoint = EditGroup::builder()
999 .group("simple/group")
1000 .extra_shared_runners_minutes_limit(1)
1001 .build()
1002 .unwrap();
1003 api::ignore(endpoint).query(&client).unwrap();
1004 }
1005
1006 #[test]
1007 fn endpoint_file_template_project_id() {
1008 let endpoint = ExpectedUrl::builder()
1009 .method(Method::PUT)
1010 .endpoint("groups/simple%2Fgroup")
1011 .content_type("application/x-www-form-urlencoded")
1012 .body_str("file_template_project_id=1")
1013 .build()
1014 .unwrap();
1015 let client = SingleTestClient::new_raw(endpoint, "");
1016
1017 let endpoint = EditGroup::builder()
1018 .group("simple/group")
1019 .file_template_project_id(1)
1020 .build()
1021 .unwrap();
1022 api::ignore(endpoint).query(&client).unwrap();
1023 }
1024
1025 #[test]
1026 fn endpoint_prevent_forking_outside_group() {
1027 let endpoint = ExpectedUrl::builder()
1028 .method(Method::PUT)
1029 .endpoint("groups/simple%2Fgroup")
1030 .content_type("application/x-www-form-urlencoded")
1031 .body_str("prevent_forking_outside_group=true")
1032 .build()
1033 .unwrap();
1034 let client = SingleTestClient::new_raw(endpoint, "");
1035
1036 let endpoint = EditGroup::builder()
1037 .group("simple/group")
1038 .prevent_forking_outside_group(true)
1039 .build()
1040 .unwrap();
1041 api::ignore(endpoint).query(&client).unwrap();
1042 }
1043
1044 #[test]
1045 fn endpoint_allowed_email_domains() {
1046 let endpoint = ExpectedUrl::builder()
1047 .method(Method::PUT)
1048 .endpoint("groups/simple%2Fgroup")
1049 .content_type("application/x-www-form-urlencoded")
1050 .body_str("allowed_email_domains=example.com%2Cexample.org")
1051 .build()
1052 .unwrap();
1053 let client = SingleTestClient::new_raw(endpoint, "");
1054
1055 let endpoint = EditGroup::builder()
1056 .group("simple/group")
1057 .allowed_email_domain("example.com")
1058 .allowed_email_domains(["example.org"].iter().copied())
1059 .build()
1060 .unwrap();
1061 api::ignore(endpoint).query(&client).unwrap();
1062 }
1063
1064 #[test]
1065 fn endpoint_ip_restriction_ranges() {
1066 let endpoint = ExpectedUrl::builder()
1067 .method(Method::PUT)
1068 .endpoint("groups/simple%2Fgroup")
1069 .content_type("application/x-www-form-urlencoded")
1070 .body_str("ip_restriction_ranges=10.0.0.0%2F8%2C192.168.1.1%2C192.168.1.128%2F7")
1071 .build()
1072 .unwrap();
1073 let client = SingleTestClient::new_raw(endpoint, "");
1074
1075 let endpoint = EditGroup::builder()
1076 .group("simple/group")
1077 .ip_restriction_range("10.0.0.0/8")
1078 .ip_restriction_ranges(["192.168.1.1", "192.168.1.128/7"].iter().copied())
1079 .build()
1080 .unwrap();
1081 api::ignore(endpoint).query(&client).unwrap();
1082 }
1083
1084 #[test]
1085 fn endpoint_wiki_access_level() {
1086 let endpoint = ExpectedUrl::builder()
1087 .method(Method::PUT)
1088 .endpoint("groups/simple%2Fgroup")
1089 .content_type("application/x-www-form-urlencoded")
1090 .body_str("wiki_access_level=disabled")
1091 .build()
1092 .unwrap();
1093 let client = SingleTestClient::new_raw(endpoint, "");
1094
1095 let endpoint = EditGroup::builder()
1096 .group("simple/group")
1097 .wiki_access_level(FeatureAccessLevel::Disabled)
1098 .build()
1099 .unwrap();
1100 api::ignore(endpoint).query(&client).unwrap();
1101 }
1102
1103 #[test]
1104 fn endpoint_duo_availability() {
1105 let endpoint = ExpectedUrl::builder()
1106 .method(Method::PUT)
1107 .endpoint("groups/simple%2Fgroup")
1108 .content_type("application/x-www-form-urlencoded")
1109 .body_str("duo_availability=default_off")
1110 .build()
1111 .unwrap();
1112 let client = SingleTestClient::new_raw(endpoint, "");
1113
1114 let endpoint = EditGroup::builder()
1115 .group("simple/group")
1116 .duo_availability(DuoAvailability::DefaultOff)
1117 .build()
1118 .unwrap();
1119 api::ignore(endpoint).query(&client).unwrap();
1120 }
1121
1122 #[test]
1123 fn endpoint_experiment_features_enabled() {
1124 let endpoint = ExpectedUrl::builder()
1125 .method(Method::PUT)
1126 .endpoint("groups/simple%2Fgroup")
1127 .content_type("application/x-www-form-urlencoded")
1128 .body_str("experiment_features_enabled=true")
1129 .build()
1130 .unwrap();
1131 let client = SingleTestClient::new_raw(endpoint, "");
1132
1133 let endpoint = EditGroup::builder()
1134 .group("simple/group")
1135 .experiment_features_enabled(true)
1136 .build()
1137 .unwrap();
1138 api::ignore(endpoint).query(&client).unwrap();
1139 }
1140
1141 #[test]
1142 fn endpoint_math_rendering_limits_enabled() {
1143 let endpoint = ExpectedUrl::builder()
1144 .method(Method::PUT)
1145 .endpoint("groups/simple%2Fgroup")
1146 .content_type("application/x-www-form-urlencoded")
1147 .body_str("math_rendering_limits_enabled=true")
1148 .build()
1149 .unwrap();
1150 let client = SingleTestClient::new_raw(endpoint, "");
1151
1152 let endpoint = EditGroup::builder()
1153 .group("simple/group")
1154 .math_rendering_limits_enabled(true)
1155 .build()
1156 .unwrap();
1157 api::ignore(endpoint).query(&client).unwrap();
1158 }
1159
1160 #[test]
1161 fn endpoint_lock_math_rendering_limits_enabled() {
1162 let endpoint = ExpectedUrl::builder()
1163 .method(Method::PUT)
1164 .endpoint("groups/simple%2Fgroup")
1165 .content_type("application/x-www-form-urlencoded")
1166 .body_str("lock_math_rendering_limits_enabled=true")
1167 .build()
1168 .unwrap();
1169 let client = SingleTestClient::new_raw(endpoint, "");
1170
1171 let endpoint = EditGroup::builder()
1172 .group("simple/group")
1173 .lock_math_rendering_limits_enabled(true)
1174 .build()
1175 .unwrap();
1176 api::ignore(endpoint).query(&client).unwrap();
1177 }
1178
1179 #[test]
1180 fn endpoint_duo_features_enabled() {
1181 let endpoint = ExpectedUrl::builder()
1182 .method(Method::PUT)
1183 .endpoint("groups/simple%2Fgroup")
1184 .content_type("application/x-www-form-urlencoded")
1185 .body_str("duo_features_enabled=true")
1186 .build()
1187 .unwrap();
1188 let client = SingleTestClient::new_raw(endpoint, "");
1189
1190 let endpoint = EditGroup::builder()
1191 .group("simple/group")
1192 .duo_features_enabled(true)
1193 .build()
1194 .unwrap();
1195 api::ignore(endpoint).query(&client).unwrap();
1196 }
1197
1198 #[test]
1199 fn endpoint_max_artifacts_size() {
1200 let endpoint = ExpectedUrl::builder()
1201 .method(Method::PUT)
1202 .endpoint("groups/simple%2Fgroup")
1203 .content_type("application/x-www-form-urlencoded")
1204 .body_str("max_artifacts_size=1024")
1205 .build()
1206 .unwrap();
1207 let client = SingleTestClient::new_raw(endpoint, "");
1208
1209 let endpoint = EditGroup::builder()
1210 .group("simple/group")
1211 .max_artifacts_size(1024)
1212 .build()
1213 .unwrap();
1214 api::ignore(endpoint).query(&client).unwrap();
1215 }
1216
1217 #[test]
1218 fn endpoint_unique_project_download_limit() {
1219 let endpoint = ExpectedUrl::builder()
1220 .method(Method::PUT)
1221 .endpoint("groups/simple%2Fgroup")
1222 .content_type("application/x-www-form-urlencoded")
1223 .body_str("unique_project_download_limit=100")
1224 .build()
1225 .unwrap();
1226 let client = SingleTestClient::new_raw(endpoint, "");
1227
1228 let endpoint = EditGroup::builder()
1229 .group("simple/group")
1230 .unique_project_download_limit(100)
1231 .build()
1232 .unwrap();
1233 api::ignore(endpoint).query(&client).unwrap();
1234 }
1235
1236 #[test]
1237 fn endpoint_unique_project_download_limit_interval_in_seconds() {
1238 let endpoint = ExpectedUrl::builder()
1239 .method(Method::PUT)
1240 .endpoint("groups/simple%2Fgroup")
1241 .content_type("application/x-www-form-urlencoded")
1242 .body_str("unique_project_download_limit_interval_in_seconds=3600")
1243 .build()
1244 .unwrap();
1245 let client = SingleTestClient::new_raw(endpoint, "");
1246
1247 let endpoint = EditGroup::builder()
1248 .group("simple/group")
1249 .unique_project_download_limit_interval(Duration::from_secs(3600))
1250 .build()
1251 .unwrap();
1252 api::ignore(endpoint).query(&client).unwrap();
1253 }
1254
1255 #[test]
1256 fn endpoint_unique_project_download_limit_allowlist() {
1257 let endpoint = ExpectedUrl::builder()
1258 .method(Method::PUT)
1259 .endpoint("groups/simple%2Fgroup")
1260 .content_type("application/x-www-form-urlencoded")
1261 .body_str(concat!(
1262 "unique_project_download_limit_allowlist%5B%5D=auditor",
1263 "&unique_project_download_limit_allowlist%5B%5D=robot",
1264 ))
1265 .build()
1266 .unwrap();
1267 let client = SingleTestClient::new_raw(endpoint, "");
1268
1269 let endpoint = EditGroup::builder()
1270 .group("simple/group")
1271 .unique_project_download_limit_allow("robot")
1272 .unique_project_download_limit_allow_users(["robot", "auditor"].iter().copied())
1273 .build()
1274 .unwrap();
1275 api::ignore(endpoint).query(&client).unwrap();
1276 }
1277
1278 #[test]
1279 fn endpoint_unique_project_download_limit_alertlist() {
1280 let endpoint = ExpectedUrl::builder()
1281 .method(Method::PUT)
1282 .endpoint("groups/simple%2Fgroup")
1283 .content_type("application/x-www-form-urlencoded")
1284 .body_str(concat!(
1285 "unique_project_download_limit_alertlist%5B%5D=1",
1286 "&unique_project_download_limit_alertlist%5B%5D=2",
1287 ))
1288 .build()
1289 .unwrap();
1290 let client = SingleTestClient::new_raw(endpoint, "");
1291
1292 let endpoint = EditGroup::builder()
1293 .group("simple/group")
1294 .unique_project_download_limit_alert(2)
1295 .unique_project_download_limit_alert_users([2, 1].iter().copied())
1296 .build()
1297 .unwrap();
1298 api::ignore(endpoint).query(&client).unwrap();
1299 }
1300
1301 #[test]
1302 fn endpoint_auto_ban_user_on_excessive_projects_download() {
1303 let endpoint = ExpectedUrl::builder()
1304 .method(Method::PUT)
1305 .endpoint("groups/simple%2Fgroup")
1306 .content_type("application/x-www-form-urlencoded")
1307 .body_str("auto_ban_user_on_excessive_projects_download=true")
1308 .build()
1309 .unwrap();
1310 let client = SingleTestClient::new_raw(endpoint, "");
1311
1312 let endpoint = EditGroup::builder()
1313 .group("simple/group")
1314 .auto_ban_user_on_excessive_projects_download(true)
1315 .build()
1316 .unwrap();
1317 api::ignore(endpoint).query(&client).unwrap();
1318 }
1319}