Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b08b3719a1
commit
d865630025
38 changed files with 592 additions and 61 deletions
|
@ -1 +1 @@
|
|||
aaafc8c4691520f9391a704476f933ffc2fe82fe
|
||||
687bc5d8f36102e2c8033cce76094d5d318cd961
|
||||
|
|
50
app/assets/javascripts/helpers/cve_id_request_helper.js
Normal file
50
app/assets/javascripts/helpers/cve_id_request_helper.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
export function createCveIdRequestIssueBody(fullPath, iid) {
|
||||
return `### Vulnerability Submission
|
||||
|
||||
**NOTE:** Only maintainers of GitLab-hosted projects may request a CVE for
|
||||
a vulnerability within their project.
|
||||
|
||||
Project issue: ${fullPath}#${iid}
|
||||
|
||||
#### Publishing Schedule
|
||||
|
||||
After a CVE request is validated, a CVE identifier will be assigned. On what
|
||||
schedule should the details of the CVE be published?
|
||||
|
||||
* [ ] Publish immediately
|
||||
* [ ] Wait to publish
|
||||
|
||||
<!--
|
||||
Please fill out the yaml codeblock below
|
||||
-->
|
||||
|
||||
\`\`\`yaml
|
||||
reporter:
|
||||
name: "TODO" # "First Last"
|
||||
email: "TODO" # "email@domain.tld"
|
||||
vulnerability:
|
||||
description: "TODO" # "[VULNTYPE] in [COMPONENT] in [VENDOR][PRODUCT] [VERSION] allows [ATTACKER] to [IMPACT] via [VECTOR]"
|
||||
cwe: "TODO" # "CWE-22" # Path Traversal
|
||||
product:
|
||||
gitlab_path: "${fullPath}"
|
||||
vendor: "TODO" # "Deluxe Sandwich Maker Company"
|
||||
name: "TODO" # "Deluxe Sandwich Maker 2"
|
||||
affected_versions:
|
||||
- "TODO" # "1.2.3"
|
||||
- "TODO" # ">1.3.0, <=1.3.9"
|
||||
fixed_versions:
|
||||
- "TODO" # "1.2.4"
|
||||
- "TODO" # "1.3.10"
|
||||
impact: "TODO" # "CVSS v3 string" # https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator
|
||||
solution: "TODO" # "Upgrade to version 1.2.4 or 1.3.10"
|
||||
credit: "TODO"
|
||||
references:
|
||||
- "TODO" # "https://some.domain.tld/a/reference"
|
||||
\`\`\`
|
||||
|
||||
CVSS scores can be computed by means of the [NVD CVSS Calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator).
|
||||
|
||||
/relate ${fullPath}#${iid}
|
||||
/label ~"devops::secure" ~"group::vulnerability research" ~"vulnerability research::cve" ~"advisory::queued"
|
||||
`;
|
||||
}
|
|
@ -11,6 +11,7 @@ import {
|
|||
featureAccessLevelEveryone,
|
||||
featureAccessLevel,
|
||||
featureAccessLevelNone,
|
||||
CVE_ID_REQUEST_BUTTON_I18N,
|
||||
} from '../constants';
|
||||
import { toggleHiddenClassBySelector } from '../external';
|
||||
import projectFeatureSetting from './project_feature_setting.vue';
|
||||
|
@ -19,6 +20,10 @@ import projectSettingRow from './project_setting_row.vue';
|
|||
const PAGE_FEATURE_ACCESS_LEVEL = s__('ProjectSettings|Everyone');
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
...CVE_ID_REQUEST_BUTTON_I18N,
|
||||
},
|
||||
|
||||
components: {
|
||||
projectFeatureSetting,
|
||||
projectSettingRow,
|
||||
|
@ -31,6 +36,11 @@ export default {
|
|||
mixins: [settingsMixin, glFeatureFlagsMixin()],
|
||||
|
||||
props: {
|
||||
requestCveAvailable: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
currentSettings: {
|
||||
type: Object,
|
||||
required: true,
|
||||
|
@ -99,6 +109,11 @@ export default {
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
cveIdRequestHelpPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
registryHelpPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -152,6 +167,7 @@ export default {
|
|||
requestAccessEnabled: true,
|
||||
highlightChangesClass: false,
|
||||
emailsDisabled: false,
|
||||
cveIdRequestEnabled: true,
|
||||
featureAccessLevelEveryone,
|
||||
featureAccessLevelMembers,
|
||||
};
|
||||
|
@ -230,6 +246,9 @@ export default {
|
|||
'ProjectSettings|View and edit files in this project. Non-project members will only have read access.',
|
||||
);
|
||||
},
|
||||
cveIdRequestIsDisabled() {
|
||||
return this.visibilityLevel !== visibilityOptions.PUBLIC;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
@ -417,6 +436,19 @@ export default {
|
|||
:options="featureAccessLevelOptions"
|
||||
name="project[project_feature_attributes][issues_access_level]"
|
||||
/>
|
||||
<project-setting-row
|
||||
v-if="requestCveAvailable"
|
||||
:help-path="cveIdRequestHelpPath"
|
||||
:help-text="$options.i18n.cve_request_toggle_label"
|
||||
>
|
||||
<gl-toggle
|
||||
v-model="cveIdRequestEnabled"
|
||||
class="gl-my-2"
|
||||
:disabled="cveIdRequestIsDisabled"
|
||||
name="project[project_setting_attributes][cve_id_request_enabled]"
|
||||
data-testid="cve_id_request_toggle"
|
||||
/>
|
||||
</project-setting-row>
|
||||
</project-setting-row>
|
||||
<project-setting-row
|
||||
ref="repository-settings"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { __ } from '~/locale';
|
||||
import { s__, __ } from '~/locale';
|
||||
|
||||
export const visibilityOptions = {
|
||||
PRIVATE: 0,
|
||||
|
@ -42,3 +42,7 @@ export const featureAccessLevelEveryone = [
|
|||
featureAccessLevel.EVERYONE,
|
||||
featureAccessLevelDescriptions[featureAccessLevel.EVERYONE],
|
||||
];
|
||||
|
||||
export const CVE_ID_REQUEST_BUTTON_I18N = {
|
||||
cve_request_toggle_label: s__('CVE|Enable CVE ID requests in the issue sidebar'),
|
||||
};
|
||||
|
|
88
app/graphql/mutations/merge_requests/accept.rb
Normal file
88
app/graphql/mutations/merge_requests/accept.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Mutations
|
||||
module MergeRequests
|
||||
class Accept < Base
|
||||
NOT_MERGEABLE = 'This branch cannot be merged'
|
||||
HOOKS_VALIDATION_ERROR = 'Pre-merge hooks failed'
|
||||
SHA_MISMATCH = 'The merge-head is not at the anticipated SHA'
|
||||
MERGE_FAILED = 'The merge failed'
|
||||
ALREADY_SCHEDULED = 'The merge request is already scheduled to be merged'
|
||||
|
||||
graphql_name 'MergeRequestAccept'
|
||||
authorize :accept_merge_request
|
||||
description <<~DESC
|
||||
Accepts a merge request.
|
||||
When accepted, the source branch will be merged into the target branch, either
|
||||
immediately if possible, or using one of the automatic merge strategies.
|
||||
DESC
|
||||
|
||||
argument :strategy,
|
||||
::Types::MergeStrategyEnum,
|
||||
required: false,
|
||||
as: :auto_merge_strategy,
|
||||
description: 'How to merge this merge request.'
|
||||
|
||||
argument :commit_message, ::GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: 'Custom merge commit message.'
|
||||
argument :squash_commit_message, ::GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: 'Custom squash commit message (if squash is true).'
|
||||
argument :sha, ::GraphQL::STRING_TYPE,
|
||||
required: true,
|
||||
description: 'The HEAD SHA at the time when this merge was requested.'
|
||||
|
||||
argument :should_remove_source_branch, ::GraphQL::BOOLEAN_TYPE,
|
||||
required: false,
|
||||
description: 'Should the source branch be removed.'
|
||||
argument :squash, ::GraphQL::BOOLEAN_TYPE,
|
||||
required: false,
|
||||
default_value: false,
|
||||
description: 'Squash commits on the source branch before merge.'
|
||||
|
||||
def resolve(project_path:, iid:, **args)
|
||||
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42317')
|
||||
merge_request = authorized_find!(project_path: project_path, iid: iid)
|
||||
project = merge_request.target_project
|
||||
merge_params = args.compact.with_indifferent_access
|
||||
merge_service = ::MergeRequests::MergeService.new(project, current_user, merge_params)
|
||||
|
||||
if error = validate(merge_request, merge_service, merge_params)
|
||||
return { merge_request: merge_request, errors: [error] }
|
||||
end
|
||||
|
||||
merge_request.update(merge_error: nil, squash: merge_params[:squash])
|
||||
|
||||
result = if merge_params.key?(:auto_merge_strategy)
|
||||
service = AutoMergeService.new(project, current_user, merge_params)
|
||||
service.execute(merge_request, merge_params[:auto_merge_strategy])
|
||||
else
|
||||
merge_service.execute(merge_request)
|
||||
end
|
||||
|
||||
{
|
||||
merge_request: merge_request,
|
||||
errors: result == :failed ? [MERGE_FAILED] : []
|
||||
}
|
||||
rescue ::MergeRequests::MergeBaseService::MergeError => e
|
||||
{
|
||||
merge_request: merge_request,
|
||||
errors: [e.message]
|
||||
}
|
||||
end
|
||||
|
||||
def validate(merge_request, merge_service, merge_params)
|
||||
if merge_request.auto_merge_enabled?
|
||||
ALREADY_SCHEDULED
|
||||
elsif !merge_request.mergeable?(skip_ci_check: merge_params.key?(:auto_merge_strategy))
|
||||
NOT_MERGEABLE
|
||||
elsif !merge_service.hooks_validation_pass?(merge_request)
|
||||
HOOKS_VALIDATION_ERROR
|
||||
elsif merge_params[:sha] != merge_request.diff_head_sha
|
||||
SHA_MISMATCH
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -6,12 +6,18 @@ module Mutations
|
|||
# This is a Base class for the Note update mutations and is not
|
||||
# mounted as a GraphQL mutation itself.
|
||||
class Base < Mutations::Notes::Base
|
||||
QUICK_ACTION_ONLY_WARNING = <<~NB
|
||||
If the body of the Note contains only quick actions,
|
||||
the Note will be destroyed during the update, and no Note will be
|
||||
returned.
|
||||
NB
|
||||
|
||||
authorize :admin_note
|
||||
|
||||
argument :id,
|
||||
::Types::GlobalIDType[::Note],
|
||||
required: true,
|
||||
description: 'The global ID of the note to update.'
|
||||
::Types::GlobalIDType[::Note],
|
||||
required: true,
|
||||
description: 'The global ID of the note to update.'
|
||||
|
||||
def resolve(args)
|
||||
note = authorized_find!(id: args[:id])
|
||||
|
|
|
@ -5,16 +5,20 @@ module Mutations
|
|||
module Update
|
||||
class ImageDiffNote < Mutations::Notes::Update::Base
|
||||
graphql_name 'UpdateImageDiffNote'
|
||||
description <<~DESC
|
||||
Updates a DiffNote on an image (a `Note` where the `position.positionType` is `"image"`).
|
||||
#{QUICK_ACTION_ONLY_WARNING}
|
||||
DESC
|
||||
|
||||
argument :body,
|
||||
GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||
GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||
|
||||
argument :position,
|
||||
Types::Notes::UpdateDiffImagePositionInputType,
|
||||
required: false,
|
||||
description: copy_field_description(Types::Notes::NoteType, :position)
|
||||
Types::Notes::UpdateDiffImagePositionInputType,
|
||||
required: false,
|
||||
description: copy_field_description(Types::Notes::NoteType, :position)
|
||||
|
||||
def ready?(**args)
|
||||
# As both arguments are optional, validate here that one of the
|
||||
|
@ -34,10 +38,9 @@ module Mutations
|
|||
private
|
||||
|
||||
def pre_update_checks!(note, _args)
|
||||
unless note.is_a?(DiffNote) && note.position.on_image?
|
||||
raise Gitlab::Graphql::Errors::ResourceNotAvailable,
|
||||
'Resource is not an ImageDiffNote'
|
||||
end
|
||||
return if note.is_a?(DiffNote) && note.position.on_image?
|
||||
|
||||
raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Resource is not an ImageDiffNote'
|
||||
end
|
||||
|
||||
def note_params(note, args)
|
||||
|
|
|
@ -5,16 +5,17 @@ module Mutations
|
|||
module Update
|
||||
class Note < Mutations::Notes::Update::Base
|
||||
graphql_name 'UpdateNote'
|
||||
description "Updates a Note.\n#{QUICK_ACTION_ONLY_WARNING}"
|
||||
|
||||
argument :body,
|
||||
GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||
GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
description: copy_field_description(Types::Notes::NoteType, :body)
|
||||
|
||||
argument :confidential,
|
||||
GraphQL::BOOLEAN_TYPE,
|
||||
required: false,
|
||||
description: 'The confidentiality flag of a note. Default is false.'
|
||||
GraphQL::BOOLEAN_TYPE,
|
||||
required: false,
|
||||
description: 'The confidentiality flag of a note. Default is false.'
|
||||
|
||||
private
|
||||
|
||||
|
|
9
app/graphql/types/merge_strategy_enum.rb
Normal file
9
app/graphql/types/merge_strategy_enum.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
class MergeStrategyEnum < BaseEnum
|
||||
AutoMergeService.all_strategies_ordered_by_preference.each do |strat|
|
||||
value strat.upcase, value: strat, description: "Use the #{strat} merge strategy."
|
||||
end
|
||||
end
|
||||
end
|
|
@ -44,6 +44,7 @@ module Types
|
|||
mount_mutation Mutations::Issues::Update
|
||||
mount_mutation Mutations::Issues::Move
|
||||
mount_mutation Mutations::Labels::Create
|
||||
mount_mutation Mutations::MergeRequests::Accept
|
||||
mount_mutation Mutations::MergeRequests::Create
|
||||
mount_mutation Mutations::MergeRequests::Update
|
||||
mount_mutation Mutations::MergeRequests::SetLabels
|
||||
|
@ -58,14 +59,8 @@ module Types
|
|||
mount_mutation Mutations::Notes::Create::Note, calls_gitaly: true
|
||||
mount_mutation Mutations::Notes::Create::DiffNote, calls_gitaly: true
|
||||
mount_mutation Mutations::Notes::Create::ImageDiffNote, calls_gitaly: true
|
||||
mount_mutation Mutations::Notes::Update::Note,
|
||||
description: 'Updates a Note. If the body of the Note contains only quick actions, ' \
|
||||
'the Note will be destroyed during the update, and no Note will be ' \
|
||||
'returned'
|
||||
mount_mutation Mutations::Notes::Update::ImageDiffNote,
|
||||
description: 'Updates a DiffNote on an image (a `Note` where the `position.positionType` is `"image"`). ' \
|
||||
'If the body of the Note contains only quick actions, the Note will be ' \
|
||||
'destroyed during the update, and no Note will be returned'
|
||||
mount_mutation Mutations::Notes::Update::Note
|
||||
mount_mutation Mutations::Notes::Update::ImageDiffNote
|
||||
mount_mutation Mutations::Notes::RepositionImageDiffNote
|
||||
mount_mutation Mutations::Notes::Destroy
|
||||
mount_mutation Mutations::Releases::Create
|
||||
|
|
|
@ -9,7 +9,10 @@ class MergeRequestPolicy < IssuablePolicy
|
|||
# Although :read_merge_request is computed in the policy context,
|
||||
# it would not be safe to prevent :create_note there, since
|
||||
# note permissions are shared, and this would apply too broadly.
|
||||
rule { ~can?(:read_merge_request) }.prevent :create_note
|
||||
rule { ~can?(:read_merge_request) }.policy do
|
||||
prevent :create_note
|
||||
prevent :accept_merge_request
|
||||
end
|
||||
|
||||
rule { can?(:update_merge_request) }.policy do
|
||||
enable :approve_merge_request
|
||||
|
@ -18,6 +21,12 @@ class MergeRequestPolicy < IssuablePolicy
|
|||
rule { ~anonymous & can?(:read_merge_request) }.policy do
|
||||
enable :create_todo
|
||||
end
|
||||
|
||||
condition(:can_merge) { @subject.can_be_merged_by?(@user) }
|
||||
|
||||
rule { can_merge }.policy do
|
||||
enable :accept_merge_request
|
||||
end
|
||||
end
|
||||
|
||||
MergeRequestPolicy.prepend_if_ee('EE::MergeRequestPolicy')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- expanded = expanded_by_default?
|
||||
%section.qa-deploy-keys-settings.settings.no-animate#js-deploy-keys-settings{ class: ('expanded' if expanded), data: { qa_selector: 'deploy_keys_settings_content' } }
|
||||
.settings-header
|
||||
%h4= _('Deploy keys')
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Deploy keys')
|
||||
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%p
|
||||
|
|
|
@ -21,4 +21,4 @@
|
|||
= _('Allow this key to push to this repository')
|
||||
|
||||
.form-group.row
|
||||
= f.submit _("Add key"), class: "btn-success btn"
|
||||
= f.submit _("Add key"), class: "btn gl-button btn-confirm"
|
||||
|
|
|
@ -118,6 +118,8 @@
|
|||
%script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: issuable_sidebar[:confidential], is_editable: can_edit_issuable }.to_json.html_safe
|
||||
#js-confidential-entry-point
|
||||
|
||||
= render_if_exists 'shared/issuable/sidebar_cve_id_request', issuable_sidebar: issuable_sidebar
|
||||
|
||||
%script#js-lock-issue-data{ type: "application/json" }= { is_locked: !!issuable_sidebar[:discussion_locked], is_editable: can_edit_issuable }.to_json.html_safe
|
||||
#js-lock-entry-point
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Project Settings Repository Deploy keys header expands/collapses on click / tap
|
||||
merge_request: 55234
|
||||
author: Daniel Schömer
|
||||
type: changed
|
5
changelogs/unreleased/322745-add-missing-token-names.yml
Normal file
5
changelogs/unreleased/322745-add-missing-token-names.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update cluster agent tokens with null names
|
||||
merge_request: 55673
|
||||
author:
|
||||
type: changed
|
5
changelogs/unreleased/add_request_cve_issue.yml
Normal file
5
changelogs/unreleased/add_request_cve_issue.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Adds Request CVE ID button to issue sidebar
|
||||
merge_request: 41203
|
||||
author:
|
||||
type: added
|
5
changelogs/unreleased/ajk-graphql-accept-mr.yml
Normal file
5
changelogs/unreleased/ajk-graphql-accept-mr.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add mutation to accept merge requests
|
||||
merge_request: 54758
|
||||
author:
|
||||
type: added
|
5
changelogs/unreleased/btn-confirm-shared-deploy-keys.yml
Normal file
5
changelogs/unreleased/btn-confirm-shared-deploy-keys.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Move from btn-success to btn-confirm in shared/deploy_keys directory
|
||||
merge_request: 55299
|
||||
author: Yogi (@yo)
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable codequality report comparison with backend
|
||||
merge_request: 54241
|
||||
author:
|
||||
type: performance
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/300796
|
|||
milestone: '13.9'
|
||||
type: development
|
||||
group: group::testing
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
key_path: elasticsearch_enabled
|
||||
description: Whether Elasticsearch is enabled
|
||||
product_section: growth
|
||||
product_stage: growth
|
||||
product_group: group::product intelligence
|
||||
product_category: collection
|
||||
value_type: boolean
|
||||
status: data_available
|
||||
time_frame: none
|
||||
data_source:
|
||||
distribution:
|
||||
- ce
|
||||
tier:
|
||||
- free
|
||||
skip_validation: true
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddCveIdRequestProjectSetting < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
add_column :project_settings, :cve_id_request_enabled, :boolean, default: true, null: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :project_settings, :cve_id_request_enabled
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddNotNullConstraintToClusterTokenName < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# This will add the `NOT NULL` constraint WITHOUT validating it
|
||||
add_not_null_constraint :cluster_agent_tokens, :name, validate: false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_not_null_constraint :cluster_agent_tokens, :name
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CleanupClusterTokensWithNullName < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
BATCH_SIZE = 1000
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
class AgentToken < ActiveRecord::Base
|
||||
include EachBatch
|
||||
|
||||
self.table_name = 'cluster_agent_tokens'
|
||||
end
|
||||
|
||||
def up
|
||||
AgentToken.each_batch(of: BATCH_SIZE) do |relation|
|
||||
relation.where('name IS NULL').update_all("name = 'agent-token-' || id")
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op : can't go back to `NULL` without first dropping the `NOT NULL` constraint
|
||||
end
|
||||
end
|
1
db/schema_migrations/20200816133024
Normal file
1
db/schema_migrations/20200816133024
Normal file
|
@ -0,0 +1 @@
|
|||
37196d54d03791f7509e411d5c545f22aa70f7c07d1f13d76f70008a06e72b57
|
1
db/schema_migrations/20210303165301
Normal file
1
db/schema_migrations/20210303165301
Normal file
|
@ -0,0 +1 @@
|
|||
fa82a0f6c57a527a143da56ae0d70245a7d711b5e5ff3eb959fd6b2cf5872dac
|
1
db/schema_migrations/20210303165302
Normal file
1
db/schema_migrations/20210303165302
Normal file
|
@ -0,0 +1 @@
|
|||
1cb74abdc7134c3252425c3ceb8cd9dc4b157d64b1a2ff7928153e78b05d9121
|
|
@ -16270,6 +16270,7 @@ CREATE TABLE project_settings (
|
|||
has_vulnerabilities boolean DEFAULT false NOT NULL,
|
||||
allow_editing_commit_messages boolean DEFAULT false NOT NULL,
|
||||
prevent_merge_without_jira_issue boolean DEFAULT false NOT NULL,
|
||||
cve_id_request_enabled boolean DEFAULT true NOT NULL,
|
||||
CONSTRAINT check_bde223416c CHECK ((show_default_award_emojis IS NOT NULL))
|
||||
);
|
||||
|
||||
|
@ -19952,6 +19953,9 @@ ALTER TABLE ONLY chat_names
|
|||
ALTER TABLE ONLY chat_teams
|
||||
ADD CONSTRAINT chat_teams_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE cluster_agent_tokens
|
||||
ADD CONSTRAINT check_0fb634d04d CHECK ((name IS NOT NULL)) NOT VALID;
|
||||
|
||||
ALTER TABLE vulnerability_scanners
|
||||
ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID;
|
||||
|
||||
|
|
|
@ -2784,6 +2784,16 @@ Autogenerated return type of MarkAsSpamSnippet.
|
|||
| `webUrl` | String | Web URL of the merge request. |
|
||||
| `workInProgress` | Boolean! | Indicates if the merge request is a draft. |
|
||||
|
||||
### `MergeRequestAcceptPayload`
|
||||
|
||||
Autogenerated return type of MergeRequestAccept.
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
|
||||
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
||||
| `mergeRequest` | MergeRequest | The merge request after mutation. |
|
||||
|
||||
### `MergeRequestCreatePayload`
|
||||
|
||||
Autogenerated return type of MergeRequestCreate.
|
||||
|
@ -5636,6 +5646,14 @@ State of a GitLab merge request.
|
|||
| `merged` | Merge Request has been merged. |
|
||||
| `opened` | In open state. |
|
||||
|
||||
### `MergeStrategyEnum`
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| `ADD_TO_MERGE_TRAIN_WHEN_PIPELINE_SUCCEEDS` | Use the add_to_merge_train_when_pipeline_succeeds merge strategy. |
|
||||
| `MERGE_TRAIN` | Use the merge_train merge strategy. |
|
||||
| `MERGE_WHEN_PIPELINE_SUCCEEDS` | Use the merge_when_pipeline_succeeds merge strategy. |
|
||||
|
||||
### `MilestoneStateEnum`
|
||||
|
||||
Current state of milestone.
|
||||
|
|
|
@ -6360,13 +6360,13 @@ Tiers: `free`, `premium`, `ultimate`
|
|||
|
||||
Whether Elasticsearch is enabled
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/settings/20210204124924_elasticsearch_enabled.yml)
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/settings/20210204124924_elasticsearch_enabled.yml)
|
||||
|
||||
Group: `group::product intelligence`
|
||||
Group: `group::global search`
|
||||
|
||||
Status: `data_available`
|
||||
|
||||
Tiers: `free`
|
||||
Tiers: `premium`, `ultimate`
|
||||
|
||||
### `g_project_management_epic_created_monthly`
|
||||
|
||||
|
|
|
@ -19,16 +19,14 @@ module Gitlab
|
|||
commit = Commit.new(commit, project)
|
||||
commit.lazy_author # preload author
|
||||
|
||||
sha = commit.sha
|
||||
if prev_sha != sha
|
||||
if prev_sha != commit.sha
|
||||
groups << current_group if current_group
|
||||
current_group = { commit: commit, lines: [] }
|
||||
end
|
||||
|
||||
line = highlighted_lines[i].html_safe if highlight
|
||||
current_group[:lines] << line
|
||||
current_group[:lines] << (highlight ? highlighted_lines[i].html_safe : line)
|
||||
|
||||
prev_sha = sha
|
||||
prev_sha = commit.sha
|
||||
i += 1
|
||||
end
|
||||
groups << current_group if current_group
|
||||
|
|
|
@ -38,9 +38,11 @@ module Gitlab
|
|||
if line[0, 1] == "\t"
|
||||
lines << line[1, line.size]
|
||||
elsif m = /^(\w{40}) (\d+) (\d+)/.match(line)
|
||||
commit_id, old_lineno, lineno = m[1], m[2].to_i, m[3].to_i
|
||||
# Removed these instantiations for performance but keeping them for reference:
|
||||
# commit_id, old_lineno, lineno = m[1], m[2].to_i, m[3].to_i
|
||||
commit_id = m[1]
|
||||
commits[commit_id] = nil unless commits.key?(commit_id)
|
||||
info[lineno] = [commit_id, old_lineno]
|
||||
info[m[3].to_i] = [commit_id, m[2].to_i]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,8 +52,7 @@ module Gitlab
|
|||
|
||||
# get it together
|
||||
info.sort.each do |lineno, (commit_id, old_lineno)|
|
||||
commit = commits[commit_id]
|
||||
final << BlameLine.new(lineno, old_lineno, commit, lines[lineno - 1])
|
||||
final << BlameLine.new(lineno, old_lineno, commits[commit_id], lines[lineno - 1])
|
||||
end
|
||||
|
||||
@lines = final
|
||||
|
|
|
@ -5312,6 +5312,27 @@ msgstr ""
|
|||
msgid "CPU"
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|As a maintainer, requesting a CVE for a vulnerability in your project will help your users stay secure and informed."
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|CVE ID Request"
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|Common Vulnerability Enumeration (CVE) identifiers are used to track distinct vulnerabilities in specific versions of code."
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|Create CVE ID Request"
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|Enable CVE ID requests in the issue sidebar"
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|Request CVE ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "CVE|Why Request a CVE ID?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Callback URL"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ const defaultProps = {
|
|||
showDefaultAwardEmojis: true,
|
||||
allowEditingCommitMessages: false,
|
||||
},
|
||||
isGitlabCom: true,
|
||||
canDisableEmails: true,
|
||||
canChangeVisibilityLevel: true,
|
||||
allowedVisibilityOptions: [0, 10, 20],
|
||||
|
|
171
spec/graphql/mutations/merge_requests/accept_spec.rb
Normal file
171
spec/graphql/mutations/merge_requests/accept_spec.rb
Normal file
|
@ -0,0 +1,171 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::MergeRequests::Accept do
|
||||
include AfterNextHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public, :repository) }
|
||||
|
||||
subject(:mutation) { described_class.new(context: context, object: nil, field: nil) }
|
||||
|
||||
let_it_be(:context) do
|
||||
GraphQL::Query::Context.new(
|
||||
query: OpenStruct.new(schema: GitlabSchema),
|
||||
values: { current_user: user },
|
||||
object: nil
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
project.repository.expire_all_method_caches
|
||||
end
|
||||
|
||||
describe '#resolve' do
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
end
|
||||
|
||||
def common_args(merge_request)
|
||||
{
|
||||
project_path: project.full_path,
|
||||
iid: merge_request.iid.to_s,
|
||||
sha: merge_request.diff_head_sha,
|
||||
squash: false # default value
|
||||
}
|
||||
end
|
||||
|
||||
it 'merges the merge request' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
|
||||
result = mutation.resolve(**common_args(merge_request))
|
||||
|
||||
expect(result).to include(errors: be_empty, merge_request: be_merged)
|
||||
end
|
||||
|
||||
it 'rejects the mutation if the SHA is a mismatch' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request).merge(sha: 'not a good sha')
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).not_to include(merge_request: be_merged)
|
||||
expect(result).to include(errors: [described_class::SHA_MISMATCH])
|
||||
end
|
||||
|
||||
it 'respects the merge commit message' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request).merge(commit_message: 'my super custom message')
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).to include(merge_request: be_merged)
|
||||
expect(project.repository.commit(merge_request.target_branch)).to have_attributes(
|
||||
message: args[:commit_message]
|
||||
)
|
||||
end
|
||||
|
||||
it 'respects the squash flag' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request).merge(squash: true)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).to include(merge_request: be_merged)
|
||||
expect(result[:merge_request].squash_commit_sha).to be_present
|
||||
end
|
||||
|
||||
it 'respects the squash_commit_message argument' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request).merge(squash: true, squash_commit_message: 'squish')
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
sha = result[:merge_request].squash_commit_sha
|
||||
|
||||
expect(result).to include(merge_request: be_merged)
|
||||
expect(project.repository.commit(sha)).to have_attributes(message: "squish\n")
|
||||
end
|
||||
|
||||
it 'respects the should_remove_source_branch argument when true' do
|
||||
b = project.repository.add_branch(user, generate(:branch), 'master')
|
||||
merge_request = create(:merge_request, source_branch: b.name, source_project: project)
|
||||
args = common_args(merge_request).merge(should_remove_source_branch: true)
|
||||
|
||||
expect(::MergeRequests::DeleteSourceBranchWorker).to receive(:perform_async)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).to include(merge_request: be_merged)
|
||||
end
|
||||
|
||||
it 'respects the should_remove_source_branch argument when false' do
|
||||
b = project.repository.add_branch(user, generate(:branch), 'master')
|
||||
merge_request = create(:merge_request, source_branch: b.name, source_project: project)
|
||||
args = common_args(merge_request).merge(should_remove_source_branch: false)
|
||||
|
||||
expect(::MergeRequests::DeleteSourceBranchWorker).not_to receive(:perform_async)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).to include(merge_request: be_merged)
|
||||
end
|
||||
|
||||
it 'rejects unmergeable MRs' do
|
||||
merge_request = create(:merge_request, :closed, source_project: project)
|
||||
args = common_args(merge_request)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).not_to include(merge_request: be_merged)
|
||||
expect(result).to include(errors: [described_class::NOT_MERGEABLE])
|
||||
end
|
||||
|
||||
it 'rejects merges when we cannot validate the hooks' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request)
|
||||
expect_next(::MergeRequests::MergeService)
|
||||
.to receive(:hooks_validation_pass?).with(merge_request).and_return(false)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).not_to include(merge_request: be_merged)
|
||||
expect(result).to include(errors: [described_class::HOOKS_VALIDATION_ERROR])
|
||||
end
|
||||
|
||||
it 'rejects merges when the merge service returns an error' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request)
|
||||
expect_next(::MergeRequests::MergeService)
|
||||
.to receive(:execute).with(merge_request).and_return(:failed)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).not_to include(merge_request: be_merged)
|
||||
expect(result).to include(errors: [described_class::MERGE_FAILED])
|
||||
end
|
||||
|
||||
it 'rejects merges when the merge service raises merge error' do
|
||||
merge_request = create(:merge_request, source_project: project)
|
||||
args = common_args(merge_request)
|
||||
expect_next(::MergeRequests::MergeService)
|
||||
.to receive(:execute).and_raise(::MergeRequests::MergeBaseService::MergeError, 'boom')
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).not_to include(merge_request: be_merged)
|
||||
expect(result).to include(errors: ['boom'])
|
||||
end
|
||||
|
||||
it "can use the MERGE_WHEN_PIPELINE_SUCCEEDS strategy" do
|
||||
enum = ::Types::MergeStrategyEnum.values['MERGE_WHEN_PIPELINE_SUCCEEDS']
|
||||
merge_request = create(:merge_request, :with_head_pipeline, source_project: project)
|
||||
args = common_args(merge_request).merge(auto_merge_strategy: enum.value)
|
||||
|
||||
result = mutation.resolve(**args)
|
||||
|
||||
expect(result).not_to include(merge_request: be_merged)
|
||||
expect(result).to include(errors: be_empty, merge_request: be_auto_merge_enabled)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'accepting a merge request', :request_store do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :public, :repository) }
|
||||
let!(:merge_request) { create(:merge_request, source_project: project) }
|
||||
let(:input) do
|
||||
{
|
||||
project_path: project.full_path,
|
||||
iid: merge_request.iid.to_s,
|
||||
sha: merge_request.diff_head_sha
|
||||
}
|
||||
end
|
||||
|
||||
let(:mutation) { graphql_mutation(:merge_request_accept, input, 'mergeRequest { state }') }
|
||||
let(:mutation_response) { graphql_mutation_response(:merge_request_accept) }
|
||||
|
||||
context 'when the user is not allowed to accept a merge request' do
|
||||
before do
|
||||
project.add_reporter(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'a mutation that returns a top-level access error'
|
||||
end
|
||||
|
||||
context 'when user has permissions to create a merge request' do
|
||||
before do
|
||||
project.add_maintainer(current_user)
|
||||
end
|
||||
|
||||
it 'merges the merge request' do
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
expect(mutation_response['mergeRequest']).to include(
|
||||
'state' => 'merged'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -141,6 +141,7 @@ project_setting:
|
|||
- show_default_award_emojis
|
||||
- squash_option
|
||||
- updated_at
|
||||
- cve_id_request_enabled
|
||||
|
||||
build_service_desk_setting: # service_desk_setting
|
||||
unexposed_attributes:
|
||||
|
|
Loading…
Reference in a new issue