diff --git a/lib/gitlab/client.rb b/lib/gitlab/client.rb index 3317e2a3a..e5e327c84 100644 --- a/lib/gitlab/client.rb +++ b/lib/gitlab/client.rb @@ -37,6 +37,7 @@ class Client < API include Markdown include MergeRequestApprovals include MergeRequests + include MergeTrains include Milestones include Namespaces include Notes diff --git a/lib/gitlab/client/merge_trains.rb b/lib/gitlab/client/merge_trains.rb new file mode 100644 index 000000000..7f32bfaf8 --- /dev/null +++ b/lib/gitlab/client/merge_trains.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +class Gitlab::Client + # Defines methods related to merge trains. + # @see https://docs.gitlab.com/ee/api/merge_trains.html + module MergeTrains + # Get list of merge trains for a project. + # + # @example + # Gitlab.merge_trains(1, scope: :active, sort: :asc) + # + # @param [Integer, String] project The ID or name of a project. + # @param [Hash] options A customizable set of options. + # @option options [String] :scope The scope of merge trains to return, one of: :active, :complete + # @option options [String] :sort Sort by created_at either 'asc' or 'desc' + # @return [Array] + def merge_trains(project, options = {}) + get("/projects/#{url_encode project}/merge_trains", query: options) + end + + # Get all merge requests added to a merge train for the requested target branch. + # + # @param [Integer, String] project The ID or name of a project. + # @param [String] target_branch The target branch of the merge train. + # @param [Hash] options A customizable set of options. + # @option options [String] :scope The scope of merge trains to return, one of: :active, :complete + # @option options [String] :sort Sort by created_at either 'asc' or 'desc' + # @return [Array] + def merge_train_merge_requests(project, target_branch, options = {}) + get("/projects/#{url_encode project}/merge_trains/#{target_branch}", query: options) + end + + # Get merge train information for the requested merge request. + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] merge_request_iid The IID of the merge request. + # @return [Gitlab::ObjectifiedHash] + def merge_train_status(project, merge_request_iid) + get("/projects/#{url_encode project}/merge_trains/merge_requests/#{merge_request_iid}") + end + + # Add a merge request to the merge train targeting the merge request’s target branch. + # + # @param [Integer, String] project The ID or name of a project. + # @param [Integer] merge_request_iid The IID of the merge request. + # @param [Hash] options A customizable set of options. + # @option options [Boolean] :when_pipeline_succeeds Add merge request to merge train when pipeline succeeds. + # @option options [String] :sha If present, the SHA must match the HEAD of the source branch, otherwise the merge fails. + # @option options [Boolean] :squash If true, the commits are squashed into a single commit on merge. + # @return [Array] + def add_merge_request_to_merge_train(project, merge_request_iid, options = {}) + post("/projects/#{url_encode project}/merge_trains/merge_requests/#{merge_request_iid}", query: options) + end + end +end diff --git a/spec/fixtures/add_mr_to_merge_train.json b/spec/fixtures/add_mr_to_merge_train.json new file mode 100644 index 000000000..ae3a82375 --- /dev/null +++ b/spec/fixtures/add_mr_to_merge_train.json @@ -0,0 +1,42 @@ +[ + { + "id": 267, + "merge_request": { + "id": 273, + "iid": 1, + "project_id": 597, + "title": "My title 9", + "description": null, + "state": "opened", + "created_at": "2022-10-31T19:06:05.725Z", + "updated_at": "2022-10-31T19:06:05.725Z", + "web_url": "http://localhost/namespace18/project21/-/merge_requests/1" + }, + "user": { + "id": 933, + "username": "user12", + "name": "Sidney Jones31", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/6c8365de387cb3db10ecc7b1880203c4?s=80\u0026d=identicon", + "web_url": "http://localhost/user12" + }, + "pipeline": { + "id": 273, + "iid": 1, + "project_id": 598, + "sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0", + "ref": "main", + "status": "pending", + "source": "push", + "created_at": "2022-10-31T19:06:06.231Z", + "updated_at": "2022-10-31T19:06:06.231Z", + "web_url": "http://localhost/namespace19/project22/-/pipelines/273" + }, + "created_at": "2022-10-31T19:06:06.237Z", + "updated_at":"2022-10-31T19:06:06.237Z", + "target_branch":"main", + "status":"idle", + "merged_at":null, + "duration":null + } +] diff --git a/spec/fixtures/merge_train_merge_requests.json b/spec/fixtures/merge_train_merge_requests.json new file mode 100644 index 000000000..ae3a82375 --- /dev/null +++ b/spec/fixtures/merge_train_merge_requests.json @@ -0,0 +1,42 @@ +[ + { + "id": 267, + "merge_request": { + "id": 273, + "iid": 1, + "project_id": 597, + "title": "My title 9", + "description": null, + "state": "opened", + "created_at": "2022-10-31T19:06:05.725Z", + "updated_at": "2022-10-31T19:06:05.725Z", + "web_url": "http://localhost/namespace18/project21/-/merge_requests/1" + }, + "user": { + "id": 933, + "username": "user12", + "name": "Sidney Jones31", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/6c8365de387cb3db10ecc7b1880203c4?s=80\u0026d=identicon", + "web_url": "http://localhost/user12" + }, + "pipeline": { + "id": 273, + "iid": 1, + "project_id": 598, + "sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0", + "ref": "main", + "status": "pending", + "source": "push", + "created_at": "2022-10-31T19:06:06.231Z", + "updated_at": "2022-10-31T19:06:06.231Z", + "web_url": "http://localhost/namespace19/project22/-/pipelines/273" + }, + "created_at": "2022-10-31T19:06:06.237Z", + "updated_at":"2022-10-31T19:06:06.237Z", + "target_branch":"main", + "status":"idle", + "merged_at":null, + "duration":null + } +] diff --git a/spec/fixtures/merge_train_status.json b/spec/fixtures/merge_train_status.json new file mode 100644 index 000000000..fec7c57e2 --- /dev/null +++ b/spec/fixtures/merge_train_status.json @@ -0,0 +1,40 @@ +{ + "id": 267, + "merge_request": { + "id": 273, + "iid": 1, + "project_id": 597, + "title": "My title 9", + "description": null, + "state": "opened", + "created_at": "2022-10-31T19:06:05.725Z", + "updated_at": "2022-10-31T19:06:05.725Z", + "web_url": "http://localhost/namespace18/project21/-/merge_requests/1" + }, + "user": { + "id": 933, + "username": "user12", + "name": "Sidney Jones31", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/6c8365de387cb3db10ecc7b1880203c4?s=80\u0026d=identicon", + "web_url": "http://localhost/user12" + }, + "pipeline": { + "id": 273, + "iid": 1, + "project_id": 598, + "sha": "b83d6e391c22777fca1ed3012fce84f633d7fed0", + "ref": "main", + "status": "pending", + "source": "push", + "created_at": "2022-10-31T19:06:06.231Z", + "updated_at": "2022-10-31T19:06:06.231Z", + "web_url": "http://localhost/namespace19/project22/-/pipelines/273" + }, + "created_at": "2022-10-31T19:06:06.237Z", + "updated_at":"2022-10-31T19:06:06.237Z", + "target_branch":"main", + "status":"idle", + "merged_at":null, + "duration":null +} diff --git a/spec/fixtures/merge_trains.json b/spec/fixtures/merge_trains.json new file mode 100644 index 000000000..3c74da084 --- /dev/null +++ b/spec/fixtures/merge_trains.json @@ -0,0 +1,39 @@ +[ + { + "id": 110, + "merge_request": { + "id": 126, + "iid": 59, + "project_id": 20, + "title": "Test MR 1580978354", + "description": "", + "state": "merged", + "created_at": "2020-02-06T08:39:14.883Z", + "updated_at": "2020-02-06T08:40:57.038Z", + "web_url": "http://local.gitlab.test:8181/root/merge-train-race-condition/-/merge_requests/59" + }, + "user": { + "id": 1, + "name": "Administrator", + "username": "root", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "http://local.gitlab.test:8181/root" + }, + "pipeline": { + "id": 246, + "sha": "bcc17a8ffd51be1afe45605e714085df28b80b13", + "ref": "refs/merge-requests/59/train", + "status": "success", + "created_at": "2020-02-06T08:40:42.410Z", + "updated_at": "2020-02-06T08:40:46.912Z", + "web_url": "http://local.gitlab.test:8181/root/merge-train-race-condition/pipelines/246" + }, + "created_at": "2020-02-06T08:39:47.217Z", + "updated_at": "2020-02-06T08:40:57.720Z", + "target_branch": "feature-1580973432", + "status": "merged", + "merged_at": "2020-02-06T08:40:57.719Z", + "duration": 70 + } +] diff --git a/spec/gitlab/client/merge_trains_spec.rb b/spec/gitlab/client/merge_trains_spec.rb new file mode 100644 index 000000000..30ef010d9 --- /dev/null +++ b/spec/gitlab/client/merge_trains_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Client do + describe '.merge_trains' do + before do + stub_get('/projects/3/merge_trains', 'merge_trains') + @merge_trains = Gitlab.merge_trains(3) + end + + it 'gets the correct resource' do + expect(a_get('/projects/3/merge_trains')).to have_been_made + end + + it 'returns a paginated response of mrege trains' do + expect(@merge_trains).to be_a Gitlab::PaginatedResponse + expect(@merge_trains.first.target_branch).to eq('feature-1580973432') + end + end + + describe '.merge_train_merge_requests' do + before do + stub_get('/projects/3/merge_trains/main', 'merge_train_merge_requests') + @merge_train_merge_requests = Gitlab.merge_train_merge_requests(3, 'main') + end + + it 'gets the correct resource' do + expect(a_get('/projects/3/merge_trains/main')).to have_been_made + end + + it 'returns a paginated response of merge train merge requests' do + expect(@merge_train_merge_requests).to be_a Gitlab::PaginatedResponse + expect(@merge_train_merge_requests.first.id).to eq(267) + end + end + + describe '.merge_train_status' do + before do + stub_get('/projects/3/merge_trains/merge_requests/1', 'merge_train_status') + @merge_train_status = Gitlab.merge_train_status(3, 1) + end + + it 'gets the correct resource' do + expect(a_get('/projects/3/merge_trains/merge_requests/1')).to have_been_made + end + + it 'returns merge train status' do + expect(@merge_train_status).to be_a Gitlab::ObjectifiedHash + expect(@merge_train_status.id).to eq(267) + end + end + + describe '.add_merge_request_to_merge_train' do + before do + stub_post('/projects/3/merge_trains/merge_requests/1', 'add_mr_to_merge_train') + @merge_train_status = Gitlab.add_merge_request_to_merge_train(3, 1) + end + + it 'gets the correct resource' do + expect(a_post('/projects/3/merge_trains/merge_requests/1')).to have_been_made + end + + it 'adds merge request to merge train and returns merge trains' do + expect(@merge_train_status).to be_a Gitlab::PaginatedResponse + expect(@merge_train_status.first.id).to eq(267) + end + end +end