diff --git a/CHANGELOG.md b/CHANGELOG.md index b9608b653861d1134fb802c9daea81a08cc201d3..1f1e1413fd324c312d69d364272fb9e1b4d8b087 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v0.1707.1 (unreleased) + +## Additions + + * Add `api::projects::variables` to list and delete project-level CI/CD variables. + # v0.1707.0 ## Additions diff --git a/src/api/README.md b/src/api/README.md index 60a4018cdba716c4cfe78bc66f2925f157a060ae..b1ee2d8c0708532e69741b163e028fa944b889b9 100644 --- a/src/api/README.md +++ b/src/api/README.md @@ -38,9 +38,11 @@ These API endpoints have been implemented. * `POST /groups/:group/share` `groups/share.rs` * `DELETE /groups/:group/share/:group2` `groups/unshare.rs` * `GET /groups/:group/subgroups` `groups/subgroups/subgroups.rs` + * `GET /groups/:group/variables` `groups/variables/variables.rs` * `POST /groups/:group/variables` `groups/variables/create.rs` * `GET /groups/:group/variables/:key` `groups/variables/variable.rs` * `PUT /groups/:group/variables/:key` `groups/variables/update.rs` + * `DELETE /groups/:group/variables/:key` `groups/variables/delete.rs` * `GET /job` `job/job.rs` * `GET /merge_requests` `merge_requests/merge_requests.rs` * `GET /personal_access_tokens` `personal_access_tokens/personal_access_tokens.rs` @@ -247,9 +249,11 @@ These API endpoints have been implemented. Arguably, this should be `POST /projects/:project/repository/commits/:sha/statuses`. https://gitlab.com/gitlab-org/gitlab/-/issues/217412 * `POST /projects/:project/unarchive` `projects/unarchive.rs` + * `GET /projects/:project/variables` `projects/variables/variables.rs` * `POST /projects/:project/variables` `projects/variables/create.rs` * `GET /projects/:project/variables/:key` `projects/variables/variable.rs` * `PUT /projects/:project/variables/:key` `projects/variables/update.rs` + * `DELETE /projects/:project/variables/:key` `projects/variables/delete.rs` * `GET /runners` `runners/runners.rs` * `POST /runners` `runners/create.rs` * `DELETE /runners` `runners/delete_by_token.rs` @@ -346,8 +350,6 @@ instead of having to search the page for missing endpoints. * `POST /groups/:group/transfer` https://gitlab.kitware.com/help/api/groups.md#transfer-a-group-to-a-new-parent-group-turn-a-subgroup-to-a-top-level-group * `GET /groups/:group/transfer_locations` https://gitlab.kitware.com/help/api/groups.md#get-groups-to-which-a-user-can-transfer-a-group * `GET /groups/:group/users` https://gitlab.kitware.com/help/api/groups.md#list-group-users (EXPERIMENTAL) - * `GET /groups/:group/variables` https://gitlab.kitware.com/help/api/group_level_variables.md#list-group-variables - * `DELETE /groups/:group/variables/:key` https://gitlab.kitware.com/help/api/group_level_variables.md#remove-variable * `GET /job/allowed_agents` https://gitlab.kitware.com/help/api/jobs.md#get-gitlab-agent-by-ci_job_token * `POST /projects/:project/approvals` https://gitlab.kitware.com/help/api/merge_request_approvals.md#change-configuration * `POST /projects/:project/approval_rules` https://gitlab.kitware.com/help/api/merge_request_approvals.md#create-project-level-rule @@ -517,8 +519,6 @@ instead of having to search the page for missing endpoints. * `POST /projects/:project/unstar` https://gitlab.kitware.com/help/api/projects.md#unstar-a-project * `POST /projects/:project/uploads` https://gitlab.kitware.com/help/api/projects.md#upload-a-file * `GET /projects/:project/users` https://gitlab.kitware.com/help/api/projects.md#get-project-users - * `GET /projects/:project/variables` https://gitlab.kitware.com/help/api/project_level_variables.md#list-project-variables - * `DELETE /projects/:project/variables/:key` https://gitlab.kitware.com/help/api/project_level_variables.md#remove-variable * `POST /projects/user/:user` https://gitlab.kitware.com/help/api/projects.md#create-project-for-user * `GET /registry/repositories/:id` https://gitlab.kitware.com/help/api/container_registry.md#get-details-of-a-single-repository * `POST /service_accounts` https://gitlab.kitware.com/help/api/users.md#create-service-account-user @@ -631,7 +631,6 @@ These pages document other endpoints not mentioned above: * https://gitlab.kitware.com/help/api/group_import_export.md * https://gitlab.kitware.com/help/api/group_iterations.md * https://gitlab.kitware.com/help/api/group_labels.md - * https://gitlab.kitware.com/help/api/group_level_variables.md * https://gitlab.kitware.com/help/api/group_protected_branches.md * https://gitlab.kitware.com/help/api/group_protected_environments.md * https://gitlab.kitware.com/help/api/group_relations_export.md diff --git a/src/api/groups.rs b/src/api/groups.rs index b1639919b4cb83ea348e38287e63aa35073c29a5..7a258d8493fd7c8b88c161bdf55d27762c89f14f 100644 --- a/src/api/groups.rs +++ b/src/api/groups.rs @@ -26,7 +26,6 @@ pub mod runners; mod share; pub mod subgroups; mod unshare; - pub mod variables; pub use create::BranchProtection; diff --git a/src/api/groups/variables.rs b/src/api/groups/variables.rs index 23e1d75849a9690c17db9a017c52e42325e4869e..e7c05edc6629bc2518eae23ecc0fee820922219b 100644 --- a/src/api/groups/variables.rs +++ b/src/api/groups/variables.rs @@ -9,14 +9,20 @@ //! These endpoints are used for querying a project's variables. mod create; +mod delete; mod update; mod variable; +mod variables; pub use self::create::CreateGroupVariable; pub use self::create::CreateGroupVariableBuilder; pub use self::create::CreateGroupVariableBuilderError; pub use self::create::GroupVariableType; +pub use self::delete::DeleteGroupVariable; +pub use self::delete::DeleteGroupVariableBuilder; +pub use self::delete::DeleteGroupVariableBuilderError; + pub use self::update::UpdateGroupVariable; pub use self::update::UpdateGroupVariableBuilder; pub use self::update::UpdateGroupVariableBuilderError; @@ -25,3 +31,7 @@ pub use self::variable::GroupVariable; pub use self::variable::GroupVariableBuilder; pub use self::variable::GroupVariableBuilderError; pub use self::variable::GroupVariableFilter; + +pub use self::variables::GroupVariables; +pub use self::variables::GroupVariablesBuilder; +pub use self::variables::GroupVariablesBuilderError; diff --git a/src/api/groups/variables/delete.rs b/src/api/groups/variables/delete.rs new file mode 100644 index 0000000000000000000000000000000000000000..b5979fe56e8b510679301aee5ef5c2c30218dedf --- /dev/null +++ b/src/api/groups/variables/delete.rs @@ -0,0 +1,142 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use derive_builder::Builder; + +use crate::api::common::{self, NameOrId}; +use crate::api::endpoint_prelude::*; +use crate::api::groups::variables::GroupVariableFilter; + +/// Delete a variable of a group. +#[derive(Debug, Builder, Clone)] +#[builder(setter(strip_option))] +pub struct DeleteGroupVariable<'a> { + /// The group to remove the variable from + #[builder(setter(into))] + group: NameOrId<'a>, + /// The name of the variable. + #[builder(setter(into))] + key: Cow<'a, str>, + /// The environment scope filter of the variable. + #[builder(default)] + filter: Option>, +} + +impl<'a> DeleteGroupVariable<'a> { + /// Create a builder for the endpoint. + pub fn builder() -> DeleteGroupVariableBuilder<'a> { + DeleteGroupVariableBuilder::default() + } +} + +impl Endpoint for DeleteGroupVariable<'_> { + fn method(&self) -> Method { + Method::DELETE + } + + fn endpoint(&self) -> Cow<'static, str> { + format!( + "groups/{}/variables/{}", + self.group, + common::path_escaped(&self.key), + ) + .into() + } + + fn body(&self) -> Result)>, BodyError> { + let mut params = FormParams::default(); + + if let Some(filter) = self.filter.as_ref() { + filter.add_query(&mut params); + } + + params.into_body() + } +} + +#[cfg(test)] +mod tests { + use http::Method; + + use crate::api::groups::variables::delete::{ + DeleteGroupVariable, DeleteGroupVariableBuilderError, GroupVariableFilter, + }; + use crate::api::{self, Query}; + use crate::test::client::{ExpectedUrl, SingleTestClient}; + + #[test] + fn all_parameters_are_needed() { + let err = DeleteGroupVariable::builder().build().unwrap_err(); + crate::test::assert_missing_field!(err, DeleteGroupVariableBuilderError, "group"); + } + + #[test] + fn group_is_necessary() { + let err = DeleteGroupVariable::builder() + .key("testkey") + .build() + .unwrap_err(); + crate::test::assert_missing_field!(err, DeleteGroupVariableBuilderError, "group"); + } + + #[test] + fn key_is_necessary() { + let err = DeleteGroupVariable::builder().group(1).build().unwrap_err(); + crate::test::assert_missing_field!(err, DeleteGroupVariableBuilderError, "key"); + } + + #[test] + fn sufficient_parameters() { + DeleteGroupVariable::builder() + .group(1) + .key("testkey") + .build() + .unwrap(); + } + + #[test] + fn endpoint() { + let endpoint = ExpectedUrl::builder() + .method(Method::DELETE) + .endpoint("groups/simple%2Fgroup/variables/testkey") + .content_type("application/x-www-form-urlencoded") + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = DeleteGroupVariable::builder() + .group("simple/group") + .key("testkey") + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn endpoint_filter() { + let endpoint = ExpectedUrl::builder() + .method(Method::DELETE) + .endpoint("groups/simple%2Fgroup/variables/testkey") + .content_type("application/x-www-form-urlencoded") + .body_str("filter%5Benvironment_scope%5D=production") + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = DeleteGroupVariable::builder() + .group("simple/group") + .key("testkey") + .filter( + GroupVariableFilter::builder() + .environment_scope("production") + .build() + .unwrap(), + ) + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } +} diff --git a/src/api/groups/variables/variables.rs b/src/api/groups/variables/variables.rs new file mode 100644 index 0000000000000000000000000000000000000000..de8f96e7876ded73733d97414b7b7c547c0c3656 --- /dev/null +++ b/src/api/groups/variables/variables.rs @@ -0,0 +1,74 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use derive_builder::Builder; + +use crate::api::common::NameOrId; +use crate::api::endpoint_prelude::*; + +/// Query for list of variables +#[derive(Debug, Builder, Clone)] +#[builder(setter(strip_option))] +pub struct GroupVariables<'a> { + /// The group to query variables from + #[builder(setter(into))] + group: NameOrId<'a>, +} + +impl<'a> GroupVariables<'a> { + /// Create a builder for the endpoint. + pub fn builder() -> GroupVariablesBuilder<'a> { + GroupVariablesBuilder::default() + } +} + +impl Endpoint for GroupVariables<'_> { + fn method(&self) -> Method { + Method::GET + } + + fn endpoint(&self) -> Cow<'static, str> { + format!("groups/{}/variables", self.group).into() + } +} + +impl Pageable for GroupVariables<'_> {} + +#[cfg(test)] +mod tests { + use http::Method; + + use crate::api::groups::variables::variables::{GroupVariables, GroupVariablesBuilderError}; + use crate::api::{self, Query}; + use crate::test::client::{ExpectedUrl, SingleTestClient}; + + #[test] + fn all_parameters_are_needed() { + let err = GroupVariables::builder().build().unwrap_err(); + crate::test::assert_missing_field!(err, GroupVariablesBuilderError, "group"); + } + + #[test] + fn sufficient_parameters() { + GroupVariables::builder().group(1).build().unwrap(); + } + + #[test] + fn endpoint() { + let endpoint = ExpectedUrl::builder() + .method(Method::GET) + .endpoint("groups/simple%2Fgroup/variables") + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = GroupVariables::builder() + .group("simple/group") + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } +} diff --git a/src/api/projects/variables.rs b/src/api/projects/variables.rs index 983f4f9674de7daf71cf4b2851394c45f7f8f8c6..9a11c48d8bda2aa9294200cb56c5737857310e80 100644 --- a/src/api/projects/variables.rs +++ b/src/api/projects/variables.rs @@ -9,14 +9,20 @@ //! These endpoints are used for querying a project's variables. mod create; +mod delete; mod update; mod variable; +mod variables; pub use self::create::CreateProjectVariable; pub use self::create::CreateProjectVariableBuilder; pub use self::create::CreateProjectVariableBuilderError; pub use self::create::ProjectVariableType; +pub use self::delete::DeleteProjectVariable; +pub use self::delete::DeleteProjectVariableBuilder; +pub use self::delete::DeleteProjectVariableBuilderError; + pub use self::update::UpdateProjectVariable; pub use self::update::UpdateProjectVariableBuilder; pub use self::update::UpdateProjectVariableBuilderError; @@ -25,3 +31,7 @@ pub use self::variable::ProjectVariable; pub use self::variable::ProjectVariableBuilder; pub use self::variable::ProjectVariableBuilderError; pub use self::variable::ProjectVariableFilter; + +pub use self::variables::ProjectVariables; +pub use self::variables::ProjectVariablesBuilder; +pub use self::variables::ProjectVariablesBuilderError; diff --git a/src/api/projects/variables/delete.rs b/src/api/projects/variables/delete.rs new file mode 100644 index 0000000000000000000000000000000000000000..c8ec4aa4ae7e056671c2bbc04ae52d2bcbe31e3d --- /dev/null +++ b/src/api/projects/variables/delete.rs @@ -0,0 +1,145 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use derive_builder::Builder; + +use crate::api::common::{self, NameOrId}; +use crate::api::endpoint_prelude::*; +use crate::api::projects::variables::ProjectVariableFilter; + +/// Delete a variable of a project. +#[derive(Debug, Builder, Clone)] +#[builder(setter(strip_option))] +pub struct DeleteProjectVariable<'a> { + /// The project to remove the variable from. + #[builder(setter(into))] + project: NameOrId<'a>, + /// The name of the variable. + #[builder(setter(into))] + key: Cow<'a, str>, + /// The environment scope filter of the variable. + #[builder(default)] + filter: Option>, +} + +impl<'a> DeleteProjectVariable<'a> { + /// Create a builder for the endpoint. + pub fn builder() -> DeleteProjectVariableBuilder<'a> { + DeleteProjectVariableBuilder::default() + } +} + +impl Endpoint for DeleteProjectVariable<'_> { + fn method(&self) -> Method { + Method::DELETE + } + + fn endpoint(&self) -> Cow<'static, str> { + format!( + "projects/{}/variables/{}", + self.project, + common::path_escaped(&self.key), + ) + .into() + } + + fn body(&self) -> Result)>, BodyError> { + let mut params = FormParams::default(); + + if let Some(filter) = self.filter.as_ref() { + filter.add_query(&mut params); + } + + params.into_body() + } +} + +#[cfg(test)] +mod tests { + use http::Method; + + use crate::api::projects::variables::delete::{ + DeleteProjectVariable, DeleteProjectVariableBuilderError, ProjectVariableFilter, + }; + use crate::api::{self, Query}; + use crate::test::client::{ExpectedUrl, SingleTestClient}; + + #[test] + fn all_parameters_are_needed() { + let err = DeleteProjectVariable::builder().build().unwrap_err(); + crate::test::assert_missing_field!(err, DeleteProjectVariableBuilderError, "project"); + } + + #[test] + fn project_is_necessary() { + let err = DeleteProjectVariable::builder() + .key("testkey") + .build() + .unwrap_err(); + crate::test::assert_missing_field!(err, DeleteProjectVariableBuilderError, "project"); + } + + #[test] + fn key_is_necessary() { + let err = DeleteProjectVariable::builder() + .project(1) + .build() + .unwrap_err(); + crate::test::assert_missing_field!(err, DeleteProjectVariableBuilderError, "key"); + } + + #[test] + fn sufficient_parameters() { + DeleteProjectVariable::builder() + .project(1) + .key("testkey") + .build() + .unwrap(); + } + + #[test] + fn endpoint() { + let endpoint = ExpectedUrl::builder() + .method(Method::DELETE) + .endpoint("projects/simple%2Fproject/variables/testkey") + .content_type("application/x-www-form-urlencoded") + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = DeleteProjectVariable::builder() + .project("simple/project") + .key("testkey") + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } + + #[test] + fn endpoint_filter() { + let endpoint = ExpectedUrl::builder() + .method(Method::DELETE) + .endpoint("projects/simple%2Fproject/variables/testkey") + .content_type("application/x-www-form-urlencoded") + .body_str("filter%5Benvironment_scope%5D=production") + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = DeleteProjectVariable::builder() + .project("simple/project") + .key("testkey") + .filter( + ProjectVariableFilter::builder() + .environment_scope("production") + .build() + .unwrap(), + ) + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } +} diff --git a/src/api/projects/variables/variables.rs b/src/api/projects/variables/variables.rs new file mode 100644 index 0000000000000000000000000000000000000000..c52d9476852834aad4fc23a188db681c17f7d569 --- /dev/null +++ b/src/api/projects/variables/variables.rs @@ -0,0 +1,76 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use derive_builder::Builder; + +use crate::api::common::NameOrId; +use crate::api::endpoint_prelude::*; + +/// Query for list of variables +#[derive(Debug, Builder, Clone)] +#[builder(setter(strip_option))] +pub struct ProjectVariables<'a> { + /// The project to query variables from + #[builder(setter(into))] + project: NameOrId<'a>, +} + +impl<'a> ProjectVariables<'a> { + /// Create a builder for the endpoint. + pub fn builder() -> ProjectVariablesBuilder<'a> { + ProjectVariablesBuilder::default() + } +} + +impl Endpoint for ProjectVariables<'_> { + fn method(&self) -> Method { + Method::GET + } + + fn endpoint(&self) -> Cow<'static, str> { + format!("projects/{}/variables", self.project).into() + } +} + +impl Pageable for ProjectVariables<'_> {} + +#[cfg(test)] +mod tests { + use http::Method; + + use crate::api::projects::variables::variables::{ + ProjectVariables, ProjectVariablesBuilderError, + }; + use crate::api::{self, Query}; + use crate::test::client::{ExpectedUrl, SingleTestClient}; + + #[test] + fn all_parameters_are_needed() { + let err = ProjectVariables::builder().build().unwrap_err(); + crate::test::assert_missing_field!(err, ProjectVariablesBuilderError, "project"); + } + + #[test] + fn sufficient_parameters() { + ProjectVariables::builder().project(1).build().unwrap(); + } + + #[test] + fn endpoint() { + let endpoint = ExpectedUrl::builder() + .method(Method::GET) + .endpoint("projects/simple%2Fproject/variables") + .build() + .unwrap(); + let client = SingleTestClient::new_raw(endpoint, ""); + + let endpoint = ProjectVariables::builder() + .project("simple/project") + .build() + .unwrap(); + api::ignore(endpoint).query(&client).unwrap(); + } +}