Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-04-06 15:08:20 +00:00
parent b161512b30
commit 78782cd1eb
142 changed files with 2089 additions and 782 deletions

View File

@ -628,13 +628,6 @@ Layout/ArgumentAlignment:
- 'app/services/pages/migrate_from_legacy_storage_service.rb'
- 'app/services/post_receive_service.rb'
- 'app/services/preview_markdown_service.rb'
- 'app/services/projects/create_service.rb'
- 'app/services/projects/fork_service.rb'
- 'app/services/projects/hashed_storage/base_repository_service.rb'
- 'app/services/projects/import_service.rb'
- 'app/services/projects/lfs_pointers/lfs_download_link_list_service.rb'
- 'app/services/projects/overwrite_project_service.rb'
- 'app/services/projects/update_remote_mirror_service.rb'
- 'app/services/protected_branches/api_service.rb'
- 'app/services/protected_branches/legacy_api_create_service.rb'
- 'app/services/quick_actions/interpret_service.rb'
@ -1598,10 +1591,6 @@ Layout/ArgumentAlignment:
- 'ee/spec/services/issue_feature_flags/list_service_spec.rb'
- 'ee/spec/services/merge_request_approval_settings/update_service_spec.rb'
- 'ee/spec/services/merge_requests/build_service_spec.rb'
- 'ee/spec/services/projects/create_service_spec.rb'
- 'ee/spec/services/projects/gitlab_projects_import_service_spec.rb'
- 'ee/spec/services/projects/prometheus/alerts/notify_service_spec.rb'
- 'ee/spec/services/projects/restore_service_spec.rb'
- 'ee/spec/services/protected_environments/create_service_spec.rb'
- 'ee/spec/services/protected_environments/update_service_spec.rb'
- 'ee/spec/services/quick_actions/interpret_service_spec.rb'
@ -2694,23 +2683,6 @@ Layout/ArgumentAlignment:
- 'spec/services/pages/migrate_legacy_storage_to_deployment_service_spec.rb'
- 'spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb'
- 'spec/services/preview_markdown_service_spec.rb'
- 'spec/services/projects/all_merge_requests_count_service_spec.rb'
- 'spec/services/projects/container_repository/gitlab/cleanup_tags_service_spec.rb'
- 'spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb'
- 'spec/services/projects/create_service_spec.rb'
- 'spec/services/projects/destroy_service_spec.rb'
- 'spec/services/projects/fork_service_spec.rb'
- 'spec/services/projects/group_links/create_service_spec.rb'
- 'spec/services/projects/group_links/destroy_service_spec.rb'
- 'spec/services/projects/group_links/update_service_spec.rb'
- 'spec/services/projects/hashed_storage/migration_service_spec.rb'
- 'spec/services/projects/lfs_pointers/lfs_link_service_spec.rb'
- 'spec/services/projects/open_merge_requests_count_service_spec.rb'
- 'spec/services/projects/prometheus/alerts/notify_service_spec.rb'
- 'spec/services/projects/transfer_service_spec.rb'
- 'spec/services/projects/unlink_fork_service_spec.rb'
- 'spec/services/projects/update_pages_service_spec.rb'
- 'spec/services/projects/update_service_spec.rb'
- 'spec/services/protected_branches/api_service_spec.rb'
- 'spec/services/push_event_payload_service_spec.rb'
- 'spec/services/quick_actions/interpret_service_spec.rb'
@ -2743,7 +2715,6 @@ Layout/ArgumentAlignment:
- 'spec/support/shared_contexts/merge_request_edit_shared_context.rb'
- 'spec/support/shared_contexts/merge_requests_allowing_collaboration_shared_context.rb'
- 'spec/support/shared_contexts/requests/api/graphql/releases_and_group_releases_shared_context.rb'
- 'spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb'
- 'spec/support/shared_examples/controllers/snippets_sort_order_shared_examples.rb'
- 'spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb'
- 'spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb'

View File

@ -1,9 +1,7 @@
---
Naming/InclusiveLanguage:
Details: grace period
Exclude:
- 'app/controllers/admin/application_settings/appearances_controller.rb'
- 'app/controllers/application_controller.rb'
- 'app/controllers/concerns/requires_whitelisted_monitoring_client.rb'
- 'app/controllers/health_check_controller.rb'
- 'app/controllers/health_controller.rb'
@ -13,7 +11,6 @@ Naming/InclusiveLanguage:
- 'app/helpers/markup_helper.rb'
- 'app/models/application_setting.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/models/clusters/applications/jupyter.rb'
- 'app/models/concerns/cache_markdown_field.rb'
- 'app/services/application_settings/update_service.rb'
- 'app/services/projects/download_service.rb'
@ -37,7 +34,6 @@ Naming/InclusiveLanguage:
- 'lib/api/settings.rb'
- 'lib/banzai/filter/asset_proxy_filter.rb'
- 'lib/gitlab/asset_proxy.rb'
- 'lib/gitlab/auth.rb'
- 'lib/gitlab/auth/ip_rate_limiter.rb'
- 'lib/gitlab/ci/config/external/file/base.rb'
- 'lib/gitlab/git/hook_env.rb'
@ -45,7 +41,6 @@ Naming/InclusiveLanguage:
- 'lib/gitlab/markdown_cache/active_record/extension.rb'
- 'lib/gitlab/markdown_cache/field_data.rb'
- 'lib/gitlab/middleware/basic_health_check.rb'
- 'lib/gitlab/middleware/go.rb'
- 'lib/gitlab/sanitizers/exif.rb'
- 'lib/gitlab/sanitizers/svg.rb'
- 'lib/gitlab/sanitizers/svg/whitelist.rb'
@ -61,7 +56,6 @@ Naming/InclusiveLanguage:
- 'rubocop/cop/ignored_columns.rb'
- 'rubocop/cop/inject_enterprise_edition_module.rb'
- 'rubocop/cop/migration/add_columns_to_wide_tables.rb'
- 'spec/controllers/application_controller_spec.rb'
- 'spec/controllers/concerns/issuable_collections_spec.rb'
- 'spec/controllers/health_check_controller_spec.rb'
- 'spec/controllers/metrics_controller_spec.rb'
@ -70,7 +64,6 @@ Naming/InclusiveLanguage:
- 'spec/lib/banzai/filter/asset_proxy_filter_spec.rb'
- 'spec/lib/gitlab/asset_proxy_spec.rb'
- 'spec/lib/gitlab/auth/ip_rate_limiter_spec.rb'
- 'spec/lib/gitlab/auth_spec.rb'
- 'spec/lib/gitlab/git/hook_env_spec.rb'
- 'spec/lib/gitlab/github_import/markdown/attachment_spec.rb'
- 'spec/lib/gitlab/import_export/attribute_configuration_spec.rb'
@ -81,7 +74,6 @@ Naming/InclusiveLanguage:
- 'spec/lib/gitlab/sanitizers/exif_spec.rb'
- 'spec/lib/system_check/app/git_user_default_ssh_config_check_spec.rb'
- 'spec/models/application_setting_spec.rb'
- 'spec/models/clusters/applications/jupyter_spec.rb'
- 'spec/requests/api/settings_spec.rb'
- 'spec/requests/health_controller_spec.rb'
- 'spec/rubocop/cop/avoid_return_from_blocks_spec.rb'

View File

@ -0,0 +1,9 @@
---
RSpec/SharedGroupsMetadata:
Details: grace period
Exclude:
- 'ee/spec/requests/ee/admin/plan_limits_controller_spec.rb'
- 'ee/spec/support/shared_contexts/saas_registration_settings_context.rb'
- 'spec/lib/gitlab/ci/config/entry/retry_spec.rb'
- 'spec/lib/gitlab/git/merge_base_spec.rb'
- 'spec/models/container_repository_spec.rb'

View File

