Commit 7351a484 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent b4ded0ba
...@@ -21,6 +21,9 @@ const MAX_CHAR_LIMIT = 5000; ...@@ -21,6 +21,9 @@ const MAX_CHAR_LIMIT = 5000;
export default function renderMermaid($els) { export default function renderMermaid($els) {
if (!$els.length) return; if (!$els.length) return;
// A diagram may have been truncated in search results which will cause errors, so abort the render.
if (document.querySelector('body').dataset.page === 'search:show') return;
import(/* webpackChunkName: 'mermaid' */ 'mermaid') import(/* webpackChunkName: 'mermaid' */ 'mermaid')
.then(mermaid => { .then(mermaid => {
mermaid.initialize({ mermaid.initialize({
......
...@@ -18,7 +18,7 @@ const firstDayOfWeekChoices = Object.freeze({ ...@@ -18,7 +18,7 @@ const firstDayOfWeekChoices = Object.freeze({
const LOADING_HTML = ` const LOADING_HTML = `
<div class="text-center"> <div class="text-center">
<i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i> <div class="spinner spinner-md"></div>
</div> </div>
`; `;
......
...@@ -57,10 +57,8 @@ import UserOverviewBlock from './user_overview_block'; ...@@ -57,10 +57,8 @@ import UserOverviewBlock from './user_overview_block';
* </div> * </div>
* </div> * </div>
* *
* <div class="loading-status"> * <div class="loading">
* <div class="loading"> * Loading Animation
* Loading Animation
* </div>
* </div> * </div>
*/ */
...@@ -242,7 +240,7 @@ export default class UserTabs { ...@@ -242,7 +240,7 @@ export default class UserTabs {
} }
toggleLoading(status) { toggleLoading(status) {
return this.$parentEl.find('.loading-status .loading').toggleClass('hide', !status); return this.$parentEl.find('.loading').toggleClass('hide', !status);
} }
setCurrentAction(source) { setCurrentAction(source) {
......
...@@ -581,6 +581,7 @@ img.emoji { ...@@ -581,6 +581,7 @@ img.emoji {
.gl-line-height-24 { line-height: $gl-line-height-24; } .gl-line-height-24 { line-height: $gl-line-height-24; }
.gl-line-height-14 { line-height: $gl-line-height-14; } .gl-line-height-14 { line-height: $gl-line-height-14; }
.gl-font-size-0 { font-size: 0; }
.gl-font-size-12 { font-size: $gl-font-size-12; } .gl-font-size-12 { font-size: $gl-font-size-12; }
.gl-font-size-14 { font-size: $gl-font-size-14; } .gl-font-size-14 { font-size: $gl-font-size-14; }
.gl-font-size-16 { font-size: $gl-font-size-16; } .gl-font-size-16 { font-size: $gl-font-size-16; }
......
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
.tree-controls { .tree-controls {
text-align: right; text-align: right;
.btn { > .btn,
.project-action-button > .btn,
.git-clone-holder > .btn {
margin-left: 8px; margin-left: 8px;
} }
......
...@@ -37,10 +37,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -37,10 +37,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
define_method(action) { perform_update if submitted? } define_method(action) { perform_update if submitted? }
end end
def show
render :general
end
def update def update
perform_update perform_update
end end
...@@ -73,7 +69,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -73,7 +69,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
RepositoryCheck::ClearWorker.perform_async RepositoryCheck::ClearWorker.perform_async
redirect_to( redirect_to(
admin_application_settings_path, general_admin_application_settings_path,
notice: _('Started asynchronous removal of all repository check states.') notice: _('Started asynchronous removal of all repository check states.')
) )
end end
...@@ -256,7 +252,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -256,7 +252,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
session[:ask_for_usage_stats_consent] = current_user.requires_usage_stats_consent? session[:ask_for_usage_stats_consent] = current_user.requires_usage_stats_consent?
end end
redirect_path = referer_path(request) || admin_application_settings_path redirect_path = referer_path(request) || general_admin_application_settings_path
respond_to do |format| respond_to do |format|
if successful if successful
......
...@@ -25,6 +25,14 @@ module Ci ...@@ -25,6 +25,14 @@ module Ci
# rubocop:enable Cop/ActiveRecordSerialize # rubocop:enable Cop/ActiveRecordSerialize
state_machine :status do state_machine :status do
after_transition created: :pending do |bridge|
next unless bridge.downstream_project
bridge.run_after_commit do
bridge.schedule_downstream_pipeline!
end
end
event :manual do event :manual do
transition all => :manual transition all => :manual
end end
...@@ -38,6 +46,12 @@ module Ci ...@@ -38,6 +46,12 @@ module Ci
raise NotImplementedError raise NotImplementedError
end end
def schedule_downstream_pipeline!
raise InvalidBridgeTypeError unless downstream_project
::Ci::CreateCrossProjectPipelineWorker.perform_async(self.id)
end
def inherit_status_from_downstream!(pipeline) def inherit_status_from_downstream!(pipeline)
case pipeline.status case pipeline.status
when 'success' when 'success'
......
...@@ -31,6 +31,7 @@ module Clusters ...@@ -31,6 +31,7 @@ module Clusters
has_many :cluster_projects, class_name: 'Clusters::Project' has_many :cluster_projects, class_name: 'Clusters::Project'
has_many :projects, through: :cluster_projects, class_name: '::Project' has_many :projects, through: :cluster_projects, class_name: '::Project'
has_one :cluster_project, -> { order(id: :desc) }, class_name: 'Clusters::Project' has_one :cluster_project, -> { order(id: :desc) }, class_name: 'Clusters::Project'
has_many :deployment_clusters
has_many :cluster_groups, class_name: 'Clusters::Group' has_many :cluster_groups, class_name: 'Clusters::Group'
has_many :groups, through: :cluster_groups, class_name: '::Group' has_many :groups, through: :cluster_groups, class_name: '::Group'
......
...@@ -17,7 +17,12 @@ module CommitStatusEnums ...@@ -17,7 +17,12 @@ module CommitStatusEnums
archived_failure: 9, archived_failure: 9,
unmet_prerequisites: 10, unmet_prerequisites: 10,
scheduler_failure: 11, scheduler_failure: 11,
data_integrity_failure: 12 data_integrity_failure: 12,
insufficient_bridge_permissions: 1_001,
downstream_bridge_project_not_found: 1_002,
invalid_bridge_trigger: 1_003,
bridge_pipeline_is_child_pipeline: 1_006,
downstream_pipeline_creation_failed: 1_007
} }
end end
end end
......
...@@ -18,6 +18,8 @@ class Deployment < ApplicationRecord ...@@ -18,6 +18,8 @@ class Deployment < ApplicationRecord
has_many :merge_requests, has_many :merge_requests,
through: :deployment_merge_requests through: :deployment_merge_requests
has_one :deployment_cluster
has_internal_id :iid, scope: :project, track_if: -> { !importing? }, init: ->(s) do has_internal_id :iid, scope: :project, track_if: -> { !importing? }, init: ->(s) do
Deployment.where(project: s.project).maximum(:iid) if s&.project Deployment.where(project: s.project).maximum(:iid) if s&.project
end end
......
# frozen_string_literal: true
class DeploymentCluster < ApplicationRecord
belongs_to :deployment, optional: false
belongs_to :cluster, optional: false, class_name: 'Clusters::Cluster'
end
...@@ -190,6 +190,7 @@ class Project < ApplicationRecord ...@@ -190,6 +190,7 @@ class Project < ApplicationRecord
has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting' has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting'
has_one :metrics_setting, inverse_of: :project, class_name: 'ProjectMetricsSetting' has_one :metrics_setting, inverse_of: :project, class_name: 'ProjectMetricsSetting'
has_one :grafana_integration, inverse_of: :project has_one :grafana_integration, inverse_of: :project
has_one :project_setting, ->(project) { where_or_create_by(project: project) }, inverse_of: :project
# Merge Requests for target project should be removed with it # Merge Requests for target project should be removed with it
has_many :merge_requests, foreign_key: 'target_project_id', inverse_of: :target_project has_many :merge_requests, foreign_key: 'target_project_id', inverse_of: :target_project
......
# frozen_string_literal: true
class ProjectSetting < ApplicationRecord
belongs_to :project, inverse_of: :project_setting
self.primary_key = :project_id
def self.where_or_create_by(attrs)
where(primary_key => safe_find_or_create_by(attrs))
end
end
...@@ -13,7 +13,12 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated ...@@ -13,7 +13,12 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
archived_failure: 'The job is archived and cannot be run', archived_failure: 'The job is archived and cannot be run',
unmet_prerequisites: 'The job failed to complete prerequisite tasks', unmet_prerequisites: 'The job failed to complete prerequisite tasks',
scheduler_failure: 'The scheduler failed to assign job to the runner, please try again or contact system administrator', scheduler_failure: 'The scheduler failed to assign job to the runner, please try again or contact system administrator',
data_integrity_failure: 'There has been a structural integrity problem detected, please contact system administrator' data_integrity_failure: 'There has been a structural integrity problem detected, please contact system administrator',
invalid_bridge_trigger: 'This job could not be executed because downstream pipeline trigger definition is invalid',
downstream_bridge_project_not_found: 'This job could not be executed because downstream bridge project could not be found',
insufficient_bridge_permissions: 'This job could not be executed because of insufficient permissions to create a downstream pipeline',
bridge_pipeline_is_child_pipeline: 'This job belongs to a child pipeline and cannot create further child pipelines',
downstream_pipeline_creation_failed: 'The downstream pipeline could not be created'
}.freeze }.freeze
private_constant :CALLOUT_FAILURE_MESSAGES private_constant :CALLOUT_FAILURE_MESSAGES
......
# frozen_string_literal: true
module Ci
# TODO: rename this (and worker) to CreateDownstreamPipelineService
class CreateCrossProjectPipelineService < ::BaseService
include Gitlab::Utils::StrongMemoize
def execute(bridge)
@bridge = bridge
pipeline_params = @bridge.downstream_pipeline_params
target_ref = pipeline_params.dig(:target_revision, :ref)
return unless ensure_preconditions!(target_ref)
service = ::Ci::CreatePipelineService.new(
pipeline_params.fetch(:project),
current_user,
pipeline_params.fetch(:target_revision))
downstream_pipeline = service.execute(
pipeline_params.fetch(:source), pipeline_params[:execute_params]) do |pipeline|
@bridge.sourced_pipelines.build(
source_pipeline: @bridge.pipeline,
source_project: @bridge.project,
project: @bridge.downstream_project,
pipeline: pipeline)
pipeline.variables.build(@bridge.downstream_variables)
end
downstream_pipeline.tap do |pipeline|
@bridge.drop!(:downstream_pipeline_creation_failed) if pipeline.has_yaml_errors?
end
end
private
def ensure_preconditions!(target_ref)
unless downstream_project_accessible?
@bridge.drop!(:downstream_bridge_project_not_found)
return false
end
# TODO: Remove this condition if favour of model validation
# https://gitlab.com/gitlab-org/gitlab/issues/38338
if downstream_project == project && !@bridge.triggers_child_pipeline?
@bridge.drop!(:invalid_bridge_trigger)
return false
end
# TODO: Remove this condition if favour of model validation
# https://gitlab.com/gitlab-org/gitlab/issues/38338
if @bridge.triggers_child_pipeline? && @bridge.pipeline.parent_pipeline.present?
@bridge.drop!(:bridge_pipeline_is_child_pipeline)
return false
end
unless can_create_downstream_pipeline?(target_ref)
@bridge.drop!(:insufficient_bridge_permissions)
return false
end
true
end
def downstream_project_accessible?
downstream_project.present? &&
can?(current_user, :read_project, downstream_project)
end
def can_create_downstream_pipeline?(target_ref)
can?(current_user, :update_pipeline, project) &&
can?(current_user, :create_pipeline, downstream_project) &&
can_update_branch?(target_ref)
end
def can_update_branch?(target_ref)
::Gitlab::UserAccess.new(current_user, project: downstream_project).can_update_branch?(target_ref)
end
def downstream_project
strong_memoize(:downstream_project) do
@bridge.downstream_project
end
end
end
end
...@@ -79,6 +79,8 @@ module MergeRequests ...@@ -79,6 +79,8 @@ module MergeRequests
end end
merge_request.update!(merge_commit_sha: commit_id) merge_request.update!(merge_commit_sha: commit_id)
ensure
merge_request.update_column(:in_progress_merge_commit_sha, nil)
end end
def try_merge def try_merge
...@@ -89,8 +91,6 @@ module MergeRequests ...@@ -89,8 +91,6 @@ module MergeRequests
rescue => e rescue => e
handle_merge_error(log_message: e.message) handle_merge_error(log_message: e.message)
raise_error('Something went wrong during merge') raise_error('Something went wrong during merge')
ensure
merge_request.update!(in_progress_merge_commit_sha: nil)
end end
def after_merge def after_merge
......
...@@ -90,6 +90,7 @@ module Projects ...@@ -90,6 +90,7 @@ module Projects
end end
@project.track_project_repository @project.track_project_repository
@project.create_project_setting unless @project.project_setting
event_service.create_project(@project, current_user) event_service.create_project(@project, current_user)
system_hook_service.execute_hooks_for(@project, :create) system_hook_service.execute_hooks_for(@project, :create)
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
.well-segment.admin-well.admin-well-features .well-segment.admin-well.admin-well-features
%h4 Features %h4 Features
= feature_entry(_('Sign up'), = feature_entry(_('Sign up'),
href: admin_application_settings_path(anchor: 'js-signup-settings'), href: general_admin_application_settings_path(anchor: 'js-signup-settings'),
enabled: allow_signup?) enabled: allow_signup?)
= feature_entry(_('LDAP'), = feature_entry(_('LDAP'),
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
doc_href: help_page_path('administration/auth/ldap')) doc_href: help_page_path('administration/auth/ldap'))
= feature_entry(_('Gravatar'), = feature_entry(_('Gravatar'),
href: admin_application_settings_path(anchor: 'js-account-settings'), href: general_admin_application_settings_path(anchor: 'js-account-settings'),
enabled: gravatar_enabled?) enabled: gravatar_enabled?)
= feature_entry(_('OmniAuth'), = feature_entry(_('OmniAuth'),
href: admin_application_settings_path(anchor: 'js-signin-settings'), href: general_admin_application_settings_path(anchor: 'js-signin-settings'),
enabled: Gitlab::Auth.omniauth_enabled?, enabled: Gitlab::Auth.omniauth_enabled?,
doc_href: help_page_path('integration/omniauth')) doc_href: help_page_path('integration/omniauth'))
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
.float-right .float-right
= version_status_badge = version_status_badge
%p %p
%a{ href: admin_application_settings_path } %a{ href: general_admin_application_settings_path }
GitLab GitLab
%span.float-right %span.float-right
= Gitlab::VERSION = Gitlab::VERSION
......
%h2#usage-ping Usage ping
.bs-callout.clearfix
%p
User cohorts are shown because the usage ping is enabled. The data sent with
this is shown below. To disable this, visit
= succeed '.' do
= link_to 'application settings', admin_application_settings_path(anchor: 'usage-statistics')
%pre.usage-data.js-syntax-highlight.code.highlight{ data: { endpoint: usage_data_admin_application_settings_path(format: :html) } }
...@@ -221,7 +221,7 @@ ...@@ -221,7 +221,7 @@
= _('Appearance') = _('Appearance')
= nav_link(controller: :application_settings) do = nav_link(controller: :application_settings) do
= link_to admin_application_settings_path do = link_to general_admin_application_settings_path do
.nav-icon-container .nav-icon-container
= sprite_icon('settings') = sprite_icon('settings')
%span.nav-item-name.qa-admin-settings-item %span.nav-item-name.qa-admin-settings-item
...@@ -229,11 +229,11 @@ ...@@ -229,11 +229,11 @@
%ul.sidebar-sub-level-items.qa-admin-sidebar-settings-submenu %ul.sidebar-sub-level-items.qa-admin-sidebar-settings-submenu
= nav_link(controller: :application_settings, html_options: { class: "fly-out-top-item" } ) do = nav_link(controller: :application_settings, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_application_settings_path do = link_to general_admin_application_settings_path do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
= _('Settings') = _('Settings')
%li.divider.fly-out-top-item %li.divider.fly-out-top-item
= nav_link(path: 'application_settings#show') do = nav_link(path: 'application_settings#general') do
= link_to general_admin_application_settings_path, title: _('General'), class: 'qa-admin-settings-general-item' do = link_to general_admin_application_settings_path, title: _('General'), class: 'qa-admin-settings-general-item' do
%span %span
= _('General') = _('General')
......
...@@ -75,7 +75,7 @@ ...@@ -75,7 +75,7 @@
= link_to new_project_tag_path(@project) do = link_to new_project_tag_path(@project) do
#{ _('New tag') } #{ _('New tag') }
.tree-controls< .tree-controls{ class: ("gl-font-size-0" if vue_file_list_enabled?) }<
= render_if_exists 'projects/tree/lock_link' = render_if_exists 'projects/tree/lock_link'
- if vue_file_list_enabled? - if vue_file_list_enabled?
#js-tree-history-link.d-inline-block{ data: { history_link: project_commits_path(@project, @ref) } } #js-tree-history-link.d-inline-block{ data: { history_link: project_commits_path(@project, @ref) } }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.calendar-block.prepend-top-default.append-bottom-default .calendar-block.prepend-top-default.append-bottom-default
.user-calendar.d-none.d-sm-block{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } } .user-calendar.d-none.d-sm-block{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
%h4.center.light %h4.center.light
= spinner nil, true .spinner.spinner-md
.user-calendar-activities.d-none.d-sm-block .user-calendar-activities.d-none.d-sm-block
.row .row
.col-md-12.col-lg-6 .col-md-12.col-lg-6
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
= link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all" = link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_path } } .overview-content-list{ data: { href: user_path } }
.center.light.loading .center.light.loading
= spinner nil, true .spinner.spinner-md
.col-md-12.col-lg-6 .col-md-12.col-lg-6
.projects-block .projects-block
...@@ -27,4 +27,4 @@ ...@@ -27,4 +27,4 @@
= link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all" = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_projects_path } } .overview-content-list{ data: { href: user_projects_path } }
.center.light.loading .center.light.loading
= spinner nil, true .spinner.spinner-md
...@@ -130,7 +130,8 @@ ...@@ -130,7 +130,8 @@
%h4.prepend-top-20 %h4.prepend-top-20
= s_('UserProfile|Most Recent Activity') = s_('UserProfile|Most Recent Activity')
.content_list{ data: { href: user_path } } .content_list{ data: { href: user_path } }
= spinner .loading
.spinner.spinner-md
- if profile_tab?(:groups) - if profile_tab?(:groups)
#groups.tab-pane #groups.tab-pane
...@@ -152,8 +153,8 @@ ...@@ -152,8 +153,8 @@
#snippets.tab-pane #snippets.tab-pane
-# This tab is always loaded via AJAX -# This tab is always loaded via AJAX
.loading-status .loading.hide
= spinner .spinner.spinner-md
- if profile_tabs.empty? - if profile_tabs.empty?
.row .row
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class AdminEmailWorker class AdminEmailWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category_not_owned! feature_category_not_owned!
......
...@@ -531,6 +531,12 @@ ...@@ -531,6 +531,12 @@
:latency_sensitive: :latency_sensitive:
:resource_boundary: :unknown :resource_boundary: :unknown
:weight: 3 :weight: 3
- :name: pipeline_default:ci_create_cross_project_pipeline
:feature_category: :continuous_integration
:has_external_dependencies:
:latency_sensitive:
:resource_boundary: :cpu
:weight: 3
- :name: pipeline_default:ci_pipeline_bridge_status - :name: pipeline_default:ci_pipeline_bridge_status
:feature_category: :continuous_integration :feature_category: :continuous_integration
:has_external_dependencies: :has_external_dependencies:
......
# frozen_string_literal: true
module Ci
class CreateCrossProjectPipelineWorker
include ::ApplicationWorker
include ::PipelineQueue
worker_resource_boundary :cpu
def perform(bridge_id)
::Ci::Bridge.find_by_id(bridge_id).try do |bridge|
::Ci::CreateCrossProjectPipelineService
.new(bridge.project, bridge.user)
.execute(bridge)
end
end
end
end
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class ExpireBuildArtifactsWorker class ExpireBuildArtifactsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :continuous_integration feature_category :continuous_integration
......
...@@ -4,7 +4,10 @@ class GitlabUsagePingWorker ...@@ -4,7 +4,10 @@ class GitlabUsagePingWorker
LEASE_TIMEOUT = 86400 LEASE_TIMEOUT = 86400
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category_not_owned! feature_category_not_owned!
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class ImportExportProjectCleanupWorker class ImportExportProjectCleanupWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :importers feature_category :importers
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class PruneOldEventsWorker class PruneOldEventsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category_not_owned! feature_category_not_owned!
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
# table. # table.
class PruneWebHookLogsWorker class PruneWebHookLogsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :integrations feature_category :integrations
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class RemoveUnreferencedLfsObjectsWorker class RemoveUnreferencedLfsObjectsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :git_lfs feature_category :git_lfs
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class RepositoryArchiveCacheWorker class RepositoryArchiveCacheWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :source_code_management feature_category :source_code_management
......
...@@ -3,7 +3,10 @@ ...@@ -3,7 +3,10 @@
module RepositoryCheck module RepositoryCheck
class DispatchWorker class DispatchWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
include ::EachShardWorker include ::EachShardWorker
include ExclusiveLeaseGuard include ExclusiveLeaseGuard
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
class RequestsProfilesWorker class RequestsProfilesWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :source_code_management feature_category :source_code_management
......
...@@ -2,7 +2,11 @@ ...@@ -2,7 +2,11 @@
class StuckImportJobsWorker class StuckImportJobsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext # rubocop:disable Scalability/CronWorkerContext
# This worker updates several import states inline and does not schedule
# other jobs. So no context needed
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
feature_category :importers feature_category :importers
worker_resource_boundary :cpu worker_resource_boundary :cpu
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
class TrendingProjectsWorker class TrendingProjectsWorker
include ApplicationWorker include ApplicationWorker
# rubocop:disable Scalability/CronWorkerContext
# This worker does not perform work scoped to a context
include CronjobQueue
# rubocop:enable Scalability/CronWorkerContext
include CronjobQueue # rubocop:disable Scalability/CronWorkerContext include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
feature_category :source_code_management feature_category :source_code_management
......
---
title: Deprecate /admin/application_settings in favor of /admin/application_settings/general. The former path is to be removed in 13.0.
merge_request: 22252
author: Alexander Oleynikov
type: changed
---
title: Fix merge train unnecessarily retries pipeline by a race condition
merge_request: 24566
author:
type: fixed
---
title: Introduce project_settings table
merge_request: 19761
author:
type: added
...@@ -107,7 +107,11 @@ namespace :admin do ...@@ -107,7 +107,11 @@ namespace :admin do
end end
end end
resource :application_settings, only: [:show, :update] do resource :application_settings, only: :update do
# This redirect should be removed with 13.0 release.
# https://gitlab.com/gitlab-org/gitlab/issues/199427
get '/', to: redirect('admin/application_settings/general'), as: nil
resources :services, only: [:index, :edit, :update] resources :services, only: [:index, :edit, :update]
get :usage_data get :usage_data
......
# frozen_string_literal: true
class CreateProjectSettings < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
create_table :project_settings, id: false do |t|
t.timestamps_with_timezone null: false
t.references :project, primary_key: true, default: nil, type: :integer, index: false, foreign_key: { on_delete: :cascade }
end
end
end
# frozen_string_literal: true
class CreateDeploymentClusters < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
create_table :deployment_clusters, id: false, force: :cascade do |t|
t.references :deployment, foreign_key: { on_delete: :cascade }, primary_key: true, type: :integer, index: false, default: nil
t.references :cluster, foreign_key: { on_delete: :cascade }, type: :integer, index: false, null: false
t.string :kubernetes_namespace, limit: 255
t.index [:cluster_id, :kubernetes_namespace], name: 'idx_deployment_clusters_on_cluster_id_and_kubernetes_namespace'
t.index [:cluster_id, :deployment_id], unique: true
end
end
end
# frozen_string_literal: true
class BackfillProjectSettings < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'BackfillProjectSettings'
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 10_000
disable_ddl_transaction!
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
say "Scheduling `#{MIGRATION}` jobs"
queue_background_migration_jobs_by_range_at_intervals(Project, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
end
def down
# NOOP
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_02_06_111847) do ActiveRecord::Schema.define(version: 2020_02_07_151640) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm" enable_extension "pg_trgm"
...@@ -1341,6 +1341,13 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do ...@@ -1341,6 +1341,13 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do
t.index ["token_encrypted"], name: "index_deploy_tokens_on_token_encrypted", unique: true t.index ["token_encrypted"], name: "index_deploy_tokens_on_token_encrypted", unique: true
end end
create_table "deployment_clusters", primary_key: "deployment_id", id: :integer, default: nil, force: :cascade do |t|
t.integer "cluster_id", null: false
t.string "kubernetes_namespace", limit: 255
t.index ["cluster_id", "deployment_id"], name: "index_deployment_clusters_on_cluster_id_and_deployment_id", unique: true
t.index ["cluster_id", "kubernetes_namespace"], name: "idx_deployment_clusters_on_cluster_id_and_kubernetes_namespace"
end
create_table "deployment_merge_requests", id: false, force: :cascade do |t| create_table "deployment_merge_requests", id: false, force: :cascade do |t|
t.integer "deployment_id", null: false t.integer "deployment_id", null: false
t.integer "merge_request_id", null: false t.integer "merge_request_id", null: false
...@@ -3296,6 +3303,11 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do ...@@ -3296,6 +3303,11 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do
t.index ["project_id"], name: "index_project_repository_states_on_project_id", unique: true t.index ["project_id"], name: "index_project_repository_states_on_project_id", unique: true
end end
create_table "project_settings", primary_key: "project_id", id: :integer, default: nil, force: :cascade do |t|
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
end
create_table "project_statistics", id: :serial, force: :cascade do |t| create_table "project_statistics", id: :serial, force: :cascade do |t|
t.integer "project_id", null: false t.integer "project_id", null: false
t.integer "namespace_id", null: false t.integer "namespace_id", null: false
...@@ -3745,7 +3757,7 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do ...@@ -3745,7 +3757,7 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do
t.string "sso_url", null: false t.string "sso_url", null: false
t.boolean "enforced_sso", default: false, null: false t.boolean "enforced_sso", default: false, null: false
t.boolean "enforced_group_managed_accounts", default: false, null: false t.boolean "enforced_group_managed_accounts", default: false, null: false
t.boolean "prohibited_outer_forks", default: false, null: false t.boolean "prohibited_outer_forks", default: false
t.index ["group_id"], name: "index_saml_providers_on_group_id" t.index ["group_id"], name: "index_saml_providers_on_group_id"
end end
...@@ -4659,6 +4671,8 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do ...@@ -4659,6 +4671,8 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do
add_foreign_key "dependency_proxy_blobs", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "dependency_proxy_blobs", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "dependency_proxy_group_settings", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "dependency_proxy_group_settings", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "deploy_keys_projects", "projects", name: "fk_58a901ca7e", on_delete: :cascade add_foreign_key "deploy_keys_projects", "projects", name: "fk_58a901ca7e", on_delete: :cascade
add_foreign_key "deployment_clusters", "clusters", on_delete: :cascade
add_foreign_key "deployment_clusters", "deployments", on_delete: :cascade
add_foreign_key "deployment_merge_requests", "deployments", on_delete: :cascade add_foreign_key "deployment_merge_requests", "deployments", on_delete: :cascade
add_foreign_key "deployment_merge_requests", "merge_requests", on_delete: :cascade add_foreign_key "deployment_merge_requests", "merge_requests", on_delete: :cascade
add_foreign_key "deployments", "clusters", name: "fk_289bba3222", on_delete: :nullify add_foreign_key "deployments", "clusters", name: "fk_289bba3222", on_delete: :nullify
...@@ -4881,6 +4895,7 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do ...@@ -4881,6 +4895,7 @@ ActiveRecord::Schema.define(version: 2020_02_06_111847) do
add_foreign_key "project_repositories", "projects", on_delete: :cascade add_foreign_key "project_repositories", "projects", on_delete: :cascade
add_foreign_key "project_repositories", "shards", on_delete: :restrict add_foreign_key "project_repositories", "shards", on_delete: :restrict
add_foreign_key "project_repository_states", "projects", on_delete: :cascade add_foreign_key "project_repository_states", "projects", on_delete: :cascade
add_foreign_key "project_settings", "projects", on_delete: :cascade
add_foreign_key "project_statistics", "projects", on_delete: :cascade add_foreign_key "project_statistics", "projects", on_delete: :cascade
add_foreign_key "project_tracing_settings", "projects", on_delete: :cascade add_foreign_key "project_tracing_settings", "projects", on_delete: :cascade
add_foreign_key "projects", "pool_repositories", name: "fk_6e5c14658a", on_delete: :nullify add_foreign_key "projects", "pool_repositories", name: "fk_6e5c14658a", on_delete: :nullify
......
...@@ -249,7 +249,7 @@ on the **secondary** node. ...@@ -249,7 +249,7 @@ on the **secondary** node.
Geo synchronizes repositories over HTTP/HTTPS, and therefore requires this clone Geo synchronizes repositories over HTTP/HTTPS, and therefore requires this clone
method to be enabled. Navigate to **Admin Area > Settings** method to be enabled. Navigate to **Admin Area > Settings**
(`/admin/application_settings`) on the **primary** node, and set (`/admin/application_settings/general`) on the **primary** node, and set
`Enabled Git access protocols` to `Both SSH and HTTP(S)` or `Only HTTP(S)`. `Enabled Git access protocols` to `Both SSH and HTTP(S)` or `Only HTTP(S)`.
### Step 7. Verify proper functioning of the **secondary** node ### Step 7. Verify proper functioning of the **secondary** node
......
...@@ -33,8 +33,8 @@ bundle exec rake gitlab:import_export:data RAILS_ENV=production ...@@ -33,8 +33,8 @@ bundle exec rake gitlab:import_export:data RAILS_ENV=production
Note the following: Note the following:
- Importing is not possible if the version of the import instance is older than that of the exporter. - Importing is not possible if the version of the import instance is older than that of the exporter.
- The project import option must be enabled in - The project import option must be enabled in application settings
application settings (`/admin/application_settings`) under **Import sources**, which is available (`/admin/application_settings/general`) under **Import sources**, which is available
under **{admin}** **Admin Area >** **{settings}** **Settings > Visibility and access controls**. under **{admin}** **Admin Area >** **{settings}** **Settings > Visibility and access controls**.
- The exports are stored in a temporary [shared directory](../../development/shared_files.md) - The exports are stored in a temporary [shared directory](../../development/shared_files.md)
and are deleted every 24 hours by a specific worker. and are deleted every 24 hours by a specific worker.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
These API calls allow you to read and modify GitLab instance These API calls allow you to read and modify GitLab instance
[application settings](#list-of-settings-that-can-be-accessed-via-api-calls) [application settings](#list-of-settings-that-can-be-accessed-via-api-calls)
as appear in `/admin/application_settings`. You have to be an as appear in `/admin/application_settings/general`. You have to be an
administrator in order to perform this action. administrator in order to perform this action.
## Get current application settings ## Get current application settings
......
...@@ -201,7 +201,7 @@ The table below shows what kind of documentation goes where. ...@@ -201,7 +201,7 @@ The table below shows what kind of documentation goes where.
describing what can be achieved by accessing GitLab's admin interface describing what can be achieved by accessing GitLab's admin interface
(_not to be confused with `doc/administration` where server access is (_not to be confused with `doc/administration` where server access is
required_). required_).
1. Every category under `/admin/application_settings` should have its 1. Every category under `/admin/application_settings/` should have its
own document located at `doc/user/admin_area/settings/`. For example, own document located at `doc/user/admin_area/settings/`. For example,
the **Visibility and Access Controls** category should have a document the **Visibility and Access Controls** category should have a document
located at `doc/user/admin_area/settings/visibility_and_access_controls.md`. located at `doc/user/admin_area/settings/visibility_and_access_controls.md`.
......
...@@ -276,6 +276,18 @@ class SomeCrossCuttingConcernWorker ...@@ -276,6 +276,18 @@ class SomeCrossCuttingConcernWorker
end end
``` ```
## Job weights
Some jobs have a weight declared. This is only used when running Sidekiq
in the default execution mode - using
[`sidekiq-cluster`](../administration/operations/extra_sidekiq_processes.md)
does not account for weights.
As we are [moving towards using `sidekiq-cluster` in
Core](https://gitlab.com/gitlab-org/gitlab/issues/34396), newly-added
workers do not need to have weights specified. They can simply use the
default weight, which is 1.
## Worker context ## Worker context
To have some more information about workers in the logs, we add To have some more information about workers in the logs, we add
......
...@@ -49,7 +49,7 @@ From GitLab 12.6, the minimum password length set in this configuration file wil ...@@ -49,7 +49,7 @@ From GitLab 12.6, the minimum password length set in this configuration file wil
The user password length is set to a minimum of 8 characters by default. The user password length is set to a minimum of 8 characters by default.
To change that using GitLab UI: To change that using GitLab UI:
In **Admin Area > Settings** (`/admin/application_settings`), go to the section **Sign-up restrictions**. In **Admin Area > Settings** (`/admin/application_settings/general`), go to the section **Sign-up restrictions**.
[Minimum password length settings](../user/admin_area/img/minimum_password_length_settings_v12_6.png) [Minimum password length settings](../user/admin_area/img/minimum_password_length_settings_v12_6.png)
......
...@@ -17,7 +17,7 @@ algorithms. ...@@ -17,7 +17,7 @@ algorithms.
GitLab allows you to restrict the allowed SSH key technology as well as specify GitLab allows you to restrict the allowed SSH key technology as well as specify
the minimum key length for each technology. the minimum key length for each technology.
In **Admin Area > Settings** (`/admin/application_settings`), expand the In **Admin Area > Settings** (`/admin/application_settings/general`), expand the
**Visibility and access controls** section: **Visibility and access controls** section:
![SSH keys restriction admin settings](img/ssh_keys_restrictions_settings.png) ![SSH keys restriction admin settings](img/ssh_keys_restrictions_settings.png)
......
...@@ -25,7 +25,8 @@ won't be able to leave the 2FA configuration area at `/profile/two_factor_auth`. ...@@ -25,7 +25,8 @@ won't be able to leave the 2FA configuration area at `/profile/two_factor_auth`.
To enable 2FA for all users: To enable 2FA for all users:
1. Navigate to **Admin Area > Settings > General** (`/admin/application_settings`). 1. Navigate to **Admin Area > Settings > General**
(`/admin/application_settings/general`).
1. Expand the **Sign-in restrictions** section, where you can configure both. 1. Expand the **Sign-in restrictions** section, where you can configure both.
If you want 2FA enforcement to take effect on next login, change the grace If you want 2FA enforcement to take effect on next login, change the grace
......
...@@ -8,7 +8,7 @@ GitLab can be configured to require confirmation of a user's email address when ...@@ -8,7 +8,7 @@ GitLab can be configured to require confirmation of a user's email address when
the user signs up. When this setting is enabled, the user is unable to sign in until the user signs up. When this setting is enabled, the user is unable to sign in until
they confirm their email address. they confirm their email address.
In **Admin Area > Settings** (`/admin/application_settings`), go to the section In **Admin Area > Settings** (`/admin/application_settings/general`), go to the section
**Sign-up Restrictions** and look for the **Send confirmation email on sign-up** option. **Sign-up Restrictions** and look for the **Send confirmation email on sign-up** option.
<!-- ## Troubleshooting <!-- ## Troubleshooting
......
...@@ -17,8 +17,8 @@ Note the following: ...@@ -17,8 +17,8 @@ Note the following:
- Importing is not possible if the import instance version differs from - Importing is not possible if the import instance version differs from
that of the exporter. that of the exporter.
- The project import option must be enabled in - The project import option must be enabled in application settings
application settings (`/admin/application_settings`) under under **Import sources**, which is (`/admin/application_settings/general`) under **Import sources**, which is
available under **{admin}** **Admin Area >** **{settings}** **Settings > Visibility and access controls**. available under **{admin}** **Admin Area >** **{settings}** **Settings > Visibility and access controls**.
Ask your administrator if you don't see the **GitLab export** button when Ask your administrator if you don't see the **GitLab export** button when
creating a new project. creating a new project.
......
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Backfill project_settings for a range of projects
class BackfillProjectSettings
def perform(start_id, end_id)
ActiveRecord::Base.connection.execute <<~SQL
INSERT INTO project_settings (project_id, created_at, updated_at)
SELECT projects.id, now(), now()
FROM projects
WHERE projects.id BETWEEN #{start_id} AND #{end_id}
ON CONFLICT (project_id) DO NOTHING;
SQL
end
end
end
end
...@@ -24,8 +24,14 @@ module Gitlab ...@@ -24,8 +24,14 @@ module Gitlab
# non-environment job. # non-environment job.
return unless deployment.valid? && deployment.environment.persisted? return unless deployment.valid? && deployment.environment.persisted?
deployment.cluster_id = if cluster_id = deployment.environment.deployment_platform&.cluster_id
deployment.environment.deployment_platform&.cluster_id # double write cluster_id until 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
deployment.cluster_id = cluster_id
deployment.deployment_cluster = ::DeploymentCluster.new(
cluster_id: cluster_id,
kubernetes_namespace: deployment.environment.deployment_namespace
)
end
# Allocate IID for deployments. # Allocate IID for deployments.
# This operation must be outside of transactions of pipeline creations. # This operation must be outside of transactions of pipeline creations.
......
...@@ -18,7 +18,12 @@ module Gitlab ...@@ -18,7 +18,12 @@ module Gitlab
archived_failure: 'archived failure', archived_failure: 'archived failure',
unmet_prerequisites: 'unmet prerequisites', unmet_prerequisites: 'unmet prerequisites',
scheduler_failure: 'scheduler failure', scheduler_failure: 'scheduler failure',
data_integrity_failure: 'data integrity failure' data_integrity_failure: 'data integrity failure',
invalid_bridge_trigger: 'downstream pipeline trigger definition is invalid',
downstream_bridge_project_not_found: 'downstream project could not be found',
insufficient_bridge_permissions: 'no permissions to trigger downstream pipeline',
bridge_pipeline_is_child_pipeline: 'creation of child pipeline not allowed from another child pipeline',
downstream_pipeline_creation_failed: 'downstream pipeline can not be created'
}.freeze }.freeze
private_constant :REASONS private_constant :REASONS
......
...@@ -23,7 +23,7 @@ module RuboCop ...@@ -23,7 +23,7 @@ module RuboCop
PATTERN PATTERN
def_node_search :schedules_with_batch_context?, <<~PATTERN def_node_search :schedules_with_batch_context?, <<~PATTERN
(send (...) {:bulk_perform_async_with_contexts :bulk_perform_in_with_contexts} (...)) (send (...) {:bulk_perform_async_with_contexts :bulk_perform_in_with_contexts} _*)
PATTERN PATTERN
def on_send(node) def on_send(node)
......
...@@ -56,49 +56,49 @@ describe Admin::ApplicationSettingsController do ...@@ -56,49 +56,49 @@ describe Admin::ApplicationSettingsController do
it 'updates the password_authentication_enabled_for_git setting' do it 'updates the password_authentication_enabled_for_git setting' do
put :update, params: { application_setting: { password_authentication_enabled_for_git: "0" } } put :update, params: { application_setting: { password_authentication_enabled_for_git: "0" } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.password_authentication_enabled_for_git).to eq(false) expect(ApplicationSetting.current.password_authentication_enabled_for_git).to eq(false)
end end
it 'updates the default_project_visibility for string value' do it 'updates the default_project_visibility for string value' do
put :update, params: { application_setting: { default_project_visibility: "20" } } put :update, params: { application_setting: { default_project_visibility: "20" } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.default_project_visibility).to eq(Gitlab::VisibilityLevel::PUBLIC) expect(ApplicationSetting.current.default_project_visibility).to eq(Gitlab::VisibilityLevel::PUBLIC)
end end
it 'update the restricted levels for string values' do it 'update the restricted levels for string values' do
put :update, params: { application_setting: { restricted_visibility_levels: %w[10 20] } } put :update, params: { application_setting: { restricted_visibility_levels: %w[10 20] } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.restricted_visibility_levels).to eq([10, 20]) expect(ApplicationSetting.current.restricted_visibility_levels).to eq([10, 20])
end end
it 'updates the restricted_visibility_levels when empty array is passed' do it 'updates the restricted_visibility_levels when empty array is passed' do
put :update, params: { application_setting: { restricted_visibility_levels: [""] } } put :update, params: { application_setting: { restricted_visibility_levels: [""] } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.restricted_visibility_levels).to be_empty expect(ApplicationSetting.current.restricted_visibility_levels).to be_empty
end end
it 'updates the receive_max_input_size setting' do it 'updates the receive_max_input_size setting' do
put :update, params: { application_setting: { receive_max_input_size: "1024" } } put :update, params: { application_setting: { receive_max_input_size: "1024" } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.receive_max_input_size).to eq(1024) expect(ApplicationSetting.current.receive_max_input_size).to eq(1024)
end end
it 'updates the default_project_creation for string value' do it 'updates the default_project_creation for string value' do
put :update, params: { application_setting: { default_project_creation: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS } } put :update, params: { application_setting: { default_project_creation: ::Gitlab::Access::MAINTAINER_PROJECT_ACCESS } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.default_project_creation).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS) expect(ApplicationSetting.current.default_project_creation).to eq(::Gitlab::Access::MAINTAINER_PROJECT_ACCESS)
end end
it 'updates minimum_password_length setting' do it 'updates minimum_password_length setting' do
put :update, params: { application_setting: { minimum_password_length: 10 } } put :update, params: { application_setting: { minimum_password_length: 10 } }
expect(response).to redirect_to(admin_application_settings_path) expect(response).to redirect_to(general_admin_application_settings_path)
expect(ApplicationSetting.current.minimum_password_length).to eq(10) expect(ApplicationSetting.current.minimum_password_length).to eq(10)
end end
......
...@@ -29,7 +29,7 @@ describe Projects::PipelinesController do ...@@ -29,7 +29,7 @@ describe Projects::PipelinesController do
stub_feature_flags(ci_pipeline_persisted_stages: true) stub_feature_flags(ci_pipeline_persisted_stages: true)
end end
it 'returns serialized pipelines', :request_store do it 'returns serialized pipelines' do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
get_pipelines_index_json get_pipelines_index_json
...@@ -60,7 +60,6 @@ describe Projects::PipelinesController do ...@@ -60,7 +60,6 @@ describe Projects::PipelinesController do
# There appears to be one extra query for Pipelines#has_warnings? for some reason # There appears to be one extra query for Pipelines#has_warnings? for some reason
expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1) expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response['pipelines'].count).to eq 10 expect(json_response['pipelines'].count).to eq 10
end end
...@@ -90,11 +89,18 @@ describe Projects::PipelinesController do ...@@ -90,11 +89,18 @@ describe Projects::PipelinesController do
end end
it 'does not execute N+1 queries' do it 'does not execute N+1 queries' do
queries = ActiveRecord::QueryRecorder.new do get_pipelines_index_json
control_count = ActiveRecord::QueryRecorder.new do
get_pipelines_index_json get_pipelines_index_json
end end.count
expect(queries.count).to be <= 36 create_all_pipeline_types
# There appears to be one extra query for Pipelines#has_warnings? for some reason
expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['pipelines'].count).to eq 10
end end
end end
......
...@@ -121,7 +121,7 @@ describe 'Admin disables Git access protocol', :js do ...@@ -121,7 +121,7 @@ describe 'Admin disables Git access protocol', :js do
end end
def switch_git_protocol(value) def switch_git_protocol(value)
visit admin_application_settings_path visit general_admin_application_settings_path
page.within('.as-visibility-access') do page.within('.as-visibility-access') do
find('#application_setting_enabled_git_access_protocol').find(:xpath, "option[#{value}]").select_option find('#application_setting_enabled_git_access_protocol').find(:xpath, "option[#{value}]").select_option
......
...@@ -37,7 +37,7 @@ describe 'Admin mode', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode ...@@ -37,7 +37,7 @@ describe 'Admin mode', :clean_gitlab_redis_shared_state, :do_not_mock_admin_mode
end end
it 'is necessary to provide credentials again before opening pages in admin scope' do it 'is necessary to provide credentials again before opening pages in admin scope' do
visit admin_application_settings_path # admin logged out because not in admin_mode visit general_admin_application_settings_path # admin logged out because not in admin_mode
expect(page).to have_current_path(new_admin_session_path) expect(page).to have_current_path(new_admin_session_path)
end end
......
...@@ -458,11 +458,11 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc ...@@ -458,11 +458,11 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin) sign_in(admin)
visit admin_application_settings_path visit general_admin_application_settings_path
end end
it 'loads admin settings page without redirect for reauthentication' do it 'loads admin settings page without redirect for reauthentication' do
expect(current_path).to eq admin_application_settings_path expect(current_path).to eq general_admin_application_settings_path
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::BackgroundMigration::BackfillProjectSettings, :migration, schema: 20200114113341 do
let(:projects) { table(:projects) }
let(:project_settings) { table(:project_settings) }
let(:namespace) { table(:namespaces).create(name: 'user', path: 'user') }
let(:project) { projects.create(namespace_id: namespace.id) }
subject { described_class.new }
describe '#perform' do
it 'creates settings for all projects in range' do
projects.create(id: 5, namespace_id: namespace.id)
projects.create(id: 7, namespace_id: namespace.id)
projects.create(id: 8, namespace_id: namespace.id)
subject.perform(5, 7)
expect(project_settings.all.pluck(:project_id)).to contain_exactly(5, 7)
end
end
end
...@@ -33,13 +33,18 @@ describe Gitlab::Ci::Pipeline::Seed::Deployment do ...@@ -33,13 +33,18 @@ describe Gitlab::Ci::Pipeline::Seed::Deployment do
expect(subject.iid).to be_present expect(subject.iid).to be_present
expect(subject.environment.name).to eq('production') expect(subject.environment.name).to eq('production')
expect(subject.cluster).to be_nil expect(subject.cluster).to be_nil
expect(subject.deployment_cluster).to be_nil
end end
context 'when environment has deployment platform' do context 'when environment has deployment platform' do
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
it 'returns a deployment with cluster id' do it 'sets the cluster and deployment_cluster' do
expect(subject.cluster).to eq(cluster) expect(subject.cluster).to eq(cluster) # until we stop double writing in 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
expect(subject.deployment_cluster).to have_attributes(
cluster_id: cluster.id,
kubernetes_namespace: subject.environment.deployment_namespace
)
end end
end end
......
...@@ -452,6 +452,7 @@ project: ...@@ -452,6 +452,7 @@ project:
- package_files - package_files
- tracing_setting - tracing_setting
- alerting_setting - alerting_setting
- project_setting
- webide_pipelines - webide_pipelines
- reviews - reviews
- incident_management_setting - incident_management_setting
...@@ -613,4 +614,4 @@ epic: ...@@ -613,4 +614,4 @@ epic:
- due_date_sourcing_epic - due_date_sourcing_epic
- events - events
- resource_label_events - resource_label_events
- user_mentions - user_mentions
\ No newline at end of file
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200122123016_backfill_project_settings.rb')
describe BackfillProjectSettings, :migration, :sidekiq, schema: 20200114113341 do
let(:projects) { table(:projects) }
let(:namespace) { table(:namespaces).create(name: 'user', path: 'user') }
let(:project) { projects.create(namespace_id: namespace.id) }
describe '#up' do
before do
stub_const("#{described_class}::BATCH_SIZE", 2)
projects.create(id: 1, namespace_id: namespace.id)
projects.create(id: 2, namespace_id: namespace.id)
projects.create(id: 3, namespace_id: namespace.id)
end
it 'schedules BackfillProjectSettings background jobs' do
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 1, 2)
expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 3, 3)
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
end
end
end
end
end
...@@ -53,6 +53,16 @@ describe Ci::Bridge do ...@@ -53,6 +53,16 @@ describe Ci::Bridge do
end end
end end
describe 'state machine transitions' do
context 'when bridge points towards downstream' do
it 'schedules downstream pipeline creation' do
expect(bridge).to receive(:schedule_downstream_pipeline!)
bridge.enqueue!
end
end
end
describe '#inherit_status_from_downstream!' do describe '#inherit_status_from_downstream!' do
let(:downstream_pipeline) { build(:ci_pipeline, status: downstream_status) } let(:downstream_pipeline) { build(:ci_pipeline, status: downstream_status) }
......
...@@ -26,6 +26,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do ...@@ -26,6 +26,7 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
it { is_expected.to have_one(:application_runner) } it { is_expected.to have_one(:application_runner) }
it { is_expected.to have_many(:kubernetes_namespaces) } it { is_expected.to have_many(:kubernetes_namespaces) }
it { is_expected.to have_one(:cluster_project) } it { is_expected.to have_one(:cluster_project) }
it { is_expected.to have_many(:deployment_clusters) }
it { is_expected.to delegate_method(:status).to(:provider) } it { is_expected.to delegate_method(:status).to(:provider) }
it { is_expected.to delegate_method(:status_reason).to(:provider) } it { is_expected.to delegate_method(:status_reason).to(:provider) }
......
# frozen_string_literal: true
require 'spec_helper'
describe DeploymentCluster do
let(:cluster) { create(:cluster) }
let(:deployment) { create(:deployment) }
let(:kubernetes_namespace) { 'an-example-namespace' }
subject { described_class.new(deployment: deployment, cluster: cluster, kubernetes_namespace: kubernetes_namespace) }
it { is_expected.to belong_to(:deployment).required }
it { is_expected.to belong_to(:cluster).required }
it do
is_expected.to have_attributes(
cluster_id: cluster.id,
deployment_id: deployment.id,
kubernetes_namespace: kubernetes_namespace
)
end
end
...@@ -10,6 +10,7 @@ describe Deployment do ...@@ -10,6 +10,7 @@ describe Deployment do
it { is_expected.to belong_to(:cluster).class_name('Clusters::Cluster') } it { is_expected.to belong_to(:cluster).class_name('Clusters::Cluster') }
it { is_expected.to belong_to(:user) } it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:deployable) } it { is_expected.to belong_to(:deployable) }
it { is_expected.to have_one(:deployment_cluster) }
it { is_expected.to have_many(:deployment_merge_requests) } it { is_expected.to have_many(:deployment_merge_requests) }
it { is_expected.to have_many(:merge_requests).through(:deployment_merge_requests) } it { is_expected.to have_many(:merge_requests).through(:deployment_merge_requests) }
......
# frozen_string_literal: true
require 'spec_helper'
describe ProjectSetting, type: :model do
it { is_expected.to belong_to(:project) }
end
...@@ -69,6 +69,7 @@ describe Project do ...@@ -69,6 +69,7 @@ describe Project do
it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) } it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) }
it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') } it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') }
it { is_expected.to have_one(:error_tracking_setting).class_name('ErrorTracking::ProjectErrorTrackingSetting') } it { is_expected.to have_one(:error_tracking_setting).class_name('ErrorTracking::ProjectErrorTrackingSetting') }
it { is_expected.to have_one(:project_setting) }
it { is_expected.to have_many(:commit_statuses) } it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:ci_pipelines) } it { is_expected.to have_many(:ci_pipelines) }
it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:builds) }
...@@ -155,6 +156,11 @@ describe Project do ...@@ -155,6 +156,11 @@ describe Project do
expect(project.pages_metadatum).to be_an_instance_of(ProjectPagesMetadatum) expect(project.pages_metadatum).to be_an_instance_of(ProjectPagesMetadatum)
expect(project.pages_metadatum).to be_persisted expect(project.pages_metadatum).to be_persisted
end end
it 'automatically creates a project setting row' do
expect(project.project_setting).to be_an_instance_of(ProjectSetting)
expect(project.project_setting).to be_persisted
end
end end
context 'updating cd_cd_settings' do context 'updating cd_cd_settings' do
......
...@@ -58,7 +58,9 @@ describe RuboCop::Cop::Scalability::CronWorkerContext do ...@@ -58,7 +58,9 @@ describe RuboCop::Cop::Scalability::CronWorkerContext do
include CronjobQueue include CronjobQueue
def perform def perform
SomeOtherWorker.bulk_perform_async_with_contexts(contexts_for_arguments) SomeOtherWorker.bulk_perform_async_with_contexts(things,
arguments_proc: -> (thing) { thing.id },
context_proc: -> (thing) { { project: thing.project } })
end end
end end
CODE CODE
...@@ -70,7 +72,9 @@ describe RuboCop::Cop::Scalability::CronWorkerContext do ...@@ -70,7 +72,9 @@ describe RuboCop::Cop::Scalability::CronWorkerContext do
include CronjobQueue include CronjobQueue
def perform def perform
SomeOtherWorker.bulk_perform_in_with_contexts(contexts_for_arguments) SomeOtherWorker.bulk_perform_in_with_contexts(10.minutes, things,
arguments_proc: -> (thing) { thing.id },
context_proc: -> (thing) { { project: thing.project } })
end end
end end
CODE CODE
......
This diff is collapsed.
...@@ -31,6 +31,11 @@ describe MergeRequests::MergeService do ...@@ -31,6 +31,11 @@ describe MergeRequests::MergeService do
it { expect(merge_request).to be_valid } it { expect(merge_request).to be_valid }
it { expect(merge_request).to be_merged } it { expect(merge_request).to be_merged }
it 'persists merge_commit_sha and nullifies in_progress_merge_commit_sha' do
expect(merge_request.merge_commit_sha).not_to be_nil
expect(merge_request.in_progress_merge_commit_sha).to be_nil
end
it 'sends email to user2 about merge of new merge_request' do it 'sends email to user2 about merge of new merge_request' do
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
expect(email.to.first).to eq(user2.email) expect(email.to.first).to eq(user2.email)
......
...@@ -43,6 +43,12 @@ describe Projects::CreateService, '#execute' do ...@@ -43,6 +43,12 @@ describe Projects::CreateService, '#execute' do
create_project(user, opts) create_project(user, opts)
end end
it 'creates associated project settings' do
project = create_project(user, opts)
expect(project.project_setting).to be_persisted
end
end end
context "admin creates project with other user's namespace_id" do context "admin creates project with other user's namespace_id" do
......
# frozen_string_literal: true
require 'spec_helper'
describe Ci::CreateCrossProjectPipelineWorker do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let(:bridge) { create(:ci_bridge, user: user, pipeline: pipeline) }
let(:service) { double('pipeline creation service') }
describe '#perform' do
context 'when bridge exists' do
it 'calls cross project pipeline creation service' do
expect(Ci::CreateCrossProjectPipelineService)
.to receive(:new)
.with(project, user)
.and_return(service)
expect(service).to receive(:execute).with(bridge)
described_class.new.perform(bridge.id)
end
end
context 'when bridge does not exist' do
it 'does nothing' do
expect(Ci::CreateCrossProjectPipelineService)
.not_to receive(:new)
described_class.new.perform(1234)
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment