Skip to main content

gitlab/api/projects/
create.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use std::cmp::Ordering;
8use std::collections::BTreeSet;
9
10use derive_builder::Builder;
11
12use crate::api::common::{EnableState, VisibilityLevel};
13use crate::api::endpoint_prelude::*;
14use crate::api::ParamValue;
15
16/// Access levels available for most features.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[non_exhaustive]
19pub enum FeatureAccessLevel {
20    /// The feature is not available at all.
21    Disabled,
22    /// The features is only available to project members.
23    Private,
24    /// The feature is available to everyone with access to the project.
25    Enabled,
26}
27
28impl FeatureAccessLevel {
29    /// The variable type query parameter.
30    pub(crate) fn as_str(self) -> &'static str {
31        match self {
32            FeatureAccessLevel::Disabled => "disabled",
33            FeatureAccessLevel::Private => "private",
34            FeatureAccessLevel::Enabled => "enabled",
35        }
36    }
37}
38
39impl ParamValue<'static> for FeatureAccessLevel {
40    fn as_value(&self) -> Cow<'static, str> {
41        self.as_str().into()
42    }
43}
44
45/// Access levels available for features.
46///
47/// Note that only the `pages` feature currently uses this.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49#[non_exhaustive]
50pub enum FeatureAccessLevelPublic {
51    /// The feature is not available at all.
52    Disabled,
53    /// The features is only available to project members.
54    Private,
55    /// The feature is available to everyone with access to the project.
56    Enabled,
57    /// The feature is publicly available regardless of project access.
58    Public,
59}
60
61impl FeatureAccessLevelPublic {
62    /// The variable type query parameter.
63    pub(crate) fn as_str(self) -> &'static str {
64        match self {
65            FeatureAccessLevelPublic::Disabled => "disabled",
66            FeatureAccessLevelPublic::Private => "private",
67            FeatureAccessLevelPublic::Enabled => "enabled",
68            FeatureAccessLevelPublic::Public => "public",
69        }
70    }
71}
72
73impl ParamValue<'static> for FeatureAccessLevelPublic {
74    fn as_value(&self) -> Cow<'static, str> {
75        self.as_str().into()
76    }
77}
78
79/// How often the container expiration policy is applied.
80///
81/// Note that GitLab only supports a few discrete values for this setting.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
83#[non_exhaustive]
84pub enum ContainerExpirationCadence {
85    /// Every day.
86    OneDay,
87    /// Every week.
88    OneWeek,
89    /// Every other week.
90    TwoWeeks,
91    /// Every month.
92    OneMonth,
93    /// Quaterly.
94    ThreeMonths,
95}
96
97impl ContainerExpirationCadence {
98    /// The variable type query parameter.
99    pub(crate) fn as_str(self) -> &'static str {
100        match self {
101            ContainerExpirationCadence::OneDay => "1d",
102            ContainerExpirationCadence::OneWeek => "7d",
103            ContainerExpirationCadence::TwoWeeks => "14d",
104            ContainerExpirationCadence::OneMonth => "1month",
105            ContainerExpirationCadence::ThreeMonths => "3month",
106        }
107    }
108}
109
110impl ParamValue<'static> for ContainerExpirationCadence {
111    fn as_value(&self) -> Cow<'static, str> {
112        self.as_str().into()
113    }
114}
115
116/// How many container instances to keep around.
117///
118/// Note that GitLab only supports a few discrete values for this setting.
119#[derive(Debug, Clone, Copy, Eq)]
120#[non_exhaustive]
121pub enum ContainerExpirationKeepN {
122    /// Only one.
123    One,
124    /// Up to five.
125    Five,
126    /// Up to ten.
127    Ten,
128    /// Up to twenty-five.
129    TwentyFive,
130    /// Up to fifty.
131    Fifty,
132    /// Up to one hundred.
133    OneHundred,
134    /// Arbitrary number.
135    Arbitrary(u64),
136}
137
138impl From<u64> for ContainerExpirationKeepN {
139    fn from(n: u64) -> Self {
140        Self::Arbitrary(n)
141    }
142}
143
144impl PartialEq for ContainerExpirationKeepN {
145    fn eq(&self, other: &Self) -> bool {
146        self.as_u64().eq(&other.as_u64())
147    }
148}
149
150impl PartialOrd for ContainerExpirationKeepN {
151    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
152        Some(self.cmp(other))
153    }
154}
155
156impl Ord for ContainerExpirationKeepN {
157    fn cmp(&self, other: &Self) -> Ordering {
158        self.as_u64().cmp(&other.as_u64())
159    }
160}
161
162impl ContainerExpirationKeepN {
163    /// The variable type query parameter.
164    pub(crate) fn as_str(self) -> Cow<'static, str> {
165        match self {
166            ContainerExpirationKeepN::One => "1".into(),
167            ContainerExpirationKeepN::Five => "5".into(),
168            ContainerExpirationKeepN::Ten => "10".into(),
169            ContainerExpirationKeepN::TwentyFive => "25".into(),
170            ContainerExpirationKeepN::Fifty => "50".into(),
171            ContainerExpirationKeepN::OneHundred => "100".into(),
172            ContainerExpirationKeepN::Arbitrary(n) => n.to_string().into(),
173        }
174    }
175
176    fn as_u64(self) -> u64 {
177        match self {
178            ContainerExpirationKeepN::One => 1,
179            ContainerExpirationKeepN::Five => 5,
180            ContainerExpirationKeepN::Ten => 10,
181            ContainerExpirationKeepN::TwentyFive => 25,
182            ContainerExpirationKeepN::Fifty => 50,
183            ContainerExpirationKeepN::OneHundred => 100,
184            ContainerExpirationKeepN::Arbitrary(n) => n,
185        }
186    }
187}
188
189impl ParamValue<'static> for ContainerExpirationKeepN {
190    fn as_value(&self) -> Cow<'static, str> {
191        self.as_str()
192    }
193}
194
195/// How old containers need to be before they are candidates for expiration.
196///
197/// Note that GitLab only supports a few discrete values for this setting.
198#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
199#[non_exhaustive]
200pub enum ContainerExpirationOlderThan {
201    /// One week old.
202    OneWeek,
203    /// Two weeks old.
204    TwoWeeks,
205    /// One month old.
206    OneMonth,
207    /// Three months old.
208    ThreeMonths,
209}
210
211impl ContainerExpirationOlderThan {
212    /// The variable type query parameter.
213    pub(crate) fn as_str(self) -> &'static str {
214        match self {
215            ContainerExpirationOlderThan::OneWeek => "7d",
216            ContainerExpirationOlderThan::TwoWeeks => "14d",
217            ContainerExpirationOlderThan::OneMonth => "30d",
218            ContainerExpirationOlderThan::ThreeMonths => "90d",
219        }
220    }
221}
222
223impl ParamValue<'static> for ContainerExpirationOlderThan {
224    fn as_value(&self) -> Cow<'static, str> {
225        self.as_str().into()
226    }
227}
228
229/// The expiration policies for container images attached to the project.
230#[derive(Debug, Clone, Builder)]
231#[builder(setter(strip_option))]
232pub struct ContainerExpirationPolicy<'a> {
233    /// How often the policy should be applied.
234    #[builder(default)]
235    cadence: Option<ContainerExpirationCadence>,
236    /// Whether the policy is enabled or not.
237    #[builder(setter(into), default)]
238    enabled: Option<bool>,
239    /// How many container images to keep.
240    #[builder(setter(into), default)]
241    keep_n: Option<ContainerExpirationKeepN>,
242    /// Only consider containers older than this age.
243    #[builder(default)]
244    older_than: Option<ContainerExpirationOlderThan>,
245    /// Delete images with names matching a regular expression.
246    ///
247    /// See the [Ruby documentation](https://ruby-doc.org/core-2.7.1/Regexp.html) for supported
248    /// syntax.
249    #[builder(setter(into), default)]
250    name_regex_delete: Option<Cow<'a, str>>,
251    /// Keep images with names matching a regular expression.
252    ///
253    /// See the [Ruby documentation](https://ruby-doc.org/core-2.7.1/Regexp.html) for supported
254    /// syntax.
255    #[builder(setter(into), default)]
256    name_regex_keep: Option<Cow<'a, str>>,
257}
258
259impl<'a> ContainerExpirationPolicy<'a> {
260    /// Create a builder for the container expiration policy.
261    pub fn builder() -> ContainerExpirationPolicyBuilder<'a> {
262        ContainerExpirationPolicyBuilder::default()
263    }
264
265    pub(crate) fn add_query<'b>(&'b self, params: &mut FormParams<'b>) {
266        params
267            .push_opt(
268                "container_expiration_policy_attributes[cadence]",
269                self.cadence,
270            )
271            .push_opt(
272                "container_expiration_policy_attributes[enabled]",
273                self.enabled,
274            )
275            .push_opt(
276                "container_expiration_policy_attributes[keep_n]",
277                self.keep_n,
278            )
279            .push_opt(
280                "container_expiration_policy_attributes[older_than]",
281                self.older_than,
282            )
283            .push_opt(
284                "container_expiration_policy_attributes[name_regex_delete]",
285                self.name_regex_delete.as_ref(),
286            )
287            .push_opt(
288                "container_expiration_policy_attributes[name_regex_keep]",
289                self.name_regex_keep.as_ref(),
290            );
291    }
292}
293
294/// The deploy strategy used when Auto DevOps is enabled.
295#[derive(Debug, Clone, Copy, PartialEq, Eq)]
296#[non_exhaustive]
297pub enum AutoDevOpsDeployStrategy {
298    /// Continuous deployment.
299    Continuous,
300    /// Manual deployment.
301    Manual,
302    /// Interval deployments.
303    TimedIncremental,
304}
305
306impl AutoDevOpsDeployStrategy {
307    /// The variable type query parameter.
308    pub(crate) fn as_str(self) -> &'static str {
309        match self {
310            AutoDevOpsDeployStrategy::Continuous => "continuous",
311            AutoDevOpsDeployStrategy::Manual => "manual",
312            AutoDevOpsDeployStrategy::TimedIncremental => "timed_incremental",
313        }
314    }
315}
316
317impl ParamValue<'static> for AutoDevOpsDeployStrategy {
318    fn as_value(&self) -> Cow<'static, str> {
319        self.as_str().into()
320    }
321}
322
323/// How merge requests should be merged when using the "Merge" button.
324#[derive(Debug, Clone, Copy, PartialEq, Eq)]
325#[non_exhaustive]
326pub enum MergeMethod {
327    /// Always create a merge commit.
328    Merge,
329    /// Always create a merge commit, but require that the branch be fast-forward capable.
330    RebaseMerge,
331    /// Only fast-forward merges are allowed.
332    FastForward,
333}
334
335impl MergeMethod {
336    /// The variable type query parameter.
337    pub(crate) fn as_str(self) -> &'static str {
338        match self {
339            MergeMethod::Merge => "merge",
340            MergeMethod::RebaseMerge => "rebase_merge",
341            MergeMethod::FastForward => "ff",
342        }
343    }
344}
345
346impl ParamValue<'static> for MergeMethod {
347    fn as_value(&self) -> Cow<'static, str> {
348        self.as_str().into()
349    }
350}
351
352/// How squashing should be presented in the project.
353#[derive(Debug, Clone, Copy, PartialEq, Eq)]
354#[non_exhaustive]
355pub enum SquashOption {
356    /// Never allow squashing.
357    Never,
358    /// Always squash.
359    Always,
360    /// Default to squashing.
361    DefaultOn,
362    /// Default to not squashing.
363    DefaultOff,
364}
365
366impl SquashOption {
367    /// The variable type query parameter.
368    pub(crate) fn as_str(self) -> &'static str {
369        match self {
370            SquashOption::Never => "never",
371            SquashOption::Always => "always",
372            SquashOption::DefaultOn => "default_on",
373            SquashOption::DefaultOff => "default_off",
374        }
375    }
376}
377
378impl ParamValue<'static> for SquashOption {
379    fn as_value(&self) -> Cow<'static, str> {
380        self.as_str().into()
381    }
382}
383
384/// The default Git strategy for CI jobs.
385#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
386#[non_exhaustive]
387pub enum BuildGitStrategy {
388    /// Clone the repository every time.
389    Clone,
390    /// Fetch into an existing checkout (will clone if not available).
391    #[default]
392    Fetch,
393    /// Do not update the repository at all.
394    None,
395}
396
397impl BuildGitStrategy {
398    /// The variable type query parameter.
399    pub(crate) fn as_str(self) -> &'static str {
400        match self {
401            BuildGitStrategy::Clone => "clone",
402            BuildGitStrategy::Fetch => "fetch",
403            BuildGitStrategy::None => "none",
404        }
405    }
406}
407
408impl ParamValue<'static> for BuildGitStrategy {
409    fn as_value(&self) -> Cow<'static, str> {
410        self.as_str().into()
411    }
412}
413
414/// A structure to handle the fact that at least one of the name and path is required.
415#[derive(Debug, Clone)]
416enum ProjectName<'a> {
417    /// The name of the new project.
418    ///
419    /// The `path` is based on the name.
420    Name { name: Cow<'a, str> },
421    /// The path of the new project.
422    ///
423    /// The `name` is the path.
424    Path { path: Cow<'a, str> },
425    /// Provide both the name and path manually.
426    NameAndPath {
427        name: Cow<'a, str>,
428        path: Cow<'a, str>,
429    },
430}
431
432impl<'a> ProjectName<'a> {
433    fn with_name(self, name: Cow<'a, str>) -> Self {
434        match self {
435            ProjectName::Name {
436                ..
437            } => {
438                ProjectName::Name {
439                    name,
440                }
441            },
442            ProjectName::NameAndPath {
443                path, ..
444            }
445            | ProjectName::Path {
446                path,
447            } => {
448                ProjectName::NameAndPath {
449                    name,
450                    path,
451                }
452            },
453        }
454    }
455
456    fn with_path(self, path: Cow<'a, str>) -> Self {
457        match self {
458            ProjectName::Path {
459                ..
460            } => {
461                ProjectName::Path {
462                    path,
463                }
464            },
465            ProjectName::NameAndPath {
466                name, ..
467            }
468            | ProjectName::Name {
469                name,
470            } => {
471                ProjectName::NameAndPath {
472                    name,
473                    path,
474                }
475            },
476        }
477    }
478}
479
480/// Create a new project on an instance.
481#[derive(Debug, Builder, Clone)]
482#[builder(setter(strip_option))]
483pub struct CreateProject<'a> {
484    /// The name and/or path of the project.
485    #[builder(private)]
486    name_and_path: ProjectName<'a>,
487    /// The namespace of the new project.
488    ///
489    /// By default, the project is created in the API caller's namespace.
490    #[builder(default)]
491    namespace_id: Option<u64>,
492    /// The default branch of the new project.
493    ///
494    /// Defaults to `main`. Requires `initialize_with_readme` to be `true`.
495    #[builder(setter(into), default)]
496    default_branch: Option<Cow<'a, str>>,
497    /// The description of the new project.
498    #[builder(setter(into), default)]
499    description: Option<Cow<'a, str>>,
500
501    /// Set the access level for issues.
502    #[builder(default)]
503    issues_access_level: Option<FeatureAccessLevel>,
504    /// Set the access level for repository access.
505    #[builder(default)]
506    repository_access_level: Option<FeatureAccessLevel>,
507    /// Set the access level for container registry access.
508    #[builder(default)]
509    container_registry_access_level: Option<FeatureAccessLevel>,
510    /// Set the access level for merge requests.
511    #[builder(default)]
512    merge_requests_access_level: Option<FeatureAccessLevel>,
513    /// Set the access level for making a fork of the project.
514    #[builder(default)]
515    forking_access_level: Option<FeatureAccessLevel>,
516    /// Set the access level for CI pipeline access.
517    #[builder(default)]
518    builds_access_level: Option<FeatureAccessLevel>,
519    /// Set the access level for access to view the wiki.
520    #[builder(default)]
521    wiki_access_level: Option<FeatureAccessLevel>,
522    /// Set the access level for snippets.
523    #[builder(default)]
524    snippets_access_level: Option<FeatureAccessLevel>,
525    /// Set the access level for GitLab Pages on the project.
526    #[builder(default)]
527    pages_access_level: Option<FeatureAccessLevelPublic>,
528    /// Set the access level for requirements features.
529    #[builder(default)]
530    requirements_access_level: Option<FeatureAccessLevel>,
531    /// Set the access level for analytics features.
532    #[builder(default)]
533    analytics_access_level: Option<FeatureAccessLevel>,
534    /// Set the access level for security and compliance features.
535    #[builder(default)]
536    security_and_compliance_access_level: Option<FeatureAccessLevel>,
537    /// Set the access level for release access.
538    #[builder(default)]
539    releases_access_level: Option<FeatureAccessLevel>,
540    /// Set the access level for environment access.
541    #[builder(default)]
542    environments_access_level: Option<FeatureAccessLevel>,
543    /// Set the access level for feature flag access.
544    #[builder(default)]
545    feature_flags_access_level: Option<FeatureAccessLevel>,
546    /// Set the access level for infrastructure access.
547    #[builder(default)]
548    infrastructure_access_level: Option<FeatureAccessLevel>,
549    /// Set the access level for monitoring access.
550    #[builder(default)]
551    monitor_access_level: Option<FeatureAccessLevel>,
552    /// Set the access level for model experiment access.
553    #[builder(default)]
554    model_experiments_access_level: Option<FeatureAccessLevel>,
555
556    /// Whether to enable email notifications or not.
557    #[builder(default)]
558    emails_enabled: Option<bool>,
559    /// Whether the default set of award emojis are shown for this project.
560    #[builder(default)]
561    show_default_award_emojis: Option<bool>,
562    /// Whether to allow non-members to set pipeline variables when triggering pipelines or not.
563    #[builder(default)]
564    restrict_user_defined_variables: Option<bool>,
565    /// Whether outdated diff discussions are resolved when a merge request is updated or not.
566    #[builder(default)]
567    resolve_outdated_diff_discussions: Option<bool>,
568    /// The expiration policy for containers.
569    #[builder(default)]
570    container_expiration_policy_attributes: Option<ContainerExpirationPolicy<'a>>,
571    /// Whether the project can use shared runners or not.
572    #[builder(default)]
573    shared_runners_enabled: Option<bool>,
574    /// The visibility level of the project.
575    #[builder(default)]
576    visibility: Option<VisibilityLevel>,
577    /// A URL to import the repository from.
578    ///
579    /// Mutually exclusive with `initialize_with_readme`.
580    #[builder(setter(into), default)]
581    import_url: Option<Cow<'a, str>>,
582    /// Whether job results are visible to non-project members or not.
583    #[builder(default)]
584    public_builds: Option<bool>,
585    /// Whether the CI pipeline is required to succeed before merges are allowed.
586    #[builder(default)]
587    only_allow_merge_if_pipeline_succeeds: Option<bool>,
588    /// Whether the CI pipeline can be skipped before merges are allowed.
589    #[builder(default)]
590    allow_merge_on_skipped_pipeline: Option<bool>,
591    /// Whether all discussions must be resolved before merges are allowed.
592    #[builder(default)]
593    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,
594    /// If `true`, merge requests may not be merged unless all status checks are passing.
595    #[builder(default)]
596    only_allow_merge_if_all_status_checks_passed: Option<bool>,
597    /// The template for merge commit messages.
598    #[builder(setter(into), default)]
599    merge_commit_template: Option<Cow<'a, str>>,
600    /// The merge method to use for the project.
601    #[builder(default)]
602    merge_method: Option<MergeMethod>,
603    /// Whether merge pipelines are enabled.
604    #[builder(default)]
605    merge_pipelines_enabled: Option<bool>,
606    /// Whether merge trains are enabled.
607    #[builder(default)]
608    merge_trains_enabled: Option<bool>,
609    /// Whether MRs default to targing this project or the upstream project.
610    #[builder(default)]
611    mr_default_target_self: Option<bool>,
612    /// The squash option for the project.
613    #[builder(default)]
614    squash_option: Option<SquashOption>,
615    /// Whether issues referenced on the default branch should be closed or not.
616    #[builder(default)]
617    autoclose_referenced_issues: Option<bool>,
618    /// Whether to enabled the "Remove source branch" option in new merge requests by default or
619    /// not.
620    #[builder(default)]
621    remove_source_branch_after_merge: Option<bool>,
622    /// Whether `git-lfs` support should be enabled or not.
623    ///
624    /// See the [git-lfs](https://git-lfs.github.com/) website for more information.
625    #[builder(default)]
626    lfs_enabled: Option<bool>,
627    /// Whether users may request access to the repository or not.
628    #[builder(default)]
629    request_access_enabled: Option<bool>,
630    /// A list of topics to apply to the repository.
631    #[builder(setter(name = "_topics"), default, private)]
632    topics: BTreeSet<Cow<'a, str>>,
633    // TODO: Figure out how to actually use this.
634    // avatar   mixed   no  Image file for avatar of the project
635    // avatar: ???,
636    /// Whether to show a link to create or view a merge request when pushing a branch from the
637    /// command line or not.
638    #[builder(default)]
639    printing_merge_request_link_enabled: Option<bool>,
640    /// The default Git strategy for CI jobs of the project.
641    #[builder(default)]
642    build_git_strategy: Option<BuildGitStrategy>,
643    /// The default timeout for jobs of the project (in seconds).
644    #[builder(default)]
645    build_timeout: Option<u64>,
646    /// Whether to automatically cancel pipelines when branches are updated when using a previous
647    /// version of the branch.
648    #[builder(setter(into), default)]
649    auto_cancel_pending_pipelines: Option<EnableState>,
650    /// The path to the GitLab CI configuration file within the repository.
651    ///
652    /// Defaults to `.gitlab-ci.yml`.
653    #[builder(setter(into), default)]
654    ci_config_path: Option<Cow<'a, str>>,
655    /// Whether Auto DevOps are enabled or not.
656    #[builder(default)]
657    auto_devops_enabled: Option<bool>,
658    /// The Auto Deploy strategy of the project.
659    #[builder(default)]
660    auto_devops_deploy_strategy: Option<AutoDevOpsDeployStrategy>,
661    /// The storage shard on which to store the repository.
662    #[builder(setter(into), default)]
663    repository_storage: Option<Cow<'a, str>>,
664    /// The classification label of the project.
665    #[builder(setter(into), default)]
666    external_authorization_classification_label: Option<Cow<'a, str>>,
667    /// Whether to enable pull mirroring for the project or not.
668    #[builder(default)]
669    mirror: Option<bool>,
670    /// Whether mirror updates trigger CI builds ir not.
671    #[builder(default)]
672    mirror_trigger_builds: Option<bool>,
673    /// Initialize the project with a readme.
674    ///
675    /// Mutually exclusive with `import_url`.
676    #[builder(default)]
677    initialize_with_readme: Option<bool>,
678    /// The name of a template project to use.
679    #[builder(setter(into), default)]
680    template_name: Option<Cow<'a, str>>,
681    /// The ID of the template project to use.
682    #[builder(default)]
683    template_project_id: Option<u64>,
684    /// Whether to use a custom instance or group template.
685    #[builder(default)]
686    use_custom_template: Option<bool>,
687    /// Whether the template project should come from the group or the instance.
688    #[builder(setter(name = "_group_with_project_templates_id"), default, private)]
689    group_with_project_templates_id: Option<u64>,
690    /// Whether the package repository is enabled or not.
691    #[builder(default)]
692    packages_enabled: Option<bool>,
693    /// Whether group runners are enabled for this project or not.
694    #[builder(default)]
695    group_runners_enabled: Option<bool>,
696}
697
698impl<'a> CreateProject<'a> {
699    /// Create a builder for the endpoint.
700    pub fn builder() -> CreateProjectBuilder<'a> {
701        CreateProjectBuilder::default()
702    }
703}
704
705impl<'a> CreateProjectBuilder<'a> {
706    /// Set the name of the project.
707    ///
708    /// If not set, it will default to the value of `path`.
709    pub fn name<N>(&mut self, name: N) -> &mut Self
710    where
711        N: Into<Cow<'a, str>>,
712    {
713        let name = name.into();
714        self.name_and_path = Some(if let Some(name_and_path) = self.name_and_path.take() {
715            name_and_path.with_name(name)
716        } else {
717            ProjectName::Name {
718                name,
719            }
720        });
721        self
722    }
723
724    /// Set the path of the project.
725    ///
726    /// If not set, it will default to the value of `name` after processing to make it a valid
727    /// path.
728    pub fn path<P>(&mut self, path: P) -> &mut Self
729    where
730        P: Into<Cow<'a, str>>,
731    {
732        let path = path.into();
733        self.name_and_path = Some(if let Some(name_and_path) = self.name_and_path.take() {
734            name_and_path.with_path(path)
735        } else {
736            ProjectName::Path {
737                path,
738            }
739        });
740        self
741    }
742
743    /// Add a optic.
744    pub fn topic<T>(&mut self, topic: T) -> &mut Self
745    where
746        T: Into<Cow<'a, str>>,
747    {
748        self.topics
749            .get_or_insert_with(BTreeSet::new)
750            .insert(topic.into());
751        self
752    }
753
754    /// Add multiple topics.
755    pub fn topics<I, T>(&mut self, iter: I) -> &mut Self
756    where
757        I: Iterator<Item = T>,
758        T: Into<Cow<'a, str>>,
759    {
760        self.topics
761            .get_or_insert_with(BTreeSet::new)
762            .extend(iter.map(Into::into));
763        self
764    }
765
766    /// Whether the template project should come from the group or the instance.
767    ///
768    /// Note that setting this also sets `use_custom_template` to `true` automatically.
769    pub fn group_with_project_templates_id(&mut self, id: u64) -> &mut Self {
770        self.group_with_project_templates_id = Some(Some(id));
771        self.use_custom_template(true);
772        self
773    }
774}
775
776impl Endpoint for CreateProject<'_> {
777    fn method(&self) -> Method {
778        Method::POST
779    }
780
781    fn endpoint(&self) -> Cow<'static, str> {
782        "projects".into()
783    }
784
785    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
786        let mut params = FormParams::default();
787
788        match &self.name_and_path {
789            ProjectName::Name {
790                name,
791            } => {
792                params.push("name", name);
793            },
794            ProjectName::Path {
795                path,
796            } => {
797                params.push("path", path);
798            },
799            ProjectName::NameAndPath {
800                name,
801                path,
802            } => {
803                params.push("name", name).push("path", path);
804            },
805        }
806
807        params
808            .push_opt("namespace_id", self.namespace_id)
809            .push_opt("default_branch", self.default_branch.as_ref())
810            .push_opt("description", self.description.as_ref())
811            .push_opt("issues_access_level", self.issues_access_level)
812            .push_opt("repository_access_level", self.repository_access_level)
813            .push_opt(
814                "container_registry_access_level",
815                self.container_registry_access_level,
816            )
817            .push_opt(
818                "merge_requests_access_level",
819                self.merge_requests_access_level,
820            )
821            .push_opt("forking_access_level", self.forking_access_level)
822            .push_opt("builds_access_level", self.builds_access_level)
823            .push_opt("wiki_access_level", self.wiki_access_level)
824            .push_opt("snippets_access_level", self.snippets_access_level)
825            .push_opt("pages_access_level", self.pages_access_level)
826            .push_opt("requirements_access_level", self.requirements_access_level)
827            .push_opt("analytics_access_level", self.analytics_access_level)
828            .push_opt(
829                "security_and_compliance_access_level",
830                self.security_and_compliance_access_level,
831            )
832            .push_opt("releases_access_level", self.releases_access_level)
833            .push_opt("environments_access_level", self.environments_access_level)
834            .push_opt(
835                "feature_flags_access_level",
836                self.feature_flags_access_level,
837            )
838            .push_opt(
839                "infrastructure_access_level",
840                self.infrastructure_access_level,
841            )
842            .push_opt("monitor_access_level", self.monitor_access_level)
843            .push_opt(
844                "model_experiments_access_level",
845                self.model_experiments_access_level,
846            )
847            .push_opt("emails_enabled", self.emails_enabled)
848            .push_opt("show_default_award_emojis", self.show_default_award_emojis)
849            .push_opt(
850                "restrict_user_defined_variables",
851                self.restrict_user_defined_variables,
852            )
853            .push_opt(
854                "resolve_outdated_diff_discussions",
855                self.resolve_outdated_diff_discussions,
856            )
857            .push_opt("shared_runners_enabled", self.shared_runners_enabled)
858            .push_opt("visibility", self.visibility)
859            .push_opt("import_url", self.import_url.as_ref())
860            .push_opt("public_builds", self.public_builds)
861            .push_opt(
862                "only_allow_merge_if_pipeline_succeeds",
863                self.only_allow_merge_if_pipeline_succeeds,
864            )
865            .push_opt(
866                "allow_merge_on_skipped_pipeline",
867                self.allow_merge_on_skipped_pipeline,
868            )
869            .push_opt(
870                "only_allow_merge_if_all_discussions_are_resolved",
871                self.only_allow_merge_if_all_discussions_are_resolved,
872            )
873            .push_opt(
874                "only_allow_merge_if_all_status_checks_passed",
875                self.only_allow_merge_if_all_status_checks_passed,
876            )
877            .push_opt("merge_commit_template", self.merge_commit_template.as_ref())
878            .push_opt("merge_method", self.merge_method)
879            .push_opt("merge_pipelines_enabled", self.merge_pipelines_enabled)
880            .push_opt("merge_trains_enabled", self.merge_trains_enabled)
881            .push_opt("mr_default_target_self", self.mr_default_target_self)
882            .push_opt("squash_option", self.squash_option)
883            .push_opt(
884                "autoclose_referenced_issues",
885                self.autoclose_referenced_issues,
886            )
887            .push_opt(
888                "remove_source_branch_after_merge",
889                self.remove_source_branch_after_merge,
890            )
891            .push_opt("lfs_enabled", self.lfs_enabled)
892            .push_opt("request_access_enabled", self.request_access_enabled)
893            .extend(self.topics.iter().map(|value| ("topics[]", value)))
894            .push_opt(
895                "printing_merge_request_link_enabled",
896                self.printing_merge_request_link_enabled,
897            )
898            .push_opt("build_git_strategy", self.build_git_strategy)
899            .push_opt("build_timeout", self.build_timeout)
900            .push_opt(
901                "auto_cancel_pending_pipelines",
902                self.auto_cancel_pending_pipelines,
903            )
904            .push_opt("ci_config_path", self.ci_config_path.as_ref())
905            .push_opt("auto_devops_enabled", self.auto_devops_enabled)
906            .push_opt(
907                "auto_devops_deploy_strategy",
908                self.auto_devops_deploy_strategy,
909            )
910            .push_opt("repository_storage", self.repository_storage.as_ref())
911            .push_opt(
912                "external_authorization_classification_label",
913                self.external_authorization_classification_label.as_ref(),
914            )
915            .push_opt("mirror", self.mirror)
916            .push_opt("mirror_trigger_builds", self.mirror_trigger_builds)
917            .push_opt("initialize_with_readme", self.initialize_with_readme)
918            .push_opt("template_name", self.template_name.as_ref())
919            .push_opt("template_project_id", self.template_project_id)
920            .push_opt("use_custom_template", self.use_custom_template)
921            .push_opt(
922                "group_with_project_templates_id",
923                self.group_with_project_templates_id,
924            )
925            .push_opt("packages_enabled", self.packages_enabled)
926            .push_opt("group_runners_enabled", self.group_runners_enabled);
927
928        if let Some(policy) = self.container_expiration_policy_attributes.as_ref() {
929            policy.add_query(&mut params);
930        }
931
932        params.into_body()
933    }
934}
935
936#[cfg(test)]
937mod tests {
938    use http::Method;
939
940    use crate::api::common::{EnableState, VisibilityLevel};
941    use crate::api::projects::{
942        AutoDevOpsDeployStrategy, BuildGitStrategy, ContainerExpirationCadence,
943        ContainerExpirationKeepN, ContainerExpirationOlderThan, ContainerExpirationPolicy,
944        CreateProject, CreateProjectBuilderError, FeatureAccessLevel, FeatureAccessLevelPublic,
945        MergeMethod, SquashOption,
946    };
947    use crate::api::{self, Query};
948    use crate::test::client::{ExpectedUrl, SingleTestClient};
949
950    #[test]
951    fn feature_access_level_as_str() {
952        let items = &[
953            (FeatureAccessLevel::Disabled, "disabled"),
954            (FeatureAccessLevel::Private, "private"),
955            (FeatureAccessLevel::Enabled, "enabled"),
956        ];
957
958        for (i, s) in items {
959            assert_eq!(i.as_str(), *s);
960        }
961    }
962
963    #[test]
964    fn feature_access_level_public_as_str() {
965        let items = &[
966            (FeatureAccessLevelPublic::Disabled, "disabled"),
967            (FeatureAccessLevelPublic::Private, "private"),
968            (FeatureAccessLevelPublic::Enabled, "enabled"),
969            (FeatureAccessLevelPublic::Public, "public"),
970        ];
971
972        for (i, s) in items {
973            assert_eq!(i.as_str(), *s);
974        }
975    }
976
977    #[test]
978    fn container_expiration_cadence_as_str() {
979        let items = &[
980            (ContainerExpirationCadence::OneDay, "1d"),
981            (ContainerExpirationCadence::OneWeek, "7d"),
982            (ContainerExpirationCadence::TwoWeeks, "14d"),
983            (ContainerExpirationCadence::OneMonth, "1month"),
984            (ContainerExpirationCadence::ThreeMonths, "3month"),
985        ];
986
987        for (i, s) in items {
988            assert_eq!(i.as_str(), *s);
989        }
990    }
991
992    #[test]
993    fn container_expiration_keep_n_ordering() {
994        let items = &[
995            ContainerExpirationKeepN::One,
996            ContainerExpirationKeepN::Five,
997            ContainerExpirationKeepN::Ten,
998            ContainerExpirationKeepN::Arbitrary(11),
999            ContainerExpirationKeepN::TwentyFive,
1000            30.into(),
1001            ContainerExpirationKeepN::Fifty,
1002            ContainerExpirationKeepN::OneHundred,
1003        ];
1004
1005        let mut last = None;
1006        for item in items {
1007            if let Some(prev) = last {
1008                assert!(prev < item);
1009            }
1010            last = Some(item);
1011        }
1012    }
1013
1014    #[test]
1015    fn container_expiration_keep_n_as_u64() {
1016        let items = &[
1017            (ContainerExpirationKeepN::One, 1u64),
1018            (ContainerExpirationKeepN::Five, 5),
1019            (ContainerExpirationKeepN::Ten, 10),
1020            (ContainerExpirationKeepN::Arbitrary(11), 11),
1021            (ContainerExpirationKeepN::TwentyFive, 25),
1022            (ContainerExpirationKeepN::Fifty, 50),
1023            (ContainerExpirationKeepN::OneHundred, 100),
1024        ];
1025
1026        for (i, v) in items {
1027            assert_eq!(i.as_u64(), *v);
1028        }
1029    }
1030
1031    #[test]
1032    fn container_expiration_keep_n_as_str() {
1033        let items = &[
1034            (ContainerExpirationKeepN::One, "1"),
1035            (ContainerExpirationKeepN::Five, "5"),
1036            (ContainerExpirationKeepN::Ten, "10"),
1037            (ContainerExpirationKeepN::Arbitrary(11), "11"),
1038            (ContainerExpirationKeepN::TwentyFive, "25"),
1039            (30.into(), "30"),
1040            (ContainerExpirationKeepN::Fifty, "50"),
1041            (ContainerExpirationKeepN::OneHundred, "100"),
1042        ];
1043
1044        for (i, s) in items {
1045            assert_eq!(i.as_str(), *s);
1046        }
1047    }
1048
1049    #[test]
1050    fn container_expiration_older_than_ordering() {
1051        let items = &[
1052            ContainerExpirationOlderThan::OneWeek,
1053            ContainerExpirationOlderThan::TwoWeeks,
1054            ContainerExpirationOlderThan::OneMonth,
1055            ContainerExpirationOlderThan::ThreeMonths,
1056        ];
1057
1058        let mut last = None;
1059        for item in items {
1060            if let Some(prev) = last {
1061                assert!(prev < item);
1062            }
1063            last = Some(item);
1064        }
1065    }
1066
1067    #[test]
1068    fn container_expiration_older_than_as_str() {
1069        let items = &[
1070            (ContainerExpirationOlderThan::OneWeek, "7d"),
1071            (ContainerExpirationOlderThan::TwoWeeks, "14d"),
1072            (ContainerExpirationOlderThan::OneMonth, "30d"),
1073            (ContainerExpirationOlderThan::ThreeMonths, "90d"),
1074        ];
1075
1076        for (i, s) in items {
1077            assert_eq!(i.as_str(), *s);
1078        }
1079    }
1080
1081    #[test]
1082    fn container_expiration_policy_default() {
1083        ContainerExpirationPolicy::builder().build().unwrap();
1084    }
1085
1086    #[test]
1087    fn auto_dev_ops_deploy_strategy_as_str() {
1088        let items = &[
1089            (AutoDevOpsDeployStrategy::Continuous, "continuous"),
1090            (AutoDevOpsDeployStrategy::Manual, "manual"),
1091            (
1092                AutoDevOpsDeployStrategy::TimedIncremental,
1093                "timed_incremental",
1094            ),
1095        ];
1096
1097        for (i, s) in items {
1098            assert_eq!(i.as_str(), *s);
1099        }
1100    }
1101
1102    #[test]
1103    fn merge_method_as_str() {
1104        let items = &[
1105            (MergeMethod::Merge, "merge"),
1106            (MergeMethod::RebaseMerge, "rebase_merge"),
1107            (MergeMethod::FastForward, "ff"),
1108        ];
1109
1110        for (i, s) in items {
1111            assert_eq!(i.as_str(), *s);
1112        }
1113    }
1114
1115    #[test]
1116    fn squash_option_as_str() {
1117        let items = &[
1118            (SquashOption::Never, "never"),
1119            (SquashOption::Always, "always"),
1120            (SquashOption::DefaultOn, "default_on"),
1121            (SquashOption::DefaultOff, "default_off"),
1122        ];
1123
1124        for (i, s) in items {
1125            assert_eq!(i.as_str(), *s);
1126        }
1127    }
1128
1129    #[test]
1130    fn build_git_strategy_default() {
1131        assert_eq!(BuildGitStrategy::default(), BuildGitStrategy::Fetch);
1132    }
1133
1134    #[test]
1135    fn build_git_strategy_as_str() {
1136        let items = &[
1137            (BuildGitStrategy::Clone, "clone"),
1138            (BuildGitStrategy::Fetch, "fetch"),
1139            (BuildGitStrategy::None, "none"),
1140        ];
1141
1142        for (i, s) in items {
1143            assert_eq!(i.as_str(), *s);
1144        }
1145    }
1146
1147    #[test]
1148    fn name_and_path_is_needed() {
1149        let err = CreateProject::builder().build().unwrap_err();
1150        crate::test::assert_missing_field!(err, CreateProjectBuilderError, "name_and_path");
1151    }
1152
1153    #[test]
1154    fn name_is_sufficient() {
1155        CreateProject::builder().name("name").build().unwrap();
1156    }
1157
1158    #[test]
1159    fn path_is_sufficient() {
1160        CreateProject::builder().path("path").build().unwrap();
1161    }
1162
1163    #[test]
1164    fn endpoint_name() {
1165        let endpoint = ExpectedUrl::builder()
1166            .method(Method::POST)
1167            .endpoint("projects")
1168            .content_type("application/x-www-form-urlencoded")
1169            .body_str("name=name")
1170            .build()
1171            .unwrap();
1172        let client = SingleTestClient::new_raw(endpoint, "");
1173
1174        let endpoint = CreateProject::builder().name("name").build().unwrap();
1175        api::ignore(endpoint).query(&client).unwrap();
1176    }
1177
1178    #[test]
1179    fn endpoint_path() {
1180        let endpoint = ExpectedUrl::builder()
1181            .method(Method::POST)
1182            .endpoint("projects")
1183            .content_type("application/x-www-form-urlencoded")
1184            .body_str("path=path")
1185            .build()
1186            .unwrap();
1187        let client = SingleTestClient::new_raw(endpoint, "");
1188
1189        let endpoint = CreateProject::builder().path("path").build().unwrap();
1190        api::ignore(endpoint).query(&client).unwrap();
1191    }
1192
1193    #[test]
1194    fn endpoint_name_and_path() {
1195        let endpoint = ExpectedUrl::builder()
1196            .method(Method::POST)
1197            .endpoint("projects")
1198            .content_type("application/x-www-form-urlencoded")
1199            .body_str(concat!("name=name", "&path=path"))
1200            .build()
1201            .unwrap();
1202        let client = SingleTestClient::new_raw(endpoint, "");
1203
1204        let endpoint = CreateProject::builder()
1205            .name("name")
1206            .path("path")
1207            .build()
1208            .unwrap();
1209        api::ignore(endpoint).query(&client).unwrap();
1210    }
1211
1212    #[test]
1213    fn endpoint_path_and_name() {
1214        let endpoint = ExpectedUrl::builder()
1215            .method(Method::POST)
1216            .endpoint("projects")
1217            .content_type("application/x-www-form-urlencoded")
1218            .body_str(concat!("name=name", "&path=path"))
1219            .build()
1220            .unwrap();
1221        let client = SingleTestClient::new_raw(endpoint, "");
1222
1223        let endpoint = CreateProject::builder()
1224            .path("path")
1225            .name("name")
1226            .build()
1227            .unwrap();
1228        api::ignore(endpoint).query(&client).unwrap();
1229    }
1230
1231    #[test]
1232    fn endpoint_namespace_id() {
1233        let endpoint = ExpectedUrl::builder()
1234            .method(Method::POST)
1235            .endpoint("projects")
1236            .content_type("application/x-www-form-urlencoded")
1237            .body_str(concat!("name=name", "&namespace_id=1"))
1238            .build()
1239            .unwrap();
1240        let client = SingleTestClient::new_raw(endpoint, "");
1241
1242        let endpoint = CreateProject::builder()
1243            .name("name")
1244            .namespace_id(1)
1245            .build()
1246            .unwrap();
1247        api::ignore(endpoint).query(&client).unwrap();
1248    }
1249
1250    #[test]
1251    fn endpoint_default_branch() {
1252        let endpoint = ExpectedUrl::builder()
1253            .method(Method::POST)
1254            .endpoint("projects")
1255            .content_type("application/x-www-form-urlencoded")
1256            .body_str(concat!("name=name", "&default_branch=master"))
1257            .build()
1258            .unwrap();
1259        let client = SingleTestClient::new_raw(endpoint, "");
1260
1261        let endpoint = CreateProject::builder()
1262            .name("name")
1263            .default_branch("master")
1264            .build()
1265            .unwrap();
1266        api::ignore(endpoint).query(&client).unwrap();
1267    }
1268
1269    #[test]
1270    fn endpoint_description() {
1271        let endpoint = ExpectedUrl::builder()
1272            .method(Method::POST)
1273            .endpoint("projects")
1274            .content_type("application/x-www-form-urlencoded")
1275            .body_str(concat!("name=name", "&description=description"))
1276            .build()
1277            .unwrap();
1278        let client = SingleTestClient::new_raw(endpoint, "");
1279
1280        let endpoint = CreateProject::builder()
1281            .name("name")
1282            .description("description")
1283            .build()
1284            .unwrap();
1285        api::ignore(endpoint).query(&client).unwrap();
1286    }
1287
1288    #[test]
1289    fn endpoint_issues_access_level() {
1290        let endpoint = ExpectedUrl::builder()
1291            .method(Method::POST)
1292            .endpoint("projects")
1293            .content_type("application/x-www-form-urlencoded")
1294            .body_str(concat!("name=name", "&issues_access_level=enabled"))
1295            .build()
1296            .unwrap();
1297        let client = SingleTestClient::new_raw(endpoint, "");
1298
1299        let endpoint = CreateProject::builder()
1300            .name("name")
1301            .issues_access_level(FeatureAccessLevel::Enabled)
1302            .build()
1303            .unwrap();
1304        api::ignore(endpoint).query(&client).unwrap();
1305    }
1306
1307    #[test]
1308    fn endpoint_repository_access_level() {
1309        let endpoint = ExpectedUrl::builder()
1310            .method(Method::POST)
1311            .endpoint("projects")
1312            .content_type("application/x-www-form-urlencoded")
1313            .body_str(concat!("name=name", "&repository_access_level=disabled"))
1314            .build()
1315            .unwrap();
1316        let client = SingleTestClient::new_raw(endpoint, "");
1317
1318        let endpoint = CreateProject::builder()
1319            .name("name")
1320            .repository_access_level(FeatureAccessLevel::Disabled)
1321            .build()
1322            .unwrap();
1323        api::ignore(endpoint).query(&client).unwrap();
1324    }
1325
1326    #[test]
1327    fn endpoint_container_registry_access_level() {
1328        let endpoint = ExpectedUrl::builder()
1329            .method(Method::POST)
1330            .endpoint("projects")
1331            .content_type("application/x-www-form-urlencoded")
1332            .body_str(concat!(
1333                "name=name",
1334                "&container_registry_access_level=disabled",
1335            ))
1336            .build()
1337            .unwrap();
1338        let client = SingleTestClient::new_raw(endpoint, "");
1339
1340        let endpoint = CreateProject::builder()
1341            .name("name")
1342            .container_registry_access_level(FeatureAccessLevel::Disabled)
1343            .build()
1344            .unwrap();
1345        api::ignore(endpoint).query(&client).unwrap();
1346    }
1347
1348    #[test]
1349    fn endpoint_merge_requests_access_level() {
1350        let endpoint = ExpectedUrl::builder()
1351            .method(Method::POST)
1352            .endpoint("projects")
1353            .content_type("application/x-www-form-urlencoded")
1354            .body_str(concat!("name=name", "&merge_requests_access_level=private"))
1355            .build()
1356            .unwrap();
1357        let client = SingleTestClient::new_raw(endpoint, "");
1358
1359        let endpoint = CreateProject::builder()
1360            .name("name")
1361            .merge_requests_access_level(FeatureAccessLevel::Private)
1362            .build()
1363            .unwrap();
1364        api::ignore(endpoint).query(&client).unwrap();
1365    }
1366
1367    #[test]
1368    fn endpoint_forking_access_level() {
1369        let endpoint = ExpectedUrl::builder()
1370            .method(Method::POST)
1371            .endpoint("projects")
1372            .content_type("application/x-www-form-urlencoded")
1373            .body_str(concat!("name=name", "&forking_access_level=enabled"))
1374            .build()
1375            .unwrap();
1376        let client = SingleTestClient::new_raw(endpoint, "");
1377
1378        let endpoint = CreateProject::builder()
1379            .name("name")
1380            .forking_access_level(FeatureAccessLevel::Enabled)
1381            .build()
1382            .unwrap();
1383        api::ignore(endpoint).query(&client).unwrap();
1384    }
1385
1386    #[test]
1387    fn endpoint_builds_access_level() {
1388        let endpoint = ExpectedUrl::builder()
1389            .method(Method::POST)
1390            .endpoint("projects")
1391            .content_type("application/x-www-form-urlencoded")
1392            .body_str(concat!("name=name", "&builds_access_level=enabled"))
1393            .build()
1394            .unwrap();
1395        let client = SingleTestClient::new_raw(endpoint, "");
1396
1397        let endpoint = CreateProject::builder()
1398            .name("name")
1399            .builds_access_level(FeatureAccessLevel::Enabled)
1400            .build()
1401            .unwrap();
1402        api::ignore(endpoint).query(&client).unwrap();
1403    }
1404
1405    #[test]
1406    fn endpoint_wiki_access_level() {
1407        let endpoint = ExpectedUrl::builder()
1408            .method(Method::POST)
1409            .endpoint("projects")
1410            .content_type("application/x-www-form-urlencoded")
1411            .body_str(concat!("name=name", "&wiki_access_level=disabled"))
1412            .build()
1413            .unwrap();
1414        let client = SingleTestClient::new_raw(endpoint, "");
1415
1416        let endpoint = CreateProject::builder()
1417            .name("name")
1418            .wiki_access_level(FeatureAccessLevel::Disabled)
1419            .build()
1420            .unwrap();
1421        api::ignore(endpoint).query(&client).unwrap();
1422    }
1423
1424    #[test]
1425    fn endpoint_snippets_access_level() {
1426        let endpoint = ExpectedUrl::builder()
1427            .method(Method::POST)
1428            .endpoint("projects")
1429            .content_type("application/x-www-form-urlencoded")
1430            .body_str(concat!("name=name", "&snippets_access_level=disabled"))
1431            .build()
1432            .unwrap();
1433        let client = SingleTestClient::new_raw(endpoint, "");
1434
1435        let endpoint = CreateProject::builder()
1436            .name("name")
1437            .snippets_access_level(FeatureAccessLevel::Disabled)
1438            .build()
1439            .unwrap();
1440        api::ignore(endpoint).query(&client).unwrap();
1441    }
1442
1443    #[test]
1444    fn endpoint_pages_access_level() {
1445        let endpoint = ExpectedUrl::builder()
1446            .method(Method::POST)
1447            .endpoint("projects")
1448            .content_type("application/x-www-form-urlencoded")
1449            .body_str(concat!("name=name", "&pages_access_level=public"))
1450            .build()
1451            .unwrap();
1452        let client = SingleTestClient::new_raw(endpoint, "");
1453
1454        let endpoint = CreateProject::builder()
1455            .name("name")
1456            .pages_access_level(FeatureAccessLevelPublic::Public)
1457            .build()
1458            .unwrap();
1459        api::ignore(endpoint).query(&client).unwrap();
1460    }
1461
1462    #[test]
1463    fn endpoint_requirements_access_level() {
1464        let endpoint = ExpectedUrl::builder()
1465            .method(Method::POST)
1466            .endpoint("projects")
1467            .content_type("application/x-www-form-urlencoded")
1468            .body_str(concat!("name=name", "&requirements_access_level=enabled"))
1469            .build()
1470            .unwrap();
1471        let client = SingleTestClient::new_raw(endpoint, "");
1472
1473        let endpoint = CreateProject::builder()
1474            .name("name")
1475            .requirements_access_level(FeatureAccessLevel::Enabled)
1476            .build()
1477            .unwrap();
1478        api::ignore(endpoint).query(&client).unwrap();
1479    }
1480
1481    #[test]
1482    fn endpoint_analytics_access_level() {
1483        let endpoint = ExpectedUrl::builder()
1484            .method(Method::POST)
1485            .endpoint("projects")
1486            .content_type("application/x-www-form-urlencoded")
1487            .body_str(concat!("name=name", "&analytics_access_level=private"))
1488            .build()
1489            .unwrap();
1490        let client = SingleTestClient::new_raw(endpoint, "");
1491
1492        let endpoint = CreateProject::builder()
1493            .name("name")
1494            .analytics_access_level(FeatureAccessLevel::Private)
1495            .build()
1496            .unwrap();
1497        api::ignore(endpoint).query(&client).unwrap();
1498    }
1499
1500    #[test]
1501    fn endpoint_security_and_compliance_access_level() {
1502        let endpoint = ExpectedUrl::builder()
1503            .method(Method::POST)
1504            .endpoint("projects")
1505            .content_type("application/x-www-form-urlencoded")
1506            .body_str(concat!(
1507                "name=name",
1508                "&security_and_compliance_access_level=private",
1509            ))
1510            .build()
1511            .unwrap();
1512        let client = SingleTestClient::new_raw(endpoint, "");
1513
1514        let endpoint = CreateProject::builder()
1515            .name("name")
1516            .security_and_compliance_access_level(FeatureAccessLevel::Private)
1517            .build()
1518            .unwrap();
1519        api::ignore(endpoint).query(&client).unwrap();
1520    }
1521
1522    #[test]
1523    fn endpoint_releases_access_level() {
1524        let endpoint = ExpectedUrl::builder()
1525            .method(Method::POST)
1526            .endpoint("projects")
1527            .content_type("application/x-www-form-urlencoded")
1528            .body_str(concat!("name=name", "&releases_access_level=private"))
1529            .build()
1530            .unwrap();
1531        let client = SingleTestClient::new_raw(endpoint, "");
1532
1533        let endpoint = CreateProject::builder()
1534            .name("name")
1535            .releases_access_level(FeatureAccessLevel::Private)
1536            .build()
1537            .unwrap();
1538        api::ignore(endpoint).query(&client).unwrap();
1539    }
1540
1541    #[test]
1542    fn endpoint_environments_access_level() {
1543        let endpoint = ExpectedUrl::builder()
1544            .method(Method::POST)
1545            .endpoint("projects")
1546            .content_type("application/x-www-form-urlencoded")
1547            .body_str(concat!("name=name", "&environments_access_level=private"))
1548            .build()
1549            .unwrap();
1550        let client = SingleTestClient::new_raw(endpoint, "");
1551
1552        let endpoint = CreateProject::builder()
1553            .name("name")
1554            .environments_access_level(FeatureAccessLevel::Private)
1555            .build()
1556            .unwrap();
1557        api::ignore(endpoint).query(&client).unwrap();
1558    }
1559
1560    #[test]
1561    fn endpoint_feature_flags_access_level() {
1562        let endpoint = ExpectedUrl::builder()
1563            .method(Method::POST)
1564            .endpoint("projects")
1565            .content_type("application/x-www-form-urlencoded")
1566            .body_str(concat!("name=name", "&feature_flags_access_level=private"))
1567            .build()
1568            .unwrap();
1569        let client = SingleTestClient::new_raw(endpoint, "");
1570
1571        let endpoint = CreateProject::builder()
1572            .name("name")
1573            .feature_flags_access_level(FeatureAccessLevel::Private)
1574            .build()
1575            .unwrap();
1576        api::ignore(endpoint).query(&client).unwrap();
1577    }
1578
1579    #[test]
1580    fn endpoint_infrastructure_access_level() {
1581        let endpoint = ExpectedUrl::builder()
1582            .method(Method::POST)
1583            .endpoint("projects")
1584            .content_type("application/x-www-form-urlencoded")
1585            .body_str(concat!("name=name", "&infrastructure_access_level=private"))
1586            .build()
1587            .unwrap();
1588        let client = SingleTestClient::new_raw(endpoint, "");
1589
1590        let endpoint = CreateProject::builder()
1591            .name("name")
1592            .infrastructure_access_level(FeatureAccessLevel::Private)
1593            .build()
1594            .unwrap();
1595        api::ignore(endpoint).query(&client).unwrap();
1596    }
1597
1598    #[test]
1599    fn endpoint_monitor_access_level() {
1600        let endpoint = ExpectedUrl::builder()
1601            .method(Method::POST)
1602            .endpoint("projects")
1603            .content_type("application/x-www-form-urlencoded")
1604            .body_str(concat!("name=name", "&monitor_access_level=private"))
1605            .build()
1606            .unwrap();
1607        let client = SingleTestClient::new_raw(endpoint, "");
1608
1609        let endpoint = CreateProject::builder()
1610            .name("name")
1611            .monitor_access_level(FeatureAccessLevel::Private)
1612            .build()
1613            .unwrap();
1614        api::ignore(endpoint).query(&client).unwrap();
1615    }
1616
1617    #[test]
1618    fn endpoint_model_experiments_access_level() {
1619        let endpoint = ExpectedUrl::builder()
1620            .method(Method::POST)
1621            .endpoint("projects")
1622            .content_type("application/x-www-form-urlencoded")
1623            .body_str(concat!(
1624                "name=name",
1625                "&model_experiments_access_level=private",
1626            ))
1627            .build()
1628            .unwrap();
1629        let client = SingleTestClient::new_raw(endpoint, "");
1630
1631        let endpoint = CreateProject::builder()
1632            .name("name")
1633            .model_experiments_access_level(FeatureAccessLevel::Private)
1634            .build()
1635            .unwrap();
1636        api::ignore(endpoint).query(&client).unwrap();
1637    }
1638
1639    #[test]
1640    fn endpoint_emails_enabled() {
1641        let endpoint = ExpectedUrl::builder()
1642            .method(Method::POST)
1643            .endpoint("projects")
1644            .content_type("application/x-www-form-urlencoded")
1645            .body_str(concat!("name=name", "&emails_enabled=true"))
1646            .build()
1647            .unwrap();
1648        let client = SingleTestClient::new_raw(endpoint, "");
1649
1650        let endpoint = CreateProject::builder()
1651            .name("name")
1652            .emails_enabled(true)
1653            .build()
1654            .unwrap();
1655        api::ignore(endpoint).query(&client).unwrap();
1656    }
1657
1658    #[test]
1659    fn endpoint_show_default_award_emojis() {
1660        let endpoint = ExpectedUrl::builder()
1661            .method(Method::POST)
1662            .endpoint("projects")
1663            .content_type("application/x-www-form-urlencoded")
1664            .body_str(concat!("name=name", "&show_default_award_emojis=false"))
1665            .build()
1666            .unwrap();
1667        let client = SingleTestClient::new_raw(endpoint, "");
1668
1669        let endpoint = CreateProject::builder()
1670            .name("name")
1671            .show_default_award_emojis(false)
1672            .build()
1673            .unwrap();
1674        api::ignore(endpoint).query(&client).unwrap();
1675    }
1676
1677    #[test]
1678    fn endpoint_restrict_user_defined_variables() {
1679        let endpoint = ExpectedUrl::builder()
1680            .method(Method::POST)
1681            .endpoint("projects")
1682            .content_type("application/x-www-form-urlencoded")
1683            .body_str(concat!(
1684                "name=name",
1685                "&restrict_user_defined_variables=false",
1686            ))
1687            .build()
1688            .unwrap();
1689        let client = SingleTestClient::new_raw(endpoint, "");
1690
1691        let endpoint = CreateProject::builder()
1692            .name("name")
1693            .restrict_user_defined_variables(false)
1694            .build()
1695            .unwrap();
1696        api::ignore(endpoint).query(&client).unwrap();
1697    }
1698
1699    #[test]
1700    fn endpoint_resolve_outdated_diff_discussions() {
1701        let endpoint = ExpectedUrl::builder()
1702            .method(Method::POST)
1703            .endpoint("projects")
1704            .content_type("application/x-www-form-urlencoded")
1705            .body_str(concat!(
1706                "name=name",
1707                "&resolve_outdated_diff_discussions=false",
1708            ))
1709            .build()
1710            .unwrap();
1711        let client = SingleTestClient::new_raw(endpoint, "");
1712
1713        let endpoint = CreateProject::builder()
1714            .name("name")
1715            .resolve_outdated_diff_discussions(false)
1716            .build()
1717            .unwrap();
1718        api::ignore(endpoint).query(&client).unwrap();
1719    }
1720
1721    #[test]
1722    fn endpoint_container_expiration_policy_attributes_cadence() {
1723        let endpoint = ExpectedUrl::builder()
1724            .method(Method::POST)
1725            .endpoint("projects")
1726            .content_type("application/x-www-form-urlencoded")
1727            .body_str(concat!(
1728                "name=name",
1729                "&container_expiration_policy_attributes%5Bcadence%5D=7d",
1730            ))
1731            .build()
1732            .unwrap();
1733        let client = SingleTestClient::new_raw(endpoint, "");
1734
1735        let endpoint = CreateProject::builder()
1736            .name("name")
1737            .container_expiration_policy_attributes(
1738                ContainerExpirationPolicy::builder()
1739                    .cadence(ContainerExpirationCadence::OneWeek)
1740                    .build()
1741                    .unwrap(),
1742            )
1743            .build()
1744            .unwrap();
1745        api::ignore(endpoint).query(&client).unwrap();
1746    }
1747
1748    #[test]
1749    fn endpoint_container_expiration_policy_attributes_enabled() {
1750        let endpoint = ExpectedUrl::builder()
1751            .method(Method::POST)
1752            .endpoint("projects")
1753            .content_type("application/x-www-form-urlencoded")
1754            .body_str(concat!(
1755                "name=name",
1756                "&container_expiration_policy_attributes%5Benabled%5D=true",
1757            ))
1758            .build()
1759            .unwrap();
1760        let client = SingleTestClient::new_raw(endpoint, "");
1761
1762        let endpoint = CreateProject::builder()
1763            .name("name")
1764            .container_expiration_policy_attributes(
1765                ContainerExpirationPolicy::builder()
1766                    .enabled(true)
1767                    .build()
1768                    .unwrap(),
1769            )
1770            .build()
1771            .unwrap();
1772        api::ignore(endpoint).query(&client).unwrap();
1773    }
1774
1775    #[test]
1776    fn endpoint_container_expiration_policy_attributes_keep_n() {
1777        let endpoint = ExpectedUrl::builder()
1778            .method(Method::POST)
1779            .endpoint("projects")
1780            .content_type("application/x-www-form-urlencoded")
1781            .body_str(concat!(
1782                "name=name",
1783                "&container_expiration_policy_attributes%5Bkeep_n%5D=5",
1784            ))
1785            .build()
1786            .unwrap();
1787        let client = SingleTestClient::new_raw(endpoint, "");
1788
1789        let endpoint = CreateProject::builder()
1790            .name("name")
1791            .container_expiration_policy_attributes(
1792                ContainerExpirationPolicy::builder()
1793                    .keep_n(ContainerExpirationKeepN::Five)
1794                    .build()
1795                    .unwrap(),
1796            )
1797            .build()
1798            .unwrap();
1799        api::ignore(endpoint).query(&client).unwrap();
1800    }
1801
1802    #[test]
1803    fn endpoint_container_expiration_policy_attributes_older_than() {
1804        let endpoint = ExpectedUrl::builder()
1805            .method(Method::POST)
1806            .endpoint("projects")
1807            .content_type("application/x-www-form-urlencoded")
1808            .body_str(concat!(
1809                "name=name",
1810                "&container_expiration_policy_attributes%5Bolder_than%5D=7d",
1811            ))
1812            .build()
1813            .unwrap();
1814        let client = SingleTestClient::new_raw(endpoint, "");
1815
1816        let endpoint = CreateProject::builder()
1817            .name("name")
1818            .container_expiration_policy_attributes(
1819                ContainerExpirationPolicy::builder()
1820                    .older_than(ContainerExpirationOlderThan::OneWeek)
1821                    .build()
1822                    .unwrap(),
1823            )
1824            .build()
1825            .unwrap();
1826        api::ignore(endpoint).query(&client).unwrap();
1827    }
1828
1829    #[test]
1830    fn endpoint_container_expiration_policy_attributes_name_regex_delete() {
1831        let endpoint = ExpectedUrl::builder()
1832            .method(Method::POST)
1833            .endpoint("projects")
1834            .content_type("application/x-www-form-urlencoded")
1835            .body_str(concat!(
1836                "name=name",
1837                "&container_expiration_policy_attributes%5Bname_regex_delete%5D=%3Alatest",
1838            ))
1839            .build()
1840            .unwrap();
1841        let client = SingleTestClient::new_raw(endpoint, "");
1842
1843        let endpoint = CreateProject::builder()
1844            .name("name")
1845            .container_expiration_policy_attributes(
1846                ContainerExpirationPolicy::builder()
1847                    .name_regex_delete(":latest")
1848                    .build()
1849                    .unwrap(),
1850            )
1851            .build()
1852            .unwrap();
1853        api::ignore(endpoint).query(&client).unwrap();
1854    }
1855
1856    #[test]
1857    fn endpoint_container_expiration_policy_attributes_name_regex_keep() {
1858        let endpoint = ExpectedUrl::builder()
1859            .method(Method::POST)
1860            .endpoint("projects")
1861            .content_type("application/x-www-form-urlencoded")
1862            .body_str(concat!(
1863                "name=name",
1864                "&container_expiration_policy_attributes%5Bname_regex_keep%5D=%3Alatest",
1865            ))
1866            .build()
1867            .unwrap();
1868        let client = SingleTestClient::new_raw(endpoint, "");
1869
1870        let endpoint = CreateProject::builder()
1871            .name("name")
1872            .container_expiration_policy_attributes(
1873                ContainerExpirationPolicy::builder()
1874                    .name_regex_keep(":latest")
1875                    .build()
1876                    .unwrap(),
1877            )
1878            .build()
1879            .unwrap();
1880        api::ignore(endpoint).query(&client).unwrap();
1881    }
1882
1883    #[test]
1884    fn endpoint_container_expiration_policy_attributes_all() {
1885        let endpoint = ExpectedUrl::builder()
1886            .method(Method::POST)
1887            .endpoint("projects")
1888            .content_type("application/x-www-form-urlencoded")
1889            .body_str(concat!(
1890                "name=name",
1891                "&container_expiration_policy_attributes%5Bcadence%5D=7d",
1892                "&container_expiration_policy_attributes%5Benabled%5D=true",
1893                "&container_expiration_policy_attributes%5Bkeep_n%5D=5",
1894                "&container_expiration_policy_attributes%5Bolder_than%5D=7d",
1895                "&container_expiration_policy_attributes%5Bname_regex_delete%5D=%3Aoldest",
1896                "&container_expiration_policy_attributes%5Bname_regex_keep%5D=%3Alatest",
1897            ))
1898            .build()
1899            .unwrap();
1900        let client = SingleTestClient::new_raw(endpoint, "");
1901
1902        let endpoint = CreateProject::builder()
1903            .name("name")
1904            .container_expiration_policy_attributes(
1905                ContainerExpirationPolicy::builder()
1906                    .cadence(ContainerExpirationCadence::OneWeek)
1907                    .enabled(true)
1908                    .keep_n(ContainerExpirationKeepN::Five)
1909                    .older_than(ContainerExpirationOlderThan::OneWeek)
1910                    .name_regex_keep(":latest")
1911                    .name_regex_delete(":oldest")
1912                    .build()
1913                    .unwrap(),
1914            )
1915            .build()
1916            .unwrap();
1917        api::ignore(endpoint).query(&client).unwrap();
1918    }
1919
1920    #[test]
1921    fn endpoint_shared_runners_enabled() {
1922        let endpoint = ExpectedUrl::builder()
1923            .method(Method::POST)
1924            .endpoint("projects")
1925            .content_type("application/x-www-form-urlencoded")
1926            .body_str(concat!("name=name", "&shared_runners_enabled=false"))
1927            .build()
1928            .unwrap();
1929        let client = SingleTestClient::new_raw(endpoint, "");
1930
1931        let endpoint = CreateProject::builder()
1932            .name("name")
1933            .shared_runners_enabled(false)
1934            .build()
1935            .unwrap();
1936        api::ignore(endpoint).query(&client).unwrap();
1937    }
1938
1939    #[test]
1940    fn endpoint_visibility() {
1941        let endpoint = ExpectedUrl::builder()
1942            .method(Method::POST)
1943            .endpoint("projects")
1944            .content_type("application/x-www-form-urlencoded")
1945            .body_str(concat!("name=name", "&visibility=public"))
1946            .build()
1947            .unwrap();
1948        let client = SingleTestClient::new_raw(endpoint, "");
1949
1950        let endpoint = CreateProject::builder()
1951            .name("name")
1952            .visibility(VisibilityLevel::Public)
1953            .build()
1954            .unwrap();
1955        api::ignore(endpoint).query(&client).unwrap();
1956    }
1957
1958    #[test]
1959    fn endpoint_import_url() {
1960        let endpoint = ExpectedUrl::builder()
1961            .method(Method::POST)
1962            .endpoint("projects")
1963            .content_type("application/x-www-form-urlencoded")
1964            .body_str(concat!(
1965                "name=name",
1966                "&import_url=https%3A%2F%2Ftest.invalid%2Fpath%3Fsome%3Dfoo",
1967            ))
1968            .build()
1969            .unwrap();
1970        let client = SingleTestClient::new_raw(endpoint, "");
1971
1972        let endpoint = CreateProject::builder()
1973            .name("name")
1974            .import_url("https://test.invalid/path?some=foo")
1975            .build()
1976            .unwrap();
1977        api::ignore(endpoint).query(&client).unwrap();
1978    }
1979
1980    #[test]
1981    fn endpoint_public_builds() {
1982        let endpoint = ExpectedUrl::builder()
1983            .method(Method::POST)
1984            .endpoint("projects")
1985            .content_type("application/x-www-form-urlencoded")
1986            .body_str(concat!("name=name", "&public_builds=true"))
1987            .build()
1988            .unwrap();
1989        let client = SingleTestClient::new_raw(endpoint, "");
1990
1991        let endpoint = CreateProject::builder()
1992            .name("name")
1993            .public_builds(true)
1994            .build()
1995            .unwrap();
1996        api::ignore(endpoint).query(&client).unwrap();
1997    }
1998
1999    #[test]
2000    fn endpoint_only_allow_merge_if_pipeline_succeeds() {
2001        let endpoint = ExpectedUrl::builder()
2002            .method(Method::POST)
2003            .endpoint("projects")
2004            .content_type("application/x-www-form-urlencoded")
2005            .body_str(concat!(
2006                "name=name",
2007                "&only_allow_merge_if_pipeline_succeeds=false",
2008            ))
2009            .build()
2010            .unwrap();
2011        let client = SingleTestClient::new_raw(endpoint, "");
2012
2013        let endpoint = CreateProject::builder()
2014            .name("name")
2015            .only_allow_merge_if_pipeline_succeeds(false)
2016            .build()
2017            .unwrap();
2018        api::ignore(endpoint).query(&client).unwrap();
2019    }
2020
2021    #[test]
2022    fn endpoint_allow_merge_on_skipped_pipeline() {
2023        let endpoint = ExpectedUrl::builder()
2024            .method(Method::POST)
2025            .endpoint("projects")
2026            .content_type("application/x-www-form-urlencoded")
2027            .body_str(concat!(
2028                "name=name",
2029                "&allow_merge_on_skipped_pipeline=false",
2030            ))
2031            .build()
2032            .unwrap();
2033        let client = SingleTestClient::new_raw(endpoint, "");
2034
2035        let endpoint = CreateProject::builder()
2036            .name("name")
2037            .allow_merge_on_skipped_pipeline(false)
2038            .build()
2039            .unwrap();
2040        api::ignore(endpoint).query(&client).unwrap();
2041    }
2042
2043    #[test]
2044    fn endpoint_only_allow_merge_if_all_discussions_are_resolved() {
2045        let endpoint = ExpectedUrl::builder()
2046            .method(Method::POST)
2047            .endpoint("projects")
2048            .content_type("application/x-www-form-urlencoded")
2049            .body_str(concat!(
2050                "name=name",
2051                "&only_allow_merge_if_all_discussions_are_resolved=true",
2052            ))
2053            .build()
2054            .unwrap();
2055        let client = SingleTestClient::new_raw(endpoint, "");
2056
2057        let endpoint = CreateProject::builder()
2058            .name("name")
2059            .only_allow_merge_if_all_discussions_are_resolved(true)
2060            .build()
2061            .unwrap();
2062        api::ignore(endpoint).query(&client).unwrap();
2063    }
2064
2065    #[test]
2066    fn endpoint_only_allow_merge_if_all_status_checks_passed() {
2067        let endpoint = ExpectedUrl::builder()
2068            .method(Method::POST)
2069            .endpoint("projects")
2070            .content_type("application/x-www-form-urlencoded")
2071            .body_str(concat!(
2072                "name=name",
2073                "&only_allow_merge_if_all_status_checks_passed=false",
2074            ))
2075            .build()
2076            .unwrap();
2077        let client = SingleTestClient::new_raw(endpoint, "");
2078
2079        let endpoint = CreateProject::builder()
2080            .name("name")
2081            .only_allow_merge_if_all_status_checks_passed(false)
2082            .build()
2083            .unwrap();
2084        api::ignore(endpoint).query(&client).unwrap();
2085    }
2086
2087    #[test]
2088    fn endpoint_merge_commit_template() {
2089        let endpoint = ExpectedUrl::builder()
2090            .method(Method::POST)
2091            .endpoint("projects")
2092            .content_type("application/x-www-form-urlencoded")
2093            .body_str(concat!("name=name", "&merge_commit_template=template"))
2094            .build()
2095            .unwrap();
2096        let client = SingleTestClient::new_raw(endpoint, "");
2097
2098        let endpoint = CreateProject::builder()
2099            .name("name")
2100            .merge_commit_template("template")
2101            .build()
2102            .unwrap();
2103        api::ignore(endpoint).query(&client).unwrap();
2104    }
2105
2106    #[test]
2107    fn endpoint_merge_method() {
2108        let endpoint = ExpectedUrl::builder()
2109            .method(Method::POST)
2110            .endpoint("projects")
2111            .content_type("application/x-www-form-urlencoded")
2112            .body_str(concat!("name=name", "&merge_method=ff"))
2113            .build()
2114            .unwrap();
2115        let client = SingleTestClient::new_raw(endpoint, "");
2116
2117        let endpoint = CreateProject::builder()
2118            .name("name")
2119            .merge_method(MergeMethod::FastForward)
2120            .build()
2121            .unwrap();
2122        api::ignore(endpoint).query(&client).unwrap();
2123    }
2124
2125    #[test]
2126    fn endpoint_merge_pipelines_enabled() {
2127        let endpoint = ExpectedUrl::builder()
2128            .method(Method::POST)
2129            .endpoint("projects")
2130            .content_type("application/x-www-form-urlencoded")
2131            .body_str(concat!("name=name", "&merge_pipelines_enabled=true"))
2132            .build()
2133            .unwrap();
2134        let client = SingleTestClient::new_raw(endpoint, "");
2135
2136        let endpoint = CreateProject::builder()
2137            .name("name")
2138            .merge_pipelines_enabled(true)
2139            .build()
2140            .unwrap();
2141        api::ignore(endpoint).query(&client).unwrap();
2142    }
2143
2144    #[test]
2145    fn endpoint_merge_trains_enabled() {
2146        let endpoint = ExpectedUrl::builder()
2147            .method(Method::POST)
2148            .endpoint("projects")
2149            .content_type("application/x-www-form-urlencoded")
2150            .body_str(concat!("name=name", "&merge_trains_enabled=true"))
2151            .build()
2152            .unwrap();
2153        let client = SingleTestClient::new_raw(endpoint, "");
2154
2155        let endpoint = CreateProject::builder()
2156            .name("name")
2157            .merge_trains_enabled(true)
2158            .build()
2159            .unwrap();
2160        api::ignore(endpoint).query(&client).unwrap();
2161    }
2162
2163    #[test]
2164    fn endpoint_mr_default_target_self() {
2165        let endpoint = ExpectedUrl::builder()
2166            .method(Method::POST)
2167            .endpoint("projects")
2168            .content_type("application/x-www-form-urlencoded")
2169            .body_str(concat!("name=name", "&mr_default_target_self=true"))
2170            .build()
2171            .unwrap();
2172        let client = SingleTestClient::new_raw(endpoint, "");
2173
2174        let endpoint = CreateProject::builder()
2175            .name("name")
2176            .mr_default_target_self(true)
2177            .build()
2178            .unwrap();
2179        api::ignore(endpoint).query(&client).unwrap();
2180    }
2181
2182    #[test]
2183    fn endpoint_squash_option() {
2184        let endpoint = ExpectedUrl::builder()
2185            .method(Method::POST)
2186            .endpoint("projects")
2187            .content_type("application/x-www-form-urlencoded")
2188            .body_str(concat!("name=name", "&squash_option=never"))
2189            .build()
2190            .unwrap();
2191        let client = SingleTestClient::new_raw(endpoint, "");
2192
2193        let endpoint = CreateProject::builder()
2194            .name("name")
2195            .squash_option(SquashOption::Never)
2196            .build()
2197            .unwrap();
2198        api::ignore(endpoint).query(&client).unwrap();
2199    }
2200
2201    #[test]
2202    fn endpoint_autoclose_referenced_issues() {
2203        let endpoint = ExpectedUrl::builder()
2204            .method(Method::POST)
2205            .endpoint("projects")
2206            .content_type("application/x-www-form-urlencoded")
2207            .body_str(concat!("name=name", "&autoclose_referenced_issues=true"))
2208            .build()
2209            .unwrap();
2210        let client = SingleTestClient::new_raw(endpoint, "");
2211
2212        let endpoint = CreateProject::builder()
2213            .name("name")
2214            .autoclose_referenced_issues(true)
2215            .build()
2216            .unwrap();
2217        api::ignore(endpoint).query(&client).unwrap();
2218    }
2219
2220    #[test]
2221    fn endpoint_remove_source_branch_after_merge() {
2222        let endpoint = ExpectedUrl::builder()
2223            .method(Method::POST)
2224            .endpoint("projects")
2225            .content_type("application/x-www-form-urlencoded")
2226            .body_str(concat!(
2227                "name=name",
2228                "&remove_source_branch_after_merge=true",
2229            ))
2230            .build()
2231            .unwrap();
2232        let client = SingleTestClient::new_raw(endpoint, "");
2233
2234        let endpoint = CreateProject::builder()
2235            .name("name")
2236            .remove_source_branch_after_merge(true)
2237            .build()
2238            .unwrap();
2239        api::ignore(endpoint).query(&client).unwrap();
2240    }
2241
2242    #[test]
2243    fn endpoint_lfs_enabled() {
2244        let endpoint = ExpectedUrl::builder()
2245            .method(Method::POST)
2246            .endpoint("projects")
2247            .content_type("application/x-www-form-urlencoded")
2248            .body_str(concat!("name=name", "&lfs_enabled=false"))
2249            .build()
2250            .unwrap();
2251        let client = SingleTestClient::new_raw(endpoint, "");
2252
2253        let endpoint = CreateProject::builder()
2254            .name("name")
2255            .lfs_enabled(false)
2256            .build()
2257            .unwrap();
2258        api::ignore(endpoint).query(&client).unwrap();
2259    }
2260
2261    #[test]
2262    fn endpoint_request_access_enabled() {
2263        let endpoint = ExpectedUrl::builder()
2264            .method(Method::POST)
2265            .endpoint("projects")
2266            .content_type("application/x-www-form-urlencoded")
2267            .body_str(concat!("name=name", "&request_access_enabled=true"))
2268            .build()
2269            .unwrap();
2270        let client = SingleTestClient::new_raw(endpoint, "");
2271
2272        let endpoint = CreateProject::builder()
2273            .name("name")
2274            .request_access_enabled(true)
2275            .build()
2276            .unwrap();
2277        api::ignore(endpoint).query(&client).unwrap();
2278    }
2279
2280    #[test]
2281    fn endpoint_topics() {
2282        let endpoint = ExpectedUrl::builder()
2283            .method(Method::POST)
2284            .endpoint("projects")
2285            .content_type("application/x-www-form-urlencoded")
2286            .body_str(concat!(
2287                "name=name",
2288                "&topics%5B%5D=topic1",
2289                "&topics%5B%5D=topic2",
2290            ))
2291            .build()
2292            .unwrap();
2293        let client = SingleTestClient::new_raw(endpoint, "");
2294
2295        let endpoint = CreateProject::builder()
2296            .name("name")
2297            .topic("topic1")
2298            .topics(["topic1", "topic2"].iter().copied())
2299            .build()
2300            .unwrap();
2301        api::ignore(endpoint).query(&client).unwrap();
2302    }
2303
2304    #[test]
2305    fn endpoint_printing_merge_request_link_enabled() {
2306        let endpoint = ExpectedUrl::builder()
2307            .method(Method::POST)
2308            .endpoint("projects")
2309            .content_type("application/x-www-form-urlencoded")
2310            .body_str(concat!(
2311                "name=name",
2312                "&printing_merge_request_link_enabled=false",
2313            ))
2314            .build()
2315            .unwrap();
2316        let client = SingleTestClient::new_raw(endpoint, "");
2317
2318        let endpoint = CreateProject::builder()
2319            .name("name")
2320            .printing_merge_request_link_enabled(false)
2321            .build()
2322            .unwrap();
2323        api::ignore(endpoint).query(&client).unwrap();
2324    }
2325
2326    #[test]
2327    fn endpoint_build_git_strategy() {
2328        let endpoint = ExpectedUrl::builder()
2329            .method(Method::POST)
2330            .endpoint("projects")
2331            .content_type("application/x-www-form-urlencoded")
2332            .body_str(concat!("name=name", "&build_git_strategy=fetch"))
2333            .build()
2334            .unwrap();
2335        let client = SingleTestClient::new_raw(endpoint, "");
2336
2337        let endpoint = CreateProject::builder()
2338            .name("name")
2339            .build_git_strategy(BuildGitStrategy::Fetch)
2340            .build()
2341            .unwrap();
2342        api::ignore(endpoint).query(&client).unwrap();
2343    }
2344
2345    #[test]
2346    fn endpoint_build_timeout() {
2347        let endpoint = ExpectedUrl::builder()
2348            .method(Method::POST)
2349            .endpoint("projects")
2350            .content_type("application/x-www-form-urlencoded")
2351            .body_str(concat!("name=name", "&build_timeout=1"))
2352            .build()
2353            .unwrap();
2354        let client = SingleTestClient::new_raw(endpoint, "");
2355
2356        let endpoint = CreateProject::builder()
2357            .name("name")
2358            .build_timeout(1)
2359            .build()
2360            .unwrap();
2361        api::ignore(endpoint).query(&client).unwrap();
2362    }
2363
2364    #[test]
2365    fn endpoint_auto_cancel_pending_pipelines() {
2366        let endpoint = ExpectedUrl::builder()
2367            .method(Method::POST)
2368            .endpoint("projects")
2369            .content_type("application/x-www-form-urlencoded")
2370            .body_str(concat!(
2371                "name=name",
2372                "&auto_cancel_pending_pipelines=enabled",
2373            ))
2374            .build()
2375            .unwrap();
2376        let client = SingleTestClient::new_raw(endpoint, "");
2377
2378        let endpoint = CreateProject::builder()
2379            .name("name")
2380            .auto_cancel_pending_pipelines(EnableState::Enabled)
2381            .build()
2382            .unwrap();
2383        api::ignore(endpoint).query(&client).unwrap();
2384    }
2385
2386    #[test]
2387    fn endpoint_ci_config_path() {
2388        let endpoint = ExpectedUrl::builder()
2389            .method(Method::POST)
2390            .endpoint("projects")
2391            .content_type("application/x-www-form-urlencoded")
2392            .body_str(concat!("name=name", "&ci_config_path=.gitlab-ci.yaml"))
2393            .build()
2394            .unwrap();
2395        let client = SingleTestClient::new_raw(endpoint, "");
2396
2397        let endpoint = CreateProject::builder()
2398            .name("name")
2399            .ci_config_path(".gitlab-ci.yaml")
2400            .build()
2401            .unwrap();
2402        api::ignore(endpoint).query(&client).unwrap();
2403    }
2404
2405    #[test]
2406    fn endpoint_auto_devops_enabled() {
2407        let endpoint = ExpectedUrl::builder()
2408            .method(Method::POST)
2409            .endpoint("projects")
2410            .content_type("application/x-www-form-urlencoded")
2411            .body_str(concat!("name=name", "&auto_devops_enabled=false"))
2412            .build()
2413            .unwrap();
2414        let client = SingleTestClient::new_raw(endpoint, "");
2415
2416        let endpoint = CreateProject::builder()
2417            .name("name")
2418            .auto_devops_enabled(false)
2419            .build()
2420            .unwrap();
2421        api::ignore(endpoint).query(&client).unwrap();
2422    }
2423
2424    #[test]
2425    fn endpoint_auto_devops_deploy_strategy() {
2426        let endpoint = ExpectedUrl::builder()
2427            .method(Method::POST)
2428            .endpoint("projects")
2429            .content_type("application/x-www-form-urlencoded")
2430            .body_str(concat!("name=name", "&auto_devops_deploy_strategy=manual"))
2431            .build()
2432            .unwrap();
2433        let client = SingleTestClient::new_raw(endpoint, "");
2434
2435        let endpoint = CreateProject::builder()
2436            .name("name")
2437            .auto_devops_deploy_strategy(AutoDevOpsDeployStrategy::Manual)
2438            .build()
2439            .unwrap();
2440        api::ignore(endpoint).query(&client).unwrap();
2441    }
2442
2443    #[test]
2444    fn endpoint_repository_storage() {
2445        let endpoint = ExpectedUrl::builder()
2446            .method(Method::POST)
2447            .endpoint("projects")
2448            .content_type("application/x-www-form-urlencoded")
2449            .body_str(concat!("name=name", "&repository_storage=shard1"))
2450            .build()
2451            .unwrap();
2452        let client = SingleTestClient::new_raw(endpoint, "");
2453
2454        let endpoint = CreateProject::builder()
2455            .name("name")
2456            .repository_storage("shard1")
2457            .build()
2458            .unwrap();
2459        api::ignore(endpoint).query(&client).unwrap();
2460    }
2461
2462    #[test]
2463    fn endpoint_external_authorization_classification_label() {
2464        let endpoint = ExpectedUrl::builder()
2465            .method(Method::POST)
2466            .endpoint("projects")
2467            .content_type("application/x-www-form-urlencoded")
2468            .body_str(concat!(
2469                "name=name",
2470                "&external_authorization_classification_label=external",
2471            ))
2472            .build()
2473            .unwrap();
2474        let client = SingleTestClient::new_raw(endpoint, "");
2475
2476        let endpoint = CreateProject::builder()
2477            .name("name")
2478            .external_authorization_classification_label("external")
2479            .build()
2480            .unwrap();
2481        api::ignore(endpoint).query(&client).unwrap();
2482    }
2483
2484    #[test]
2485    fn endpoint_mirror() {
2486        let endpoint = ExpectedUrl::builder()
2487            .method(Method::POST)
2488            .endpoint("projects")
2489            .content_type("application/x-www-form-urlencoded")
2490            .body_str(concat!("name=name", "&mirror=true"))
2491            .build()
2492            .unwrap();
2493        let client = SingleTestClient::new_raw(endpoint, "");
2494
2495        let endpoint = CreateProject::builder()
2496            .name("name")
2497            .mirror(true)
2498            .build()
2499            .unwrap();
2500        api::ignore(endpoint).query(&client).unwrap();
2501    }
2502
2503    #[test]
2504    fn endpoint_mirror_trigger_builds() {
2505        let endpoint = ExpectedUrl::builder()
2506            .method(Method::POST)
2507            .endpoint("projects")
2508            .content_type("application/x-www-form-urlencoded")
2509            .body_str(concat!("name=name", "&mirror_trigger_builds=false"))
2510            .build()
2511            .unwrap();
2512        let client = SingleTestClient::new_raw(endpoint, "");
2513
2514        let endpoint = CreateProject::builder()
2515            .name("name")
2516            .mirror_trigger_builds(false)
2517            .build()
2518            .unwrap();
2519        api::ignore(endpoint).query(&client).unwrap();
2520    }
2521
2522    #[test]
2523    fn endpoint_initialize_with_readme() {
2524        let endpoint = ExpectedUrl::builder()
2525            .method(Method::POST)
2526            .endpoint("projects")
2527            .content_type("application/x-www-form-urlencoded")
2528            .body_str(concat!("name=name", "&initialize_with_readme=false"))
2529            .build()
2530            .unwrap();
2531        let client = SingleTestClient::new_raw(endpoint, "");
2532
2533        let endpoint = CreateProject::builder()
2534            .name("name")
2535            .initialize_with_readme(false)
2536            .build()
2537            .unwrap();
2538        api::ignore(endpoint).query(&client).unwrap();
2539    }
2540
2541    #[test]
2542    fn endpoint_template_name() {
2543        let endpoint = ExpectedUrl::builder()
2544            .method(Method::POST)
2545            .endpoint("projects")
2546            .content_type("application/x-www-form-urlencoded")
2547            .body_str(concat!("name=name", "&template_name=template"))
2548            .build()
2549            .unwrap();
2550        let client = SingleTestClient::new_raw(endpoint, "");
2551
2552        let endpoint = CreateProject::builder()
2553            .name("name")
2554            .template_name("template")
2555            .build()
2556            .unwrap();
2557        api::ignore(endpoint).query(&client).unwrap();
2558    }
2559
2560    #[test]
2561    fn endpoint_template_project_id() {
2562        let endpoint = ExpectedUrl::builder()
2563            .method(Method::POST)
2564            .endpoint("projects")
2565            .content_type("application/x-www-form-urlencoded")
2566            .body_str(concat!("name=name", "&template_project_id=1"))
2567            .build()
2568            .unwrap();
2569        let client = SingleTestClient::new_raw(endpoint, "");
2570
2571        let endpoint = CreateProject::builder()
2572            .name("name")
2573            .template_project_id(1)
2574            .build()
2575            .unwrap();
2576        api::ignore(endpoint).query(&client).unwrap();
2577    }
2578
2579    #[test]
2580    fn endpoint_use_custom_template() {
2581        let endpoint = ExpectedUrl::builder()
2582            .method(Method::POST)
2583            .endpoint("projects")
2584            .content_type("application/x-www-form-urlencoded")
2585            .body_str(concat!("name=name", "&use_custom_template=false"))
2586            .build()
2587            .unwrap();
2588        let client = SingleTestClient::new_raw(endpoint, "");
2589
2590        let endpoint = CreateProject::builder()
2591            .name("name")
2592            .use_custom_template(false)
2593            .build()
2594            .unwrap();
2595        api::ignore(endpoint).query(&client).unwrap();
2596    }
2597
2598    #[test]
2599    fn endpoint_group_with_project_templates_id() {
2600        let endpoint = ExpectedUrl::builder()
2601            .method(Method::POST)
2602            .endpoint("projects")
2603            .content_type("application/x-www-form-urlencoded")
2604            .body_str(concat!(
2605                "name=name",
2606                "&use_custom_template=true",
2607                "&group_with_project_templates_id=1",
2608            ))
2609            .build()
2610            .unwrap();
2611        let client = SingleTestClient::new_raw(endpoint, "");
2612
2613        let endpoint = CreateProject::builder()
2614            .name("name")
2615            .group_with_project_templates_id(1)
2616            .build()
2617            .unwrap();
2618        api::ignore(endpoint).query(&client).unwrap();
2619    }
2620
2621    #[test]
2622    fn endpoint_packages_enabled() {
2623        let endpoint = ExpectedUrl::builder()
2624            .method(Method::POST)
2625            .endpoint("projects")
2626            .content_type("application/x-www-form-urlencoded")
2627            .body_str(concat!("name=name", "&packages_enabled=false"))
2628            .build()
2629            .unwrap();
2630        let client = SingleTestClient::new_raw(endpoint, "");
2631
2632        let endpoint = CreateProject::builder()
2633            .name("name")
2634            .packages_enabled(false)
2635            .build()
2636            .unwrap();
2637        api::ignore(endpoint).query(&client).unwrap();
2638    }
2639
2640    #[test]
2641    fn endpoint_group_runners_enabled() {
2642        let endpoint = ExpectedUrl::builder()
2643            .method(Method::POST)
2644            .endpoint("projects")
2645            .content_type("application/x-www-form-urlencoded")
2646            .body_str(concat!("name=name", "&group_runners_enabled=false"))
2647            .build()
2648            .unwrap();
2649        let client = SingleTestClient::new_raw(endpoint, "");
2650
2651        let endpoint = CreateProject::builder()
2652            .name("name")
2653            .group_runners_enabled(false)
2654            .build()
2655            .unwrap();
2656        api::ignore(endpoint).query(&client).unwrap();
2657    }
2658}