@ -229,6 +229,7 @@ const defaultSerializerConfig = {
[TableRow.name]: renderTableRow,
[TaskItem.name]: preserveUnchanged((state, node) => {
state.write(`[${node.attrs.checked ? 'x' : ' '}] `);
if (!node.textContent) state.write(' ');
state.renderContent(node);
}),
[TaskList.name]: preserveUnchanged((state, node) => {

View File

@ -87,8 +87,8 @@
.filtered-search-term {
display: flex;
flex-shrink: 0;
margin-top: 4px;
margin-bottom: 4px;
margin-top: 2px;
margin-bottom: 2px;
.selectable {
display: flex;
@ -195,7 +195,7 @@
display: flex;
width: 100%;
min-width: 0;
border: 1px solid $border-color;
border: 1px solid $gray-400;
background-color: $white;
border-radius: $border-radius-default;
@ -206,8 +206,7 @@
&.focus,
&.focus:hover {
border-color: $blue-300;
box-shadow: 0 0 4px $dropdown-input-focus-shadow;
@include gl-focus;
}
gl-emoji {
@ -227,7 +226,7 @@
min-width: 200px;
padding-right: 25px;
padding-left: 0;
height: $input-height;
height: #{$input-height - 2px};
line-height: inherit;
&,
@ -261,7 +260,7 @@
flex: 1;
position: relative;
min-width: 0;
height: 2rem;
height: #{$input-height - 2px};
background-color: $input-bg;
border-radius: $border-radius-default;
}
@ -292,10 +291,11 @@
}
.filtered-search-history-dropdown-toggle-button.gl-button {
border-radius: $border-radius-default 0 0 $border-radius-default;
border-right: 1px solid $border-color;
box-shadow: none;
$inner-border: #{$border-radius-default - 1px};
border-radius: $inner-border 0 0 $inner-border;
color: $gl-text-color-secondary;
margin: -1px 0 -1px -1px;
box-shadow: inset 0 0 0 1px $gray-400;
flex: 1;
transition: color 0.1s linear;
width: auto;
@ -303,7 +303,6 @@
&:hover,
&:focus {
color: $gl-text-color;
border-color: $border-color;
}
}

View File

@ -89,7 +89,7 @@ class ApplicationController < ActionController::Base
render_403
end
rescue_from Gitlab::Auth::IpBlacklisted do
rescue_from Gitlab::Auth::IpBlocked do
Gitlab::AuthLogger.error(
message: 'Rack_Attack',
env: :blocklist,

View File

@ -208,7 +208,7 @@ class ProjectsController < Projects::ApplicationController
end
def new_issuable_address
return render_404 unless Gitlab::IncomingEmail.supports_issue_creation?
return render_404 unless Gitlab::Email::IncomingEmail.supports_issue_creation?
current_user.reset_incoming_email_token!
render json: { new_address: @project.new_issuable_address(current_user, params[:issuable_type]) }

View File

@ -25,6 +25,8 @@ module Groups
groups_with_guest_access_plus
end
groups = by_hierarchy(groups)
groups = by_ignorable(groups)
groups = by_search(groups)
sort(groups).with_route
@ -48,5 +50,25 @@ module Groups
Ability.allowed?(current_user, :admin_project, project_to_be_shared) &&
project_to_be_shared.allowed_to_share_with_group?
end
def by_ignorable(groups)
# groups already linked to this project or groups above the project's
# current hierarchy needs to be ignored.
groups.id_not_in(project_to_be_shared.related_group_ids)
end
def by_hierarchy(groups)
return groups if project_to_be_shared.personal? || sharing_outside_hierarchy_allowed?
groups.id_in(root_ancestor.self_and_descendants_ids)
end
def sharing_outside_hierarchy_allowed?
!root_ancestor.prevent_sharing_groups_outside_hierarchy
end
def root_ancestor
project_to_be_shared.root_ancestor
end
end
end

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
module Resolvers
module Analytics
module CycleAnalytics
class BaseCountResolver < BaseResolver
type Types::Analytics::CycleAnalytics::MetricType, null: true
argument :from, Types::TimeType,
required: true,
description: 'After the date.'
argument :to, Types::TimeType,
required: true,
description: 'Before the date.'
def ready?(**args)
start_date = args[:from]
end_date = args[:to]
if start_date >= end_date
raise Gitlab::Graphql::Errors::ArgumentError,
'`from` argument must be before `to` argument'
end
max_days = Gitlab::Analytics::CycleAnalytics::RequestParams::MAX_RANGE_DAYS
if (end_date.beginning_of_day - start_date.beginning_of_day) > max_days
raise Gitlab::Graphql::Errors::ArgumentError,
"Max of #{max_days.inspect} timespan is allowed"
end
super
end
end
end
end
end

View File

@ -3,7 +3,7 @@
module Resolvers
module Analytics
module CycleAnalytics
class BaseIssueResolver < BaseResolver
class BaseIssueResolver < BaseCountResolver
type Types::Analytics::CycleAnalytics::MetricType, null: true
argument :assignee_usernames, [GraphQL::Types::String],
@ -22,14 +22,6 @@ module Resolvers
required: false,
description: 'Labels applied to the issue.'
argument :from, Types::TimeType,
required: true,
description: 'Issues created after the date.'
argument :to, Types::TimeType,
required: true,
description: 'Issues created before the date.'
def finder_params
{ project_id: object.project.id }
end

View File

@ -1,19 +1,10 @@
# frozen_string_literal: true
# rubocop:disable Graphql/ResolverType (inherited from Resolvers::Analytics::CycleAnalytics::BaseCountResolver)
module Resolvers
module Analytics
module CycleAnalytics
class DeploymentCountResolver < BaseResolver
type Types::Analytics::CycleAnalytics::MetricType, null: true
argument :from, Types::TimeType,
required: true,
description: 'Deployments finished after the date.'
argument :to, Types::TimeType,
required: true,
description: 'Deployments finished before the date.'
class DeploymentCountResolver < BaseCountResolver
def resolve(**args)
value = count(args)
{
@ -57,6 +48,7 @@ module Resolvers
end
end
end
# rubocop:enable Graphql/ResolverType
mod = Resolvers::Analytics::CycleAnalytics::DeploymentCountResolver
mod.prepend_mod_with('Resolvers::Analytics::CycleAnalytics::DeploymentCountResolver')

View File

@ -2,6 +2,6 @@
module AccountsHelper
def incoming_email_token_enabled?
current_user.incoming_email_token && Gitlab::IncomingEmail.supports_issue_creation?
current_user.incoming_email_token && Gitlab::Email::IncomingEmail.supports_issue_creation?
end
end

View File

@ -132,8 +132,8 @@ class Notify < ApplicationMailer
@reason = headers['X-GitLab-NotificationReason']
if Gitlab::IncomingEmail.enabled? && @sent_notification
headers['Reply-To'] = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key)).tap do |address|
if Gitlab::Email::IncomingEmail.enabled? && @sent_notification
headers['Reply-To'] = Mail::Address.new(Gitlab::Email::IncomingEmail.reply_address(reply_key)).tap do |address|
address.display_name = reply_display_name(model)
end
@ -221,8 +221,8 @@ class Notify < ApplicationMailer
return unless !@labels_url && @sent_notification && @sent_notification.unsubscribable?
list_unsubscribe_methods = [unsubscribe_sent_notification_url(@sent_notification, force: true)]
if Gitlab::IncomingEmail.enabled? && Gitlab::IncomingEmail.supports_wildcard?
list_unsubscribe_methods << "mailto:#{Gitlab::IncomingEmail.unsubscribe_address(reply_key)}"
if Gitlab::Email::IncomingEmail.enabled? && Gitlab::Email::IncomingEmail.supports_wildcard?
list_unsubscribe_methods << "mailto:#{Gitlab::Email::IncomingEmail.unsubscribe_address(reply_key)}"
end
headers['List-Unsubscribe'] = list_unsubscribe_methods.map { |e| "<#{e}>" }.join(',')

View File

@ -597,8 +597,14 @@ module Ci
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
.append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false, masked: true)
.append(key: 'CI_JOB_STARTED_AT', value: started_at&.iso8601)
.append(key: 'CI_BUILD_ID', value: id.to_s)
.append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false, masked: true)
if Feature.disabled?(:ci_remove_legacy_predefined_variables, project)
variables
.append(key: 'CI_BUILD_ID', value: id.to_s)
.append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false, masked: true)
end
variables
.append(key: 'CI_REGISTRY_USER', value: ::Gitlab::Auth::CI_JOB_USER)
.append(key: 'CI_REGISTRY_PASSWORD', value: token.to_s, public: false, masked: true)
.append(key: 'CI_REPOSITORY_URL', value: repo_url.to_s, public: false)

View File

@ -1585,7 +1585,7 @@ class Project < ApplicationRecord
end
def new_issuable_address(author, address_type)
return unless Gitlab::IncomingEmail.supports_issue_creation? && author
return unless Gitlab::Email::IncomingEmail.supports_issue_creation? && author
# check since this can come from a request parameter
return unless %w(issue merge_request).include?(address_type)
@ -1596,7 +1596,7 @@ class Project < ApplicationRecord
# example: incoming+h5bp-html5-boilerplate-8-1234567890abcdef123456789-issue@localhost.com
# example: incoming+h5bp-html5-boilerplate-8-1234567890abcdef123456789-merge-request@localhost.com
Gitlab::IncomingEmail.reply_address("#{full_path_slug}-#{project_id}-#{author.incoming_email_token}-#{suffix}")
Gitlab::Email::IncomingEmail.reply_address("#{full_path_slug}-#{project_id}-#{author.incoming_email_token}-#{suffix}")
end
def build_commit_note(commit)
@ -2904,11 +2904,11 @@ class Project < ApplicationRecord
end
def service_desk_custom_address
return unless Gitlab::ServiceDeskEmail.enabled?
return unless Gitlab::Email::ServiceDeskEmail.enabled?
key = service_desk_setting&.project_key || default_service_desk_suffix
Gitlab::ServiceDeskEmail.address_for_key("#{full_path_slug}-#{key}")
Gitlab::Email::ServiceDeskEmail.address_for_key("#{full_path_slug}-#{key}")
end
def default_service_desk_suffix

View File

@ -1974,7 +1974,7 @@ class User < ApplicationRecord
end
def enabled_incoming_email_token
incoming_email_token if Gitlab::IncomingEmail.supports_issue_creation?
incoming_email_token if Gitlab::Email::IncomingEmail.supports_issue_creation?
end
def sync_attribute?(attribute)

View File

@ -118,7 +118,7 @@ module Packages
# used by ExclusiveLeaseGuard
def lease_key
"packages:npm:create_package_service:packages:#{project.id}_#{name}"
"packages:npm:create_package_service:packages:#{project.id}_#{name}_#{version}"
end
# used by ExclusiveLeaseGuard

View File

@ -144,8 +144,10 @@ module Projects
# completes), and any other affected users in the background
def setup_authorizations
if @project.group
group_access_level = @project.group.max_member_access_for_user(current_user,
only_concrete_membership: true)
group_access_level = @project.group.max_member_access_for_user(
current_user,
only_concrete_membership: true
)
if group_access_level > GroupMember::NO_ACCESS
current_user.project_authorizations.safe_find_or_create_by!(

View File

@ -92,8 +92,10 @@ module Projects
def build_fork_network_member(fork_to_project)
if allowed_fork?
fork_to_project.build_fork_network_member(forked_from_project: @project,
fork_network: fork_network)
fork_to_project.build_fork_network_member(
forked_from_project: @project,
fork_network: fork_network
)
else
fork_to_project.errors.add(:forked_from_project_id, 'is forbidden')
end

View File

@ -9,7 +9,7 @@ module Projects
include Gitlab::ShellAdapter
attr_reader :old_disk_path, :new_disk_path, :old_storage_version,
:logger, :move_wiki, :move_design
:logger, :move_wiki, :move_design
def initialize(project:, old_disk_path:, logger: nil)
@project = project

View File

@ -36,8 +36,11 @@ module Projects
)
message = Projects::ImportErrorFilter.filter_message(e.message)
error(s_("ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}") %
{ project_safe_import_url: project.safe_import_url, project_full_path: project.full_path, message: message })
error(
s_(
"ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
) % { project_safe_import_url: project.safe_import_url, project_full_path: project.full_path, message: message }
)
end
protected

View File

@ -51,9 +51,7 @@ module Projects
end
def download_links_for(oids)
response = Gitlab::HTTP.post(remote_uri,
body: request_body(oids),
headers: headers)
response = Gitlab::HTTP.post(remote_uri, body: request_body(oids), headers: headers)
raise DownloadLinksRequestEntityTooLargeError if response.request_entity_too_large?
raise DownloadLinksError, response.message unless response.success?
@ -78,10 +76,12 @@ module Projects
raise DownloadLinkNotFound unless link
link_list << LfsDownloadObject.new(oid: entry['oid'],
size: entry['size'],
headers: headers,
link: add_credentials(link))
link_list << LfsDownloadObject.new(
oid: entry['oid'],
size: entry['size'],
headers: headers,
link: add_credentials(link)
)
rescue DownloadLinkNotFound, Addressable::URI::InvalidURIError
log_error("Link for Lfs Object with oid #{entry['oid']} not found or invalid.")
end

View File

@ -45,11 +45,13 @@ module Projects
duration = ::Gitlab::Metrics::System.monotonic_time - start_time
Gitlab::AppJsonLogger.info(class: self.class.name,
namespace_id: source_project.namespace_id,
project_id: source_project.id,
duration_s: duration.to_f,
error: exception.class.name)
Gitlab::AppJsonLogger.info(
class: self.class.name,
namespace_id: source_project.namespace_id,
project_id: source_project.id,
duration_s: duration.to_f,
error: exception.class.name
)
end
def move_relationships_between(source_project, target_project)
@ -83,9 +85,11 @@ module Projects
# we won't be able to query the database (only through its cached data),
# for its former relationships. That's why we're adding it to the network
# as a fork of the target project
ForkNetworkMember.create!(fork_network: fork_network,
project: source_project,
forked_from_project: @project)
ForkNetworkMember.create!(
fork_network: fork_network,
project: source_project,
forked_from_project: @project
)
end
def remove_source_project_from_fork_network(source_project)

View File

@ -75,12 +75,14 @@ module Projects
end
if message.present?
Gitlab::AppJsonLogger.info(message: "Error synching remote mirror",
project_id: project.id,
project_path: project.full_path,
remote_mirror_id: remote_mirror.id,
lfs_sync_failed: lfs_sync_failed,
divergent_ref_list: response.divergent_refs)
Gitlab::AppJsonLogger.info(
message: "Error synching remote mirror",
project_id: project.id,
project_path: project.full_path,
remote_mirror_id: remote_mirror.id,
lfs_sync_failed: lfs_sync_failed,
divergent_ref_list: response.divergent_refs
)
end
[failed, message]

View File

@ -17,3 +17,5 @@ module Users
end
end
end
Users::UnbanService.prepend_mod_with('Users::UnbanService')

View File

@ -101,7 +101,7 @@
doc_href: help_page_path('integration/omniauth'))
= feature_entry(_('Reply by email'),
enabled: Gitlab::IncomingEmail.enabled?,
enabled: Gitlab::Email::IncomingEmail.enabled?,
doc_href: help_page_path('administration/reply_by_email'))
= render_if_exists 'admin/dashboard/elastic_and_geo'

View File

@ -10,7 +10,7 @@
.info-well.gl-display-none.gl-sm-display-flex.project-last-commit.gl-flex-direction-column.gl-mt-5
#js-last-commit.gl-m-auto
= gl_loading_icon(size: 'md')
#js-code-owners
#js-code-owners{ data: { branch: @ref, branch_rules_path: project_settings_repository_path(project, anchor: 'js-branch-rules') } }
.nav-block.gl-display-flex.gl-xs-flex-direction-column.gl-align-items-stretch
= render 'projects/tree/tree_header', tree: @tree, is_project_overview: is_project_overview

View File

@ -12,7 +12,7 @@
enabled: "#{@project.service_desk_enabled}",
incoming_email: (@project.service_desk_incoming_address if @project.service_desk_enabled),
custom_email: (@project.service_desk_custom_address if @project.service_desk_enabled),
custom_email_enabled: "#{Gitlab::ServiceDeskEmail.enabled?}",
custom_email_enabled: "#{Gitlab::Email::ServiceDeskEmail.enabled?}",
selected_template: "#{@project.service_desk_setting&.issue_template_key}",
selected_file_template_project_id: "#{@project.service_desk_setting&.file_template_project_id}",
outgoing_name: "#{@project.service_desk_setting&.outgoing_name}",

