diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/api/api.rb | 3 | ||||
| -rw-r--r-- | lib/api/branches.rb | 6 | ||||
| -rw-r--r-- | lib/api/entities.rb | 17 | ||||
| -rw-r--r-- | lib/api/helpers.rb | 2 | ||||
| -rw-r--r-- | lib/api/protected_branches.rb | 85 | ||||
| -rw-r--r-- | lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb | 107 | ||||
| -rw-r--r-- | lib/gitlab/email/handler/create_note_handler.rb | 1 | ||||
| -rw-r--r-- | lib/gitlab/email/receiver.rb | 13 | ||||
| -rw-r--r-- | lib/gitlab/git/repository.rb | 7 | ||||
| -rw-r--r-- | lib/gitlab/o_auth/user.rb | 9 | ||||
| -rw-r--r-- | lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb | 15 | ||||
| -rw-r--r-- | lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb | 11 | ||||
| -rw-r--r-- | lib/gitlab/prometheus/queries/query_additional_metrics.rb | 23 | ||||
| -rw-r--r-- | lib/tasks/gitlab/gitaly.rake | 2 |
14 files changed, 271 insertions, 30 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb index ae10da2d85f..982a2b88d62 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -48,8 +48,8 @@ module API end before { header['X-Frame-Options'] = 'SAMEORIGIN' } - before { Gitlab::I18n.locale = current_user&.preferred_language } + # The locale is set to the current user's locale when `current_user` is loaded after { Gitlab::I18n.use_default_locale } rescue_from Gitlab::Access::AccessDeniedError do @@ -123,6 +123,7 @@ module API mount ::API::ProjectHooks mount ::API::Projects mount ::API::ProjectSnippets + mount ::API::ProtectedBranches mount ::API::Repositories mount ::API::Runner mount ::API::Runners diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 9dd60d1833b..d3dbf941298 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -37,6 +37,7 @@ module API present branch, with: Entities::RepoBranch, project: user_project end + # Note: This API will be deprecated in favor of the protected branches API. # Note: The internal data model moved from `developers_can_{merge,push}` to `allowed_to_{merge,push}` # in `gitlab-org/gitlab-ce!5081`. The API interface has not been changed (to maintain compatibility), # but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`. @@ -65,9 +66,9 @@ module API service_args = [user_project, current_user, protected_branch_params] protected_branch = if protected_branch - ProtectedBranches::ApiUpdateService.new(*service_args).execute(protected_branch) + ::ProtectedBranches::ApiUpdateService.new(*service_args).execute(protected_branch) else - ProtectedBranches::ApiCreateService.new(*service_args).execute + ::ProtectedBranches::ApiCreateService.new(*service_args).execute end if protected_branch.valid? @@ -77,6 +78,7 @@ module API end end + # Note: This API will be deprecated in favor of the protected branches API. desc 'Unprotect a single branch' do success Entities::RepoBranch end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index ce25be34ec4..298831a8fdb 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -240,7 +240,7 @@ module API end expose :protected do |repo_branch, options| - ProtectedBranch.protected?(options[:project], repo_branch.name) + ::ProtectedBranch.protected?(options[:project], repo_branch.name) end expose :developers_can_push do |repo_branch, options| @@ -299,6 +299,19 @@ module API expose :deleted_file?, as: :deleted_file end + class ProtectedRefAccess < Grape::Entity + expose :access_level + expose :access_level_description do |protected_ref_access| + protected_ref_access.humanize + end + end + + class ProtectedBranch < Grape::Entity + expose :name + expose :push_access_levels, using: Entities::ProtectedRefAccess + expose :merge_access_levels, using: Entities::ProtectedRefAccess + end + class Milestone < Grape::Entity expose :id, :iid expose :project_id, if: -> (entity, options) { entity&.project_id } @@ -483,7 +496,7 @@ module API class Event < Grape::Entity expose :title, :project_id, :action_name - expose :target_id, :target_type, :author_id + expose :target_id, :target_iid, :target_type, :author_id expose :data, :target_title expose :created_at expose :note, using: Entities::Note, if: ->(event, options) { event.note? } diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 234825480f2..99b8b62691f 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -16,6 +16,8 @@ module API @current_user = initial_current_user + Gitlab::I18n.locale = @current_user&.preferred_language + sudo! @current_user diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb new file mode 100644 index 00000000000..d742f2e18d0 --- /dev/null +++ b/lib/api/protected_branches.rb @@ -0,0 +1,85 @@ +module API + class ProtectedBranches < Grape::API + include PaginationParams + + BRANCH_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX) + + before { authorize_admin_project } + + params do + requires :id, type: String, desc: 'The ID of a project' + end + resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do + desc "Get a project's protected branches" do + success Entities::ProtectedBranch + end + params do + use :pagination + end + get ':id/protected_branches' do + protected_branches = user_project.protected_branches.preload(:push_access_levels, :merge_access_levels) + + present paginate(protected_branches), with: Entities::ProtectedBranch, project: user_project + end + + desc 'Get a single protected branch' do + success Entities::ProtectedBranch + end + params do + requires :name, type: String, desc: 'The name of the branch or wildcard' + end + get ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do + protected_branch = user_project.protected_branches.find_by!(name: params[:name]) + + present protected_branch, with: Entities::ProtectedBranch, project: user_project + end + + desc 'Protect a single branch or wildcard' do + success Entities::ProtectedBranch + end + params do + requires :name, type: String, desc: 'The name of the protected branch' + optional :push_access_level, type: Integer, default: Gitlab::Access::MASTER, + values: ProtectedBranchAccess::ALLOWED_ACCESS_LEVELS, + desc: 'Access levels allowed to push (defaults: `40`, master access level)' + optional :merge_access_level, type: Integer, default: Gitlab::Access::MASTER, + values: ProtectedBranchAccess::ALLOWED_ACCESS_LEVELS, + desc: 'Access levels allowed to merge (defaults: `40`, master access level)' + end + post ':id/protected_branches' do + protected_branch = user_project.protected_branches.find_by(name: params[:name]) + if protected_branch + conflict!("Protected branch '#{params[:name]}' already exists") + end + + protected_branch_params = { + name: params[:name], + push_access_levels_attributes: [{ access_level: params[:push_access_level] }], + merge_access_levels_attributes: [{ access_level: params[:merge_access_level] }] + } + + service_args = [user_project, current_user, protected_branch_params] + + protected_branch = ::ProtectedBranches::CreateService.new(*service_args).execute + + if protected_branch.persisted? + present protected_branch, with: Entities::ProtectedBranch, project: user_project + else + render_api_error!(protected_branch.errors.full_messages, 422) + end + end + + desc 'Unprotect a single branch' + params do + requires :name, type: String, desc: 'The name of the protected branch' + end + delete ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do + protected_branch = user_project.protected_branches.find_by!(name: params[:name]) + + protected_branch.destroy + + status 204 + end + end + end +end diff --git a/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb b/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb new file mode 100644 index 00000000000..0fbc6b70989 --- /dev/null +++ b/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb @@ -0,0 +1,107 @@ +module Gitlab + module BackgroundMigration + class DeserializeMergeRequestDiffsAndCommits + attr_reader :diff_ids, :commit_rows, :file_rows + + class MergeRequestDiff < ActiveRecord::Base + self.table_name = 'merge_request_diffs' + end + + BUFFER_ROWS = 1000 + + def perform(start_id, stop_id) + merge_request_diffs = MergeRequestDiff + .select(:id, :st_commits, :st_diffs) + .where('st_commits IS NOT NULL OR st_diffs IS NOT NULL') + .where(id: start_id..stop_id) + + reset_buffers! + + merge_request_diffs.each do |merge_request_diff| + commits, files = single_diff_rows(merge_request_diff) + + diff_ids << merge_request_diff.id + commit_rows.concat(commits) + file_rows.concat(files) + + if diff_ids.length > BUFFER_ROWS || + commit_rows.length > BUFFER_ROWS || + file_rows.length > BUFFER_ROWS + + flush_buffers! + end + end + + flush_buffers! + end + + private + + def reset_buffers! + @diff_ids = [] + @commit_rows = [] + @file_rows = [] + end + + def flush_buffers! + if diff_ids.any? + MergeRequestDiff.transaction do + Gitlab::Database.bulk_insert('merge_request_diff_commits', commit_rows) + Gitlab::Database.bulk_insert('merge_request_diff_files', file_rows) + + MergeRequestDiff.where(id: diff_ids).update_all(st_commits: nil, st_diffs: nil) + end + end + + reset_buffers! + end + + def single_diff_rows(merge_request_diff) + sha_attribute = Gitlab::Database::ShaAttribute.new + commits = YAML.load(merge_request_diff.st_commits) rescue [] + + commit_rows = commits.map.with_index do |commit, index| + commit_hash = commit.to_hash.with_indifferent_access.except(:parent_ids) + sha = commit_hash.delete(:id) + + commit_hash.merge( + merge_request_diff_id: merge_request_diff.id, + relative_order: index, + sha: sha_attribute.type_cast_for_database(sha) + ) + end + + diffs = YAML.load(merge_request_diff.st_diffs) rescue [] + diffs = [] unless valid_raw_diffs?(diffs) + + file_rows = diffs.map.with_index do |diff, index| + diff_hash = diff.to_hash.with_indifferent_access.merge( + binary: false, + merge_request_diff_id: merge_request_diff.id, + relative_order: index + ) + + # Compatibility with old diffs created with Psych. + diff_hash.tap do |hash| + diff_text = hash[:diff] + + if diff_text.encoding == Encoding::BINARY && !diff_text.ascii_only? + hash[:binary] = true + hash[:diff] = [diff_text].pack('m0') + end + end + end + + [commit_rows, file_rows] + end + + # Unlike MergeRequestDiff#valid_raw_diff?, don't count Rugged objects as + # valid, because we don't render them usefully anyway. + def valid_raw_diffs?(diffs) + return false unless diffs.respond_to?(:each) + + diffs.all? { |diff| diff.is_a?(Hash) } + end + end + end +end diff --git a/lib/gitlab/email/handler/create_note_handler.rb b/lib/gitlab/email/handler/create_note_handler.rb index 31579e94a87..8eea33b9ab5 100644 --- a/lib/gitlab/email/handler/create_note_handler.rb +++ b/lib/gitlab/email/handler/create_note_handler.rb @@ -15,7 +15,6 @@ module Gitlab def execute raise SentNotificationNotFoundError unless sent_notification - raise AutoGeneratedEmailError if mail.header.to_s =~ /auto-(generated|replied)/ validate_permission!(:create_note) diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb index 0d6b08b5d29..c8f4591d060 100644 --- a/lib/gitlab/email/receiver.rb +++ b/lib/gitlab/email/receiver.rb @@ -26,6 +26,9 @@ module Gitlab raise EmptyEmailError if @raw.blank? mail = build_mail + + ignore_auto_submitted!(mail) + mail_key = extract_mail_key(mail) handler = Handler.for(mail, mail_key) @@ -87,6 +90,16 @@ module Gitlab break key if key end end + + def ignore_auto_submitted!(mail) + # Mail::Header#[] is case-insensitive + auto_submitted = mail.header['Auto-Submitted']&.value + + # Mail::Field#value would strip leading and trailing whitespace + raise AutoGeneratedEmailError if + # See also https://tools.ietf.org/html/rfc3834 + auto_submitted && auto_submitted != 'no' + end end end end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index d79589dfca5..ffe2c8b91bb 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -350,6 +350,13 @@ module Gitlab rugged.merge_base(from, to) end + # Gitaly note: JV: check gitlab-ee before removing this method. + def rugged_is_ancestor?(ancestor_id, descendant_id) + return false if ancestor_id.nil? || descendant_id.nil? + + merge_base_commit(ancestor_id, descendant_id) == ancestor_id + end + # Returns true is +from+ is direct ancestor to +to+, otherwise false def is_ancestor?(from, to) gitaly_commit_client.is_ancestor(from, to) diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb index 3f2bbd9f6a6..e8330917e91 100644 --- a/lib/gitlab/o_auth/user.rb +++ b/lib/gitlab/o_auth/user.rb @@ -166,12 +166,17 @@ module Gitlab username ||= auth_hash.username email ||= auth_hash.email + valid_username = ::Namespace.clean_path(username) + + uniquify = Uniquify.new + valid_username = uniquify.string(valid_username) { |s| !DynamicPathValidator.valid_user_path?(s) } + name = auth_hash.name - name = ::Namespace.clean_path(username) if name.strip.empty? + name = valid_username if name.strip.empty? { name: name, - username: ::Namespace.clean_path(username), + username: valid_username, email: email, password: auth_hash.password, password_confirmation: auth_hash.password, diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb index 67c69d9ccf3..69d055c901c 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb @@ -6,14 +6,13 @@ module Gitlab def query(deployment_id) Deployment.find_by(id: deployment_id).try do |deployment| - query_context = { - environment_slug: deployment.environment.slug, - environment_filter: %{container_name!="POD",environment="#{deployment.environment.slug}"}, - timeframe_start: (deployment.created_at - 30.minutes).to_f, - timeframe_end: (deployment.created_at + 30.minutes).to_f - } - - query_metrics(query_context) + query_metrics( + common_query_context( + deployment.environment, + timeframe_start: (deployment.created_at - 30.minutes).to_f, + timeframe_end: (deployment.created_at + 30.minutes).to_f + ) + ) end end end diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb index b5a679ddd79..db4708b22e4 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb @@ -6,14 +6,9 @@ module Gitlab def query(environment_id) Environment.find_by(id: environment_id).try do |environment| - query_context = { - environment_slug: environment.slug, - environment_filter: %{container_name!="POD",environment="#{environment.slug}"}, - timeframe_start: 8.hours.ago.to_f, - timeframe_end: Time.now.to_f - } - - query_metrics(query_context) + query_metrics( + common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f) + ) end end end diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index e44be770544..7ac6162b54d 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -42,15 +42,18 @@ module Gitlab end def process_query(context, query) - query_with_result = query.dup + query = query.dup result = if query.key?(:query_range) - client_query_range(query[:query_range] % context, start: context[:timeframe_start], stop: context[:timeframe_end]) + query[:query_range] %= context + client_query_range(query[:query_range], start: context[:timeframe_start], stop: context[:timeframe_end]) else - client_query(query[:query] % context, time: context[:timeframe_end]) + query[:query] %= context + client_query(query[:query], time: context[:timeframe_end]) end - query_with_result[:result] = result&.map(&:deep_symbolize_keys) - query_with_result + + query[:result] = result&.map(&:deep_symbolize_keys) + query end def available_metrics @@ -67,6 +70,16 @@ module Gitlab result.select { |group| group.metrics.any? } end + + def common_query_context(environment, timeframe_start:, timeframe_end:) + { + timeframe_start: timeframe_start, + timeframe_end: timeframe_end, + ci_environment_slug: environment.slug, + kube_namespace: environment.project.kubernetes_service&.actual_namespace || '', + environment_filter: %{container_name!="POD",environment="#{environment.slug}"} + } + end end end end diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake index 680e76af471..3703f9cfb5c 100644 --- a/lib/tasks/gitlab/gitaly.rake +++ b/lib/tasks/gitlab/gitaly.rake @@ -21,7 +21,7 @@ namespace :gitlab do create_gitaly_configuration # In CI we run scripts/gitaly-test-build instead of this command unless ENV['CI'].present? - Bundler.with_original_env { run_command!(%w[/usr/bin/env -u BUNDLE_GEMFILE] + [command]) } + Bundler.with_original_env { run_command!([command]) } end end end |
