Commit 327b8cb4 authored by Ben Boeckel's avatar Ben Boeckel Committed by Kitware Robot
Browse files

Merge topic 'mr-merge-rebase-approve'

965d4326 update README to reference issue about PUT vs POST
d33f8dc6 add UnapproveMergeRequest
297fb723 add ApproveMergeRequest
a39a98b6 add RebaseMergeRequest
567f5bd7

 add MergeMergeRequest
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Ben Boeckel's avatarBen Boeckel <ben.boeckel@kitware.com>
Merge-request: !260
parents 0fbc3a64 965d4326
......@@ -11,6 +11,14 @@
labels from a project.
* Added the `api::projects::labels::PromoteLabel` endpoint to promote a project
label to a group label.
* Added the `api::projects:merge_requests::MergeMergeRequest` endpoint to
merge open merge requests.
* Added the `api::projects:merge_requests::RebaseMergeRequest` endpoint to
rebase open merge requests when using the fast-forward merge model.
* Added the `api::projects:merge_requests::ApproveMergeRequest` endpoint to
approve open merge requests.
* Added the `api::projects:merge_requests::UnapproveMergeRequest` endpoint to
unapprove approved merge requests.
# v0.1301.1
......
......@@ -58,6 +58,14 @@ These API endpoints have been implemented.
* `POST /projects/:project/merge_requests` `projects/merge_requests/create.rs`
* `GET /projects/:project/merge_requests/:merge_request` `projects/merge_requests/merge_request.rs`
* `PUT /projects/:project/merge_requests/:merge_request` `projects/merge_requests/edit.rs`
This should be a `POST` action.
https://gitlab.com/gitlab-org/gitlab/-/issues/219324
* `PUT /projects/:project/merge_requests/:merge_request/merge` `projects/merge_requests/merge.rs`
This should be a `POST` action.
https://gitlab.com/gitlab-org/gitlab/-/issues/219324
* `PUT /projects/:project/merge_requests/:merge_request/rebase` `projects/merge_requests/rebase.rs`
* `POST /projects/:project/merge_requests/:merge_request/approve` `projects/merge_requests/approve.rs`
* `POST /projects/:project/merge_requests/:merge_request/unapprove` `projects/merge_requests/unapprove.rs`
* `GET /projects/:project/merge_requests/:merge_request/award_emoji` `projects/merge_requests/awards/awards.rs`
* `GET /projects/:project/merge_requests/:merge_request/closes_issues` `projects/merge_requests/issues_closed_by.rs`
* `GET /projects/:project/merge_requests/:merge_request/discussions` `projects/merge_requests/discussions/discussions.rs`
......@@ -223,12 +231,10 @@ instead of having to search the page for missing endpoints.
* `POST /projects/:project/merge_requests/:merge_request/cancel_merge_when_pipeline_succeeds` https://gitlab.kitware.com/help/api/merge_requests.md#cancel-merge-when-pipeline-succeeds
* `GET /projects/:project/merge_requests/:merge_request/changes` https://gitlab.kitware.com/help/api/merge_requests.md#get-single-mr-changes
* `GET /projects/:project/merge_requests/:merge_request/commits` https://gitlab.kitware.com/help/api/merge_requests.md#get-single-mr-commits
* `POST /projects/:project/merge_requests/:merge_request/merge` https://gitlab.kitware.com/help/api/merge_requests.md#accept-mr
* `GET /projects/:project/merge_requests/:merge_request/merge_ref` https://gitlab.kitware.com/help/api/merge_requests.md#merge-to-default-merge-ref-path
* `GET /projects/:project/merge_requests/:merge_request/participants` https://gitlab.kitware.com/help/api/merge_requests.md#get-single-mr-participants
* `GET /projects/:project/merge_requests/:merge_request/pipelines` https://gitlab.kitware.com/help/api/merge_requests.md#list-mr-pipelines
* `POST /projects/:project/merge_requests/:merge_request/pipelines` https://gitlab.kitware.com/help/api/merge_requests.md#create-mr-pipeline
* `PUT /projects/:project/merge_requests/:merge_request/rebase` https://gitlab.kitware.com/help/api/merge_requests.md#rebase-a-merge-request
This should be a `POST` action.
https://gitlab.com/gitlab-org/gitlab/-/issues/219324
* `POST /projects/:project/merge_requests/:merge_request/reset_spent_time` https://gitlab.kitware.com/help/api/merge_requests.md#reset-spent-time-for-a-merge-request
......
......@@ -8,15 +8,19 @@
//!
//! These endpoints are used for querying projects merge requests.
mod approve;
pub mod awards;
mod create;
pub mod discussions;
mod edit;
mod issues_closed_by;
mod merge;
mod merge_request;
mod merge_requests;
pub mod notes;
mod rebase;
mod resource_label_events;
mod unapprove;
pub use self::create::CreateMergeRequest;
pub use self::create::CreateMergeRequestBuilder;
......@@ -31,6 +35,17 @@ pub use self::issues_closed_by::IssuesClosedByBuilder;
pub use self::merge_request::MergeRequest;
pub use self::merge_request::MergeRequestBuilder;
pub use self::rebase::RebaseMergeRequest;
pub use self::rebase::RebaseMergeRequestBuilder;
pub use self::merge::MergeMergeRequest;
pub use self::merge::MergeMergeRequestBuilder;
pub use self::approve::ApproveMergeRequest;
pub use self::approve::ApproveMergeRequestBuilder;
pub use self::unapprove::UnapproveMergeRequest;
pub use self::unapprove::UnapproveMergeRequestBuilder;
pub use self::merge_requests::MergeRequestOrderBy;
pub use self::merge_requests::MergeRequestScope;
pub use self::merge_requests::MergeRequestState;
......
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those s.
use derive_builder::Builder;
use crate::api::common::NameOrId;
use crate::api::endpoint_prelude::*;
/// Approve a merge request.
#[derive(Debug, Builder)]
#[builder(setter(strip_option))]
pub struct ApproveMergeRequest<'a> {
/// The project with the merge request.
#[builder(setter(into))]
project: NameOrId<'a>,
/// The ID of the merge request.
merge_request: u64,
/// Git commit SHA to approve. If set, this must match the head of the branch being approved or
/// the approval will fail.
#[builder(setter(into), default)]
sha: Option<Cow<'a, str>>,
/// Approver's password (required if `Require user password to approve` is enabled in project
/// settings). Note: no special encryption is applied to this field. TLS/HTTPS for
/// on-the-wire encryption is assumed.
#[builder(setter(into), default)]
approval_password: Option<Cow<'a, str>>,
}
impl<'a> ApproveMergeRequest<'a> {
/// Create a builder for the endpoint.
pub fn builder() -> ApproveMergeRequestBuilder<'a> {
ApproveMergeRequestBuilder::default()
}
}
impl<'a> Endpoint for ApproveMergeRequest<'a> {
fn method(&self) -> Method {
Method::POST
}
fn endpoint(&self) -> Cow<'static, str> {
format!(
"projects/{}/merge_requests/{}/approve",
self.project, self.merge_request,
)
.into()
}
fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
let mut params = FormParams::default();
params
.push_opt("sha", self.sha.as_ref())
.push_opt("approval_password", self.approval_password.as_ref());
params.into_body()
}
}
#[cfg(test)]
mod tests {
use http::Method;
use crate::api::projects::merge_requests::ApproveMergeRequest;
use crate::api::{self, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};
#[test]
fn project_and_merge_request_are_needed() {
let err = ApproveMergeRequest::builder().build().unwrap_err();
assert_eq!(err, "`project` must be initialized");
}
#[test]
fn project_is_needed() {
let err = ApproveMergeRequest::builder()
.merge_request(1)
.build()
.unwrap_err();
assert_eq!(err, "`project` must be initialized");
}
#[test]
fn merge_request_is_needed() {
let err = ApproveMergeRequest::builder()
.project(1)
.build()
.unwrap_err();
assert_eq!(err, "`merge_request` must be initialized");
}
#[test]
fn project_and_merge_request_are_sufficient() {
ApproveMergeRequest::builder()
.project(1)
.merge_request(1)
.build()
.unwrap();
}
#[test]
fn endpoint() {
let endpoint = ExpectedUrl::builder()
.method(Method::POST)
.endpoint("projects/simple%2Fproject/merge_requests/1/approve")
.content_type("application/x-www-form-urlencoded")
.body_str("")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = ApproveMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_approval_password() {
let endpoint = ExpectedUrl::builder()
.method(Method::POST)
.endpoint("projects/simple%2Fproject/merge_requests/1/approve")
.content_type("application/x-www-form-urlencoded")
.body_str("approval_password=blahblahblah")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = ApproveMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.approval_password("blahblahblah")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_sha() {
let endpoint = ExpectedUrl::builder()
.method(Method::POST)
.endpoint("projects/simple%2Fproject/merge_requests/1/approve")
.content_type("application/x-www-form-urlencoded")
.body_str("sha=blahblahblah")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = ApproveMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.sha("blahblahblah")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
}
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::*;
/// Merge a merge request.
#[derive(Debug, Builder)]
#[builder(setter(strip_option))]
pub struct MergeMergeRequest<'a> {
/// The project with the merge request.
#[builder(setter(into))]
project: NameOrId<'a>,
/// The ID of the merge request.
merge_request: u64,
/// Commit message to use on the merge commit.
#[builder(setter(into), default)]
merge_commit_message: Option<Cow<'a, str>>,
/// Commit message to use on the squash commit.
#[builder(setter(into), default)]
squash_commit_message: Option<Cow<'a, str>>,
/// Squash source branch commits into a single merge commit?
#[builder(default)]
squash: Option<bool>,
/// Remove source branch on successful merge?
#[builder(default)]
should_remove_source_branch: Option<bool>,
/// Merge when pipeline succeeds?
#[builder(default)]
merge_when_pipeline_succeeds: Option<bool>,
/// Git commit SHA to merge. If set, this must match the head of the branch being merged or the
/// merge will fail.
#[builder(setter(into), default)]
sha: Option<Cow<'a, str>>,
}
impl<'a> MergeMergeRequest<'a> {
/// Create a builder for the endpoint.
pub fn builder() -> MergeMergeRequestBuilder<'a> {
MergeMergeRequestBuilder::default()
}
}
impl<'a> Endpoint for MergeMergeRequest<'a> {
fn method(&self) -> Method {
Method::PUT
}
fn endpoint(&self) -> Cow<'static, str> {
format!(
"projects/{}/merge_requests/{}/merge",
self.project, self.merge_request,
)
.into()
}
fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
let mut params = FormParams::default();
params
.push_opt("merge_commit_message", self.merge_commit_message.as_ref())
.push_opt("squash_commit_message", self.squash_commit_message.as_ref())
.push_opt("squash", self.squash)
.push_opt(
"should_remove_source_branch",
self.should_remove_source_branch,
)
.push_opt(
"merge_when_pipeline_succeeds",
self.merge_when_pipeline_succeeds,
)
.push_opt("sha", self.sha.as_ref());
params.into_body()
}
}
#[cfg(test)]
mod tests {
use http::Method;
use crate::api::projects::merge_requests::MergeMergeRequest;
use crate::api::{self, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};
#[test]
fn project_and_merge_request_are_needed() {
let err = MergeMergeRequest::builder().build().unwrap_err();
assert_eq!(err, "`project` must be initialized");
}
#[test]
fn project_is_needed() {
let err = MergeMergeRequest::builder()
.merge_request(1)
.build()
.unwrap_err();
assert_eq!(err, "`project` must be initialized");
}
#[test]
fn merge_request_is_needed() {
let err = MergeMergeRequest::builder().project(1).build().unwrap_err();
assert_eq!(err, "`merge_request` must be initialized");
}
#[test]
fn project_and_merge_request_are_sufficient() {
MergeMergeRequest::builder()
.project(1)
.merge_request(1)
.build()
.unwrap();
}
#[test]
fn endpoint() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_merge_commit_message() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("merge_commit_message=blahblahblah")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.merge_commit_message("blahblahblah")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_squash_commit_message() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("squash_commit_message=blahblahblah")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.squash_commit_message("blahblahblah")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_merge_when_pipeline_succeeds() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("merge_when_pipeline_succeeds=true")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.merge_when_pipeline_succeeds(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_should_remove_source_branch() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("should_remove_source_branch=true")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.should_remove_source_branch(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_squash() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("squash=true")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.squash(true)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_sha() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/merge_requests/1/merge")
.content_type("application/x-www-form-urlencoded")
.body_str("sha=blahblahblah")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = MergeMergeRequest::builder()
.project("simple/project")
.merge_request(1)
.sha("blahblahblah")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
}
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those s.
//! This module implements the server-side rebasing endpoint, which is only relevant if you've set
//! your repository's merge model to __fast forward__ merging.
use derive_builder::Builder;
use crate::api::common::NameOrId;
use crate::api::endpoint_prelude::*;
/// Rebase a merge request.
#[derive(Debug, Builder)]
#[builder(setter(strip_option))]
pub struct RebaseMergeRequest<'a> {
/// The project with the merge request.
#[builder(setter(into))]
project: NameOrId<'a>,
/// The ID of the merge request.
merge_request: u64,
/// Skip CI on rebase?
#[builder(default)]
skip_ci: Option<bool>,
}
impl<'a> RebaseMergeRequest<'a> {
/// Create a builder for the endpoint.
pub fn builder() -> RebaseMergeRequestBuilder<'a> {
RebaseMergeRequestBuilder::default()
}
}
impl<'a> Endpoint for RebaseMergeRequest<'a> {
fn method(&self) -> Method {
Method::PUT
}
fn endpoint(&self) -> Cow<'static, str> {
format!(
"projects/{}/merge_requests/{}/rebase",
self.project, self.merge_request,
)
.into()
}
fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
let mut params = FormParams::default();
params.push_opt("skip_ci", self.skip_ci);
params.into_body()
}
}
#[cfg(test)]
mod tests {
use http::Method;
use crate::api::projects::merge_requests::RebaseMergeRequest;
use crate::api::{self, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};
#[test]
fn project_and_merge_request_are_needed() {
let err = RebaseMergeRequest::builder().build().unwrap_err();
assert_eq!(err, "`project` must be initialized");
}
#[test]
fn project_is_needed() {
let err = RebaseMergeRequest::builder()
.merge_request(1)
.build()
.unwrap_err();
assert_eq!(err, "`project` must be initialized");
}
#[test]
fn merge_request_is_needed() {
let err = RebaseMergeRequest::builder()
.project(1)
.build()
.unwrap_err();
assert_eq!(err, "`merge_request` must be initialized");
}
#[test]
fn project_and_merge_request_are_sufficient() {
RebaseMergeRequest::builder()
.project(1)
.merge_request(1)
.build()
.unwrap();
}