Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-11-07 03:22:58 +00:00
parent 098c9a1d51
commit ef2c517527
38 changed files with 429 additions and 143 deletions

View File

@ -138,16 +138,6 @@ Layout/LineLength:
- 'app/helpers/import_helper.rb' - 'app/helpers/import_helper.rb'
- 'app/helpers/issuables_helper.rb' - 'app/helpers/issuables_helper.rb'
- 'app/helpers/labels_helper.rb' - 'app/helpers/labels_helper.rb'
- 'app/helpers/visibility_level_helper.rb'
- 'app/helpers/whats_new_helper.rb'
- 'app/helpers/wiki_helper.rb'
- 'app/mailers/emails/members.rb'
- 'app/mailers/emails/merge_requests.rb'
- 'app/mailers/emails/pages_domains.rb'
- 'app/mailers/emails/profile.rb'
- 'app/mailers/previews/notify_preview.rb'
- 'app/models/analytics/cycle_analytics/aggregation.rb'
- 'app/models/analytics/cycle_analytics/issue_stage_event.rb'
- 'app/models/analytics/cycle_analytics/merge_request_stage_event.rb' - 'app/models/analytics/cycle_analytics/merge_request_stage_event.rb'
- 'app/models/application_record.rb' - 'app/models/application_record.rb'
- 'app/models/application_setting.rb' - 'app/models/application_setting.rb'

View File

@ -299,7 +299,6 @@ RSpec/ExampleWithoutDescription:
- 'spec/lib/bitbucket/representation/issue_spec.rb' - 'spec/lib/bitbucket/representation/issue_spec.rb'
- 'spec/lib/bitbucket/representation/pull_request_spec.rb' - 'spec/lib/bitbucket/representation/pull_request_spec.rb'
- 'spec/lib/bitbucket_server/representation/activity_spec.rb' - 'spec/lib/bitbucket_server/representation/activity_spec.rb'
- 'spec/lib/bitbucket_server/representation/comment_spec.rb'
- 'spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb' - 'spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb'
- 'spec/lib/bitbucket_server/representation/pull_request_spec.rb' - 'spec/lib/bitbucket_server/representation/pull_request_spec.rb'
- 'spec/lib/bulk_imports/groups/pipelines/group_attributes_pipeline_spec.rb' - 'spec/lib/bulk_imports/groups/pipelines/group_attributes_pipeline_spec.rb'

View File

@ -1586,7 +1586,6 @@ RSpec/NamedSubject:
- 'spec/lib/bitbucket_server/collection_spec.rb' - 'spec/lib/bitbucket_server/collection_spec.rb'
- 'spec/lib/bitbucket_server/connection_spec.rb' - 'spec/lib/bitbucket_server/connection_spec.rb'
- 'spec/lib/bitbucket_server/representation/activity_spec.rb' - 'spec/lib/bitbucket_server/representation/activity_spec.rb'
- 'spec/lib/bitbucket_server/representation/comment_spec.rb'
- 'spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb' - 'spec/lib/bitbucket_server/representation/pull_request_comment_spec.rb'
- 'spec/lib/bitbucket_server/representation/pull_request_spec.rb' - 'spec/lib/bitbucket_server/representation/pull_request_spec.rb'
- 'spec/lib/bitbucket_server/representation/repo_spec.rb' - 'spec/lib/bitbucket_server/representation/repo_spec.rb'

View File

@ -27,7 +27,6 @@ RSpec/RepeatedExampleGroupBody:
- 'spec/lib/api/entities/application_setting_spec.rb' - 'spec/lib/api/entities/application_setting_spec.rb'
- 'spec/lib/banzai/filter/references/commit_range_reference_filter_spec.rb' - 'spec/lib/banzai/filter/references/commit_range_reference_filter_spec.rb'
- 'spec/lib/banzai/filter/references/commit_reference_filter_spec.rb' - 'spec/lib/banzai/filter/references/commit_reference_filter_spec.rb'
- 'spec/lib/bitbucket_server/representation/comment_spec.rb'
- 'spec/lib/gitlab/blob_helper_spec.rb' - 'spec/lib/gitlab/blob_helper_spec.rb'
- 'spec/lib/gitlab/ci/config/entry/release_spec.rb' - 'spec/lib/gitlab/ci/config/entry/release_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/seed/build_spec.rb' - 'spec/lib/gitlab/ci/pipeline/seed/build_spec.rb'

View File

@ -146,7 +146,10 @@ module VisibilityLevelHelper
def project_visibility_level_description(level) def project_visibility_level_description(level)
case level case level
when Gitlab::VisibilityLevel::PRIVATE when Gitlab::VisibilityLevel::PRIVATE
s_("VisibilityLevel|Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group.") s_(
"VisibilityLevel|Project access must be granted explicitly to each user. " \
"If this project is part of a group, access is granted to members of the group."
)
when Gitlab::VisibilityLevel::INTERNAL when Gitlab::VisibilityLevel::INTERNAL
s_("VisibilityLevel|The project can be accessed by any logged in user except external users.") s_("VisibilityLevel|The project can be accessed by any logged in user except external users.")
when Gitlab::VisibilityLevel::PUBLIC when Gitlab::VisibilityLevel::PUBLIC
@ -155,7 +158,9 @@ module VisibilityLevelHelper
end end
def show_updated_public_description_for_setting(group) def show_updated_public_description_for_setting(group)
group && !group.new_record? && Gitlab::CurrentSettings.current_application_settings.try(:should_check_namespace_plan?) group &&
!group.new_record? &&
Gitlab::CurrentSettings.current_application_settings.try(:should_check_namespace_plan?)
end end
def group_visibility_level_description(level, group = nil) def group_visibility_level_description(level, group = nil)
@ -163,7 +168,9 @@ module VisibilityLevelHelper
when Gitlab::VisibilityLevel::PRIVATE when Gitlab::VisibilityLevel::PRIVATE
s_("VisibilityLevel|The group and its projects can only be viewed by members.") s_("VisibilityLevel|The group and its projects can only be viewed by members.")
when Gitlab::VisibilityLevel::INTERNAL when Gitlab::VisibilityLevel::INTERNAL
s_("VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users.") s_(
"VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users."
)
when Gitlab::VisibilityLevel::PUBLIC when Gitlab::VisibilityLevel::PUBLIC
unless show_updated_public_description_for_setting(group) unless show_updated_public_description_for_setting(group)
return s_('VisibilityLevel|The group and any public projects can be viewed without any authentication.') return s_('VisibilityLevel|The group and any public projects can be viewed without any authentication.')
@ -171,12 +178,16 @@ module VisibilityLevelHelper
Kernel.format( Kernel.format(
s_( s_(
'VisibilityLevel|The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication. ' \ 'VisibilityLevel|The group, any public projects, and any of their members, issues, ' \
'and merge requests can be viewed without authentication. ' \
'Public groups and projects will be indexed by search engines. ' \ 'Public groups and projects will be indexed by search engines. ' \
'Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, ' \ 'Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, ' \
'or %{group_billings_link_start}upgrade to a paid tier%{link_end}.'), 'or %{group_billings_link_start}upgrade to a paid tier%{link_end}.'
free_user_limit_doc_link_start: "<a href='#{help_page_path('user/free_user_limit.md')}' target='_blank' rel='noopener noreferrer'>".html_safe, ),
group_billings_link_start: "<a href='#{group_billings_path(group)}' target='_blank' rel='noopener noreferrer'>".html_safe, free_user_limit_doc_link_start: "<a href='#{help_page_path('user/free_user_limit.md')}' target='_blank' " \
"rel='noopener noreferrer'>".html_safe,
group_billings_link_start: "<a href='#{group_billings_path(group)}' target='_blank' " \
"rel='noopener noreferrer'>".html_safe,
link_end: "</a>".html_safe link_end: "</a>".html_safe
).html_safe ).html_safe
end end

