Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
0a56f5aadb
commit
4da4d596a8
|
|
@ -2316,16 +2316,9 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
# Overridden in EE
|
||||
def use_merge_base_pipeline_for_comparison?(_)
|
||||
return true if Feature.enabled?(:use_merge_base_for_all_report_comparisons, project)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def comparison_base_pipeline(service_class)
|
||||
target_shas = [
|
||||
(diff_head_pipeline&.target_sha if use_merge_base_pipeline_for_comparison?(service_class)),
|
||||
diff_head_pipeline&.target_sha,
|
||||
diff_base_sha,
|
||||
diff_start_sha
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
name: use_merge_base_for_all_report_comparisons
|
||||
description:
|
||||
feature_issue_url:
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/192288
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/549351
|
||||
milestone: '18.1'
|
||||
group: group::security insights
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -8,14 +8,6 @@ description: Debian project-level component files
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52885
|
||||
milestone: '13.9'
|
||||
gitlab_schema: gitlab_main_cell
|
||||
desired_sharding_key:
|
||||
project_id:
|
||||
references: projects
|
||||
backfill_via:
|
||||
parent:
|
||||
foreign_key: component_id
|
||||
table: packages_debian_project_components
|
||||
sharding_key: project_id
|
||||
belongs_to: component
|
||||
sharding_key:
|
||||
project_id: projects
|
||||
table_size: small
|
||||
desired_sharding_key_migration_job_name: BackfillPackagesDebianProjectComponentFilesProjectId
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPackagesDebianProjectComponentFilesProjectIdNotNull < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.2'
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_not_null_constraint :packages_debian_project_component_files, :project_id
|
||||
end
|
||||
|
||||
def down
|
||||
remove_not_null_constraint :packages_debian_project_component_files, :project_id
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
f6c692554287c5a8aea8f361522568fbd419dd71c83096a842f678efd59179f2
|
||||
|
|
@ -19614,6 +19614,7 @@ CREATE TABLE packages_debian_project_component_files (
|
|||
file text NOT NULL,
|
||||
file_sha256 bytea NOT NULL,
|
||||
project_id bigint,
|
||||
CONSTRAINT check_4eafc9503d CHECK ((project_id IS NOT NULL)),
|
||||
CONSTRAINT check_e5af03fa2d CHECK ((char_length(file) <= 255))
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -241,11 +241,13 @@ To request acceleration of a feature, check if an issue already exists in [epic
|
|||
|
||||
## Disable secondary site HTTP proxying
|
||||
|
||||
Secondary site HTTP proxying is enabled by default on a secondary site when it uses a unified URL, meaning, it is configured with the same `external_url` as the primary site. Disabling proxying in this case tends not to be helpful due to completely different behavior being served at the same URL, depending on routing.
|
||||
Secondary site HTTP proxying is enabled by default on a secondary site when it uses a unified URL, meaning, it is configured with the same `external_url` as the primary site. Disabling proxying in this case tends not to be helpful due to completely different behavior being served at the same URL, depending on routing. When HTTP proxying is disabled on a secondary Geo site, the site operates in read-only mode, with several important limitations you should be aware of.
|
||||
|
||||
### What happens if you disable secondary proxying
|
||||
|
||||
Disabling the proxying feature flag has the following general effects:
|
||||
Disabling the proxying feature flag has the following general effects.
|
||||
|
||||
#### HTTP and Git requests
|
||||
|
||||
- The secondary site does not proxy HTTP requests to the primary site. Instead, it attempts to serve them itself, or fail.
|
||||
- Git requests generally succeed. Git pushes are redirected or proxied to the primary site.
|
||||
|
|
@ -271,7 +273,24 @@ Disabling the proxying feature flag has the following general effects:
|
|||
|
||||
You should use the feature flag over using the `GEO_SECONDARY_PROXY` environment variable.
|
||||
|
||||
HTTP proxying is enabled by default in GitLab 15.1 on a secondary site even without a unified URL. If proxying needs to be disabled on all secondary sites, it is easiest to disable the feature flag:
|
||||
HTTP proxying is enabled by default in GitLab 15.1 on a secondary site even without a unified URL.
|
||||
|
||||
#### Terms of service acceptance
|
||||
|
||||
When proxying is disabled, users who access only the secondary site cannot properly accept terms of service or other legal agreements. This creates the following issues:
|
||||
|
||||
- **No record of acceptance**: If an employee only logs into the secondary site, their acceptance of terms and conditions is not recorded in the primary database because write operations (including terms acceptance) are not proxied when secondary proxying is disabled, even though they may be presented with the terms message.
|
||||
- **Legal compliance concerns**: Organizations may lack proper legal coverage if employees use GitLab services through a secondary-only access pattern, since there's no verifiable record of their agreement to the terms and conditions.
|
||||
|
||||
As a workaround, you must access the primary site at least once to properly accept terms and conditions. After accepted on the primary, this information is replicated to secondary sites through normal Geo synchronization.
|
||||
|
||||
{{< alert type="note" >}}
|
||||
This limitation affects organizations that require documented acceptance of terms and conditions for compliance or legal purposes. Ensure users have access to the primary site for the initial terms acceptance.
|
||||
{{< /alert >}}
|
||||
|
||||
### Disable proxy on all secondary sites
|
||||
|
||||
If you need to disable proxying on all secondary sites, it is easiest to disable the feature flag:
|
||||
|
||||
{{< tabs >}}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
---
|
||||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Describes Model Context Protocol and how to use it
|
||||
title: Use Model Context Protocol with AI-native features
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Experiment
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/519938) in GitLab 18.1 [with a flag](../../../administration/feature_flags/_index.md) named `duo_workflow_mcp_support`. Disabled by default.
|
||||
- [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/545956) in GitLab 18.2. Feature flag `duo_workflow_mcp_support` removed.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
The Model Context Protocol (MCP) provides a standardized way for AI-native features
|
||||
to securely connect to different external data sources and tools.
|
||||
|
||||
The following GitLab Duo AI-native features can act as MCP clients, and connect to and run
|
||||
external tools from MCP servers:
|
||||
|
||||
- [GitLab Duo Agentic Chat](../../gitlab_duo_chat/agentic_chat.md)
|
||||
|
||||
This means that, in addition to GitLab information, these AI-native features
|
||||
can now use context and information external to GitLab to generate more powerful
|
||||
answers for customers.
|
||||
|
||||
To use a GitLab Duo AI-native feature with MCP:
|
||||
|
||||
- Turn on MCP for your group.
|
||||
- Specify the MCP servers you want the feature to connect to.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you can use an AI-native feature with MCP, you must:
|
||||
|
||||
- [Install Visual Studio Code](https://code.visualstudio.com/download) (VS Code).
|
||||
- [Set up the GitLab Workflow extension for VS Code](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#setup).
|
||||
- Meet the following AI-native feature prerequisites:
|
||||
- [Agentic Chat prerequisites](../../gitlab_duo_chat/agentic_chat.md#use-agentic-chat-in-vs-code).
|
||||
|
||||
## Turn on MCP for your group
|
||||
|
||||
To turn MCP on or off for your group:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your group.
|
||||
1. Select **Settings > GitLab Duo**.
|
||||
1. Select **Change configuration**.
|
||||
1. Under **Model Context Protocol**, select or clear the
|
||||
**Turn on Model Context Protocol (MCP) support** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Specify the MCP servers
|
||||
|
||||
To specify the MCP servers you want the AI-native feature to connect to:
|
||||
|
||||
1. In VS Code, create an `mcp.json` file in `~/gitlab/duo/`.
|
||||
1. Populate this file with the MCP servers you want the feature to connect to.
|
||||
|
||||
For more information and examples, see the [MCP example servers documentation](https://modelcontextprotocol.io/examples). You can also find other example servers at [Smithery.ai](https://smithery.ai/)
|
||||
and [Awesome MCP Servers](https://mcpservers.org/).
|
||||
|
||||
1. Save the file.
|
||||
|
||||
## Use AI-native features with MCP
|
||||
|
||||
When an AI-native feature wants to call an external tool to answer
|
||||
the question you have asked, you must review and approve or deny the tool before
|
||||
the feature can use that tool:
|
||||
|
||||
1. Open VS Code.
|
||||
1. On the left sidebar, select the feature.
|
||||
1. In the text box, enter a question or specify a code task.
|
||||
1. Submit the question or code task.
|
||||
1. The **Tool Approval Required** dialog appears.
|
||||
|
||||
Review the tool and select **Approve** or **Deny**.
|
||||
|
||||
- If you approve the tool, the feature connects to the tool and
|
||||
generates an answer.
|
||||
|
||||
- If you deny the tool, the **Provide Rejection Reason** dialog appears.
|
||||
Optional: Enter a rejection reason into the text box and select
|
||||
**Submit Rejection**.
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Get started with the Model Context Protocol](https://modelcontextprotocol.io/introduction)
|
||||
- [Demo - Agentic Chat MCP Tool Call Approval](https://www.youtube.com/watch?v=_cHoTmG8Yj8)
|
||||
|
|
@ -85,7 +85,8 @@ Agentic Chat extends Chat capabilities with the following features:
|
|||
- **Resource Retrieval**: Can automatically retrieve detailed information about
|
||||
issues, merge requests, and pipeline logs of your current project.
|
||||
- **Multi-source Analysis**: Can combine information from multiple sources to
|
||||
provide more complete answers to complex questions.
|
||||
provide more complete answers to complex questions. You can use [Model Context Protocol](../gitlab_duo/model_context_protocol/_index.md) to connect Agentic Chat to
|
||||
external data sources and tools.
|
||||
|
||||
### Chat feature comparison
|
||||
|
||||
|
|
|
|||
|
|
@ -128,12 +128,18 @@ module API
|
|||
end
|
||||
|
||||
def automatically_mergeable?(auto_merge, merge_request)
|
||||
return unless auto_merge
|
||||
|
||||
available_strategies = AutoMergeService.new(merge_request.project,
|
||||
current_user).available_strategies(merge_request)
|
||||
|
||||
available_strategies.include?(merge_request.default_auto_merge_strategy)
|
||||
auto_merge && available_strategies.include?(merge_request.default_auto_merge_strategy)
|
||||
end
|
||||
|
||||
def immediately_mergeable?(auto_merge, merge_request)
|
||||
if auto_merge
|
||||
merge_request.diff_head_pipeline_success?
|
||||
else
|
||||
merge_request.mergeable_state?
|
||||
end
|
||||
end
|
||||
|
||||
def serializer_options_for(merge_requests)
|
||||
|
|
@ -751,7 +757,7 @@ module API
|
|||
|
||||
auto_merge = to_boolean(params[:merge_when_pipeline_succeeds]) || to_boolean(params[:auto_merge])
|
||||
automatically_mergeable = automatically_mergeable?(auto_merge, merge_request)
|
||||
immediately_mergeable = merge_request.mergeable?
|
||||
immediately_mergeable = immediately_mergeable?(auto_merge, merge_request)
|
||||
|
||||
not_allowed! if !immediately_mergeable && !automatically_mergeable
|
||||
|
||||
|
|
|
|||
|
|
@ -5045,24 +5045,6 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
end
|
||||
end
|
||||
|
||||
describe '#use_merge_base_pipeline_for_comparison?' do
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
let(:merge_request) { create(:merge_request, :with_codequality_reports, source_project: project) }
|
||||
let(:service_class) { Ci::CompareReportsBaseService }
|
||||
|
||||
subject { merge_request.use_merge_base_pipeline_for_comparison?(service_class) }
|
||||
|
||||
it { is_expected.to eq(true) }
|
||||
|
||||
context 'when use_merge_base_for_all_report_comparisons is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_merge_base_for_all_report_comparisons: false)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#comparison_base_pipeline' do
|
||||
subject(:pipeline) { merge_request.comparison_base_pipeline(service_class) }
|
||||
|
||||
|
|
@ -5078,90 +5060,44 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
)
|
||||
end
|
||||
|
||||
before do
|
||||
allow(merge_request).to receive(:use_merge_base_pipeline_for_comparison?)
|
||||
.with(service_class).and_return(uses_merge_base)
|
||||
end
|
||||
|
||||
context 'when service class uses merge base pipeline' do
|
||||
let(:uses_merge_base) { true }
|
||||
|
||||
context 'when merge request has a merge request pipeline' do
|
||||
let(:merge_request) do
|
||||
create(:merge_request, :with_merge_request_pipeline, source_project: project)
|
||||
end
|
||||
|
||||
let!(:merge_base_pipeline) do
|
||||
create(:ci_pipeline, project: project, ref: merge_request.target_branch, sha: merge_request.target_branch_sha)
|
||||
end
|
||||
|
||||
before do
|
||||
merge_request.update_head_pipeline
|
||||
end
|
||||
|
||||
it 'returns the merge_base_pipeline' do
|
||||
expect(pipeline).to eq(merge_base_pipeline)
|
||||
end
|
||||
context 'when merge request has a merge request pipeline' do
|
||||
let(:merge_request) do
|
||||
create(:merge_request, :with_merge_request_pipeline, source_project: project)
|
||||
end
|
||||
|
||||
it 'returns the base_pipeline when merge does not have a merge request pipeline' do
|
||||
expect(pipeline).to eq(base_pipeline)
|
||||
let!(:merge_base_pipeline) do
|
||||
create(:ci_pipeline, project: project, ref: merge_request.target_branch, sha: merge_request.target_branch_sha)
|
||||
end
|
||||
|
||||
context 'when there is no base pipeline' do
|
||||
let!(:start_pipeline) do
|
||||
create(:ci_pipeline,
|
||||
:success,
|
||||
project: project,
|
||||
ref: merge_request.target_branch,
|
||||
sha: merge_request.diff_start_sha
|
||||
)
|
||||
end
|
||||
before do
|
||||
merge_request.update_head_pipeline
|
||||
end
|
||||
|
||||
before do
|
||||
base_pipeline.destroy!
|
||||
end
|
||||
|
||||
it 'returns the start pipeline' do
|
||||
expect(pipeline).to eq(start_pipeline)
|
||||
end
|
||||
it 'returns the merge_base_pipeline' do
|
||||
expect(pipeline).to eq(merge_base_pipeline)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when service_class does not use merge base pipeline' do
|
||||
let(:uses_merge_base) { false }
|
||||
it 'returns the base_pipeline when merge does not have a merge request pipeline' do
|
||||
expect(pipeline).to eq(base_pipeline)
|
||||
end
|
||||
|
||||
it 'returns the base_pipeline' do
|
||||
expect(pipeline).to eq(base_pipeline)
|
||||
context 'when there is no base pipeline' do
|
||||
let!(:start_pipeline) do
|
||||
create(:ci_pipeline,
|
||||
:success,
|
||||
project: project,
|
||||
ref: merge_request.target_branch,
|
||||
sha: merge_request.diff_start_sha
|
||||
)
|
||||
end
|
||||
|
||||
context 'when merge request has a merge request pipeline' do
|
||||
let(:merge_request) do
|
||||
create(:merge_request, :with_merge_request_pipeline, source_project: project)
|
||||
end
|
||||
|
||||
it 'returns the base pipeline' do
|
||||
expect(pipeline).to eq(base_pipeline)
|
||||
end
|
||||
before do
|
||||
base_pipeline.destroy!
|
||||
end
|
||||
|
||||
context 'when there is no base pipeline' do
|
||||
let!(:start_pipeline) do
|
||||
create(:ci_pipeline,
|
||||
:success,
|
||||
project: project,
|
||||
ref: merge_request.target_branch,
|
||||
sha: merge_request.diff_start_sha
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
base_pipeline.destroy!
|
||||
end
|
||||
|
||||
it 'returns the start pipeline' do
|
||||
expect(pipeline).to eq(start_pipeline)
|
||||
end
|
||||
it 'returns the start pipeline' do
|
||||
expect(pipeline).to eq(start_pipeline)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3174,71 +3174,48 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
|
|||
end
|
||||
|
||||
shared_examples 'merging with auto merge strategies' do
|
||||
context 'when only_allow_merge_if_pipeline_succeeds is true' do
|
||||
before do
|
||||
project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true)
|
||||
end
|
||||
it 'does not merge if auto merge request is passed and the pipeline has failed' do
|
||||
create(:ci_pipeline,
|
||||
:failed,
|
||||
sha: merge_request.diff_head_sha,
|
||||
merge_requests_as_head_pipeline: [merge_request])
|
||||
|
||||
it 'sets auto merge when the pipeline has failed' do
|
||||
create(:ci_pipeline,
|
||||
:failed,
|
||||
sha: merge_request.diff_head_sha,
|
||||
merge_requests_as_head_pipeline: [merge_request])
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['merge_when_pipeline_succeeds']).to eq(true)
|
||||
expect(merge_request.reload.state).to eq('opened')
|
||||
end
|
||||
|
||||
it "sets auto merge when the pipeline is active" do
|
||||
allow_any_instance_of(MergeRequest).to receive_messages(head_pipeline: pipeline, diff_head_pipeline: pipeline)
|
||||
allow(pipeline).to receive(:active?).and_return(true)
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['title']).to eq('Test')
|
||||
expect(json_response['merge_when_pipeline_succeeds']).to eq(true)
|
||||
end
|
||||
|
||||
it 'merges when then pipeline is succeed' do
|
||||
create(:ci_pipeline, :success, sha: merge_request.diff_head_sha, merge_requests_as_head_pipeline: [merge_request])
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['state']).to eq('merged')
|
||||
end
|
||||
expect(response).to have_gitlab_http_status(:method_not_allowed)
|
||||
expect(merge_request.reload.state).to eq('opened')
|
||||
end
|
||||
|
||||
context 'when only_allow_merge_if_pipeline_succeeds is false' do
|
||||
before do
|
||||
project.update_attribute(:only_allow_merge_if_pipeline_succeeds, false)
|
||||
end
|
||||
it 'merges if the head pipeline already succeeded and auto merge request is passed' do
|
||||
create(:ci_pipeline, :success, sha: merge_request.diff_head_sha, merge_requests_as_head_pipeline: [merge_request])
|
||||
|
||||
it 'merges when the pipeline has failed' do
|
||||
create(:ci_pipeline,
|
||||
:failed,
|
||||
sha: merge_request.diff_head_sha,
|
||||
merge_requests_as_head_pipeline: [merge_request])
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['state']).to eq('merged')
|
||||
end
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(merge_request.reload.state).to eq('merged')
|
||||
end
|
||||
it "enables auto merge if the pipeline is active" do
|
||||
allow_any_instance_of(MergeRequest).to receive_messages(head_pipeline: pipeline, diff_head_pipeline: pipeline)
|
||||
allow(pipeline).to receive(:active?).and_return(true)
|
||||
|
||||
it "merges when the pipeline is active" do
|
||||
allow_any_instance_of(MergeRequest).to receive_messages(head_pipeline: pipeline, diff_head_pipeline: pipeline)
|
||||
allow(pipeline).to receive(:active?).and_return(true)
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['title']).to eq('Test')
|
||||
expect(json_response['merge_when_pipeline_succeeds']).to eq(true)
|
||||
end
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(merge_request.reload.state).to eq('merged')
|
||||
end
|
||||
it "enables auto merge if the pipeline is active and only_allow_merge_if_pipeline_succeeds is true" do
|
||||
allow_any_instance_of(MergeRequest).to receive_messages(head_pipeline: pipeline, diff_head_pipeline: pipeline)
|
||||
allow(pipeline).to receive(:active?).and_return(true)
|
||||
project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true)
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['title']).to eq('Test')
|
||||
expect(json_response['merge_when_pipeline_succeeds']).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -3280,15 +3257,15 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
|
|||
end
|
||||
end
|
||||
|
||||
it "returns 405 if branch can't be merged" do
|
||||
it "returns 422 if branch can't be merged" do
|
||||
allow_next_found_instance_of(MergeRequest) do |merge_request|
|
||||
allow(merge_request).to receive(:mergeable?).and_return(false)
|
||||
allow(merge_request).to receive(:can_be_merged?).and_return(false)
|
||||
end
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:method_not_allowed)
|
||||
expect(json_response['message']).to eq('405 Method Not Allowed')
|
||||
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
||||
expect(json_response['message']).to eq('Branch cannot be merged')
|
||||
end
|
||||
|
||||
it "returns 405 if merge_request is not open" do
|
||||
|
|
|
|||
Loading…
Reference in New Issue