Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-24 21:09:00 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-24 21:09:00 +0300
commit411cc77938f99b495e0fe802705d275a28e939ef (patch)
tree97770ec9904daeaaa1f7546b191d23b0a642da47 /app
parent3e36f70be4bd74a412b2ea1286090b54803a8c20 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/error_tracking/components/error_tracking_list.vue14
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue1
-rw-r--r--app/controllers/projects/git_http_client_controller.rb122
-rw-r--r--app/controllers/projects/git_http_controller.rb117
-rw-r--r--app/controllers/projects/lfs_api_controller.rb140
-rw-r--r--app/controllers/projects/lfs_locks_api_controller.rb76
-rw-r--r--app/controllers/projects/lfs_storage_controller.rb89
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/controllers/repositories/application_controller.rb7
-rw-r--r--app/controllers/repositories/git_http_client_controller.rb125
-rw-r--r--app/controllers/repositories/git_http_controller.rb119
-rw-r--r--app/controllers/repositories/lfs_api_controller.rb142
-rw-r--r--app/controllers/repositories/lfs_locks_api_controller.rb78
-rw-r--r--app/controllers/repositories/lfs_storage_controller.rb91
-rw-r--r--app/graphql/types/error_tracking/sentry_detailed_error_type.rb56
-rw-r--r--app/graphql/types/error_tracking/sentry_error_tags_type.rb19
-rw-r--r--app/helpers/blob_helper.rb4
-rw-r--r--app/models/clusters/applications/ingress.rb3
-rw-r--r--app/models/project.rb2
-rw-r--r--app/views/projects/blob/_header.html.haml12
-rw-r--r--app/views/projects/blob/_viewer_switcher.html.haml2
-rw-r--r--app/views/shared/members/_member.html.haml2
-rw-r--r--app/workers/authorized_projects_worker.rb1
-rw-r--r--app/workers/chat_notification_worker.rb2
-rw-r--r--app/workers/concerns/self_monitoring_project_worker.rb1
-rw-r--r--app/workers/concerns/worker_attributes.rb28
-rw-r--r--app/workers/create_evidence_worker.rb1
-rw-r--r--app/workers/create_gpg_signature_worker.rb1
-rw-r--r--app/workers/email_receiver_worker.rb1
-rw-r--r--app/workers/emails_on_push_worker.rb1
-rw-r--r--app/workers/gitlab_shell_worker.rb1
-rw-r--r--app/workers/import_issues_csv_worker.rb1
-rw-r--r--app/workers/invalid_gpg_signature_update_worker.rb1
-rw-r--r--app/workers/merge_worker.rb1
-rw-r--r--app/workers/new_issue_worker.rb1
-rw-r--r--app/workers/new_merge_request_worker.rb1
-rw-r--r--app/workers/new_note_worker.rb1
-rw-r--r--app/workers/new_release_worker.rb1
-rw-r--r--app/workers/post_receive.rb1
-rw-r--r--app/workers/process_commit_worker.rb1
-rw-r--r--app/workers/rebase_worker.rb1
-rw-r--r--app/workers/remote_mirror_notification_worker.rb1
-rw-r--r--app/workers/update_external_pull_requests_worker.rb1
-rw-r--r--app/workers/update_merge_requests_worker.rb1
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