diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-06 21:10:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-06 21:10:07 +0000 |
commit | 454973238cb3eed58f7d901b87ceb29acf6febbd (patch) | |
tree | 340dd978fd9df37553733b3244383c4bc9b3ceea /app | |
parent | 52dbfea964ea55b3393dc4146e541bc651f7e9e3 (diff) | |
download | gitlab-ce-454973238cb3eed58f7d901b87ceb29acf6febbd.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
24 files changed, 224 insertions, 26 deletions
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index cef5ae41106..0ab032b25d3 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -3,6 +3,7 @@ import { GlLoadingIcon } from '@gitlab/ui'; import { uniqueId } from 'lodash'; import BlobContent from '~/blob/components/blob_content.vue'; import BlobHeader from '~/blob/components/blob_header.vue'; +import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants'; import createFlash from '~/flash'; import { __ } from '~/locale'; import blobInfoQuery from '../queries/blob_info.query.graphql'; @@ -22,6 +23,11 @@ export default { filePath: this.path, }; }, + result() { + this.switchViewer( + this.hasRichViewer && !window.location.hash ? RICH_BLOB_VIEWER : SIMPLE_BLOB_VIEWER, + ); + }, error() { createFlash({ message: __('An error occurred while loading the file. Please try again.') }); }, @@ -44,6 +50,7 @@ export default { }, data() { return { + activeViewerType: SIMPLE_BLOB_VIEWER, project: { repository: { blobs: { @@ -69,7 +76,7 @@ export default { canModifyBlob: true, forkPath: '', simpleViewer: {}, - richViewer: {}, + richViewer: null, }, ], }, @@ -87,10 +94,19 @@ export default { return nodes[0] || {}; }, viewer() { - const viewer = this.blobInfo.richViewer || this.blobInfo.simpleViewer; - const { fileType, tooLarge, type } = viewer; - - return { fileType, tooLarge, type }; + const { richViewer, simpleViewer } = this.blobInfo; + return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer; + }, + hasRichViewer() { + return Boolean(this.blobInfo.richViewer); + }, + hasRenderError() { + return Boolean(this.viewer.renderError); + }, + }, + methods: { + switchViewer(newViewer) { + this.activeViewerType = newViewer || SIMPLE_BLOB_VIEWER; }, }, }; @@ -99,8 +115,14 @@ export default { <template> <div> <gl-loading-icon v-if="isLoading" /> - <div v-if="blobInfo && !isLoading"> - <blob-header :blob="blobInfo" /> + <div v-if="blobInfo && !isLoading" class="file-holder"> + <blob-header + :blob="blobInfo" + :hide-viewer-switcher="!hasRichViewer" + :active-viewer-type="viewer.type" + :has-render-error="hasRenderError" + @viewer-changed="switchViewer" + /> <blob-content :blob="blobInfo" :content="blobInfo.rawTextBlob" diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/assets/javascripts/repository/queries/blob_info.query.graphql index d0c3f8d8d54..07c076af54b 100644 --- a/app/assets/javascripts/repository/queries/blob_info.query.graphql +++ b/app/assets/javascripts/repository/queries/blob_info.query.graphql @@ -6,6 +6,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!) { nodes { webPath name + size rawSize rawTextBlob fileType @@ -18,11 +19,13 @@ query getBlobInfo($projectPath: ID!, $filePath: String!) { fileType tooLarge type + renderError } richViewer { fileType tooLarge type + renderError } } } diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 65b7a78cb58..cbee33853bb 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -36,6 +36,10 @@ class Projects::BlobController < Projects::ApplicationController feature_category :source_code_management + before_action do + push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml) + end + def new commit unless @repository.empty? end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 94fd6d86abc..58a05d498c7 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -59,6 +59,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action do push_frontend_feature_flag(:mr_collapsed_approval_rules, @project) + push_frontend_feature_flag(:show_relevant_approval_rule_approvers, @project, default_enabled: :yaml) end around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions] diff --git a/app/graphql/mutations/ci/job/base.rb b/app/graphql/mutations/ci/job/base.rb new file mode 100644 index 00000000000..3359def159a --- /dev/null +++ b/app/graphql/mutations/ci/job/base.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module Job + class Base < BaseMutation + JobID = ::Types::GlobalIDType[::Ci::Build] + + argument :id, JobID, + required: true, + description: 'The ID of the job to mutate.' + + def find_object(id: ) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = JobID.coerce_isolated_input(id) + GlobalID::Locator.locate(id) + end + end + end + end +end diff --git a/app/graphql/mutations/ci/job/play.rb b/app/graphql/mutations/ci/job/play.rb new file mode 100644 index 00000000000..f87904f8b25 --- /dev/null +++ b/app/graphql/mutations/ci/job/play.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module Job + class Play < Base + graphql_name 'JobPlay' + + field :job, + Types::Ci::JobType, + null: true, + description: 'The job after the mutation.' + + authorize :update_build + + def resolve(id:) + job = authorized_find!(id: id) + project = job.project + + ::Ci::PlayBuildService.new(project, current_user).execute(job) + { + job: job, + errors: errors_on_object(job) + } + end + end + end + end +end diff --git a/app/graphql/mutations/ci/job/retry.rb b/app/graphql/mutations/ci/job/retry.rb new file mode 100644 index 00000000000..a61d5dddb40 --- /dev/null +++ b/app/graphql/mutations/ci/job/retry.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module Job + class Retry < Base + graphql_name 'JobRetry' + + field :job, + Types::Ci::JobType, + null: true, + description: 'The job after the mutation.' + + authorize :update_build + + def resolve(id:) + job = authorized_find!(id: id) + project = job.project + + ::Ci::RetryBuildService.new(project, current_user).execute(job) + { + job: job, + errors: errors_on_object(job) + } + end + end + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index a820ef94719..053dfef58f9 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -94,6 +94,8 @@ module Types mount_mutation Mutations::Ci::Pipeline::Destroy mount_mutation Mutations::Ci::Pipeline::Retry mount_mutation Mutations::Ci::CiCdSettingsUpdate + mount_mutation Mutations::Ci::Job::Play + mount_mutation Mutations::Ci::Job::Retry mount_mutation Mutations::Namespace::PackageSettings::Update mount_mutation Mutations::UserCallouts::Create end diff --git a/app/graphql/types/packages/package_status_enum.rb b/app/graphql/types/packages/package_status_enum.rb new file mode 100644 index 00000000000..2e6ea5d0a50 --- /dev/null +++ b/app/graphql/types/packages/package_status_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module Packages + class PackageStatusEnum < BaseEnum + graphql_name 'PackageStatus' + + ::Packages::Package.statuses.keys.each do |status| + value status.to_s.upcase, description: "Packages with a #{status} status", value: status.to_s + end + end + end +end diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb index 9ea4c4b74ea..659af4a7057 100644 --- a/app/graphql/types/packages/package_type.rb +++ b/app/graphql/types/packages/package_type.rb @@ -25,6 +25,7 @@ module Types field :versions, ::Types::Packages::PackageType.connection_type, null: true, description: 'The other versions of the package.', deprecated: { reason: 'This field is now only returned in the PackageDetailsType', milestone: '13.11' } + field :status, Types::Packages::PackageStatusEnum, null: false, description: 'Package status.' def project Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find diff --git a/app/models/concerns/triggerable_hooks.rb b/app/models/concerns/triggerable_hooks.rb index db5df6c2c9f..8fe34632430 100644 --- a/app/models/concerns/triggerable_hooks.rb +++ b/app/models/concerns/triggerable_hooks.rb @@ -29,11 +29,11 @@ module TriggerableHooks callable_scopes = triggers.keys + [:all] return none unless callable_scopes.include?(trigger) - public_send(trigger) # rubocop:disable GitlabSecurity/PublicSend + executable.public_send(trigger) # rubocop:disable GitlabSecurity/PublicSend end def select_active(hooks_scope, data) - select do |hook| + executable.select do |hook| ActiveHookFilter.new(hook).matches?(hooks_scope, data) end end diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index b625a70b444..83858ee0c77 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -29,6 +29,10 @@ class ProjectHook < WebHook def pluralized_name _('Webhooks') end + + def web_hooks_disable_failed? + Feature.enabled?(:web_hooks_disable_failed, project) + end end ProjectHook.prepend_if_ee('EE::ProjectHook') diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 4caa45a13d4..b35542d5b93 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -6,9 +6,7 @@ class ServiceHook < WebHook belongs_to :service validates :service, presence: true - # rubocop: disable CodeReuse/ServiceClass def execute(data, hook_name = 'service_hook') - WebHookService.new(self, data, hook_name).execute + super(data, hook_name) end - # rubocop: enable CodeReuse/ServiceClass end diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index dbd5a1b032a..44538134318 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -3,6 +3,11 @@ class WebHook < ApplicationRecord include Sortable + FAILURE_THRESHOLD = 3 # three strikes + INITIAL_BACKOFF = 10.minutes + MAX_BACKOFF = 1.day + BACKOFF_GROWTH_FACTOR = 2.0 + attr_encrypted :token, mode: :per_attribute_iv, algorithm: 'aes-256-gcm', @@ -21,15 +26,27 @@ class WebHook < ApplicationRecord validates :token, format: { without: /\n/ } validates :push_events_branch_filter, branch_filter: true + scope :executable, -> do + next all unless Feature.enabled?(:web_hooks_disable_failed) + + where('recent_failures <= ? AND (disabled_until IS NULL OR disabled_until < ?)', FAILURE_THRESHOLD, Time.current) + end + + def executable? + return true unless web_hooks_disable_failed? + + recent_failures <= FAILURE_THRESHOLD && (disabled_until.nil? || disabled_until < Time.current) + end + # rubocop: disable CodeReuse/ServiceClass def execute(data, hook_name) - WebHookService.new(self, data, hook_name).execute + WebHookService.new(self, data, hook_name).execute if executable? end # rubocop: enable CodeReuse/ServiceClass # rubocop: disable CodeReuse/ServiceClass def async_execute(data, hook_name) - WebHookService.new(self, data, hook_name).async_execute + WebHookService.new(self, data, hook_name).async_execute if executable? end # rubocop: enable CodeReuse/ServiceClass @@ -41,4 +58,26 @@ class WebHook < ApplicationRecord def help_path 'user/project/integrations/webhooks' end + + def next_backoff + return MAX_BACKOFF if backoff_count >= 8 # optimization to prevent expensive exponentiation and possible overflows + + (INITIAL_BACKOFF * (BACKOFF_GROWTH_FACTOR**backoff_count)) + .clamp(INITIAL_BACKOFF, MAX_BACKOFF) + .seconds + end + + def disable! + update!(recent_failures: FAILURE_THRESHOLD + 1) + end + + def enable! + update!(recent_failures: 0, disabled_until: nil, backoff_count: 0) + end + + private + + def web_hooks_disable_failed? + Feature.enabled?(:web_hooks_disable_failed) + end end diff --git a/app/models/member.rb b/app/models/member.rb index ee9b2c8cef3..a44b7f0ff7e 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -84,10 +84,9 @@ class Member < ApplicationRecord is_external_invite = arel_table[:user_id].eq(nil).and(arel_table[:invite_token].not_eq(nil)) user_is_blocked = User.arel_table[:state].eq(:blocked) - user_ok = Arel::Nodes::Grouping.new(is_external_invite).or(user_is_blocked) - left_join_users - .where(user_ok) + .where(user_is_blocked) + .where.not(is_external_invite) .non_request .non_minimal_access .reorder(nil) diff --git a/app/models/namespaces/traversal/linear.rb b/app/models/namespaces/traversal/linear.rb index 3ebf0894b98..be43b2e04f7 100644 --- a/app/models/namespaces/traversal/linear.rb +++ b/app/models/namespaces/traversal/linear.rb @@ -63,6 +63,12 @@ module Namespaces lineage(top: self) end + def descendants + return super unless use_traversal_ids? + + self_and_descendants.where.not(id: id) + end + def ancestors(hierarchy_order: nil) return super() unless use_traversal_ids? return super() unless Feature.enabled?(:use_traversal_ids_for_ancestors, root_ancestor, default_enabled: :yaml) diff --git a/app/services/git/branch_hooks_service.rb b/app/services/git/branch_hooks_service.rb index 825faf59c13..4b802803a07 100644 --- a/app/services/git/branch_hooks_service.rb +++ b/app/services/git/branch_hooks_service.rb @@ -96,7 +96,6 @@ module Git def track_ci_config_change_event return unless Gitlab::CurrentSettings.usage_ping_enabled? - return unless ::Feature.enabled?(:usage_data_unique_users_committing_ciconfigfile, project, default_enabled: :yaml) return unless default_branch? commits_changing_ci_config.each do |commit| diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index d0099283afa..2a2053cb912 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -10,7 +10,7 @@ class SystemHooksService end def execute_hooks(data, hooks_scope = :all) - SystemHook.hooks_for(hooks_scope).find_each do |hook| + SystemHook.executable.hooks_for(hooks_scope).find_each do |hook| hook.async_execute(data, 'system_hooks') end diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb index 5a51b42f9f9..0535bc625ac 100644 --- a/app/services/web_hook_service.rb +++ b/app/services/web_hook_service.rb @@ -6,6 +6,18 @@ class WebHookService attr_reader :body, :headers, :code + def success? + false + end + + def redirection? + false + end + + def internal_server_error? + true + end + def initialize @headers = Gitlab::HTTP::Response::Headers.new({}) @body = '' @@ -33,6 +45,8 @@ class WebHookService end def execute + return { status: :error, message: 'Hook disabled' } unless hook.executable? + start_time = Gitlab::Metrics::System.monotonic_time response = if parsed_url.userinfo.blank? @@ -104,6 +118,8 @@ class WebHookService end def log_execution(trigger:, url:, request_data:, response:, execution_duration:, error_message: nil) + handle_failure(response, hook) + WebHookLog.create( web_hook: hook, trigger: trigger, @@ -118,6 +134,17 @@ class WebHookService ) end + def handle_failure(response, hook) + if response.success? || response.redirection? + hook.enable! + elsif response.internal_server_error? + next_backoff = hook.next_backoff + hook.update!(disabled_until: next_backoff.from_now, backoff_count: hook.backoff_count + 1) + else + hook.update!(recent_failures: hook.recent_failures + 1) + end + end + def build_headers(hook_name) @headers ||= begin { diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml index 01ba7c06154..001ca80dbd6 100644 --- a/app/views/clusters/clusters/show.html.haml +++ b/app/views/clusters/clusters/show.html.haml @@ -28,13 +28,13 @@ pre_installed_knative: @cluster.knative_pre_installed? ? 'true': 'false', help_path: help_page_path('user/project/clusters/index.md', anchor: 'installing-applications'), helm_help_path: help_page_path('user/clusters/applications.md', anchor: 'helm'), - ingress_help_path: help_page_path('user/project/clusters/index.md', anchor: 'getting-the-external-endpoint'), + ingress_help_path: help_page_path('user/clusters/applications.md', anchor: 'determining-the-external-endpoint-automatically'), ingress_dns_help_path: help_page_path('user/clusters/applications.md', anchor: 'pointing-your-dns-at-the-external-endpoint'), ingress_mod_security_help_path: help_page_path('user/clusters/applications.md', anchor: 'web-application-firewall-modsecurity'), - environments_help_path: help_page_path('ci/environments/index.md', anchor: 'defining-environments'), + environments_help_path: help_page_path('ci/environments/index.md', anchor: 'create-a-static-environment'), clusters_help_path: help_page_path('user/project/clusters/index.md', anchor: 'deploying-to-a-kubernetes-cluster'), deploy_boards_help_path: help_page_path('user/project/deploy_boards.md', anchor: 'enabling-deploy-boards'), - cloud_run_help_path: help_page_path('user/project/clusters/add_remove_clusters.md', anchor: 'cloud-run-for-anthos'), + cloud_run_help_path: help_page_path('user/project/clusters/add_gke_clusters.md', anchor: 'cloud-run-for-anthos'), manage_prometheus_path: manage_prometheus_path, cluster_id: @cluster.id, cilium_help_path: help_page_path('user/clusters/applications.md', anchor: 'install-cilium-using-gitlab-cicd')} } diff --git a/app/views/projects/feature_flags/edit.html.haml b/app/views/projects/feature_flags/edit.html.haml index 028595aba0b..1549f5cf6d6 100644 --- a/app/views/projects/feature_flags/edit.html.haml +++ b/app/views/projects/feature_flags/edit.html.haml @@ -12,5 +12,5 @@ user_callout_id: UserCalloutsHelper::FEATURE_FLAGS_NEW_VERSION, show_user_callout: show_feature_flags_new_version?.to_s, strategy_type_docs_page_path: help_page_path('operations/feature_flags', anchor: 'feature-flag-strategies'), - environments_scope_docs_path: help_page_path('ci/environments', anchor: 'scoping-environments-with-specs'), + environments_scope_docs_path: help_page_path('ci/environments/index.md', anchor: 'scoping-environments-with-specs'), feature_flag_issues_endpoint: feature_flag_issues_links_endpoint(@project, @feature_flag, current_user) } } diff --git a/app/views/projects/feature_flags/new.html.haml b/app/views/projects/feature_flags/new.html.haml index 3bad1d9773c..bc52f52ecf7 100644 --- a/app/views/projects/feature_flags/new.html.haml +++ b/app/views/projects/feature_flags/new.html.haml @@ -10,5 +10,5 @@ user_callout_id: UserCalloutsHelper::FEATURE_FLAGS_NEW_VERSION, show_user_callout: show_feature_flags_new_version?.to_s, strategy_type_docs_page_path: help_page_path('operations/feature_flags', anchor: 'feature-flag-strategies'), - environments_scope_docs_path: help_page_path('ci/environments', anchor: 'scoping-environments-with-specs'), + environments_scope_docs_path: help_page_path('ci/environments/index.md', anchor: 'scoping-environments-with-specs'), project_id: @project.id } } diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml index bbef5150a62..f56fd7f557d 100644 --- a/app/views/projects/registry/repositories/index.html.haml +++ b/app/views/projects/registry/repositories/index.html.haml @@ -12,7 +12,7 @@ "containers_error_image" => image_path('illustrations/docker-error-state.svg'), "repository_url" => escape_once(@project.container_registry_url), "registry_host_url_with_port" => escape_once(registry_config.host_port), - "expiration_policy_help_page_path" => help_page_path('user/packages/container_registry/index', anchor: 'expiration-policy'), + "expiration_policy_help_page_path" => help_page_path('user/packages/container_registry/index.md', anchor: 'cleanup-policy'), "garbage_collection_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'container-registry-garbage-collection'), "run_cleanup_policies_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'run-the-cleanup-policy-now'), "project_path": @project.full_path, diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml index 2a2a1a911af..9c59d5ae1fa 100644 --- a/app/views/shared/access_tokens/_table.html.haml +++ b/app/views/shared/access_tokens/_table.html.haml @@ -18,7 +18,7 @@ %th= s_('AccessTokens|Created') %th = _('Last Used') - = link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'token-activity'), target: '_blank' + = link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'view-the-last-time-a-token-was-used'), target: '_blank' %th= _('Expires') %th= _('Scopes') %th |