View File

@ -36,7 +36,9 @@ module WhatsNewHelper
when 'current_tier' when 'current_tier'
_("Only include features new to your current subscription tier.") _("Only include features new to your current subscription tier.")
when 'disabled' when 'disabled'
_("%{italic_start}What's new%{italic_end} is inactive and cannot be viewed.").html_safe % { italic_start: '<i>'.html_safe, italic_end: '</i>'.html_safe } _("%{italic_start}What's new%{italic_end} is inactive and cannot be viewed.").html_safe % {
italic_start: '<i>'.html_safe, italic_end: '</i>'.html_safe
}
end end
end end
end end

View File

@ -22,7 +22,10 @@ module WikiHelper
end end
def wiki_sidebar_toggle_button def wiki_sidebar_toggle_button
render Pajamas::ButtonComponent.new(icon: 'chevron-double-lg-left', button_options: { class: 'sidebar-toggle js-sidebar-wiki-toggle' }) render Pajamas::ButtonComponent.new(
icon: 'chevron-double-lg-left',
button_options: { class: 'sidebar-toggle js-sidebar-wiki-toggle' }
)
end end
# Produces a pure text breadcrumb for a given page. # Produces a pure text breadcrumb for a given page.
@ -68,14 +71,25 @@ module WikiHelper
link_options = { action: action, direction: reversed_direction } link_options = { action: action, direction: reversed_direction }
render Pajamas::ButtonComponent.new(href: wiki_path(wiki, **link_options), icon: "sort-#{icon_class}", button_options: { class: link_class, title: title }) render Pajamas::ButtonComponent.new(
href: wiki_path(wiki, **link_options),
icon: "sort-#{icon_class}",
button_options: { class: link_class, title: title }
)
end end
def wiki_empty_state_messages(wiki) def wiki_empty_state_messages(wiki)
case wiki.container case wiki.container
when Project when Project
writable_body = s_("WikiEmpty|Use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.") writable_body = s_(
writable_body += s_("WikiEmpty| Have a Confluence wiki already? Use that instead.") if show_enable_confluence_integration?(wiki.container) "WikiEmpty|Use GitLab Wiki to collaborate on documentation in a project or group. " \
"You can store wiki pages written in markup formats like Markdown or AsciiDoc in a " \
"separate Git repository, and access the wiki through Git, the GitLab web interface, or the API."
)
if show_enable_confluence_integration?(wiki.container)
writable_body += s_("WikiEmpty| Have a Confluence wiki already? Use that instead.")
end
{ {
writable: { writable: {
@ -84,18 +98,29 @@ module WikiHelper
}, },
readonly: { readonly: {
title: s_('WikiEmpty|This wiki doesn\'t have any content yet'), title: s_('WikiEmpty|This wiki doesn\'t have any content yet'),
body: s_('WikiEmpty|You can use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.') body: s_(
'WikiEmpty|You can use GitLab Wiki to collaborate on documentation in a project or group. ' \
'You can store wiki pages written in markup formats like Markdown or AsciiDoc in a ' \
'separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.'
)
} }
} }
when Group when Group
{ {
writable: { writable: {
title: s_('WikiEmpty|Get started with wikis'), title: s_('WikiEmpty|Get started with wikis'),
body: s_("WikiEmpty|Use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.") body: s_(
"WikiEmpty|Use GitLab Wiki to collaborate on documentation in a project or group. " \
"You can store wiki pages written in markup formats like Markdown or AsciiDoc in a " \
"separate Git repository, and access the wiki through Git, the GitLab web interface, or the API."
)
}, },
readonly: { readonly: {
title: s_('WikiEmpty|This wiki doesn\'t have any content yet'), title: s_('WikiEmpty|This wiki doesn\'t have any content yet'),
body: s_('WikiEmpty|You can use GitLab Wiki to collaborate on documentation in a project or group. You can store wiki pages written in markup formats like Markdown or AsciiDoc in a separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.') body: s_('WikiEmpty|You can use GitLab Wiki to collaborate on documentation in a project or group. ' \
'You can store wiki pages written in markup formats like Markdown or AsciiDoc in a ' \
'separate Git repository, and access the wiki through Git, the GitLab web interface, or the API.'
)
} }
} }
else else

View File