View File

@ -10,7 +10,7 @@
%ul.blob-commit-info
= render 'projects/commits/commit', commit: @last_commit, project: @project, ref: @ref
#js-code-owners{ data: { blob_path: blob.path, project_path: @project.full_path, branch: @ref } }
#js-code-owners{ data: { blob_path: blob.path, project_path: @project.full_path, branch: @ref, branch_rules_path: project_settings_repository_path(project, anchor: 'js-branch-rules') } }
= render "projects/blob/auxiliary_viewer", blob: blob
- if project.forked?

View File

@ -2,7 +2,7 @@
- show_whitespace_toggle = local_assigns.fetch(:show_whitespace_toggle, true)
- can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project)
- diff_page_context = local_assigns.fetch(:diff_page_context, nil)
- load_diff_files_async = Feature.enabled?(:async_commit_diff_files, @project) && diff_page_context == "is-commit"
- load_diff_files_async = diff_page_context == "is-commit"
- paginate_diffs = local_assigns.fetch(:paginate_diffs, false)
- paginate_diffs_per_page = local_assigns.fetch(:paginate_diffs_per_page, nil)
- page = local_assigns.fetch(:page, nil)

View File

@ -21,7 +21,7 @@ class EmailReceiverWorker # rubocop:disable Scalability/IdempotentWorker
end
def should_perform?
Gitlab::IncomingEmail.enabled?
Gitlab::Email::IncomingEmail.enabled?
end
private

View File

@ -10,7 +10,7 @@ class ServiceDeskEmailReceiverWorker < EmailReceiverWorker # rubocop:disable Sca
sidekiq_options retry: 3
def should_perform?
::Gitlab::ServiceDeskEmail.enabled?
::Gitlab::Email::ServiceDeskEmail.enabled?
end
def receiver

View File

@ -1,8 +1,8 @@
---
name: async_commit_diff_files
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38450
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369439
milestone: '13.3'
name: ci_remove_legacy_predefined_variables
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116606
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/404533
milestone: '15.11'
type: development
group: group::source code
group: group::pipeline authoring
default_enabled: false

View File

@ -1,3 +1,4 @@
# frozen_string_literal: true
Gitlab::Database::Migrations::LockRetryMixin.patch!
Gitlab::Database::Migrations::PgBackendPid.patch!

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
multiversion.check!

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
require_relative '../../tooling/danger/multiversion'
module Danger
class Multiversion < ::Danger::Plugin
include Tooling::Danger::Multiversion
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
class EnsureEpicUserMentionsBigintBackfillIsFinishedForGitlabDotCom < Gitlab::Database::Migration[2.1]
include Gitlab::Database::MigrationHelpers::ConvertToBigint
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
def up
return unless should_run?
ensure_batched_background_migration_is_finished(
job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
table_name: 'epic_user_mentions',
column_name: 'id',
job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
)
end
def down
# no-op
end
private
def should_run?
com_or_dev_or_test_but_not_jh?
end
end

View File

@ -0,0 +1,74 @@
# frozen_string_literal: true
class SwapEpicUserMentionsNoteIdToBigintForGitlabDotCom < Gitlab::Database::Migration[2.1]
include Gitlab::Database::MigrationHelpers::ConvertToBigint
disable_ddl_transaction!
TABLE_NAME = 'epic_user_mentions'
def up
return unless should_run?
swap
end
def down
return unless should_run?
swap
end
def swap
# This will replace the existing epic_user_mentions_on_epic_id_and_note_id_index
add_concurrent_index TABLE_NAME, [:epic_id, :note_id_convert_to_bigint], unique: true,
name: 'epic_user_mentions_on_epic_id_and_note_id_convert_to_bigint'
# This will replace the existing epic_user_mentions_on_epic_id_index
add_concurrent_index TABLE_NAME, :epic_id, unique: true,
name: 'tmp_epic_user_mentions_on_epic_id_index',
where: 'note_id_convert_to_bigint IS NULL'
# This will replace the existing index_epic_user_mentions_on_note_id
add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, unique: true,
name: 'index_epic_user_mentions_on_note_id_convert_to_bigint',
where: 'note_id_convert_to_bigint IS NOT NULL'
# This will replace the existing fk_rails_1c65976a49
add_concurrent_foreign_key TABLE_NAME, :notes, column: :note_id_convert_to_bigint,
name: 'fk_epic_user_mentions_note_id_convert_to_bigint',
on_delete: :cascade
with_lock_retries(raise_on_exhaustion: true) do
execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id TO note_id_tmp"
execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_convert_to_bigint TO note_id"
execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_tmp TO note_id_convert_to_bigint"
function_name = Gitlab::Database::UnidirectionalCopyTrigger
.on_table(TABLE_NAME, connection: connection)
.name(:note_id, :note_id_convert_to_bigint)
execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
execute 'DROP INDEX IF EXISTS epic_user_mentions_on_epic_id_and_note_id_index'
rename_index TABLE_NAME, 'epic_user_mentions_on_epic_id_and_note_id_convert_to_bigint',
'epic_user_mentions_on_epic_id_and_note_id_index'
execute 'DROP INDEX IF EXISTS epic_user_mentions_on_epic_id_index'
rename_index TABLE_NAME, 'tmp_epic_user_mentions_on_epic_id_index',
'epic_user_mentions_on_epic_id_index'
execute 'DROP INDEX IF EXISTS index_epic_user_mentions_on_note_id'
rename_index TABLE_NAME, 'index_epic_user_mentions_on_note_id_convert_to_bigint',
'index_epic_user_mentions_on_note_id'
execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_rails_1c65976a49"
rename_constraint(TABLE_NAME, 'fk_epic_user_mentions_note_id_convert_to_bigint', 'fk_rails_1c65976a49')
end
end
def should_run?
com_or_dev_or_test_but_not_jh?
end
end

View File

@ -0,0 +1 @@
3968fc8d21184f48f85209546fe515d0b4a407ad0837ef052ccbbbe15d0f9163

View File

@ -0,0 +1 @@
a3e306b8ebe149c319788311f4f81386c9362d081babca8bcd7c850ae1cbc183

View File

@ -15738,11 +15738,11 @@ ALTER SEQUENCE epic_metrics_id_seq OWNED BY epic_metrics.id;
CREATE TABLE epic_user_mentions (
id bigint NOT NULL,
epic_id integer NOT NULL,
note_id integer,
note_id_convert_to_bigint integer,
mentioned_users_ids integer[],
mentioned_projects_ids integer[],
mentioned_groups_ids integer[],
note_id_convert_to_bigint bigint
note_id bigint
);
CREATE SEQUENCE epic_user_mentions_id_seq

View File

