diff options
Diffstat (limited to 'app')
44 files changed, 688 insertions, 584 deletions
diff --git a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue index 3280ff48129..e57e17c38c1 100644 --- a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue +++ b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue @@ -20,6 +20,8 @@ import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import { __ } from '~/locale'; import _ from 'underscore'; +export const tableDataClass = 'table-col d-flex d-sm-table-cell'; + export default { FIRST_PAGE: 1, PREV_PAGE: 1, @@ -29,37 +31,37 @@ export default { key: 'error', label: __('Error'), thClass: 'w-60p', - tdClass: 'table-col d-flex d-sm-table-cell px-3', + tdClass: `${tableDataClass} px-3`, }, { key: 'events', label: __('Events'), thClass: 'text-right', - tdClass: 'table-col d-flex d-sm-table-cell', + tdClass: `${tableDataClass}`, }, { key: 'users', label: __('Users'), thClass: 'text-right', - tdClass: 'table-col d-flex d-sm-table-cell', + tdClass: `${tableDataClass}`, }, { key: 'lastSeen', label: __('Last seen'), thClass: '', - tdClass: 'table-col d-flex d-sm-table-cell', + tdClass: `${tableDataClass}`, }, { key: 'ignore', label: '', thClass: 'w-3rem', - tdClass: 'table-col d-flex pl-0 d-sm-table-cell', + tdClass: `${tableDataClass} pl-0`, }, { key: 'resolved', label: '', thClass: 'w-3rem', - tdClass: 'table-col d-flex pl-0 d-sm-table-cell', + tdClass: `${tableDataClass} pl-0`, }, { key: 'details', diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue index 415fa46835b..a61acf2f6eb 100644 --- a/app/assets/javascripts/jobs/components/sidebar.vue +++ b/app/assets/javascripts/jobs/components/sidebar.vue @@ -119,6 +119,7 @@ export default { :class="retryButtonClass" :href="job.retry_path" data-method="post" + data-qa-selector="retry_button" rel="nofollow" >{{ __('Retry') }}</gl-link > diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb deleted file mode 100644 index 3f6e116a62b..00000000000 --- a/app/controllers/projects/git_http_client_controller.rb +++ /dev/null @@ -1,122 +0,0 @@ -# frozen_string_literal: true - -class Projects::GitHttpClientController < Projects::ApplicationController - include ActionController::HttpAuthentication::Basic - include KerberosSpnegoHelper - include Gitlab::Utils::StrongMemoize - - attr_reader :authentication_result, :redirected_path - - delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true - delegate :type, to: :authentication_result, allow_nil: true, prefix: :auth_result - - alias_method :user, :actor - alias_method :authenticated_user, :actor - - # Git clients will not know what authenticity token to send along - skip_around_action :set_session_storage - skip_before_action :verify_authenticity_token - skip_before_action :repository - before_action :authenticate_user - - private - - def download_request? - raise NotImplementedError - end - - def upload_request? - raise NotImplementedError - end - - def authenticate_user - @authentication_result = Gitlab::Auth::Result.new - - if allow_basic_auth? && basic_auth_provided? - login, password = user_name_and_password(request) - - if handle_basic_authentication(login, password) - return # Allow access - end - elsif allow_kerberos_spnego_auth? && spnego_provided? - kerberos_user = find_kerberos_user - - if kerberos_user - @authentication_result = Gitlab::Auth::Result.new( - kerberos_user, nil, :kerberos, Gitlab::Auth.full_authentication_abilities) - - send_final_spnego_response - return # Allow access - end - elsif http_download_allowed? - - @authentication_result = Gitlab::Auth::Result.new(nil, project, :none, [:download_code]) - - return # Allow access - end - - send_challenges - render plain: "HTTP Basic: Access denied\n", status: :unauthorized - rescue Gitlab::Auth::MissingPersonalAccessTokenError - render_missing_personal_access_token - end - - def basic_auth_provided? - has_basic_credentials?(request) - end - - def send_challenges - challenges = [] - challenges << 'Basic realm="GitLab"' if allow_basic_auth? - challenges << spnego_challenge if allow_kerberos_spnego_auth? - headers['Www-Authenticate'] = challenges.join("\n") if challenges.any? - end - - def project - parse_repo_path unless defined?(@project) - - @project - end - - def parse_repo_path - @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:project_id]}") - end - - def render_missing_personal_access_token - render plain: "HTTP Basic: Access denied\n" \ - "You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \ - "You can generate one at #{profile_personal_access_tokens_url}", - status: :unauthorized - end - - def repository - strong_memoize(:repository) do - repo_type.repository_for(project) - end - end - - def repo_type - parse_repo_path unless defined?(@repo_type) - - @repo_type - end - - def handle_basic_authentication(login, password) - @authentication_result = Gitlab::Auth.find_for_git_client( - login, password, project: project, ip: request.ip) - - @authentication_result.success? - end - - def ci? - authentication_result.ci?(project) - end - - def http_download_allowed? - Gitlab::ProtocolAccess.allowed?('http') && - download_request? && - project && Guest.can?(:download_code, project) - end -end - -Projects::GitHttpClientController.prepend_if_ee('EE::Projects::GitHttpClientController') diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb deleted file mode 100644 index 236f1b967de..00000000000 --- a/app/controllers/projects/git_http_controller.rb +++ /dev/null @@ -1,117 +0,0 @@ -# frozen_string_literal: true - -class Projects::GitHttpController < Projects::GitHttpClientController - include WorkhorseRequest - - before_action :access_check - prepend_before_action :deny_head_requests, only: [:info_refs] - - rescue_from Gitlab::GitAccess::UnauthorizedError, with: :render_403_with_exception - rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception - rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422_with_exception - rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception - - # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull) - # GET /foo/bar.git/info/refs?service=git-receive-pack (git push) - def info_refs - log_user_activity if upload_pack? - - render_ok - end - - # POST /foo/bar.git/git-upload-pack (git pull) - def git_upload_pack - enqueue_fetch_statistics_update - - render_ok - end - - # POST /foo/bar.git/git-receive-pack" (git push) - def git_receive_pack - render_ok - end - - private - - def deny_head_requests - head :forbidden if request.head? - end - - def download_request? - upload_pack? - end - - def upload_pack? - git_command == 'git-upload-pack' - end - - def git_command - if action_name == 'info_refs' - params[:service] - else - action_name.dasherize - end - end - - def render_ok - set_workhorse_internal_api_content_type - render json: Gitlab::Workhorse.git_http_ok(repository, repo_type, user, action_name) - end - - def render_403_with_exception(exception) - render plain: exception.message, status: :forbidden - end - - def render_404_with_exception(exception) - render plain: exception.message, status: :not_found - end - - def render_422_with_exception(exception) - render plain: exception.message, status: :unprocessable_entity - end - - def render_503_with_exception(exception) - render plain: exception.message, status: :service_unavailable - end - - def enqueue_fetch_statistics_update - return if Gitlab::Database.read_only? - return if repo_type.wiki? - return unless project&.daily_statistics_enabled? - - ProjectDailyStatisticsWorker.perform_async(project.id) - end - - def access - @access ||= access_klass.new(access_actor, project, 'http', - authentication_abilities: authentication_abilities, - namespace_path: params[:namespace_id], - project_path: project_path, - redirected_path: redirected_path, - auth_result_type: auth_result_type) - end - - def access_actor - return user if user - return :ci if ci? - end - - def access_check - access.check(git_command, Gitlab::GitAccess::ANY) - @project ||= access.project - end - - def access_klass - @access_klass ||= repo_type.access_checker_class - end - - def project_path - @project_path ||= params[:project_id].sub(/\.git$/, '') - end - - def log_user_activity - Users::ActivityService.new(user).execute - end -end - -Projects::GitHttpController.prepend_if_ee('EE::Projects::GitHttpController') diff --git a/app/controllers/projects/lfs_api_controller.rb b/app/controllers/projects/lfs_api_controller.rb deleted file mode 100644 index 1273c55b83a..00000000000 --- a/app/controllers/projects/lfs_api_controller.rb +++ /dev/null @@ -1,140 +0,0 @@ -# frozen_string_literal: true - -class Projects::LfsApiController < Projects::GitHttpClientController - include LfsRequest - include Gitlab::Utils::StrongMemoize - - LFS_TRANSFER_CONTENT_TYPE = 'application/octet-stream' - - skip_before_action :lfs_check_access!, only: [:deprecated] - before_action :lfs_check_batch_operation!, only: [:batch] - - def batch - unless objects.present? - render_lfs_not_found - return - end - - if download_request? - render json: { objects: download_objects! } - elsif upload_request? - render json: { objects: upload_objects! } - else - raise "Never reached" - end - end - - def deprecated - render( - json: { - message: _('Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.'), - documentation_url: "#{Gitlab.config.gitlab.url}/help" - }, - status: :not_implemented - ) - end - - private - - def download_request? - params[:operation] == 'download' - end - - def upload_request? - params[:operation] == 'upload' - end - - # rubocop: disable CodeReuse/ActiveRecord - def existing_oids - @existing_oids ||= begin - project.all_lfs_objects.where(oid: objects.map { |o| o['oid'].to_s }).pluck(:oid) - end - end - # rubocop: enable CodeReuse/ActiveRecord - - def download_objects! - objects.each do |object| - if existing_oids.include?(object[:oid]) - object[:actions] = download_actions(object) - - if Guest.can?(:download_code, project) - object[:authenticated] = true - end - else - object[:error] = { - code: 404, - message: _("Object does not exist on the server or you don't have permissions to access it") - } - end - end - objects - end - - def upload_objects! - objects.each do |object| - object[:actions] = upload_actions(object) unless existing_oids.include?(object[:oid]) - end - objects - end - - def download_actions(object) - { - download: { - href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}", - header: { - Authorization: authorization_header - }.compact - } - } - end - - def upload_actions(object) - { - upload: { - href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}/#{object[:size]}", - header: { - Authorization: authorization_header, - # git-lfs v2.5.0 sets the Content-Type based on the uploaded file. This - # ensures that Workhorse can intercept the request. - 'Content-Type': LFS_TRANSFER_CONTENT_TYPE - }.compact - } - } - end - - def lfs_check_batch_operation! - if batch_operation_disallowed? - render( - json: { - message: lfs_read_only_message - }, - content_type: LfsRequest::CONTENT_TYPE, - status: :forbidden - ) - end - end - - # Overridden in EE - def batch_operation_disallowed? - upload_request? && Gitlab::Database.read_only? - end - - # Overridden in EE - def lfs_read_only_message - _('You cannot write to this read-only GitLab instance.') - end - - def authorization_header - strong_memoize(:authorization_header) do - lfs_auth_header || request.headers['Authorization'] - end - end - - def lfs_auth_header - return unless user.is_a?(User) - - Gitlab::LfsToken.new(user).basic_encoding - end -end - -Projects::LfsApiController.prepend_if_ee('EE::Projects::LfsApiController') diff --git a/app/controllers/projects/lfs_locks_api_controller.rb b/app/controllers/projects/lfs_locks_api_controller.rb deleted file mode 100644 index 6aacb9d9a56..00000000000 --- a/app/controllers/projects/lfs_locks_api_controller.rb +++ /dev/null @@ -1,76 +0,0 @@ -# frozen_string_literal: true - -class Projects::LfsLocksApiController < Projects::GitHttpClientController - include LfsRequest - - def create - @result = Lfs::LockFileService.new(project, user, lfs_params).execute - - render_json(@result[:lock]) - end - - def unlock - @result = Lfs::UnlockFileService.new(project, user, lfs_params).execute - - render_json(@result[:lock]) - end - - def index - @result = Lfs::LocksFinderService.new(project, user, lfs_params).execute - - render_json(@result[:locks]) - end - - def verify - @result = Lfs::LocksFinderService.new(project, user, {}).execute - - ours, theirs = split_by_owner(@result[:locks]) - - render_json({ ours: ours, theirs: theirs }, false) - end - - private - - def render_json(data, process = true) - render json: build_payload(data, process), - content_type: LfsRequest::CONTENT_TYPE, - status: @result[:http_status] - end - - def build_payload(data, process) - data = LfsFileLockSerializer.new.represent(data) if process - - return data if @result[:status] == :success - - # When the locking failed due to an existent Lock, the existent record - # is returned in `@result[:lock]` - error_payload(@result[:message], @result[:lock] ? data : {}) - end - - def error_payload(message, custom_attrs = {}) - custom_attrs.merge({ - message: message, - documentation_url: help_url - }) - end - - def split_by_owner(locks) - groups = locks.partition { |lock| lock.user_id == user.id } - - groups.map! do |records| - LfsFileLockSerializer.new.represent(records, root: false) - end - end - - def download_request? - params[:action] == 'index' - end - - def upload_request? - %w(create unlock verify).include?(params[:action]) - end - - def lfs_params - params.permit(:id, :path, :force) - end -end diff --git a/app/controllers/projects/lfs_storage_controller.rb b/app/controllers/projects/lfs_storage_controller.rb deleted file mode 100644 index 013e01b82aa..00000000000 --- a/app/controllers/projects/lfs_storage_controller.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -class Projects::LfsStorageController < Projects::GitHttpClientController - include LfsRequest - include WorkhorseRequest - include SendFileUpload - - skip_before_action :verify_workhorse_api!, only: :download - - def download - lfs_object = LfsObject.find_by_oid(oid) - unless lfs_object && lfs_object.file.exists? - render_lfs_not_found - return - end - - send_upload(lfs_object.file, send_params: { content_type: "application/octet-stream" }) - end - - def upload_authorize - set_workhorse_internal_api_content_type - - authorized = LfsObjectUploader.workhorse_authorize(has_length: true) - authorized.merge!(LfsOid: oid, LfsSize: size) - - render json: authorized - end - - def upload_finalize - if store_file!(oid, size) - head 200 - else - render plain: 'Unprocessable entity', status: :unprocessable_entity - end - rescue ActiveRecord::RecordInvalid - render_lfs_forbidden - rescue UploadedFile::InvalidPathError - render_lfs_forbidden - rescue ObjectStorage::RemoteStoreError - render_lfs_forbidden - end - - private - - def download_request? - action_name == 'download' - end - - def upload_request? - %w[upload_authorize upload_finalize].include? action_name - end - - def oid - params[:oid].to_s - end - - def size - params[:size].to_i - end - - # rubocop: disable CodeReuse/ActiveRecord - def store_file!(oid, size) - object = LfsObject.find_by(oid: oid, size: size) - unless object&.file&.exists? - object = create_file!(oid, size) - end - - return unless object - - link_to_project!(object) - end - # rubocop: enable CodeReuse/ActiveRecord - - def create_file!(oid, size) - uploaded_file = UploadedFile.from_params( - params, :file, LfsObjectUploader.workhorse_local_upload_path) - return unless uploaded_file - - LfsObject.create!(oid: oid, size: size, file: uploaded_file) - end - - # rubocop: disable CodeReuse/ActiveRecord - def link_to_project!(object) - if object && !object.projects.exists?(storage_project.id) - object.lfs_objects_projects.create!(project: storage_project) - end - end - # rubocop: enable CodeReuse/ActiveRecord -end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index bf05defbc2e..f4f2a16b82b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -387,6 +387,7 @@ class ProjectsController < Projects::ApplicationController :merge_method, :initialize_with_readme, :autoclose_referenced_issues, + :suggestion_commit_message, project_feature_attributes: %i[ builds_access_level diff --git a/app/controllers/repositories/application_controller.rb b/app/controllers/repositories/application_controller.rb new file mode 100644 index 00000000000..528cc310038 --- /dev/null +++ b/app/controllers/repositories/application_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Repositories + class ApplicationController < ::ApplicationController + skip_before_action :authenticate_user! + end +end diff --git a/app/controllers/repositories/git_http_client_controller.rb b/app/controllers/repositories/git_http_client_controller.rb new file mode 100644 index 00000000000..76eb7c67205 --- /dev/null +++ b/app/controllers/repositories/git_http_client_controller.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module Repositories + class GitHttpClientController < Repositories::ApplicationController + include ActionController::HttpAuthentication::Basic + include KerberosSpnegoHelper + include Gitlab::Utils::StrongMemoize + + attr_reader :authentication_result, :redirected_path + + delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true + delegate :type, to: :authentication_result, allow_nil: true, prefix: :auth_result + + alias_method :user, :actor + alias_method :authenticated_user, :actor + + # Git clients will not know what authenticity token to send along + skip_around_action :set_session_storage + skip_before_action :verify_authenticity_token + + before_action :parse_repo_path + before_action :authenticate_user + + private + + def download_request? + raise NotImplementedError + end + + def upload_request? + raise NotImplementedError + end + + def authenticate_user + @authentication_result = Gitlab::Auth::Result.new + + if allow_basic_auth? && basic_auth_provided? + login, password = user_name_and_password(request) + + if handle_basic_authentication(login, password) + return # Allow access + end + elsif allow_kerberos_spnego_auth? && spnego_provided? + kerberos_user = find_kerberos_user + + if kerberos_user + @authentication_result = Gitlab::Auth::Result.new( + kerberos_user, nil, :kerberos, Gitlab::Auth.full_authentication_abilities) + + send_final_spnego_response + return # Allow access + end + elsif http_download_allowed? + + @authentication_result = Gitlab::Auth::Result.new(nil, project, :none, [:download_code]) + + return # Allow access + end + + send_challenges + render plain: "HTTP Basic: Access denied\n", status: :unauthorized + rescue Gitlab::Auth::MissingPersonalAccessTokenError + render_missing_personal_access_token + end + + def basic_auth_provided? + has_basic_credentials?(request) + end + + def send_challenges + challenges = [] + challenges << 'Basic realm="GitLab"' if allow_basic_auth? + challenges << spnego_challenge if allow_kerberos_spnego_auth? + headers['Www-Authenticate'] = challenges.join("\n") if challenges.any? + end + + def project + parse_repo_path unless defined?(@project) + + @project + end + + def parse_repo_path + @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:repository_id]}") + end + + def render_missing_personal_access_token + render plain: "HTTP Basic: Access denied\n" \ + "You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \ + "You can generate one at #{profile_personal_access_tokens_url}", + status: :unauthorized + end + + def repository + strong_memoize(:repository) do + repo_type.repository_for(project) + end + end + + def repo_type + parse_repo_path unless defined?(@repo_type) + + @repo_type + end + + def handle_basic_authentication(login, password) + @authentication_result = Gitlab::Auth.find_for_git_client( + login, password, project: project, ip: request.ip) + + @authentication_result.success? + end + + def ci? + authentication_result.ci?(project) + end + + def http_download_allowed? + Gitlab::ProtocolAccess.allowed?('http') && + download_request? && + project && Guest.can?(:download_code, project) + end + end +end + +Repositories::GitHttpClientController.prepend_if_ee('EE::Repositories::GitHttpClientController') diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb new file mode 100644 index 00000000000..82431ae286a --- /dev/null +++ b/app/controllers/repositories/git_http_controller.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +module Repositories + class GitHttpController < Repositories::GitHttpClientController + include WorkhorseRequest + + before_action :access_check + prepend_before_action :deny_head_requests, only: [:info_refs] + + rescue_from Gitlab::GitAccess::UnauthorizedError, with: :render_403_with_exception + rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception + rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422_with_exception + rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception + + # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull) + # GET /foo/bar.git/info/refs?service=git-receive-pack (git push) + def info_refs + log_user_activity if upload_pack? + + render_ok + end + + # POST /foo/bar.git/git-upload-pack (git pull) + def git_upload_pack + enqueue_fetch_statistics_update + + render_ok + end + + # POST /foo/bar.git/git-receive-pack" (git push) + def git_receive_pack + render_ok + end + + private + + def deny_head_requests + head :forbidden if request.head? + end + + def download_request? + upload_pack? + end + + def upload_pack? + git_command == 'git-upload-pack' + end + + def git_command + if action_name == 'info_refs' + params[:service] + else + action_name.dasherize + end + end + + def render_ok + set_workhorse_internal_api_content_type + render json: Gitlab::Workhorse.git_http_ok(repository, repo_type, user, action_name) + end + + def render_403_with_exception(exception) + render plain: exception.message, status: :forbidden + end + + def render_404_with_exception(exception) + render plain: exception.message, status: :not_found + end + + def render_422_with_exception(exception) + render plain: exception.message, status: :unprocessable_entity + end + + def render_503_with_exception(exception) + render plain: exception.message, status: :service_unavailable + end + + def enqueue_fetch_statistics_update + return if Gitlab::Database.read_only? + return unless repo_type.project? + return unless project&.daily_statistics_enabled? + + ProjectDailyStatisticsWorker.perform_async(project.id) + end + + def access + @access ||= access_klass.new(access_actor, project, 'http', + authentication_abilities: authentication_abilities, + namespace_path: params[:namespace_id], + project_path: project_path, + redirected_path: redirected_path, + auth_result_type: auth_result_type) + end + + def access_actor + return user if user + return :ci if ci? + end + + def access_check + access.check(git_command, Gitlab::GitAccess::ANY) + @project ||= access.project + end + + def access_klass + @access_klass ||= repo_type.access_checker_class + end + + def project_path + @project_path ||= params[:repository_id].sub(/\.git$/, '') + end + + def log_user_activity + Users::ActivityService.new(user).execute + end + end +end + +Repositories::GitHttpController.prepend_if_ee('EE::Repositories::GitHttpController') diff --git a/app/controllers/repositories/lfs_api_controller.rb b/app/controllers/repositories/lfs_api_controller.rb new file mode 100644 index 00000000000..b1e0d1848d7 --- /dev/null +++ b/app/controllers/repositories/lfs_api_controller.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +module Repositories + class LfsApiController < Repositories::GitHttpClientController + include LfsRequest + include Gitlab::Utils::StrongMemoize + + LFS_TRANSFER_CONTENT_TYPE = 'application/octet-stream' + + skip_before_action :lfs_check_access!, only: [:deprecated] + before_action :lfs_check_batch_operation!, only: [:batch] + + def batch + unless objects.present? + render_lfs_not_found + return + end + + if download_request? + render json: { objects: download_objects! } + elsif upload_request? + render json: { objects: upload_objects! } + else + raise "Never reached" + end + end + + def deprecated + render( + json: { + message: _('Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.'), + documentation_url: "#{Gitlab.config.gitlab.url}/help" + }, + status: :not_implemented + ) + end + + private + + def download_request? + params[:operation] == 'download' + end + + def upload_request? + params[:operation] == 'upload' + end + + # rubocop: disable CodeReuse/ActiveRecord + def existing_oids + @existing_oids ||= begin + project.all_lfs_objects.where(oid: objects.map { |o| o['oid'].to_s }).pluck(:oid) + end + end + # rubocop: enable CodeReuse/ActiveRecord + + def download_objects! + objects.each do |object| + if existing_oids.include?(object[:oid]) + object[:actions] = download_actions(object) + + if Guest.can?(:download_code, project) + object[:authenticated] = true + end + else + object[:error] = { + code: 404, + message: _("Object does not exist on the server or you don't have permissions to access it") + } + end + end + objects + end + + def upload_objects! + objects.each do |object| + object[:actions] = upload_actions(object) unless existing_oids.include?(object[:oid]) + end + objects + end + + def download_actions(object) + { + download: { + href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}", + header: { + Authorization: authorization_header + }.compact + } + } + end + + def upload_actions(object) + { + upload: { + href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}/#{object[:size]}", + header: { + Authorization: authorization_header, + # git-lfs v2.5.0 sets the Content-Type based on the uploaded file. This + # ensures that Workhorse can intercept the request. + 'Content-Type': LFS_TRANSFER_CONTENT_TYPE + }.compact + } + } + end + + def lfs_check_batch_operation! + if batch_operation_disallowed? + render( + json: { + message: lfs_read_only_message + }, + content_type: LfsRequest::CONTENT_TYPE, + status: :forbidden + ) + end + end + + # Overridden in EE + def batch_operation_disallowed? + upload_request? && Gitlab::Database.read_only? + end + + # Overridden in EE + def lfs_read_only_message + _('You cannot write to this read-only GitLab instance.') + end + + def authorization_header + strong_memoize(:authorization_header) do + lfs_auth_header || request.headers['Authorization'] + end + end + + def lfs_auth_header + return unless user.is_a?(User) + + Gitlab::LfsToken.new(user).basic_encoding + end + end +end + +Repositories::LfsApiController.prepend_if_ee('EE::Repositories::LfsApiController') diff --git a/app/controllers/repositories/lfs_locks_api_controller.rb b/app/controllers/repositories/lfs_locks_api_controller.rb new file mode 100644 index 00000000000..19fc09ad4de --- /dev/null +++ b/app/controllers/repositories/lfs_locks_api_controller.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +module Repositories + class LfsLocksApiController < Repositories::GitHttpClientController + include LfsRequest + + def create + @result = Lfs::LockFileService.new(project, user, lfs_params).execute + + render_json(@result[:lock]) + end + + def unlock + @result = Lfs::UnlockFileService.new(project, user, lfs_params).execute + + render_json(@result[:lock]) + end + + def index + @result = Lfs::LocksFinderService.new(project, user, lfs_params).execute + + render_json(@result[:locks]) + end + + def verify + @result = Lfs::LocksFinderService.new(project, user, {}).execute + + ours, theirs = split_by_owner(@result[:locks]) + + render_json({ ours: ours, theirs: theirs }, false) + end + + private + + def render_json(data, process = true) + render json: build_payload(data, process), + content_type: LfsRequest::CONTENT_TYPE, + status: @result[:http_status] + end + + def build_payload(data, process) + data = LfsFileLockSerializer.new.represent(data) if process + + return data if @result[:status] == :success + + # When the locking failed due to an existent Lock, the existent record + # is returned in `@result[:lock]` + error_payload(@result[:message], @result[:lock] ? data : {}) + end + + def error_payload(message, custom_attrs = {}) + custom_attrs.merge({ + message: message, + documentation_url: help_url + }) + end + + def split_by_owner(locks) + groups = locks.partition { |lock| lock.user_id == user.id } + + groups.map! do |records| + LfsFileLockSerializer.new.represent(records, root: false) + end + end + + def download_request? + params[:action] == 'index' + end + + def upload_request? + %w(create unlock verify).include?(params[:action]) + end + + def lfs_params + params.permit(:id, :path, :force) + end + end +end diff --git a/app/controllers/repositories/lfs_storage_controller.rb b/app/controllers/repositories/lfs_storage_controller.rb new file mode 100644 index 00000000000..58f496e16d3 --- /dev/null +++ b/app/controllers/repositories/lfs_storage_controller.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +module Repositories + class LfsStorageController < Repositories::GitHttpClientController + include LfsRequest + include WorkhorseRequest + include SendFileUpload + + skip_before_action :verify_workhorse_api!, only: :download + + def download + lfs_object = LfsObject.find_by_oid(oid) + unless lfs_object && lfs_object.file.exists? + render_lfs_not_found + return + end + + send_upload(lfs_object.file, send_params: { content_type: "application/octet-stream" }) + end + + def upload_authorize + set_workhorse_internal_api_content_type + + authorized = LfsObjectUploader.workhorse_authorize(has_length: true) + authorized.merge!(LfsOid: oid, LfsSize: size) + + render json: authorized + end + + def upload_finalize + if store_file!(oid, size) + head 200 + else + render plain: 'Unprocessable entity', status: :unprocessable_entity + end + rescue ActiveRecord::RecordInvalid + render_lfs_forbidden + rescue UploadedFile::InvalidPathError + render_lfs_forbidden + rescue ObjectStorage::RemoteStoreError + render_lfs_forbidden + end + + private + + def download_request? + action_name == 'download' + end + + def upload_request? + %w[upload_authorize upload_finalize].include? action_name + end + + def oid + params[:oid].to_s + end + + def size + params[:size].to_i + end + + # rubocop: disable CodeReuse/ActiveRecord + def store_file!(oid, size) + object = LfsObject.find_by(oid: oid, size: size) + unless object&.file&.exists? + object = create_file!(oid, size) + end + + return unless object + + link_to_project!(object) + end + # rubocop: enable CodeReuse/ActiveRecord + + def create_file!(oid, size) + uploaded_file = UploadedFile.from_params( + params, :file, LfsObjectUploader.workhorse_local_upload_path) + return unless uploaded_file + + LfsObject.create!(oid: oid, size: size, file: uploaded_file) + end + + # rubocop: disable CodeReuse/ActiveRecord + def link_to_project!(object) + if object && !object.projects.exists?(storage_project.id) + object.lfs_objects_projects.create!(project: storage_project) + end + end + # rubocop: enable CodeReuse/ActiveRecord + end +end diff --git a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb index af6d8818d90..e3ccf9e61c8 100644 --- a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb +++ b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb @@ -11,77 +11,87 @@ module Types field :id, GraphQL::ID_TYPE, null: false, - description: "ID (global ID) of the error" + description: 'ID (global ID) of the error' field :sentry_id, GraphQL::STRING_TYPE, method: :id, null: false, - description: "ID (Sentry ID) of the error" + description: 'ID (Sentry ID) of the error' field :title, GraphQL::STRING_TYPE, null: false, - description: "Title of the error" + description: 'Title of the error' field :type, GraphQL::STRING_TYPE, null: false, - description: "Type of the error" + description: 'Type of the error' field :user_count, GraphQL::INT_TYPE, null: false, - description: "Count of users affected by the error" + description: 'Count of users affected by the error' field :count, GraphQL::INT_TYPE, null: false, - description: "Count of occurrences" + description: 'Count of occurrences' field :first_seen, Types::TimeType, null: false, - description: "Timestamp when the error was first seen" + description: 'Timestamp when the error was first seen' field :last_seen, Types::TimeType, null: false, - description: "Timestamp when the error was last seen" + description: 'Timestamp when the error was last seen' field :message, GraphQL::STRING_TYPE, null: true, - description: "Sentry metadata message of the error" + description: 'Sentry metadata message of the error' field :culprit, GraphQL::STRING_TYPE, null: false, - description: "Culprit of the error" + description: 'Culprit of the error' + field :external_base_url, GraphQL::STRING_TYPE, + null: false, + description: 'External Base URL of the Sentry Instance' field :external_url, GraphQL::STRING_TYPE, null: false, - description: "External URL of the error" + description: 'External URL of the error' field :sentry_project_id, GraphQL::ID_TYPE, method: :project_id, null: false, - description: "ID of the project (Sentry project)" + description: 'ID of the project (Sentry project)' field :sentry_project_name, GraphQL::STRING_TYPE, method: :project_name, null: false, - description: "Name of the project affected by the error" + description: 'Name of the project affected by the error' field :sentry_project_slug, GraphQL::STRING_TYPE, method: :project_slug, null: false, - description: "Slug of the project affected by the error" + description: 'Slug of the project affected by the error' field :short_id, GraphQL::STRING_TYPE, null: false, - description: "Short ID (Sentry ID) of the error" + description: 'Short ID (Sentry ID) of the error' field :status, Types::ErrorTracking::SentryErrorStatusEnum, null: false, - description: "Status of the error" + description: 'Status of the error' field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType], null: false, - description: "Last 24hr stats of the error" + description: 'Last 24hr stats of the error' field :first_release_last_commit, GraphQL::STRING_TYPE, null: true, - description: "Commit the error was first seen" + description: 'Commit the error was first seen' field :last_release_last_commit, GraphQL::STRING_TYPE, null: true, - description: "Commit the error was last seen" + description: 'Commit the error was last seen' field :first_release_short_version, GraphQL::STRING_TYPE, null: true, - description: "Release version the error was first seen" + description: 'Release version the error was first seen' field :last_release_short_version, GraphQL::STRING_TYPE, null: true, - description: "Release version the error was last seen" + description: 'Release version the error was last seen' field :gitlab_commit, GraphQL::STRING_TYPE, null: true, - description: "GitLab commit SHA attributed to the Error based on the release version" + description: 'GitLab commit SHA attributed to the Error based on the release version' field :gitlab_commit_path, GraphQL::STRING_TYPE, null: true, - description: "Path to the GitLab page for the GitLab commit attributed to the error" + description: 'Path to the GitLab page for the GitLab commit attributed to the error' + field :gitlab_issue_path, GraphQL::STRING_TYPE, + method: :gitlab_issue, + null: true, + description: 'URL of GitLab Issue' + field :tags, Types::ErrorTracking::SentryErrorTagsType, + null: false, + description: 'Tags associated with the Sentry Error' def first_seen DateTime.parse(object.first_seen) diff --git a/app/graphql/types/error_tracking/sentry_error_tags_type.rb b/app/graphql/types/error_tracking/sentry_error_tags_type.rb new file mode 100644 index 00000000000..e6d96571561 --- /dev/null +++ b/app/graphql/types/error_tracking/sentry_error_tags_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + module ErrorTracking + # rubocop: disable Graphql/AuthorizeTypes + class SentryErrorTagsType < ::Types::BaseObject + graphql_name 'SentryErrorTags' + description 'State of a Sentry error' + + field :level, GraphQL::STRING_TYPE, + null: true, + description: "Severity level of the Sentry Error" + field :logger, GraphQL::STRING_TYPE, + null: true, + description: "Logger of the Sentry Error" + end + # rubocop: enable Graphql/AuthorizeTypes + end +end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index c9fb28d0299..7c0f4da355d 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -47,7 +47,7 @@ module BlobHelper def edit_blob_button(project = @project, ref = @ref, path = @path, options = {}) return unless blob = readable_blob(options, path, project, ref) - common_classes = "btn btn-primary js-edit-blob #{options[:extra_class]}" + common_classes = "btn btn-primary js-edit-blob ml-2 #{options[:extra_class]}" edit_button_tag(blob, common_classes, @@ -62,7 +62,7 @@ module BlobHelper return unless blob = readable_blob(options, path, project, ref) edit_button_tag(blob, - 'btn btn-inverted btn-primary ide-edit-button', + 'btn btn-inverted btn-primary ide-edit-button ml-2', _('Web IDE'), ide_edit_path(project, ref, path, options), project, diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb index 63f216c7af5..bf189d0f517 100644 --- a/app/models/clusters/applications/ingress.rb +++ b/app/models/clusters/applications/ingress.rb @@ -4,6 +4,7 @@ module Clusters module Applications class Ingress < ApplicationRecord VERSION = '1.22.1' + MODSECURITY_LOG_CONTAINER_NAME = 'modsecurity-log' self.table_name = 'clusters_applications_ingress' @@ -85,7 +86,7 @@ module Clusters }, "extraContainers" => [ { - "name" => "modsecurity-log", + "name" => MODSECURITY_LOG_CONTAINER_NAME, "image" => "busybox", "args" => [ "/bin/sh", diff --git a/app/models/project.rb b/app/models/project.rb index cd191589351..c0103190892 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1938,6 +1938,8 @@ class Project < ApplicationRecord .append(key: 'GITLAB_CI', value: 'true') .append(key: 'CI_SERVER_URL', value: Gitlab.config.gitlab.url) .append(key: 'CI_SERVER_HOST', value: Gitlab.config.gitlab.host) + .append(key: 'CI_SERVER_PORT', value: Gitlab.config.gitlab.port.to_s) + .append(key: 'CI_SERVER_PROTOCOL', value: Gitlab.config.gitlab.protocol) .append(key: 'CI_SERVER_NAME', value: 'GitLab') .append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION) .append(key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s) diff --git a/app/views/projects/blob/_header.html.haml b/app/views/projects/blob/_header.html.haml index 77245114772..76a9d3df5d7 100644 --- a/app/views/projects/blob/_header.html.haml +++ b/app/views/projects/blob/_header.html.haml @@ -2,18 +2,16 @@ .js-file-title.file-title-flex-parent = render 'projects/blob/header_content', blob: blob - .file-actions + .file-actions< = render 'projects/blob/viewer_switcher', blob: blob unless blame - - .btn-group{ role: "group" }< - = edit_blob_button - = ide_edit_button - .btn-group{ role: "group" }< + = edit_blob_button + = ide_edit_button + .btn-group.ml-2{ role: "group" }> = render_if_exists 'projects/blob/header_file_locks_link' - if current_user = replace_blob_link = delete_blob_link - .btn-group{ role: "group" }< + .btn-group.ml-2{ role: "group" } = copy_blob_source_button(blob) unless blame = open_raw_blob_button(blob) = download_blob_button(blob) diff --git a/app/views/projects/blob/_viewer_switcher.html.haml b/app/views/projects/blob/_viewer_switcher.html.haml index 6a521069418..5e0d70b2ca9 100644 --- a/app/views/projects/blob/_viewer_switcher.html.haml +++ b/app/views/projects/blob/_viewer_switcher.html.haml @@ -2,7 +2,7 @@ - simple_viewer = blob.simple_viewer - rich_viewer = blob.rich_viewer - .btn-group.js-blob-viewer-switcher{ role: "group" } + .btn-group.js-blob-viewer-switcher.ml-2{ role: "group" }> - simple_label = "Display #{simple_viewer.switcher_title}" %button.btn.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => simple_label, title: simple_label, data: { viewer: 'simple', container: 'body' } }> = icon(simple_viewer.switcher_icon) diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index d5c1a1bee6d..d74030c566f 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -22,6 +22,8 @@ - if user == current_user %span.badge.badge-success.prepend-left-5= _("It's you") + = render_if_exists 'shared/members/ee/license_badge', user: user, group: @group + - if user.blocked? %label.badge.badge-danger %strong= _("Blocked") diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb index 9492cfe217c..1ab2fd6023f 100644 --- a/app/workers/authorized_projects_worker.rb +++ b/app/workers/authorized_projects_worker.rb @@ -6,6 +6,7 @@ class AuthorizedProjectsWorker feature_category :authentication_and_authorization latency_sensitive_worker! + weight 2 # This is a workaround for a Ruby 2.3.7 bug. rspec-mocks cannot restore the # visibility of prepended modules. See https://github.com/rspec/rspec-mocks/issues/1231 diff --git a/app/workers/chat_notification_worker.rb b/app/workers/chat_notification_worker.rb index 6162dcf9d38..f23c787559f 100644 --- a/app/workers/chat_notification_worker.rb +++ b/app/workers/chat_notification_worker.rb @@ -8,6 +8,8 @@ class ChatNotificationWorker sidekiq_options retry: false feature_category :chatops latency_sensitive_worker! + weight 2 + # TODO: break this into multiple jobs # as the `responder` uses external dependencies # See https://gitlab.com/gitlab-com/gl-infra/scalability/issues/34 diff --git a/app/workers/concerns/self_monitoring_project_worker.rb b/app/workers/concerns/self_monitoring_project_worker.rb index 44dd6866fad..1796e2441f2 100644 --- a/app/workers/concerns/self_monitoring_project_worker.rb +++ b/app/workers/concerns/self_monitoring_project_worker.rb @@ -9,6 +9,7 @@ module SelfMonitoringProjectWorker # Other Functionality. Metrics seems to be the closest feature_category for # this worker. feature_category :metrics + weight 2 end LEASE_TIMEOUT = 15.minutes.to_i diff --git a/app/workers/concerns/worker_attributes.rb b/app/workers/concerns/worker_attributes.rb index 506215ca9ed..266c8021761 100644 --- a/app/workers/concerns/worker_attributes.rb +++ b/app/workers/concerns/worker_attributes.rb @@ -7,6 +7,24 @@ module WorkerAttributes # `worker_resource_boundary` attribute VALID_RESOURCE_BOUNDARIES = [:memory, :cpu, :unknown].freeze + NAMESPACE_WEIGHTS = { + auto_devops: 2, + auto_merge: 3, + chaos: 2, + deployment: 3, + mail_scheduler: 2, + notifications: 2, + pipeline_cache: 3, + pipeline_creation: 4, + pipeline_default: 3, + pipeline_hooks: 2, + pipeline_processing: 5, + + # EE-specific + epics: 2, + incident_management: 2 + }.stringify_keys.freeze + class_methods do def feature_category(value) raise "Invalid category. Use `feature_category_not_owned!` to mark a worker as not owned" if value == :not_owned @@ -70,6 +88,16 @@ module WorkerAttributes worker_attributes[:resource_boundary] || :unknown end + def weight(value) + worker_attributes[:weight] = value + end + + def get_weight + worker_attributes[:weight] || + NAMESPACE_WEIGHTS[queue_namespace] || + 1 + end + protected # Returns a worker attribute declared on this class or its parent class. diff --git a/app/workers/create_evidence_worker.rb b/app/workers/create_evidence_worker.rb index 027dbd2f101..e6fbf59d702 100644 --- a/app/workers/create_evidence_worker.rb +++ b/app/workers/create_evidence_worker.rb @@ -4,6 +4,7 @@ class CreateEvidenceWorker include ApplicationWorker feature_category :release_governance + weight 2 def perform(release_id) release = Release.find_by_id(release_id) diff --git a/app/workers/create_gpg_signature_worker.rb b/app/workers/create_gpg_signature_worker.rb index fc36a2adccd..2043c3c8e77 100644 --- a/app/workers/create_gpg_signature_worker.rb +++ b/app/workers/create_gpg_signature_worker.rb @@ -4,6 +4,7 @@ class CreateGpgSignatureWorker include ApplicationWorker feature_category :source_code_management + weight 2 # rubocop: disable CodeReuse/ActiveRecord def perform(commit_shas, project_id) diff --git a/app/workers/email_receiver_worker.rb b/app/workers/email_receiver_worker.rb index b56bf4ed833..c2b1e642604 100644 --- a/app/workers/email_receiver_worker.rb +++ b/app/workers/email_receiver_worker.rb @@ -5,6 +5,7 @@ class EmailReceiverWorker feature_category :issue_tracking latency_sensitive_worker! + weight 2 def perform(raw) return unless Gitlab::IncomingEmail.enabled? diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb index f523f5953e1..be66e2b1188 100644 --- a/app/workers/emails_on_push_worker.rb +++ b/app/workers/emails_on_push_worker.rb @@ -8,6 +8,7 @@ class EmailsOnPushWorker feature_category :source_code_management latency_sensitive_worker! worker_resource_boundary :cpu + weight 2 def perform(project_id, recipients, push_data, options = {}) options.symbolize_keys! diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb index 57e64570c09..bd2225e6d7c 100644 --- a/app/workers/gitlab_shell_worker.rb +++ b/app/workers/gitlab_shell_worker.rb @@ -6,6 +6,7 @@ class GitlabShellWorker feature_category :source_code_management latency_sensitive_worker! + weight 2 def perform(action, *arg) Gitlab::GitalyClient::NamespaceService.allow do diff --git a/app/workers/import_issues_csv_worker.rb b/app/workers/import_issues_csv_worker.rb index d2733dc5f56..7c5584146ca 100644 --- a/app/workers/import_issues_csv_worker.rb +++ b/app/workers/import_issues_csv_worker.rb @@ -5,6 +5,7 @@ class ImportIssuesCsvWorker feature_category :issue_tracking worker_resource_boundary :cpu + weight 2 sidekiq_retries_exhausted do |job| Upload.find(job['args'][2]).destroy diff --git a/app/workers/invalid_gpg_signature_update_worker.rb b/app/workers/invalid_gpg_signature_update_worker.rb index 573efdf9fb1..e1c2eefbf0f 100644 --- a/app/workers/invalid_gpg_signature_update_worker.rb +++ b/app/workers/invalid_gpg_signature_update_worker.rb @@ -4,6 +4,7 @@ class InvalidGpgSignatureUpdateWorker include ApplicationWorker feature_category :source_code_management + weight 2 # rubocop: disable CodeReuse/ActiveRecord def perform(gpg_key_id) diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb index ed88c57e8d4..48bc205113f 100644 --- a/app/workers/merge_worker.rb +++ b/app/workers/merge_worker.rb @@ -5,6 +5,7 @@ class MergeWorker feature_category :source_code_management latency_sensitive_worker! + weight 5 def perform(merge_request_id, current_user_id, params) params = params.with_indifferent_access diff --git a/app/workers/new_issue_worker.rb b/app/workers/new_issue_worker.rb index af9ca332d3c..d696165b447 100644 --- a/app/workers/new_issue_worker.rb +++ b/app/workers/new_issue_worker.rb @@ -7,6 +7,7 @@ class NewIssueWorker feature_category :issue_tracking latency_sensitive_worker! worker_resource_boundary :cpu + weight 2 def perform(issue_id, user_id) return unless objects_found?(issue_id, user_id) diff --git a/app/workers/new_merge_request_worker.rb b/app/workers/new_merge_request_worker.rb index aa3f85c157b..e31ddae1f13 100644 --- a/app/workers/new_merge_request_worker.rb +++ b/app/workers/new_merge_request_worker.rb @@ -7,6 +7,7 @@ class NewMergeRequestWorker feature_category :source_code_management latency_sensitive_worker! worker_resource_boundary :cpu + weight 2 def perform(merge_request_id, user_id) return unless objects_found?(merge_request_id, user_id) diff --git a/app/workers/new_note_worker.rb b/app/workers/new_note_worker.rb index 2a5988a7e32..b446e376007 100644 --- a/app/workers/new_note_worker.rb +++ b/app/workers/new_note_worker.rb @@ -6,6 +6,7 @@ class NewNoteWorker feature_category :issue_tracking latency_sensitive_worker! worker_resource_boundary :cpu + weight 2 # Keep extra parameter to preserve backwards compatibility with # old `NewNoteWorker` jobs (can remove later) diff --git a/app/workers/new_release_worker.rb b/app/workers/new_release_worker.rb index a3a882f9343..edfdb2d7aff 100644 --- a/app/workers/new_release_worker.rb +++ b/app/workers/new_release_worker.rb @@ -5,6 +5,7 @@ class NewReleaseWorker queue_namespace :notifications feature_category :release_orchestration + weight 2 def perform(release_id) release = Release.preloaded.find_by_id(release_id) diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 334a98a0017..d5038f1152b 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -6,6 +6,7 @@ class PostReceive feature_category :source_code_management latency_sensitive_worker! worker_resource_boundary :cpu + weight 5 def perform(gl_repository, identifier, changes, push_options = {}) project, repo_type = Gitlab::GlRepository.parse(gl_repository) diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb index 36af51d859e..ca2896946c9 100644 --- a/app/workers/process_commit_worker.rb +++ b/app/workers/process_commit_worker.rb @@ -12,6 +12,7 @@ class ProcessCommitWorker feature_category :source_code_management latency_sensitive_worker! + weight 3 # project_id - The ID of the project this commit belongs to. # user_id - The ID of the user that pushed the commit. diff --git a/app/workers/rebase_worker.rb b/app/workers/rebase_worker.rb index fd182125c07..ddf5c31a1c2 100644 --- a/app/workers/rebase_worker.rb +++ b/app/workers/rebase_worker.rb @@ -6,6 +6,7 @@ class RebaseWorker include ApplicationWorker feature_category :source_code_management + weight 2 def perform(merge_request_id, current_user_id, skip_ci = false) current_user = User.find(current_user_id) diff --git a/app/workers/remote_mirror_notification_worker.rb b/app/workers/remote_mirror_notification_worker.rb index 8bc19230caf..706131d4e4b 100644 --- a/app/workers/remote_mirror_notification_worker.rb +++ b/app/workers/remote_mirror_notification_worker.rb @@ -4,6 +4,7 @@ class RemoteMirrorNotificationWorker include ApplicationWorker feature_category :source_code_management + weight 2 def perform(remote_mirror_id) remote_mirror = RemoteMirror.find_by_id(remote_mirror_id) diff --git a/app/workers/update_external_pull_requests_worker.rb b/app/workers/update_external_pull_requests_worker.rb index 8b0952528fa..e363b33f1b9 100644 --- a/app/workers/update_external_pull_requests_worker.rb +++ b/app/workers/update_external_pull_requests_worker.rb @@ -4,6 +4,7 @@ class UpdateExternalPullRequestsWorker include ApplicationWorker feature_category :source_code_management + weight 3 def perform(project_id, user_id, ref) project = Project.find_by_id(project_id) diff --git a/app/workers/update_merge_requests_worker.rb b/app/workers/update_merge_requests_worker.rb index acb95353983..ec9739e8a11 100644 --- a/app/workers/update_merge_requests_worker.rb +++ b/app/workers/update_merge_requests_worker.rb @@ -6,6 +6,7 @@ class UpdateMergeRequestsWorker feature_category :source_code_management latency_sensitive_worker! worker_resource_boundary :cpu + weight 3 LOG_TIME_THRESHOLD = 90 # seconds |