@ -91,7 +91,12 @@ module Emails
email_with_layout( email_with_layout(
to: member.user.notification_email_for(notification_group), to: member.user.notification_email_for(notification_group),
subject: subject(s_("Your membership will expire in %{days_to_expire} days") % { days_to_expire: @days_to_expire })) subject: subject(
s_("Your membership will expire in %{days_to_expire} days") % {
days_to_expire: @days_to_expire
}
)
)
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
@ -115,7 +120,12 @@ module Emails
private private
def member_exists? def member_exists?
Gitlab::AppLogger.info("Tried to send an email invitation for a deleted group. Member id: #{@member_id}") if member.blank? if member.blank?
Gitlab::AppLogger.info(
"Tried to send an email invitation for a deleted group. Member id: #{@member_id}"
)
end
member.present? member.present?
end end

View File

@ -25,7 +25,16 @@ module Emails
end end
# existing_commits - an array containing the first and last commits # existing_commits - an array containing the first and last commits
def push_to_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil, new_commits:, total_new_commits_count:, existing_commits:, total_existing_commits_count:) def push_to_merge_request_email(
recipient_id,
merge_request_id,
updated_by_user_id,
reason = nil,
new_commits:,
total_new_commits_count:,
existing_commits:,
total_existing_commits_count:
)
setup_merge_request_mail(merge_request_id, recipient_id) setup_merge_request_mail(merge_request_id, recipient_id)
@new_commits = new_commits @new_commits = new_commits
@ -49,7 +58,13 @@ module Emails
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_ids, updated_by_user_id, reason = nil) def reassigned_merge_request_email(
recipient_id,
merge_request_id,
previous_assignee_ids,
updated_by_user_id,
reason = nil
)
setup_merge_request_mail(merge_request_id, recipient_id) setup_merge_request_mail(merge_request_id, recipient_id)
previous_assignees = [] previous_assignees = []
@ -62,7 +77,13 @@ module Emails
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def changed_reviewer_of_merge_request_email(recipient_id, merge_request_id, previous_reviewer_ids, updated_by_user_id, reason = nil) def changed_reviewer_of_merge_request_email(
recipient_id,
merge_request_id,
previous_reviewer_ids,
updated_by_user_id,
reason = nil
)
setup_merge_request_mail(merge_request_id, recipient_id) setup_merge_request_mail(merge_request_id, recipient_id)
@previous_reviewers = [] @previous_reviewers = []
@ -87,7 +108,13 @@ module Emails
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, reason)) mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, reason))
end end
def changed_milestone_merge_request_email(recipient_id, merge_request_id, milestone, updated_by_user_id, reason = nil) def changed_milestone_merge_request_email(
recipient_id,
merge_request_id,
milestone,
updated_by_user_id,
reason = nil
)
setup_merge_request_mail(merge_request_id, recipient_id) setup_merge_request_mail(merge_request_id, recipient_id)
@milestone = milestone @milestone = milestone

View File

@ -46,7 +46,10 @@ module Emails
@domain = domain @domain = domain
@project = domain.project @project = domain.project
subject_text = _("ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'") % { domain: domain.domain } subject_text = _(
"ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for " \
"GitLab Pages domain '%{domain}'"
) % { domain: domain.domain }
mail_with_locale( mail_with_locale(
to: recipient.notification_email_for(@project.group), to: recipient.notification_email_for(@project.group),
subject: subject(subject_text) subject: subject(subject_text)

View File

@ -93,7 +93,10 @@ module Emails
@target_url = user_settings_personal_access_tokens_url @target_url = user_settings_personal_access_tokens_url
@token_name = token_name @token_name = token_name
email_with_layout(to: @user.notification_email_or_default, subject: subject(_("A new personal access token has been created"))) email_with_layout(
to: @user.notification_email_or_default,
subject: subject(_("A new personal access token has been created"))
)
end end
def access_token_about_to_expire_email(user, token_names, params = {}) def access_token_about_to_expire_email(user, token_names, params = {})
@ -106,7 +109,14 @@ module Emails
@target_url = user_settings_personal_access_tokens_url @target_url = user_settings_personal_access_tokens_url
@days_to_expire = params.fetch(:days_to_expire, PersonalAccessToken::DAYS_TO_EXPIRE) @days_to_expire = params.fetch(:days_to_expire, PersonalAccessToken::DAYS_TO_EXPIRE)
email_with_layout(to: @user.notification_email_or_default, subject: subject(_("Your personal access tokens will expire in %{days_to_expire} days or less") % { days_to_expire: @days_to_expire })) email_with_layout(
to: @user.notification_email_or_default,
subject: subject(
_("Your personal access tokens will expire in %{days_to_expire} days or less") % {
days_to_expire: @days_to_expire
}
)
)
end end
def access_token_expired_email(user, token_names = []) def access_token_expired_email(user, token_names = [])
@ -116,7 +126,10 @@ module Emails
@token_names = token_names @token_names = token_names
@target_url = user_settings_personal_access_tokens_url @target_url = user_settings_personal_access_tokens_url
email_with_layout(to: @user.notification_email_or_default, subject: subject(_("Your personal access tokens have expired"))) email_with_layout(
to: @user.notification_email_or_default,
subject: subject(_("Your personal access tokens have expired"))
)
end end
def access_token_revoked_email(user, token_name, source = nil) def access_token_revoked_email(user, token_name, source = nil)
@ -127,7 +140,10 @@ module Emails
@target_url = user_settings_personal_access_tokens_url @target_url = user_settings_personal_access_tokens_url
@source = source @source = source
email_with_layout(to: @user.notification_email_or_default, subject: subject(_("Your personal access token has been revoked"))) email_with_layout(
to: @user.notification_email_or_default,
subject: subject(_("Your personal access token has been revoked"))
)
end end
def ssh_key_expired_email(user, fingerprints) def ssh_key_expired_email(user, fingerprints)
@ -170,7 +186,12 @@ module Emails
email_with_layout( email_with_layout(
to: @user.notification_email_or_default, to: @user.notification_email_or_default,
subject: subject(_("Attempted sign in to %{host} using an incorrect verification code") % { host: Gitlab.config.gitlab.host })) subject: subject(
_("Attempted sign in to %{host} using an incorrect verification code") % {
host: Gitlab.config.gitlab.host
}
)
)
end end
def disabled_two_factor_email(user) def disabled_two_factor_email(user)
@ -178,7 +199,10 @@ module Emails
@user = user @user = user
email_with_layout(to: @user.notification_email_or_default, subject: subject(_("Two-factor authentication disabled"))) email_with_layout(
to: @user.notification_email_or_default,
subject: subject(_("Two-factor authentication disabled"))
)
end end
def new_email_address_added_email(user, email) def new_email_address_added_email(user, email)
@ -198,7 +222,12 @@ module Emails
email_with_layout( email_with_layout(
to: @user.notification_email_or_default, to: @user.notification_email_or_default,
subject: subject(s_("Achievements|%{namespace_full_path} awarded you the %{achievement_name} achievement") % { namespace_full_path: @achievement.namespace.full_path, achievement_name: @achievement.name })) subject: subject(
s_("Achievements|%{namespace_full_path} awarded you the %{achievement_name} achievement") % {
namespace_full_path: @achievement.namespace.full_path, achievement_name: @achievement.name
}
)
)
end end
end end
end end

View File

@ -60,7 +60,13 @@ class NotifyPreview < ActionMailer::Preview
diff_refs: merge_request.diff_refs diff_refs: merge_request.diff_refs
) )
create_note(noteable_type: 'merge_request', noteable_id: merge_request.id, type: 'DiffNote', position: position, note: note) create_note(
noteable_type: 'merge_request',
noteable_id: merge_request.id,
type: 'DiffNote',
position: position,
note: note
)
end end
end end
@ -119,7 +125,12 @@ class NotifyPreview < ActionMailer::Preview
end end
def issues_csv_email def issues_csv_email
Notify.issues_csv_email(user, project, '1997,Ford,E350', { truncated: false, rows_expected: 3, rows_written: 3 }).message Notify.issues_csv_email(
user,
project,
'1997,Ford,E350',
{ truncated: false, rows_expected: 3, rows_written: 3 }
).message
end end
def new_issue_email def new_issue_email
@ -190,7 +201,12 @@ class NotifyPreview < ActionMailer::Preview
def pages_domain_enabled_email def pages_domain_enabled_email
cleanup do cleanup do
pages_domain = PagesDomain.new(domain: 'my.example.com', project: project, verified_at: Time.now, enabled_until: 1.week.from_now) pages_domain = PagesDomain.new(
domain: 'my.example.com',
project: project,
verified_at: Time.now,
enabled_until: 1.week.from_now
)
Notify.pages_domain_enabled_email(pages_domain, user).message Notify.pages_domain_enabled_email(pages_domain, user).message
end end
@ -350,7 +366,10 @@ class NotifyPreview < ActionMailer::Preview
end end
def github_gists_import_errors_email def github_gists_import_errors_email
Notify.github_gists_import_errors_email(user.id, { '12345' => 'Snippet maximum file count exceeded', '67890' => 'error message 2' }).message Notify.github_gists_import_errors_email(
user.id,
{ '12345' => 'Snippet maximum file count exceeded', '67890' => 'error message 2' }
).message
end end
def bulk_import_complete def bulk_import_complete
@ -414,7 +433,8 @@ class NotifyPreview < ActionMailer::Preview
end end
def custom_email_verification def custom_email_verification
@custom_email_verification ||= project.service_desk_custom_email_verification || ServiceDesk::CustomEmailVerification.create!( @custom_email_verification ||= project.service_desk_custom_email_verification ||
ServiceDesk::CustomEmailVerification.create!(
project: project, project: project,
token: 'XXXXXXXXXXXX', token: 'XXXXXXXXXXXX',
triggerer: user, triggerer: user,
@ -424,7 +444,8 @@ class NotifyPreview < ActionMailer::Preview
end end
def custom_email_credential def custom_email_credential
@custom_email_credential ||= project.service_desk_custom_email_credential || ServiceDesk::CustomEmailCredential.create!( @custom_email_credential ||= project.service_desk_custom_email_credential ||
ServiceDesk::CustomEmailCredential.create!(
project: project, project: project,
smtp_address: 'smtp.gmail.com', # Use gmail, because Gitlab::HTTP_V2::UrlBlocker resolves DNS smtp_address: 'smtp.gmail.com', # Use gmail, because Gitlab::HTTP_V2::UrlBlocker resolves DNS
smtp_port: 587, smtp_port: 587,

View File

@ -4,9 +4,16 @@ class Analytics::CycleAnalytics::Aggregation < ApplicationRecord
include FromUnion include FromUnion
include Analytics::CycleAnalytics::Parentable include Analytics::CycleAnalytics::Parentable
validates :incremental_runtimes_in_seconds, :incremental_processed_records, :full_runtimes_in_seconds, :full_processed_records, presence: true, length: { maximum: 10 }, allow_blank: true validates :incremental_runtimes_in_seconds,
:incremental_processed_records,
:full_runtimes_in_seconds,
:full_processed_records,
presence: true,
length: { maximum: 10 },
allow_blank: true
scope :priority_order, ->(column_to_sort = :last_incremental_run_at) { order(arel_table[column_to_sort].asc.nulls_first) } scope :priority_order,
->(column_to_sort = :last_incremental_run_at) { order(arel_table[column_to_sort].asc.nulls_first) }
scope :enabled, -> { where('enabled IS TRUE') } scope :enabled, -> { where('enabled IS TRUE') }
def cursor_for(mode, model) def cursor_for(mode, model)

View File

@ -14,7 +14,8 @@ module Analytics
scope :assigned_to, ->(user) do scope :assigned_to, ->(user) do
assignees_class = IssueAssignee assignees_class = IssueAssignee
condition = assignees_class.where(user_id: user).where(arel_table[:issue_id].eq(assignees_class.arel_table[:issue_id])) condition = assignees_class.where(user_id: user)
.where(arel_table[:issue_id].eq(assignees_class.arel_table[:issue_id]))
where(condition.arel.exists) where(condition.arel.exists)
end end

View File

@ -6,10 +6,6 @@ module Ci
storage_location :ci_secure_files storage_location :ci_secure_files
# TODO: Remove this line
# See https://gitlab.com/gitlab-org/gitlab/-/issues/232917
alias_method :upload, :model
# Use Lockbox to encrypt/decrypt the stored file (registers CarrierWave callbacks) # Use Lockbox to encrypt/decrypt the stored file (registers CarrierWave callbacks)
encrypt(key: :key) encrypt(key: :key)

View File

@ -6,10 +6,6 @@ module Terraform
storage_location :terraform_state storage_location :terraform_state
# TODO: Remove this line
# See https://gitlab.com/gitlab-org/gitlab/-/issues/232917
alias_method :upload, :model
delegate :terraform_state, :project_id, to: :model delegate :terraform_state, :project_id, to: :model
# Use Lockbox to encrypt/decrypt the stored file (registers CarrierWave callbacks) # Use Lockbox to encrypt/decrypt the stored file (registers CarrierWave callbacks)

View File

@ -5,6 +5,11 @@
reporter: trizzi # (required) GitLab username of the person reporting the deprecation reporter: trizzi # (required) GitLab username of the person reporting the deprecation
stage: Package # (required) String value of the stage that the feature was created in. e.g., Growth stage: Package # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414236 # (required) Link to the deprecation issue in GitLab issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414236 # (required) Link to the deprecation issue in GitLab
impact: low
scope: group
resolution_role: developer
manual_task: true
window: "3"
body: | # (required) Do not modify this line, instead modify the lines below. body: | # (required) Do not modify this line, instead modify the lines below.
You can use GraphQL to query the amount of storage used by the GitLab Dependency Proxy. However, the `dependencyProxyTotalSizeInBytes` field is limited to ~2Gb (in bytes), which is not always large enough for the Dependency Proxy. As a result, `dependencyProxyTotalSizeInBytes` is deprecated and will be removed in GitLab 17.0. You can use GraphQL to query the amount of storage used by the GitLab Dependency Proxy. However, the `dependencyProxyTotalSizeInBytes` field is limited to ~2Gb (in bytes), which is not always large enough for the Dependency Proxy. As a result, `dependencyProxyTotalSizeInBytes` is deprecated and will be removed in GitLab 17.0.

View File

@ -0,0 +1,16 @@
- title: "Removal of `migrationState` field in `ContainerRepository` GraphQL API"
announcement_milestone: "17.6"
removal_milestone: "18.0"
breaking_change: true
reporter: trizzi
stage: Package
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/459869
impact: low
scope: project
resolution_role: developer
manual_task: true
window: "3"
body: |
The `migrationState` field in the `ContainerRepositoryType` of GitLab's GraphQL API will be removed in GitLab 18.0. This deprecation is part of our efforts to streamline and improve our API.
To prepare for this change, we recommend reviewing and updating your GraphQL queries that interact with the `ContainerRepositoryType`. Remove any references to the `migrationState` field and adjust your application logic accordingly.

View File

@ -0,0 +1,8 @@
---
migration_job_name: RequeueBackfillSecurityFindingsProjectId
description: Backfills sharding key `security_findings.project_id` from `vulnerability_scanners`.
feature_category: vulnerability_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/171503
milestone: '17.6'
queued_migration_version: 20241104065605
finalized_by: # version of the migration that finalized this BBM

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class UpdateAdminBotUserConfirmed < Gitlab::Database::Migration[2.2]
restrict_gitlab_migration gitlab_schema: :gitlab_main
milestone '17.6'
def up
execute <<~SQL
UPDATE "users" SET "confirmed_at" = now(), "private_profile" = TRUE WHERE "users"."user_type" = 11
SQL
end
def down
# noop
end
end

View File

@ -10,31 +10,12 @@ class QueueBackfillSecurityFindingsProjectId < Gitlab::Database::Migration[2.2]
SUB_BATCH_SIZE = 100 SUB_BATCH_SIZE = 100
def up def up
queue_batched_background_migration( # no-op because there was a bug in the original migration, which has been
MIGRATION, # fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/171503
:security_findings,
:id,
:project_id,
:vulnerability_scanners,
:project_id,
:scanner_id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end end
def down def down
delete_batched_background_migration( # no-op because there was a bug in the original migration, which has been
MIGRATION, # fixed by https://gitlab.com/gitlab-org/gitlab/-/merge_requests/171503
:security_findings,
:id,
[
:project_id,
:vulnerability_scanners,
:project_id,
:scanner_id
]
)
end end
end end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
class RequeueBackfillSecurityFindingsProjectId < Gitlab::Database::Migration[2.2]
milestone '17.6'
restrict_gitlab_migration gitlab_schema: :gitlab_sec
MIGRATION = "BackfillSecurityFindingsProjectId"
DELAY_INTERVAL = 2.minutes
TABLE_NAME = :security_findings
BATCH_COLUMN = :id
MAX_BATCH_SIZE = 150_000
GITLAB_OPTIMIZED_BATCH_SIZE = 50_000
GITLAB_OPTIMIZED_SUB_BATCH_SIZE = 250
JOB_ARGS = %i[project_id vulnerability_scanners project_id scanner_id]
def up
delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, JOB_ARGS)
queue_batched_background_migration(
MIGRATION,
TABLE_NAME,
BATCH_COLUMN,
*JOB_ARGS,
job_interval: DELAY_INTERVAL,
max_batch_size: MAX_BATCH_SIZE,
batch_size: GITLAB_OPTIMIZED_BATCH_SIZE,
sub_batch_size: GITLAB_OPTIMIZED_SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, JOB_ARGS)
end
end

View File

@ -0,0 +1 @@
93fc508504c8fb566244c2528d5b78d74c541d10f3e4a769c32fc18de464eedc

View File

@ -0,0 +1 @@
9428a6ad7128e71a67a2c23903ad1318a008f79b54d1bf9558d802cc378d9da3

View File

@ -2338,6 +2338,12 @@ You **turn on** or **turn off** a toggle. For example:
- Turn on the **blah** toggle. - Turn on the **blah** toggle.
## top-level group
Use lowercase for **top-level group** (hyphenated).
Do not use **root group**.
## TFA, two-factor authentication ## TFA, two-factor authentication
Use [**2FA** and **two-factor authentication**](#2fa-two-factor-authentication) instead. Use [**2FA** and **two-factor authentication**](#2fa-two-factor-authentication) instead.

View File

@ -20,7 +20,7 @@ GitLab offers two Jira integrations. You can use one or both integrations
### Jira issues integration ### Jira issues integration
> - Name [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166555) to Jira issues integration in GitLab 17.6. > - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166555) feature name to Jira issues integration in GitLab 17.6.
You can use the [Jira issues integration](configure.md) developed by GitLab with You can use the [Jira issues integration](configure.md) developed by GitLab with
Jira Cloud, Jira Data Center, or Jira Server. With this integration, you can: Jira Cloud, Jira Data Center, or Jira Server. With this integration, you can:

View File

@ -632,6 +632,24 @@ This change is a breaking change. You should [create a runner in the UI](https:/
<div class="deprecation breaking-change" data-milestone="18.0"> <div class="deprecation breaking-change" data-milestone="18.0">
### Removal of `migrationState` field in `ContainerRepository` GraphQL API
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">17.6</span>
- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/459869).
</div>
The `migrationState` field in the `ContainerRepositoryType` of GitLab's GraphQL API will be removed in GitLab 18.0. This deprecation is part of our efforts to streamline and improve our API.
To prepare for this change, we recommend reviewing and updating your GraphQL queries that interact with the `ContainerRepositoryType`. Remove any references to the `migrationState` field and adjust your application logic accordingly.
</div>
<div class="deprecation breaking-change" data-milestone="18.0">
### Remove `previousStageJobsOrNeeds` from GraphQL ### Remove `previousStageJobsOrNeeds` from GraphQL
<div class="deprecation-notes"> <div class="deprecation-notes">

View File

@ -11,7 +11,8 @@ module API
before { authenticate_non_get! } before { authenticate_non_get! }
allow_access_with_scope :ai_workflows, if: ->(request) do allow_access_with_scope :ai_workflows, if: ->(request) do
request.get? || request.head? || request.put? request.get? || request.head? ||
(request.put? && request.path.match?(%r{/api/v\d+/projects/\d+/merge_requests/\d+$})) # Only allow basic MR updates
end end
rescue_from ActiveRecord::QueryCanceled do |_e| rescue_from ActiveRecord::QueryCanceled do |_e|
@ -713,8 +714,7 @@ module API
merge_request = find_project_merge_request(params[:merge_request_iid]) merge_request = find_project_merge_request(params[:merge_request_iid])
# Merge request can not be merged because the user doesn't have # Merge request can not be merged because the user doesn't have
# permissions to push into target branch # permissions to push into target branch.
#
unauthorized! unless merge_request.can_be_merged_by?(current_user) unauthorized! unless merge_request.can_be_merged_by?(current_user)
merge_when_pipeline_succeeds = to_boolean(params[:merge_when_pipeline_succeeds]) merge_when_pipeline_succeeds = to_boolean(params[:merge_when_pipeline_succeeds])

View File

@ -8,10 +8,10 @@ module API
include ::API::Helpers::RelatedResourcesHelpers include ::API::Helpers::RelatedResourcesHelpers
expose :url do |setting| expose :url do |setting|
expose_path(api_v4_vscode_settings_sync_v1_resource_path( resource_name = setting[:setting_type]
resource_name: setting[:setting_type], id = setting[:uuid]
id: setting[:uuid] path = "/api/v4/vscode/settings_sync/v1/resource/#{resource_name}/#{id}"
)) expose_path(path)
end end
expose :created do |setting| expose :created do |setting|
setting[:updated_at]&.to_i setting[:updated_at]&.to_i

View File

@ -24,7 +24,7 @@ module API
end end
resource :vscode do resource :vscode do
resource :settings_sync do resource '/settings_sync(/:settings_context_hash)' do
content_type :json, 'application/json' content_type :json, 'application/json'
content_type :json, 'text/plain' content_type :json, 'text/plain'

View File

@ -35,6 +35,14 @@ module BitbucketServer
commit.dig('committer', 'displayName') commit.dig('committer', 'displayName')
end end
def committer_name
commit.dig('committer', 'displayName')
end
def committer_username
commit.dig('committer', 'slug')
end
def committer_email def committer_email
commit.dig('committer', 'emailAddress') commit.dig('committer', 'emailAddress')
end end
@ -53,6 +61,10 @@ module BitbucketServer
action == 'APPROVED' action == 'APPROVED'
end end
def approver_name
raw.dig('user', 'displayName')
end
def approver_username def approver_username
raw.dig('user', 'slug') raw.dig('user', 'slug')
end end
@ -65,6 +77,10 @@ module BitbucketServer
action == 'DECLINED' action == 'DECLINED'
end end
def decliner_name
raw.dig('user', 'displayName')
end
def decliner_username def decliner_username
raw.dig('user', 'slug') raw.dig('user', 'slug')
end end
@ -80,12 +96,16 @@ module BitbucketServer
def to_hash def to_hash
{ {
id: id, id: id,
committer_name: committer_user,
committer_user: committer_user, committer_user: committer_user,
committer_username: committer_username,
committer_email: committer_email, committer_email: committer_email,
merge_timestamp: merge_timestamp, merge_timestamp: merge_timestamp,
merge_commit: merge_commit, merge_commit: merge_commit,
approver_name: approver_name,
approver_username: approver_username, approver_username: approver_username,
approver_email: approver_email, approver_email: approver_email,
decliner_name: decliner_name,
decliner_username: decliner_username, decliner_username: decliner_username,
decliner_email: decliner_email, decliner_email: decliner_email,
created_at: created_at created_at: created_at

View File

@ -37,6 +37,10 @@ module BitbucketServer
raw_comment['id'] raw_comment['id']
end end
def author_name
author['displayName']
end
def author_username def author_username
author['username'] || author['username'] ||
author['slug'] || author['slug'] ||
@ -81,6 +85,7 @@ module BitbucketServer
{ {
id: id, id: id,
author_name: author_name,
author_email: author_email, author_email: author_email,
author_username: author_username, author_username: author_username,
note: note, note: note,

View File

@ -5,6 +5,14 @@ module Gitlab
class BackfillSecurityFindingsProjectId < BackfillDesiredShardingKeyJob class BackfillSecurityFindingsProjectId < BackfillDesiredShardingKeyJob
operation_name :backfill_security_findings_project_id operation_name :backfill_security_findings_project_id
feature_category :vulnerability_management feature_category :vulnerability_management
scope_to ->(relation) { relation }
def perform
each_sub_batch do |sub_batch|
sub_batch.connection.execute(construct_query(sub_batch: sub_batch.where(backfill_column => nil)))
end
end
end end
end end
end end

View File

@ -49,6 +49,8 @@ RSpec.describe BitbucketServer::Representation::Activity, feature_category: :imp
it { expect(subject.comment?).to be_falsey } it { expect(subject.comment?).to be_falsey }
it { expect(subject.inline_comment?).to be_falsey } it { expect(subject.inline_comment?).to be_falsey }
it { expect(subject.committer_user).to eq('root') } it { expect(subject.committer_user).to eq('root') }
it { expect(subject.committer_name).to eq('root') }
it { expect(subject.committer_username).to eq('slug') }
it { expect(subject.committer_email).to eq('test.user@example.com') } it { expect(subject.committer_email).to eq('test.user@example.com') }
it { expect(subject.merge_timestamp).to be_a(Time) } it { expect(subject.merge_timestamp).to be_a(Time) }
it { expect(subject.created_at).to be_a(Time) } it { expect(subject.created_at).to be_a(Time) }
@ -60,6 +62,8 @@ RSpec.describe BitbucketServer::Representation::Activity, feature_category: :imp
a_hash_including( a_hash_including(
id: 7, id: 7,
committer_user: 'root', committer_user: 'root',
committer_name: 'root',
committer_username: 'slug',
committer_email: 'test.user@example.com', committer_email: 'test.user@example.com',
merge_commit: '839fa9a2d434eb697815b8fcafaecc51accfdbbc' merge_commit: '839fa9a2d434eb697815b8fcafaecc51accfdbbc'
) )
@ -76,6 +80,7 @@ RSpec.describe BitbucketServer::Representation::Activity, feature_category: :imp
it { expect(subject.inline_comment?).to be_falsey } it { expect(subject.inline_comment?).to be_falsey }
it { expect(subject.merge_event?).to be_falsey } it { expect(subject.merge_event?).to be_falsey }
it { expect(subject.approved_event?).to be_truthy } it { expect(subject.approved_event?).to be_truthy }
it { expect(subject.approver_name).to eq('root') }
it { expect(subject.approver_username).to eq('slug') } it { expect(subject.approver_username).to eq('slug') }
it { expect(subject.approver_email).to eq('test.user@example.com') } it { expect(subject.approver_email).to eq('test.user@example.com') }
it { expect(subject.created_at).to be_a(Time) } it { expect(subject.created_at).to be_a(Time) }
@ -85,6 +90,7 @@ RSpec.describe BitbucketServer::Representation::Activity, feature_category: :imp
expect(subject.to_hash).to match( expect(subject.to_hash).to match(
a_hash_including( a_hash_including(
id: 15, id: 15,
approver_name: 'root',
approver_username: 'slug', approver_username: 'slug',
approver_email: 'test.user@example.com' approver_email: 'test.user@example.com'
) )
@ -101,6 +107,7 @@ RSpec.describe BitbucketServer::Representation::Activity, feature_category: :imp
it { expect(subject.inline_comment?).to be_falsey } it { expect(subject.inline_comment?).to be_falsey }
it { expect(subject.merge_event?).to be_falsey } it { expect(subject.merge_event?).to be_falsey }
it { expect(subject.declined_event?).to be_truthy } it { expect(subject.declined_event?).to be_truthy }
it { expect(subject.decliner_name).to eq('root') }
it { expect(subject.decliner_username).to eq('slug') } it { expect(subject.decliner_username).to eq('slug') }
it { expect(subject.decliner_email).to eq('test.user@example.com') } it { expect(subject.decliner_email).to eq('test.user@example.com') }
it { expect(subject.created_at).to be_a(Time) } it { expect(subject.created_at).to be_a(Time) }
@ -110,6 +117,7 @@ RSpec.describe BitbucketServer::Representation::Activity, feature_category: :imp
expect(subject.to_hash).to match( expect(subject.to_hash).to match(
a_hash_including( a_hash_including(
id: 18, id: 18,
decliner_name: 'root',
decliner_username: 'slug', decliner_username: 'slug',
decliner_email: 'test.user@example.com' decliner_email: 'test.user@example.com'
) )

View File

@ -6,15 +6,19 @@ RSpec.describe BitbucketServer::Representation::Comment, feature_category: :impo
let(:activities) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/activities.json'))['values'] } let(:activities) { Gitlab::Json.parse(fixture_file('importers/bitbucket_server/activities.json'))['values'] }
let(:comment) { activities.first } let(:comment) { activities.first }
subject { described_class.new(comment) } subject(:comment_representation) { described_class.new(comment) }
describe '#id' do describe '#id' do
it { expect(subject.id).to eq(9) } it { expect(comment_representation.id).to eq(9) }
end
describe '#author_name' do
it { expect(comment_representation.author_name).to eq('root') }
end end
describe '#author_username' do describe '#author_username' do
it 'returns username' do it 'returns username' do
expect(subject.author_username).to eq('username') expect(comment_representation.author_username).to eq('username')
end end
context 'when username is absent' do context 'when username is absent' do
@ -23,7 +27,7 @@ RSpec.describe BitbucketServer::Representation::Comment, feature_category: :impo
end end
it 'returns slug' do it 'returns slug' do
expect(subject.author_username).to eq('slug') expect(comment_representation.author_username).to eq('slug')
end end
end end
@ -34,55 +38,56 @@ RSpec.describe BitbucketServer::Representation::Comment, feature_category: :impo
end end
it 'returns displayName' do it 'returns displayName' do
expect(subject.author_username).to eq('root') expect(comment_representation.author_username).to eq('root')
end end
end end
end end
describe '#author_email' do describe '#author_email' do
it { expect(subject.author_email).to eq('test.user@example.com') } it { expect(comment_representation.author_email).to eq('test.user@example.com') }
end end
describe '#note' do describe '#note' do
it { expect(subject.note).to eq('is this a new line?') } it { expect(comment_representation.note).to eq('is this a new line?') }
end end
describe '#created_at' do describe '#created_at' do
it { expect(subject.created_at).to be_a(Time) } it { expect(comment_representation.created_at).to be_a(Time) }
end end
describe '#updated_at' do describe '#updated_at' do
it { expect(subject.created_at).to be_a(Time) } it { expect(comment_representation.updated_at).to be_a(Time) }
end end
describe '#comments' do describe '#comments' do
it { expect(subject.comments.count).to eq(4) } it { expect(comment_representation.comments.count).to eq(4) }
it { expect(subject.comments).to all(be_a(described_class)) } it { expect(comment_representation.comments).to all(be_a(described_class)) }
it { expect(subject.comments.map(&:note)).to match_array(["Hello world", "Ok", "hello", "hi"]) } it { expect(comment_representation.comments.map(&:note)).to match_array(["Hello world", "Ok", "hello", "hi"]) }
# The thread should look like: # The thread should look like:
# #
# is this a new line? (subject) # is this a new line? (comment_representation)
# -> Hello world (first) # -> Hello world (first)
# -> Ok (third) # -> Ok (third)
# -> Hi (fourth) # -> Hi (fourth)
# -> hello (second) # -> hello (second)
it 'comments have the right parent' do it 'comments have the right parent' do
first, second, third, fourth = subject.comments[0..4] first, second, third, fourth = comment_representation.comments[0..4]
expect(subject.parent_comment).to be_nil expect(comment_representation.parent_comment).to be_nil
expect(first.parent_comment).to eq(subject) expect(first.parent_comment).to eq(comment_representation)
expect(second.parent_comment).to eq(subject) expect(second.parent_comment).to eq(comment_representation)
expect(third.parent_comment).to eq(first) expect(third.parent_comment).to eq(first)
expect(fourth.parent_comment).to eq(first) expect(fourth.parent_comment).to eq(first)
end end
end end
describe '#to_hash' do describe '#to_hash' do
it do specify do
expect(subject.to_hash).to match( expect(comment_representation.to_hash).to match(
a_hash_including( a_hash_including(
id: 9, id: 9,
author_name: 'root',
author_email: 'test.user@example.com', author_email: 'test.user@example.com',
author_username: 'username', author_username: 'username',
note: 'is this a new line?', note: 'is this a new line?',

View File

@ -6,27 +6,14 @@ require_migration!
RSpec.describe QueueBackfillSecurityFindingsProjectId, migration: :gitlab_sec, feature_category: :vulnerability_management do RSpec.describe QueueBackfillSecurityFindingsProjectId, migration: :gitlab_sec, feature_category: :vulnerability_management do
let!(:batched_migration) { described_class::MIGRATION } let!(:batched_migration) { described_class::MIGRATION }
it 'schedules a new batched migration' do it 'does not schedules a new batched migration' do
reversible_migration do |migration| reversible_migration do |migration|
migration.before -> { migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration expect(batched_migration).not_to have_scheduled_batched_migration
} }
migration.after -> { migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration( expect(batched_migration).not_to have_scheduled_batched_migration
table_name: :security_findings,
column_name: :id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE,
gitlab_schema: :gitlab_sec,
job_arguments: [
:project_id,
:vulnerability_scanners,
:project_id,
:scanner_id
]
)
} }
end end
end end

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe RequeueBackfillSecurityFindingsProjectId, migration: :gitlab_sec, feature_category: :vulnerability_management do
let!(:batched_migration) { described_class::MIGRATION }
let(:expected_job_args) { %i[project_id vulnerability_scanners project_id scanner_id] }
it 'schedules a new batched migration' do
reversible_migration do |migration|
migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration
}
migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration(
table_name: described_class::TABLE_NAME,
column_name: described_class::BATCH_COLUMN,
interval: described_class::DELAY_INTERVAL,
max_batch_size: described_class::MAX_BATCH_SIZE,
batch_size: described_class::GITLAB_OPTIMIZED_BATCH_SIZE,
sub_batch_size: described_class::GITLAB_OPTIMIZED_SUB_BATCH_SIZE,
gitlab_schema: :gitlab_sec,
job_arguments: expected_job_args
)
}
end
end
end

View File

@ -2810,6 +2810,19 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
expect(json_response['reviewers']).to be_empty expect(json_response['reviewers']).to be_empty
end end
end end
context 'with oauth token that has ai_workflows scope' do
let(:token) { create(:oauth_access_token, user: user, scopes: [:ai_workflows]) }
it "allows access" do
put api(
"/projects/#{project.id}/merge_requests/#{merge_request.iid}?title=new_title",
oauth_access_token: token
)
expect(response).to have_gitlab_http_status(:ok)
end
end
end end
describe "POST /projects/:id/merge_requests/:merge_request_iid/context_commits" do describe "POST /projects/:id/merge_requests/:merge_request_iid/context_commits" do
@ -3066,13 +3079,10 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
context 'with oauth token that has ai_workflows scope' do context 'with oauth token that has ai_workflows scope' do
let(:token) { create(:oauth_access_token, user: user, scopes: [:ai_workflows]) } let(:token) { create(:oauth_access_token, user: user, scopes: [:ai_workflows]) }
it "allows access" do it "does not allow access" do
put api( put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", oauth_access_token: token)
"/projects/#{project.id}/merge_requests/#{merge_request.iid}?title=new_title",
oauth_access_token: token
)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:forbidden)
end end
end end
@ -4003,6 +4013,16 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
end end
describe 'PUT :id/merge_requests/:merge_request_iid/rebase' do describe 'PUT :id/merge_requests/:merge_request_iid/rebase' do
context 'with oauth token that has ai_workflows scope' do
let(:token) { create(:oauth_access_token, user: user, scopes: [:ai_workflows]) }
it "does not allow access" do
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/rebase", oauth_access_token: token)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when rebase can be performed' do context 'when rebase can be performed' do
it 'enqueues a rebase of the merge request against the target branch' do it 'enqueues a rebase of the merge request against the target branch' do
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do