@ -357,6 +357,8 @@ The following user actions on a GitLab instance generate instance audit events:
- Enabled Admin Mode. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362101) in GitLab 15.7.
- All [group events](#group-events) and [project events](#project-events).
- User was unblocked using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115727) in GitLab 15.11.
- User was banned using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116103) in GitLab 15.11.
- User was unbanned using the Admin Area or API. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/116221) in GitLab 15.11.
Instance events can also be accessed using the [Instance Audit Events API](../api/audit_events.md#instance-audit-events).

View File

@ -15484,11 +15484,11 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| ---- | ---- | ----------- |
| <a id="groupvaluestreamanalyticsflowmetricscycletimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimefrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimeprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
| <a id="groupvaluestreamanalyticsflowmetricscycletimeto"></a>`to` | [`Time!`](#time) | Before the date. |
##### `GroupValueStreamAnalyticsFlowMetrics.deploymentCount`
@ -15500,9 +15500,9 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountfrom"></a>`from` | [`Time!`](#time) | Deployments finished after the date. |
| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountfrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountto"></a>`to` | [`Time!`](#time) | Deployments finished before the date. |
| <a id="groupvaluestreamanalyticsflowmetricsdeploymentcountto"></a>`to` | [`Time!`](#time) | Before the date. |
##### `GroupValueStreamAnalyticsFlowMetrics.issueCount`
@ -15516,11 +15516,11 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| ---- | ---- | ----------- |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountfrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountfrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountlabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
| <a id="groupvaluestreamanalyticsflowmetricsissuecountto"></a>`to` | [`Time!`](#time) | Before the date. |
##### `GroupValueStreamAnalyticsFlowMetrics.leadTime`
@ -15534,11 +15534,11 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| ---- | ---- | ----------- |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimefrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeprojectids"></a>`projectIds` | [`[ID!]`](#id) | Project IDs within the group hierarchy. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
| <a id="groupvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Before the date. |
### `GroupWikiRepositoryRegistry`
@ -19985,10 +19985,10 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| ---- | ---- | ----------- |
| <a id="projectvaluestreamanalyticsflowmetricscycletimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimefrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
| <a id="projectvaluestreamanalyticsflowmetricscycletimeto"></a>`to` | [`Time!`](#time) | Before the date. |
##### `ProjectValueStreamAnalyticsFlowMetrics.deploymentCount`
@ -20000,8 +20000,8 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectvaluestreamanalyticsflowmetricsdeploymentcountfrom"></a>`from` | [`Time!`](#time) | Deployments finished after the date. |
| <a id="projectvaluestreamanalyticsflowmetricsdeploymentcountto"></a>`to` | [`Time!`](#time) | Deployments finished before the date. |
| <a id="projectvaluestreamanalyticsflowmetricsdeploymentcountfrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="projectvaluestreamanalyticsflowmetricsdeploymentcountto"></a>`to` | [`Time!`](#time) | Before the date. |
##### `ProjectValueStreamAnalyticsFlowMetrics.issueCount`
@ -20015,10 +20015,10 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| ---- | ---- | ----------- |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountfrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountfrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountlabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
| <a id="projectvaluestreamanalyticsflowmetricsissuecountto"></a>`to` | [`Time!`](#time) | Before the date. |
##### `ProjectValueStreamAnalyticsFlowMetrics.leadTime`
@ -20032,10 +20032,10 @@ Returns [`ValueStreamAnalyticsMetric`](#valuestreamanalyticsmetric).
| ---- | ---- | ----------- |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimeassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimeauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimefrom"></a>`from` | [`Time!`](#time) | Issues created after the date. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimefrom"></a>`from` | [`Time!`](#time) | After the date. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimelabelnames"></a>`labelNames` | [`[String!]`](#string) | Labels applied to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimemilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Milestone applied to the issue. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Issues created before the date. |
| <a id="projectvaluestreamanalyticsflowmetricsleadtimeto"></a>`to` | [`Time!`](#time) | Before the date. |
### `ProjectWikiRepositoryRegistry`

View File

@ -13,10 +13,9 @@ participating-stages: []
# Consolidating Groups and Projects
There are numerous features that exist exclusively within groups or
projects. The boundary between group and project features used to be clear.
However, there is growing demand to have group features within projects, and
project features within groups. For example, having issues in groups, and epics
Numerous features exist exclusively within groups or projects. The boundary between group and project features used to be clear.
However, there is growing demand to have group features in projects, and
project features in groups. For example, having issues in groups, and epics
in projects.
The [Simplify Groups & Projects Working Group](https://about.gitlab.com/company/team/structure/working-groups/simplify-groups-and-projects/)
@ -34,12 +33,12 @@ no established process in place. This results in the reimplementation of
the same feature. Those implementations diverge from each other over time as
they all live on their own. A few more problems with this approach:
- Features are coupled to their container. In practice it is not straight
- Features are coupled to their container. In practice, it is not straight
forward to decouple a feature from its container. The degree of coupling
varies across features.
- Naive duplication of features will result in a more complex and fragile codebase.
- Generalizing solutions across groups and projects may degrade system performance.
- The range of features span across many teams, and these changes will need to
- The range of features spans across many teams, and these changes will need to
manage development interference.
- The group/project hierarchy creates a natural feature hierarchy. When features
exist across containers the feature hierarchy becomes ambiguous.
@ -51,33 +50,33 @@ remains consistent.
### Performance
Resources can only be queried in elaborate / complicated ways. This caused
Resources can only be queried in elaborate/complicated ways. This caused
performance issues with authorization, epics, and many other places. As an
example, to query the projects a user has access to, the following sources need
to be considered:
- personal projects
- direct group membership
- direct project membership
- inherited group membership
- inherited project membership
- group sharing
- inherited membership via group sharing
- project sharing
- Personal projects
- Direct group membership
- Direct project membership
- Inherited group membership
- Inherited project membership
- Group sharing
- Inherited membership via group sharing
- Project sharing
Group / project membership, group / project sharing are also examples of
Group/project membership, group/project sharing are also examples of
duplicated features.
## Goals
For now this blueprint strictly relates to the engineering challenges.
For now, this blueprint strictly relates to the engineering challenges.
- Consolidate the group and project container architecture.
- Develop a set of solutions to decouple features from their container.
- Decouple engineering changes from product changes.
- Develop a strategy to make architectural changes without adversely affecting
other teams.
- Provide a solution for requests asking for features availability of other levels.
- Provide a solution for requests asking for features to be made available at other levels.
## Proposal
@ -105,9 +104,9 @@ New features should be implemented on `Namespace`. Similarly, when a feature
need to be reimplemented on a different level, moving it to `Namespace`
essentially makes it available on all levels:
- personal namespaces
- groups
- projects
- Personal namespaces
- Groups
- Projects
Various traversal queries are already available on `Namespaces` to query the
group hierarchy. `Projects` represent the leaf nodes in the hierarchy, but with
@ -116,14 +115,14 @@ retrieve projects as well.
This also enables further simplification of some of our core features:
- routes should be generated based on the `Namespace` hierarchy, instead of
mixing project with the group hierarchy.
- there is no need to differentiate between `GroupMembers` and `ProjectMembers`.
- Routes should be generated based on the `Namespace` hierarchy, instead of
mixing the project with the group hierarchy.
- There is no need to differentiate between `GroupMembers` and `ProjectMembers`.
All `Members` should be related to a `Namespace`. This can lead to simplified
querying, and potentially deduplicating policies.
As more and more features will be migrated to `Namespace`, the role of `Project`
model will diminish over time to essentially a container around repository
As more and more features will be migrated to `Namespace`, the role of the `Project`
model will diminish over time to essentially a container around the repository
related functionality.
## Iterations
@ -132,9 +131,103 @@ The work required to establish `Namespace` as a container for our features is
tracked under [Consolidate Groups and Projects](https://gitlab.com/groups/gitlab-org/-/epics/6473)
epic.
### Phase 1 (complete)
- [Phase 1 epic](https://gitlab.com/groups/gitlab-org/-/epics/6697).
- **Goals**:
1. Ensure every project receives a corresponding record in the `namespaces`
table with `type='Project'`.
1. For user namespaces, the type changes from `NULL` to `User`.
We should make sure that projects, and the project namespace, are equivalent:
- **Create project:** Use Rails callbacks to ensure a new project namespace is
created for each project. Project namespace records should contain `created_at` and
`updated_at` attributes equal to the project's `created_at`/`updated_at` attributes.
- **Update project:** Use the `after_save` callback in Rails to ensure some
attributes are kept in sync between project and project namespaces.
Read [`project#after_save`](https://gitlab.com/gitlab-org/gitlab/blob/6d26634e864d7b748dda0e283eb2477362263bc3/app/models/project.rb#L101-L101)
for more information.
- **Delete project:** Use FKs cascade delete or Rails callbacks to ensure when a `Project`
or its `ProjectNamespace` is removed, its corresponding `ProjectNamespace` or `Project`
is also removed.
- **Transfer project to a different group:** Make sure that when a project is transferred,
its corresponding project namespace is transferred to the same group.
- **Transfer group:** Make sure when transferring a group that all of its sub-projects,
either direct or through descendant groups, have their corresponding project
namespaces transferred correctly as well.
- **Export or import project**
- **Export project** continues to export only the project, and not its project namespace,
in this phase. The project namespace does not contain any specific information
to export at this point. Eventually, we want the project namespace to be exported as well.
- **Import project** creates a new project, so the project namespace is created through
Rails `after_save` callback on the project model.
- **Export or import group:** When importing or exporting a `Group`, projects are not
included in the operation. If that feature is changed to include `Project` when its group is
imported or exported, the logic must include their corresponding project namespaces
in the import or export.
After ensuring these points, run a database migration to create a `ProjectNamespace`
record for every `Project`. Project namespace records created during the migration
should have `created_at` and `updated_at` attributes set to the migration runtime.
The project namespaces' `created_at` and `updated_at` attributes would not match
their corresponding project's `created_at` and `updated_at` attributes. We want
the different dates to help audit any of the created project namespaces, in case we need it.
After this work completes, we must migrate data as described in
[Backfill `ProjectNamespace` for every Project](https://gitlab.com/gitlab-org/gitlab/-/issues/337100).
### Phase 2 (complete)
- [Phase 2 epic](https://gitlab.com/groups/gitlab-org/-/epics/6768).
- **Goal**: Link `ProjectNamespace` to other entities on the database level.
In this phase:
- Communicate the changes company-wide at the engineering level. We want to make
engineers aware of the upcoming changes, even though teams are not expected to
collaborate actively until phase 3.
- Raise awareness to avoid regressions and conflicting or duplicate work that
can be dealt with before phase 3.
### Phase 3 (ongoing)
- [Phase 3 epic](https://gitlab.com/groups/gitlab-org/-/epics/6585).
In this phase we are migrating basic, high-priority project functionality from `Project` to `ProjectNamespace`, or directly to `Namespace`. Problems to solve as part of this phase:
- [Unify members/members actions](https://gitlab.com/groups/gitlab-org/-/epics/8010) - on UI and API level.
- Starring: Right now only projects can be starred. We want to bring this to the group level.
- Common actions: Destroying, transferring, restoring. This can be unified on the controller level and then propagated lower.
- Archiving currently only works on the project level. This can be brought to the group level, similar to the mechanism for “pending deletion”.
- Avatar's serving and actions.
### Phase 4
- [Phase 4 epic](https://gitlab.com/groups/gitlab-org/-/epics/8687)
In this phase we are migrating additional functionality from `Project` to `ProjectNamespace`/`Namespace`:
- Replace usages of `Project` with `ProjectNamespace` in the code.
- API changes to expose namespaces and namespace features.
- Investigate if we extend API for `groups` or we introduce a `namespaces` endpoint and slowly deprecate `groups` and `projects` endpoints.
- Break down each feature that needs to be migrated from `Project` to `ProjectNamespace` or `Namespace`.
- Investigate if we can move a feature from `Project -> Namespace` directly vs `Project -> ProjectNamespace -> Namespace`. This can be decided on a feature by feature case.
- [Migrate Project#namespace to reference ProjectNamespace](https://gitlab.com/groups/gitlab-org/-/epics/6581).
- [Routes consolidation between Project & ProjectNamespace](https://gitlab.com/gitlab-org/gitlab/-/issues/337103).
- [Policies consolidation](https://gitlab.com/groups/gitlab-org/-/epics/6689).
### Phase 5
- [Phase 5 epic](https://gitlab.com/groups/gitlab-org/-/epics/6944)
We should strive to do the code clean up as we move through the phases. However, not everything can be cleaned up while something is still being developed. For example, dropping database columns can be done as the last task when we are sure everything is working. This phase will focus on:
- Code cleanup
- Database cleanup
## Migrating features to Namespaces
The initial iteration will provide a framework to house features under `Namespaces`. Stage groups will eventually need to migrate their own features and functionality over to `Namespaces`. This may impact these features in unexpected ways. Therefore, to minimize UX debt and maintain product consistency, stage groups will have to consider a number of factors when migrating their features over to `Namespaces`:
The initial iteration will provide a framework to house features under `Namespaces`. Stage groups will eventually need to migrate their own features and functionality over to `Namespaces`. This may impact these features in unexpected ways. Therefore, to minimize UX debt and maintain product consistency, stage groups will have to consider several factors when migrating their features over to `Namespaces`:
1. **Conceptual model**: What are the current and future state conceptual models of these features ([see object modeling for designers](https://hpadkisson.medium.com/object-modeling-for-designers-an-introduction-7871bdcf8baf))? These should be documented in Pajamas (example: [merge requests](https://design.gitlab.com/objects/merge-request/)).
1. **Merge conflicts**: What inconsistencies are there across project, group, and administrator levels? How might these be addressed? For an example of how we rationalized this for labels, please see [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/338820).
@ -151,3 +244,4 @@ The initial iteration will provide a framework to house features under `Namespac
## Related topics
- [Organization developer documentation](../../../development/organization/index.md)
- [Organization user documentation](../../../user/organization/index.md)

View File

@ -558,7 +558,7 @@ GitLab CI/CD is the open-source continuous integration service included with Git
#### GitLab Workhorse
- [Project page](https://gitlab.com/gitlab-org/gitlab-workhorse/blob/master/README.md)
- [Project page](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/workhorse/index.md)
- Configuration:
- [Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template)
- [Charts](https://docs.gitlab.com/charts/charts/gitlab/webservice/)
@ -567,7 +567,7 @@ GitLab CI/CD is the open-source continuous integration service included with Git
- Process: `gitlab-workhorse`
- GitLab.com: [Service Architecture](https://about.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) is a program designed at GitLab to help alleviate pressure from Puma. You can read more about the [historical reasons for developing](https://about.gitlab.com/blog/2016/04/12/a-brief-history-of-gitlab-workhorse/). It's designed to act as a smart reverse proxy to help speed up GitLab as a whole.
[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/workhorse) is a program designed at GitLab to help alleviate pressure from Puma. You can read more about the [historical reasons for developing](https://about.gitlab.com/blog/2016/04/12/a-brief-history-of-gitlab-workhorse/). It's designed to act as a smart reverse proxy to help speed up GitLab as a whole.
#### Grafana

View File

@ -38,87 +38,14 @@ A solution for this problem is to consolidate groups and projects into a single
entity, `namespace`. The work on this solution is split into several phases and
is tracked in [epic 6473](https://gitlab.com/groups/gitlab-org/-/epics/6473).
### Phase 1
- [Phase 1 epic](https://gitlab.com/groups/gitlab-org/-/epics/6697).
- **Goals**:
1. Ensure every project receives a corresponding record in the `namespaces`
table with `type='Project'`.
1. For user namespaces, the type changes from `NULL` to `User`.
We should make sure that projects, and the project namespace, are equivalent:
- **Create project:** use Rails callbacks to ensure a new project namespace is
created for each project. Project namespace records should contain `created_at` and
`updated_at` attributes equal to the project's `created_at`/`updated_at` attributes.
- **Update project:** use the `after_save` callback in Rails to ensure some
attributes are kept in sync between project and project namespaces.
Read [`project#after_save`](https://gitlab.com/gitlab-org/gitlab/blob/6d26634e864d7b748dda0e283eb2477362263bc3/app/models/project.rb#L101-L101)
for more information.
- **Delete project:** use FKs cascade delete or Rails callbacks to ensure when a `Project`
or its `ProjectNamespace` is removed, its corresponding `ProjectNamespace` or `Project`
is also removed.
- **Transfer project to a different group:** make sure that when a project is transferred,
its corresponding project namespace is transferred to the same group.
- **Transfer group:** make sure when transferring a group that all of its sub-projects,
either direct or through descendant groups, have their corresponding project
namespaces transferred correctly as well.
- **Export or import project**
- **Export project** continues to export only the project, and not its project namespace,
in this phase. The project namespace does not contain any specific information
to export at this point. Eventually we want the project namespace to be exported as well.
- **Import project** creates a new project, so the project namespace is created through
Rails `after_save` callback on the project model.
- **Export or import group:** when importing or exporting a `Group`, projects are not
included in the operation. If that feature is changed to include `Project` when its group is
imported or exported, the logic must include their corresponding project namespaces
in the import or export.
After ensuring these points, run a database migration to create a `ProjectNamespace`
record for every `Project`. Project namespace records created during the migration
should have `created_at` and `updated_at` attributes set to the migration runtime.
The project namespaces' `created_at` and `updated_at` attributes would not match
their corresponding project's `created_at` and `updated_at` attributes. We want
the different dates to help audit any of the created project namespaces, in case we need it.
After this work completes, we must migrate data as described in
[Backfill `ProjectNamespace` for every Project](https://gitlab.com/gitlab-org/gitlab/-/issues/337100).
### Phase 2
- [Phase 2 epic](https://gitlab.com/groups/gitlab-org/-/epics/6768).
- **Goal**: Link `ProjectNamespace` to other entities on the database level.
In this phase:
- Communicate the changes company-wide at the engineering level. We want to make
engineers aware of the upcoming changes, even though teams are not expected to
collaborate actively until phase 3.
- Raise awareness to avoid regressions, and conflicting or duplicate work that
can be dealt with before phase 3.
### Phase 3
- [Phase 3 epic](https://gitlab.com/groups/gitlab-org/-/epics/6585).
- **Goal**: Achieve feature parity between the namespace types.
Problems to solve as part of this phase:
- Routes handling through `ProjectNamespace` rather than `Project`.
- Memberships handling.
- Policies handling.
- Import and export.
- Other interactions between project namespace and project models.
Phase 3 is when the active migration of features from `Project` to `ProjectNamespace`,
or directly to `Namespace`, happens.
### How to plan features that interact with Group and ProjectNamespace
## How to plan features that interact with Group and ProjectNamespace
As of now, every Project in the system has a record in the `namespaces` table. This makes it possible to
use common interface to create features that are shared between Groups and Projects. Shared behavior can be added using
a concerns mechanism. Because the `Namespace` model is responsible for `UserNamespace` methods as well, it is discouraged
to use the `Namespace` model for shared behavior for Projects and Groups.
#### Resource-based features
### Resource-based features
To migrate resource-based features, existing functionality will need to be supported. This can be achieved in two Phases.
@ -140,7 +67,7 @@ To migrate resource-based features, existing functionality will need to be suppo
Introducing new functionality is very much dependent on every single team and feature.
#### Settings-related features
### Settings-related features
Right now, cascading settings are available for `NamespaceSettings`. By creating `ProjectNamespace`,
we can use this framework to make sure that some settings are applicable on the project level as well.
@ -149,7 +76,7 @@ When working on settings, we need to make sure that:
- They are not used in `join` queries or modify those queries.
- Updating settings is taken into consideration.
- If we want to move from project to project namespace, we follow a similar database process to the one described in [Phase 1](#phase-1).
- If we want to move from project to project namespace, we follow a similar database process to the one described in Phase 1.
## Related topics

View File

@ -15,9 +15,14 @@ Workhorse itself is not a feature, but there are
The canonical source for Workhorse is
[`gitlab-org/gitlab/workhorse`](https://gitlab.com/gitlab-org/gitlab/tree/master/workhorse).
Prior to [epic #4826](https://gitlab.com/groups/gitlab-org/-/epics/4826), it was
[`gitlab-org/gitlab-workhorse`](https://gitlab.com/gitlab-org/gitlab-workhorse/tree/master),
but that repository is no longer used for development.
## Learning Resources
- Workhorse documentation (this page)
- [GitLab Workhorse Deep Dive: Dependency Proxy](https://www.youtube.com/watch?v=9cRd-k0TRqI) _video_
- [How Dependency Proxy via Workhorse works](https://gitlab.com/gitlab-org/gitlab/-/issues/370235)
- [Workhorse overview for the Dependency Proxy](https://www.youtube.com/watch?v=WmBibT9oQms)
- [Workhorse architecture discussion](https://www.youtube.com/watch?v=QlHdh-yudtw)
## Install Workhorse

View File

@ -327,7 +327,7 @@ This table shows granted privileges for jobs triggered by specific types of user
| Push source and LFS | | | | |
1. Only if the triggering user is not an external one.
1. Only if the triggering user is a member of the project. See also [Usage of private Docker images with `if-not-present` pull policy](http://docs.gitlab.com/runner/security/index.html#usage-of-private-docker-images-with-if-not-present-pull-policy).
1. Only if the triggering user is a member of the project. See also [Usage of private Docker images with `if-not-present` pull policy](https://docs.gitlab.com/runner/security/index.html#usage-of-private-docker-images-with-if-not-present-pull-policy).
## Group members permissions

View File

@ -45,7 +45,7 @@ flowchart TB
Product Analytics uses several tools:
- [**Jitsu**](https://jitsu.com/docs) - A web and app event collection platform that provides a consistent API to collect user data and pass it through to Clickhouse.
- [**Clickhouse**](https://clickhouse.com/docs) - A database suited to store, query, and retrieve analytical data.
- [**Clickhouse**](https://clickhouse.com/docs/) - A database suited to store, query, and retrieve analytical data.
- [**Cube.js**](https://cube.dev/docs/) - An analytical graphing library that provides an API to run queries against the data stored in Clickhouse.
## Enable product analytics

View File

@ -77,7 +77,7 @@ cluster certificates:
- **Zone** - Choose the [region zone](https://cloud.google.com/compute/docs/regions-zones/)
under which to create the cluster.
- **Number of nodes** - Enter the number of nodes you wish the cluster to have.
- **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types)
- **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-resource)
of the Virtual Machine instance to base the cluster on.
- **Enable Cloud Run for Anthos** - Check this if you want to use Cloud Run for Anthos for this cluster.
See the [Cloud Run for Anthos section](#cloud-run-for-anthos) for more information.

View File

@ -58,7 +58,7 @@ git-lfs --version
```
If it doesn't recognize this command, you must install it. There are
several [installation methods](https://git-lfs.github.com/) that you can
several [installation methods](https://git-lfs.com/) that you can
choose according to your OS. To install it with Homebrew:
```shell

View File

@ -291,7 +291,7 @@ You can use [1Password](https://1password.com/) and the [1Password browser exten
1. Optional. Update **Expiration date** to modify the default expiration date.
1. Select **Add key**.
For more information about using 1Password with SSH keys, see the [1Password documentation](https://developer.1password.com/docs/ssh/get-started).
For more information about using 1Password with SSH keys, see the [1Password documentation](https://developer.1password.com/docs/ssh/get-started/).
## Add an SSH key to your GitLab account

View File

@ -3,7 +3,7 @@
module Gitlab
module Auth
MissingPersonalAccessTokenError = Class.new(StandardError)
IpBlacklisted = Class.new(StandardError)
IpBlocked = Class.new(StandardError)
# Scopes used for GitLab API access
API_SCOPE = :api
@ -51,7 +51,7 @@ module Gitlab
rate_limiter = Gitlab::Auth::IpRateLimiter.new(ip)
raise IpBlacklisted if !skip_rate_limit?(login: login) && rate_limiter.banned?
raise IpBlocked if !skip_rate_limit?(login: login) && rate_limiter.banned?
# `user_with_password_for_git` should be the last check
# because it's the most expensive, especially when LDAP

View File

@ -10,7 +10,7 @@ module Gitlab
ALLOWED_KEYS = %i[inputs].freeze
validations do
validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
validates :config, allowed_keys: ALLOWED_KEYS
end
entry :inputs, ::Gitlab::Config::Entry::ComposableHash,

View File

@ -140,11 +140,13 @@ module Gitlab
# Set environment name here so we can access it when evaluating the job's rules
variables.append(key: 'CI_ENVIRONMENT_NAME', value: job.environment) if job.environment
# legacy variables
variables.append(key: 'CI_BUILD_NAME', value: job.name)
variables.append(key: 'CI_BUILD_STAGE', value: job.stage_name)
variables.append(key: 'CI_BUILD_TRIGGERED', value: 'true') if job.trigger_request
variables.append(key: 'CI_BUILD_MANUAL', value: 'true') if job.action?
if Feature.disabled?(:ci_remove_legacy_predefined_variables, project)
# legacy variables
variables.append(key: 'CI_BUILD_NAME', value: job.name)
variables.append(key: 'CI_BUILD_STAGE', value: job.stage_name)
variables.append(key: 'CI_BUILD_TRIGGERED', value: 'true') if job.trigger_request
variables.append(key: 'CI_BUILD_MANUAL', value: 'true') if job.action?
end
end
end

View File

@ -40,7 +40,7 @@ module Gitlab
attr_reader :pipeline
def predefined_commit_variables
def predefined_commit_variables # rubocop:disable Metrics/AbcSize - Remove this rubocop:disable when FF `ci_remove_legacy_predefined_variables` is removed.
Gitlab::Ci::Variables::Collection.new.tap do |variables|
next variables unless pipeline.sha.present?
@ -57,7 +57,9 @@ module Gitlab
variables.append(key: 'CI_COMMIT_TIMESTAMP', value: pipeline.git_commit_timestamp.to_s)
variables.append(key: 'CI_COMMIT_AUTHOR', value: pipeline.git_author_full_text.to_s)
variables.concat(legacy_predefined_commit_variables)
if Feature.disabled?(:ci_remove_legacy_predefined_variables, pipeline.project)
variables.concat(legacy_predefined_commit_variables)
end
end
end
strong_memoize_attr :predefined_commit_variables
@ -81,7 +83,9 @@ module Gitlab
variables.append(key: 'CI_COMMIT_TAG', value: pipeline.ref)
variables.append(key: 'CI_COMMIT_TAG_MESSAGE', value: git_tag.message)
variables.concat(legacy_predefined_commit_tag_variables)
if Feature.disabled?(:ci_remove_legacy_predefined_variables, pipeline.project)
variables.concat(legacy_predefined_commit_tag_variables)
end
end
end
strong_memoize_attr :predefined_commit_tag_variables

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
module Gitlab
module Database
module Migrations
module PgBackendPid
module MigratorPgBackendPid
extend ::Gitlab::Utils::Override
override :with_advisory_lock_connection
def with_advisory_lock_connection
super do |conn|
Gitlab::Database::Migrations::PgBackendPid.say(conn)
yield(conn)
Gitlab::Database::Migrations::PgBackendPid.say(conn)
end
end
end
def self.patch!
ActiveRecord::Migrator.prepend(MigratorPgBackendPid)
end
def self.say(conn)
pg_backend_pid = conn.select_value('SELECT pg_backend_pid()')
db_name = Gitlab::Database.db_config_name(conn)
# rubocop:disable Rails/Output
puts "#{db_name}: == [advisory_lock_connection] " \
"object_id: #{conn.object_id}, pg_backend_pid: #{pg_backend_pid}"
# rubocop:enable Rails/Output
end
end
end
end
end

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Gitlab
module Email
module IncomingEmail
class << self
include Gitlab::Email::Common
def config
incoming_email_config
end
def key_from_address(address, wildcard_address: nil)
wildcard_address ||= config.address
regex = address_regex(wildcard_address)
return unless regex
match = address.match(regex)
return unless match
match[1]
end
private
def address_regex(wildcard_address)
return unless wildcard_address
regex = Regexp.escape(wildcard_address)
regex = regex.sub(Regexp.escape(WILDCARD_PLACEHOLDER), '(.+)')
Regexp.new(/\A<?#{regex}>?\z/).freeze
end
end
end
end
end

View File

@ -110,7 +110,7 @@ module Gitlab
when String
# Handle emails from clients which append with commas,
# example clients are Microsoft exchange and iOS app
Gitlab::IncomingEmail.scan_fallback_references(references)
email_class.scan_fallback_references(references)
when nil
[]
end
@ -203,7 +203,7 @@ module Gitlab
end
def email_class
Gitlab::IncomingEmail
Gitlab::Email::IncomingEmail
end
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Gitlab
module Email
module ServiceDeskEmail
class << self
include Gitlab::Email::Common
def config
Gitlab.config.service_desk_email
end
def key_from_address(address)
wildcard_address = config&.address
return unless wildcard_address
Gitlab::Email::IncomingEmail.key_from_address(address, wildcard_address: wildcard_address)
end
def address_for_key(key)
return if config.address.blank?
config.address.sub(WILDCARD_PLACEHOLDER, key)
end
end
end
end
end

View File

@ -12,7 +12,7 @@ module Gitlab
end
def email_class
::Gitlab::ServiceDeskEmail
::Gitlab::Email::ServiceDeskEmail
end
end
end

View File

@ -8,7 +8,7 @@ module Gitlab
class << self
def encrypted_secrets
Gitlab::IncomingEmail.encrypted_secrets
Gitlab::Email::IncomingEmail.encrypted_secrets
end
def encrypted_file_template

View File

@ -8,7 +8,7 @@ module Gitlab
class << self
def encrypted_secrets
Gitlab::ServiceDeskEmail.encrypted_secrets
Gitlab::Email::ServiceDeskEmail.encrypted_secrets
end
def encrypted_file_template

View File

@ -1,34 +0,0 @@
# frozen_string_literal: true
module Gitlab
module IncomingEmail
class << self
include Gitlab::Email::Common
def config
incoming_email_config
end
def key_from_address(address, wildcard_address: nil)
wildcard_address ||= config.address
regex = address_regex(wildcard_address)
return unless regex
match = address.match(regex)
return unless match
match[1]
end
private
def address_regex(wildcard_address)
return unless wildcard_address
regex = Regexp.escape(wildcard_address)
regex = regex.sub(Regexp.escape(WILDCARD_PLACEHOLDER), '(.+)')
Regexp.new(/\A<?#{regex}>?\z/).freeze
end
end
end
end

View File

@ -18,7 +18,7 @@ module Gitlab
request = ActionDispatch::Request.new(env)
render_go_doc(request) || @app.call(env)
rescue Gitlab::Auth::IpBlacklisted
rescue Gitlab::Auth::IpBlocked
Gitlab::AuthLogger.error(
message: 'Rack_Attack',
status: 403,

View File

@ -10,7 +10,7 @@ module Gitlab
end
def self.supported?
Gitlab::IncomingEmail.enabled? && Gitlab::IncomingEmail.supports_wildcard?
Gitlab::Email::IncomingEmail.enabled? && Gitlab::Email::IncomingEmail.supports_wildcard?
end
end
end

View File

@ -1,26 +0,0 @@
# frozen_string_literal: true
module Gitlab
module ServiceDeskEmail
class << self
include Gitlab::Email::Common
def config
Gitlab.config.service_desk_email
end
def key_from_address(address)
wildcard_address = config&.address
return unless wildcard_address
Gitlab::IncomingEmail.key_from_address(address, wildcard_address: wildcard_address)
end
def address_for_key(key)
return if config.address.blank?
config.address.sub(WILDCARD_PLACEHOLDER, key)
end
end
end
end

View File

@ -6,7 +6,7 @@ module Gitlab
module Instrumentations
class IncomingEmailEncryptedSecretsEnabledMetric < GenericMetric
value do
Gitlab::IncomingEmail.encrypted_secrets.active?
Gitlab::Email::IncomingEmail.encrypted_secrets.active?
end
end
end

View File

@ -6,7 +6,7 @@ module Gitlab
module Instrumentations
class ServiceDeskEmailEncryptedSecretsEnabledMetric < GenericMetric
value do
Gitlab::ServiceDeskEmail.encrypted_secrets.active?
Gitlab::Email::ServiceDeskEmail.encrypted_secrets.active?
end
end
end

View File

@ -240,7 +240,7 @@ module Gitlab
omniauth_enabled: alt_usage_data(fallback: nil) { Gitlab::Auth.omniauth_enabled? },
prometheus_enabled: alt_usage_data(fallback: nil) { Gitlab::Prometheus::Internal.prometheus_enabled? },
prometheus_metrics_enabled: alt_usage_data(fallback: nil) { Gitlab::Metrics.prometheus_metrics_enabled? },
reply_by_email_enabled: alt_usage_data(fallback: nil) { Gitlab::IncomingEmail.enabled? },
reply_by_email_enabled: alt_usage_data(fallback: nil) { Gitlab::Email::IncomingEmail.enabled? },
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { false },
signup_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.allow_signup? },
grafana_link_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.grafana_enabled? },

View File

@ -26349,6 +26349,9 @@ msgstr ""
msgid "Manage applications that you've authorized to use your account."
msgstr ""
msgid "Manage branch rules"
msgstr ""
msgid "Manage git repositories with fine-grained access controls that keep your code secure."
msgstr ""
@ -39986,6 +39989,9 @@ msgstr ""
msgid "SecurityReports|There was an error creating the merge request."
msgstr ""
msgid "SecurityReports|There was an error creating the merge request. Please try again."
msgstr ""
msgid "SecurityReports|There was an error deleting the comment."
msgstr ""

View File

@ -1,45 +0,0 @@
# frozen_string_literal: true
require 'rubocop/cop/rspec/base'
module RuboCop
module Cop
module RSpec
# Ensures that shared examples don't have feature category.
#
# @example
#
# # bad
# RSpec.shared_examples 'an external link with rel attribute', feature_category: :team_planning do
# end
#
# # good
# RSpec.shared_examples 'an external link with rel attribute' do
# end
#
# it 'adds rel="nofollow" to external links', feature_category: :team_planning do
# end
class FeatureCategoryOnSharedExamples < RuboCop::Cop::RSpec::Base
MSG = 'Shared examples should not have feature category set'
# @!method feature_category_value(node)
def_node_matcher :feature_category_value, <<~PATTERN
(block
(send #rspec? {#SharedGroups.all} ...
$(hash <(pair (sym :feature_category) _) ...>)
)
...
)
PATTERN
def on_block(node)
value_node = feature_category_value(node)
return unless value_node
add_offense(value_node, message: MSG)
end
end
end
end
end

View File

@ -0,0 +1,52 @@
# frozen_string_literal: true
require 'rubocop/cop/rspec/base'
module RuboCop
module Cop
module RSpec
# Ensures that shared examples and shared context don't have any metadata.
#
# @example
#
# # bad
# RSpec.shared_examples 'an external link with rel attribute', feature_category: :team_planning do
# end
#
# RSpec.shared_examples 'an external link with rel attribute', :aggregate_failures do
# end
#
# RSpec.shared_context 'an external link with rel attribute', :aggregate_failures do
# end
#
# # good
# RSpec.shared_examples 'an external link with rel attribute' do
# end
#
# shared_examples 'an external link with rel attribute' do
# end
#
# it 'adds rel="nofollow" to external links', feature_category: :team_planning do
# end
class SharedGroupsMetadata < RuboCop::Cop::RSpec::Base
MSG = 'Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388'
# @!method metadata_value(node)
def_node_matcher :metadata_value, <<~PATTERN
(block
(send #rspec? {#SharedGroups.all} _description $_ ...)
...
)
PATTERN
def on_block(node)
value_node = metadata_value(node)
return unless value_node
add_offense(value_node, message: MSG)
end
end
end
end
end

View File

@ -892,12 +892,12 @@ RSpec.describe ApplicationController, feature_category: :shared do
end
end
describe 'rescue_from Gitlab::Auth::IpBlacklisted' do
describe 'rescue_from Gitlab::Auth::IpBlocked' do
controller(described_class) do
skip_before_action :authenticate_user!
def index
raise Gitlab::Auth::IpBlacklisted
raise Gitlab::Auth::IpBlocked
end
end

View File

@ -84,22 +84,6 @@ RSpec.describe Projects::CommitController, feature_category: :source_code_manage
expect(response).to be_successful
end
it 'only loads blobs in the current page' do
stub_feature_flags(async_commit_diff_files: false)
stub_const('Projects::CommitController::COMMIT_DIFFS_PER_PAGE', 1)
commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
expect_next_instance_of(Repository) do |repository|
# This commit contains 3 changed files but we expect only the blobs for the first one to be loaded
expect(repository).to receive(:blobs_at).with([[commit.id, '.gitignore']], anything).and_call_original
end
go(id: commit.id)
expect(response).to be_ok
end
shared_examples "export as" do |format|
it "does generally work" do
go(id: commit.id, format: format)

View File

@ -12,8 +12,8 @@ RSpec.describe Projects::ServiceDeskController do
let_it_be(:user) { create(:user) }
before do
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true }
project.add_maintainer(user)
sign_in(user)

View File

@ -1773,8 +1773,8 @@ RSpec.describe ProjectsController, feature_category: :projects do
it 'updates Service Desk attributes' do
project.add_maintainer(user)
sign_in(user)
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true }
params = {
service_desk_enabled: true
}

View File

@ -106,8 +106,8 @@ RSpec.describe 'issue move to another project', feature_category: :team_planning
let(:service_desk_issue) { create(:issue, project: service_desk_project, author: ::User.support_bot) }
before do
allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
regular_project.add_reporter(user)
service_desk_project.add_reporter(user)

View File

@ -10,8 +10,8 @@ RSpec.describe 'Service Desk Issue Tracker', :js, feature_category: :team_planni
before do
# The following two conditions equate to Gitlab::ServiceDesk.supported == true
allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
project.add_maintainer(user)
sign_in(user)

View File

@ -8,18 +8,15 @@ RSpec.describe 'Commit diff', :js, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
using RSpec::Parameterized::TableSyntax
where(:view, :async_diff_file_loading) do
'inline' | true
'inline' | false
'parallel' | true
'parallel' | false
where(:view) do
[
['inline'],
['parallel']
]
end
with_them do
before do
stub_feature_flags(async_commit_diff_files: async_diff_file_loading)
project.add_maintainer(user)
sign_in user
visit project_commit_path(project, sample_commit.id, view: view)

View File

@ -12,8 +12,8 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
sign_in(user)
allow_any_instance_of(Project).to receive(:present).with(current_user: user).and_return(presenter)
allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
allow(::Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
allow(::Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true }
end
it 'shows activation checkbox' do
@ -24,7 +24,7 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
context 'when service_desk_email is disabled' do
before do
allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?).and_return(false)
allow(::Gitlab::Email::ServiceDeskEmail).to receive(:enabled?).and_return(false)
visit edit_project_path(project)
end
@ -43,8 +43,8 @@ RSpec.describe 'Service Desk Setting', :js, :clean_gitlab_redis_cache, feature_c
context 'when service_desk_email is enabled' do
before do
allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?) { true }
allow(::Gitlab::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' }
allow(::Gitlab::Email::ServiceDeskEmail).to receive(:enabled?) { true }
allow(::Gitlab::Email::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' }
visit edit_project_path(project)
end

View File

@ -0,0 +1,122 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::AcceptingProjectSharesFinder, feature_category: :subgroups do
subject(:result) { described_class.new(current_user, project, params).execute }
let_it_be_with_reload(:current_user) { create(:user) }
let_it_be(:group_1) { create(:group) }
let_it_be(:group_1_subgroup) { create(:group, parent: group_1) }
let_it_be(:group_2) { create(:group, name: 'hello-world-group') }
let_it_be(:group_3) { create(:group) }
let_it_be_with_reload(:group) { create(:group) }
let_it_be_with_reload(:project) { create(:project, group: group) }
let(:params) { {} }
context 'when admin', :enable_admin_mode do
let_it_be(:current_user) { create(:admin) }
it 'returns all groups' do
expect(result).to match_array([group_1, group_1_subgroup, group_2, group_3])
end
end
context 'when normal user' do
context 'when the user has no access to the project to be shared' do
it 'does not return any group' do
expect(result).to be_empty
end
end
context 'when the user has no access to any group' do
before do
project.add_maintainer(current_user)
end
it 'does not return any group' do
expect(result).to be_empty
end
end
context "when the project's group has enabled lock on group sharing" do
before do
project.add_maintainer(current_user)
project.namespace.update!(share_with_group_lock: true)
group_1.add_maintainer(current_user)
end
it 'does not return any group' do
expect(result).to be_empty
end
end
context 'when the user has access to groups' do
before do
project.add_maintainer(current_user)
group_1.add_guest(current_user)
group_2.add_guest(current_user)
end
it 'returns groups where the user has at least guest access' do
expect(result).to match_array([group_1, group_1_subgroup, group_2])
end
context 'when searching' do
let(:params) { { search: 'hello' } }
it 'returns groups where the search term matches' do
expect(result).to match_array([group_2])
end
end
end
context 'for sharing outside hierarchy' do
let_it_be_with_reload(:grandparent_group) { create(:group) }
let_it_be(:child_group) { create(:group, parent: grandparent_group) }
let_it_be(:grandchild_group) { create(:group, parent: child_group) }
let_it_be(:grandchild_group_subgroup) { create(:group, parent: grandchild_group) }
let_it_be(:unrelated_group) { create(:group) }
let_it_be_with_reload(:project) { create(:project, group: child_group) }
before do
project.add_maintainer(current_user)
grandparent_group.add_guest(current_user)
unrelated_group.add_guest(current_user)
end
context 'when sharing outside hierarchy is allowed' do
before do
grandparent_group.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: false)
end
it 'returns all groups where the user has at least guest access' do
expect(result).to match_array([grandchild_group, grandchild_group_subgroup, unrelated_group])
end
end
context 'when sharing outside hierarchy is not allowed' do
before do
grandparent_group.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: true)
end
it 'returns groups where the user has at least guest access, but only from within the hierarchy' do
expect(result).to match_array([grandchild_group, grandchild_group_subgroup])
end
context 'when groups are already linked to the project' do
before do
create(:project_group_link, project: project, group: grandchild_group_subgroup)
end
it 'does not appear in the result' do
expect(result).to match_array([grandchild_group])
end
end
end
end
end
end

View File

@ -0,0 +1,42 @@
Return-Path: <jake@example.com>
Received: from iceking.adventuretime.ooo ([unix socket]) by iceking (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA; Thu, 13 Jun 2013 17:03:50 -0400
Received: from mail-ie0-x234.google.com (mail-ie0-x234.google.com [IPv6:2607:f8b0:4001:c03::234]) by iceking.adventuretime.ooo (8.14.3/8.14.3/Debian-9.4) with ESMTP id r5DL3nFJ016967 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 14:03:48 -0700
Received: by 10.0.0.1 with HTTP; Thu, 13 Jun 2013 14:03:48 -0700
Date: Thu, 13 Jun 2013 17:03:48 -0400
From: Jake the Dog <jake@example.com>
To: reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
In-Reply-To: <issue_1@localhost>
References: "<reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost>,<issue_1@localhost>,<exchange@microsoft.com>"
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
Mime-Version: 1.0
Content-Type: text/plain;
charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-Sieve: CMU Sieve 2.2
X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu,
13 Jun 2013 14:03:48 -0700 (PDT)
X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1
I could not disagree more. I am obviously biased but adventure time is the
greatest show ever created. Everyone should watch it.
- Jake out
On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta
<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote:
>
>
>
> eviltrout posted in 'Adventure Time Sux' on Discourse Meta:
>
> ---
> hey guys everyone knows adventure time sucks!
>
> ---
> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3
>
> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences).
>

View File

@ -898,6 +898,59 @@ _An elephant at sunset_
);
});
it('correctly renders a table with checkboxes', () => {
expect(
serialize(
table(
// each table cell must contain at least one paragraph
tableRow(
tableHeader(paragraph('')),
tableHeader(paragraph('Item')),
tableHeader(paragraph('Description')),
),
tableRow(
tableCell(taskList(taskItem(paragraph('')))),
tableCell(paragraph('Item 1')),
tableCell(paragraph('Description 1')),
),
tableRow(
tableCell(taskList(taskItem(paragraph('some text')))),
tableCell(paragraph('Item 2')),
tableCell(paragraph('Description 2')),
),
),
).trim(),
).toBe(
`
<table>
<tr>
<th>
</th>
<th>Item</th>
<th>Description</th>
</tr>
<tr>
<td>
* [ ] &nbsp;
</td>
<td>Item 1</td>
<td>Description 1</td>
</tr>
<tr>
<td>
* [ ] some text
</td>
<td>Item 2</td>
<td>Description 2</td>
</tr>
</table>
`.trim(),
);
});
it('correctly serializes a table with line breaks', () => {
expect(
serialize(

View File

@ -677,8 +677,8 @@ RSpec.describe GitlabSchema.types['Project'] do
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
before do
allow(::Gitlab::ServiceDeskEmail).to receive(:enabled?) { true }
allow(::Gitlab::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' }
allow(::Gitlab::Email::ServiceDeskEmail).to receive(:enabled?) { true }
allow(::Gitlab::Email::ServiceDeskEmail).to receive(:address_for_key) { 'address-suffix@example.com' }
end
context 'when a user can admin issues' do

View File

@ -37,7 +37,7 @@ RSpec.describe AccessTokensHelper do
disable_feed_token: false,
static_objects_external_storage_enabled?: true
)
allow(Gitlab::IncomingEmail).to receive(:supports_issue_creation?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:supports_issue_creation?).and_return(true)
allow(helper).to receive_messages(
current_user: user,
reset_feed_token_profile_path: feed_token_reset_path,

View File

@ -216,8 +216,8 @@ RSpec.describe IssuesHelper do
let!(:new_issue) { create(:issue, author: User.support_bot, project: project2) }
before do
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true }
old_issue.update!(moved_to: new_issue)
end

View File

@ -120,8 +120,8 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
end
it 'raises an IpBlacklisted exception' do
expect { subject }.to raise_error(Gitlab::Auth::IpBlacklisted)
it 'raises an IpBlocked exception' do
expect { subject }.to raise_error(Gitlab::Auth::IpBlocked)
end
end

View File

@ -13,14 +13,29 @@ RSpec.describe Gitlab::Ci::Build::Context::Build, feature_category: :pipeline_co
it { is_expected.to include('CI_PIPELINE_IID' => pipeline.iid.to_s) }
it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) }
it { is_expected.to include('CI_JOB_NAME' => 'some-job') }
it { is_expected.to include('CI_BUILD_REF_NAME' => 'master') }
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
it { is_expected.to include('CI_BUILD_REF_NAME' => 'master') }
end
context 'without passed build-specific attributes' do
let(:context) { described_class.new(pipeline) }
it { is_expected.to include('CI_JOB_NAME' => nil) }
it { is_expected.to include('CI_BUILD_REF_NAME' => 'master') }
it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) }
it { is_expected.to include('CI_JOB_NAME' => nil) }
it { is_expected.to include('CI_COMMIT_REF_NAME' => 'master') }
it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) }
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
it { is_expected.to include('CI_BUILD_REF_NAME' => 'master') }
end
end
context 'when environment:name is provided' do

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Build::Context::Global do
RSpec.describe Gitlab::Ci::Build::Context::Global, feature_category: :pipeline_composition do
let(:pipeline) { create(:ci_pipeline) }
let(:yaml_variables) { {} }
@ -14,7 +14,14 @@ RSpec.describe Gitlab::Ci::Build::Context::Global do
it { is_expected.to include('CI_PROJECT_PATH' => pipeline.project.full_path) }
it { is_expected.not_to have_key('CI_JOB_NAME') }
it { is_expected.not_to have_key('CI_BUILD_REF_NAME') }
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
it { is_expected.not_to have_key('CI_BUILD_REF_NAME') }
end
context 'with passed yaml variables' do
let(:yaml_variables) { [{ key: 'SUPPORTED', value: 'parsed', public: true }] }

View File

@ -191,6 +191,23 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe
.to include('`some-location.yml`: header:spec config contains unknown keys: a')
end
end
context 'when header is not a hash' do
let(:content) do
<<~YAML
spec: abcd
---
run:
script: deploy $[[ inputs.abcd ]]
YAML
end
it 'surfaces header errors' do
expect(valid?).to be_falsy
expect(file.errors)
.to contain_exactly('`some-location.yml`: header:spec config should be a hash')
end
end
end
end

View File

@ -798,7 +798,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_co
[
[[{ if: '$CI_JOB_NAME == "rspec" && $VAR == null', when: 'on_failure' }]],
[[{ if: '$VARIABLE != null', when: 'delayed', start_in: '1 day' }, { if: '$CI_JOB_NAME == "rspec"', when: 'on_failure' }]],
[[{ if: '$VARIABLE == "the wrong value"', when: 'delayed', start_in: '1 day' }, { if: '$CI_BUILD_NAME == "rspec"', when: 'on_failure' }]]
[[{ if: '$VARIABLE == "the wrong value"', when: 'delayed', start_in: '1 day' }, { if: '$CI_JOB_NAME == "rspec"', when: 'on_failure' }]]
]
end
@ -811,6 +811,30 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build, feature_category: :pipeline_co
end
end
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
context 'with an explicit `when: on_failure`' do
where(:rule_set) do
[
[[{ if: '$CI_JOB_NAME == "rspec" && $VAR == null', when: 'on_failure' }]],
[[{ if: '$VARIABLE != null', when: 'delayed', start_in: '1 day' }, { if: '$CI_JOB_NAME == "rspec"', when: 'on_failure' }]],
[[{ if: '$VARIABLE == "the wrong value"', when: 'delayed', start_in: '1 day' }, { if: '$CI_BUILD_NAME == "rspec"', when: 'on_failure' }]]
]
end
with_them do
it { is_expected.to be_included }
it 'correctly populates when:' do
expect(seed_build.attributes).to include(when: 'on_failure')
end
end
end
end
context 'with an explicit `when: delayed`' do
where(:rule_set) do
[

View File

@ -30,13 +30,41 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
CI_COMMIT_REF_PROTECTED
CI_COMMIT_TIMESTAMP
CI_COMMIT_AUTHOR
CI_BUILD_REF
CI_BUILD_BEFORE_SHA
CI_BUILD_REF_NAME
CI_BUILD_REF_SLUG
])
end
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
it 'includes all predefined variables in a valid order' do
keys = subject.pluck(:key)
expect(keys).to contain_exactly(*%w[
CI_PIPELINE_IID
CI_PIPELINE_SOURCE
CI_PIPELINE_CREATED_AT
CI_COMMIT_SHA
CI_COMMIT_SHORT_SHA
CI_COMMIT_BEFORE_SHA
CI_COMMIT_REF_NAME
CI_COMMIT_REF_SLUG
CI_COMMIT_BRANCH
CI_COMMIT_MESSAGE
CI_COMMIT_TITLE
CI_COMMIT_DESCRIPTION
CI_COMMIT_REF_PROTECTED
CI_COMMIT_TIMESTAMP
CI_COMMIT_AUTHOR
CI_BUILD_REF
CI_BUILD_BEFORE_SHA
CI_BUILD_REF_NAME
CI_BUILD_REF_SLUG
])
end
end
context 'when the pipeline is running for a tag' do
let(:pipeline) { build(:ci_empty_pipeline, :created, project: project, ref: 'test', tag: true) }
@ -58,15 +86,44 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
CI_COMMIT_REF_PROTECTED
CI_COMMIT_TIMESTAMP
CI_COMMIT_AUTHOR
CI_BUILD_REF
CI_BUILD_BEFORE_SHA
CI_BUILD_REF_NAME
CI_BUILD_REF_SLUG
CI_COMMIT_TAG
CI_COMMIT_TAG_MESSAGE
CI_BUILD_TAG
])
end
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
it 'includes all predefined variables in a valid order' do
keys = subject.pluck(:key)
expect(keys).to contain_exactly(*%w[
CI_PIPELINE_IID
CI_PIPELINE_SOURCE
CI_PIPELINE_CREATED_AT
CI_COMMIT_SHA
CI_COMMIT_SHORT_SHA
CI_COMMIT_BEFORE_SHA
CI_COMMIT_REF_NAME
CI_COMMIT_REF_SLUG
CI_COMMIT_MESSAGE
CI_COMMIT_TITLE
CI_COMMIT_DESCRIPTION
CI_COMMIT_REF_PROTECTED
CI_COMMIT_TIMESTAMP
CI_COMMIT_AUTHOR
CI_BUILD_REF
CI_BUILD_BEFORE_SHA
CI_BUILD_REF_NAME
CI_BUILD_REF_SLUG
CI_COMMIT_TAG
CI_COMMIT_TAG_MESSAGE
CI_BUILD_TAG
])
end
end
end
context 'when merge request is present' do
@ -305,10 +362,24 @@ RSpec.describe Gitlab::Ci::Variables::Builder::Pipeline, feature_category: :secr
expect(subject.to_hash.keys)
.not_to include(
'CI_COMMIT_TAG',
'CI_COMMIT_TAG_MESSAGE',
'CI_BUILD_TAG'
'CI_COMMIT_TAG_MESSAGE'
)
end
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
it 'does not expose tag variables' do
expect(subject.to_hash.keys)
.not_to include(
'CI_COMMIT_TAG',
'CI_COMMIT_TAG_MESSAGE',
'CI_BUILD_TAG'
)
end
end
end
context 'without a commit' do

View File

@ -35,10 +35,6 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
value: '1' },
{ key: 'CI_ENVIRONMENT_NAME',
value: 'test' },
{ key: 'CI_BUILD_NAME',
value: 'rspec:test 1' },
{ key: 'CI_BUILD_STAGE',
value: job.stage_name },
{ key: 'CI',
value: 'true' },
{ key: 'GITLAB_CI',
@ -139,14 +135,6 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
value: pipeline.git_commit_timestamp },
{ key: 'CI_COMMIT_AUTHOR',
value: pipeline.git_author_full_text },
{ key: 'CI_BUILD_REF',
value: job.sha },
{ key: 'CI_BUILD_BEFORE_SHA',
value: job.before_sha },
{ key: 'CI_BUILD_REF_NAME',
value: job.ref },
{ key: 'CI_BUILD_REF_SLUG',
value: job.ref_slug },
{ key: 'YAML_VARIABLE',
value: 'value' },
{ key: 'GITLAB_USER_ID',
@ -166,6 +154,151 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache, featur
it { expect(subject.to_runner_variables).to eq(predefined_variables) }
context 'when FF `ci_remove_legacy_predefined_variables` is disabled' do
before do
stub_feature_flags(ci_remove_legacy_predefined_variables: false)
end
let(:predefined_variables) do
[
{ key: 'CI_JOB_NAME',
value: 'rspec:test 1' },
{ key: 'CI_JOB_NAME_SLUG',
value: 'rspec-test-1' },
{ key: 'CI_JOB_STAGE',
value: job.stage_name },
{ key: 'CI_NODE_TOTAL',
value: '1' },
{ key: 'CI_ENVIRONMENT_NAME',
value: 'test' },
{ key: 'CI_BUILD_NAME',
value: 'rspec:test 1' },
{ key: 'CI_BUILD_STAGE',
value: job.stage_name },
{ key: 'CI',
value: 'true' },
{ key: 'GITLAB_CI',
value: 'true' },
{ key: 'CI_SERVER_URL',
value: Gitlab.config.gitlab.url },
{ key: 'CI_SERVER_HOST',
value: Gitlab.config.gitlab.host },
{ key: 'CI_SERVER_PORT',
value: Gitlab.config.gitlab.port.to_s },
{ key: 'CI_SERVER_PROTOCOL',
value: Gitlab.config.gitlab.protocol },
{ key: 'CI_SERVER_SHELL_SSH_HOST',
value: Gitlab.config.gitlab_shell.ssh_host.to_s },
{ key: 'CI_SERVER_SHELL_SSH_PORT',
value: Gitlab.config.gitlab_shell.ssh_port.to_s },
{ key: 'CI_SERVER_NAME',
value: 'GitLab' },
{ key: 'CI_SERVER_VERSION',
value: Gitlab::VERSION },
{ key: 'CI_SERVER_VERSION_MAJOR',
value: Gitlab.version_info.major.to_s },
{ key: 'CI_SERVER_VERSION_MINOR',
value: Gitlab.version_info.minor.to_s },
{ key: 'CI_SERVER_VERSION_PATCH',
value: Gitlab.version_info.patch.to_s },
{ key: 'CI_SERVER_REVISION',
value: Gitlab.revision },
{ key: 'GITLAB_FEATURES',
value: project.licensed_features.join(',') },
{ key: 'CI_PROJECT_ID',
value: project.id.to_s },
{ key: 'CI_PROJECT_NAME',
value: project.path },
{ key: 'CI_PROJECT_TITLE',
value: project.title },
{ key: 'CI_PROJECT_DESCRIPTION',
value: project.description },
{ key: 'CI_PROJECT_PATH',
value: project.full_path },
{ key: 'CI_PROJECT_PATH_SLUG',
value: project.full_path_slug },
{ key: 'CI_PROJECT_NAMESPACE',
value: project.namespace.full_path },
{ key: 'CI_PROJECT_NAMESPACE_ID',
value: project.namespace.id.to_s },
{ key: 'CI_PROJECT_ROOT_NAMESPACE',
value: project.namespace.root_ancestor.path },
{ key: 'CI_PROJECT_URL',
value: project.web_url },
{ key: 'CI_PROJECT_VISIBILITY',
value: "private" },
{ key: 'CI_PROJECT_REPOSITORY_LANGUAGES',
value: project.repository_languages.map(&:name).join(',').downcase },
{ key: 'CI_PROJECT_CLASSIFICATION_LABEL',
value: project.external_authorization_classification_label },
{ key: 'CI_DEFAULT_BRANCH',
value: project.default_branch },
{ key: 'CI_CONFIG_PATH',
value: project.ci_config_path_or_default },
{ key: 'CI_PAGES_DOMAIN',
value: Gitlab.config.pages.host },
{ key: 'CI_PAGES_URL',
value: project.pages_url },
{ key: 'CI_API_V4_URL',
value: API::Helpers::Version.new('v4').root_url },
{ key: 'CI_API_GRAPHQL_URL',
value: Gitlab::Routing.url_helpers.api_graphql_url },
{ key: 'CI_TEMPLATE_REGISTRY_HOST',
value: template_registry_host },
{ key: 'CI_PIPELINE_IID',
value: pipeline.iid.to_s },
{ key: 'CI_PIPELINE_SOURCE',
value: pipeline.source },
{ key: 'CI_PIPELINE_CREATED_AT',
value: pipeline.created_at.iso8601 },
{ key: 'CI_COMMIT_SHA',
value: job.sha },
{ key: 'CI_COMMIT_SHORT_SHA',
value: job.short_sha },
{ key: 'CI_COMMIT_BEFORE_SHA',
value: job.before_sha },
{ key: 'CI_COMMIT_REF_NAME',
value: job.ref },
{ key: 'CI_COMMIT_REF_SLUG',
value: job.ref_slug },
{ key: 'CI_COMMIT_BRANCH',
value: job.ref },
{ key: 'CI_COMMIT_MESSAGE',
value: pipeline.git_commit_message },
{ key: 'CI_COMMIT_TITLE',
value: pipeline.git_commit_title },
{ key: 'CI_COMMIT_DESCRIPTION',
value: pipeline.git_commit_description },
{ key: 'CI_COMMIT_REF_PROTECTED',
value: (!!pipeline.protected_ref?).to_s },
{ key: 'CI_COMMIT_TIMESTAMP',
value: pipeline.git_commit_timestamp },
{ key: 'CI_COMMIT_AUTHOR',
value: pipeline.git_author_full_text },
{ key: 'CI_BUILD_REF',
value: job.sha },
{ key: 'CI_BUILD_BEFORE_SHA',
value: job.before_sha },
{ key: 'CI_BUILD_REF_NAME',
value: job.ref },
{ key: 'CI_BUILD_REF_SLUG',
value: job.ref_slug },
{ key: 'YAML_VARIABLE',
value: 'value' },
{ key: 'GITLAB_USER_ID',
value: user.id.to_s },
{ key: 'GITLAB_USER_EMAIL',
value: user.email },
{ key: 'GITLAB_USER_LOGIN',
value: user.username },
{ key: 'GITLAB_USER_NAME',
value: user.name }
].map { |var| var.merge(public: true, masked: false) }
end
it { expect(subject.to_runner_variables).to eq(predefined_variables) }
end
context 'variables ordering' do
def var(name, value)
{ key: name, value: value.to_s, public: true, masked: false }

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::Migrations::PgBackendPid, feature_category: :database do
describe Gitlab::Database::Migrations::PgBackendPid::MigratorPgBackendPid do
let(:klass) do
Class.new do
def with_advisory_lock_connection
yield :conn
end
end
end
it 're-yields with same arguments and wraps it with calls to .say' do
patched_instance = klass.prepend(described_class).new
expect(Gitlab::Database::Migrations::PgBackendPid).to receive(:say).twice
expect { |b| patched_instance.with_advisory_lock_connection(&b) }.to yield_with_args(:conn)
end
end
describe '.patch!' do
it 'patches ActiveRecord::Migrator' do
expect(ActiveRecord::Migrator).to receive(:prepend).with(described_class::MigratorPgBackendPid)
described_class.patch!
end
end
describe '.say' do
it 'outputs the connection information' do
conn = ActiveRecord::Base.connection
expect(conn).to receive(:object_id).and_return(9876)
expect(conn).to receive(:select_value).with('SELECT pg_backend_pid()').and_return(12345)
expect(Gitlab::Database).to receive(:db_config_name).with(conn).and_return('main')
expected_output = "main: == [advisory_lock_connection] object_id: 9876, pg_backend_pid: 12345\n"
expect { described_class.say(conn) }.to output(expected_output).to_stdout
end
end
end

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::IncomingEmail do
RSpec.describe Gitlab::Email::IncomingEmail, feature_category: :service_desk do
let(:setting_name) { :incoming_email }
it_behaves_like 'common email methods'

View File

@ -11,9 +11,10 @@ RSpec.describe Gitlab::Email::Receiver do
shared_examples 'successful receive' do
let(:handler) { double(:handler, project: project, execute: true, metrics_event: nil, metrics_params: nil) }
let(:client_id) { 'email/jake@example.com' }
let(:mail_key) { 'gitlabhq/gitlabhq+auth_token' }
it 'correctly finds the mail key' do
expect(Gitlab::Email::Handler).to receive(:for).with(an_instance_of(Mail::Message), 'gitlabhq/gitlabhq+auth_token').and_return(handler)
expect(Gitlab::Email::Handler).to receive(:for).with(an_instance_of(Mail::Message), mail_key).and_return(handler)
receiver.execute
end
@ -92,6 +93,16 @@ RSpec.describe Gitlab::Email::Receiver do
it_behaves_like 'successful receive'
end
context 'when mail key is in the references header with a comma' do
let(:email_raw) { fixture_file('emails/valid_reply_with_references_in_comma.eml') }
let(:meta_key) { :references }
let(:meta_value) { ['"<reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost>,<issue_1@localhost>,<exchange@microsoft.com>"'] }
it_behaves_like 'successful receive' do
let(:mail_key) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
end
end
context 'when all other headers are missing' do
let(:email_raw) { fixture_file('emails/missing_delivered_to_header.eml') }
let(:meta_key) { :received_recipients }

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::ServiceDeskEmail do
RSpec.describe Gitlab::Email::ServiceDeskEmail, feature_category: :service_desk do
let(:setting_name) { :service_desk_email }
it_behaves_like 'common email methods'

View File

@ -138,7 +138,7 @@ RSpec.describe Gitlab::Middleware::Go, feature_category: :source_code_management
context 'with a blacklisted ip' do
it 'returns forbidden' do
expect(Gitlab::Auth).to receive(:find_for_git_client).and_raise(Gitlab::Auth::IpBlacklisted)
expect(Gitlab::Auth).to receive(:find_for_git_client).and_raise(Gitlab::Auth::IpBlocked)
response = go
expect(response[0]).to eq(403)

View File

@ -4,8 +4,8 @@ require 'spec_helper'
RSpec.describe Gitlab::ServiceDesk do
before do
allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
end
describe 'enabled?' do
@ -39,7 +39,7 @@ RSpec.describe Gitlab::ServiceDesk do
context 'when incoming emails are disabled' do
before do
allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(false)
allow(Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(false)
end
it { is_expected.to be_falsy }
@ -47,7 +47,7 @@ RSpec.describe Gitlab::ServiceDesk do
context 'when email key is not supported' do
before do
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(false)
allow(Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(false)
end
it { is_expected.to be_falsy }

Some files were not shown because too many files have changed in this diff Show More