diff options
Diffstat (limited to 'app')
23 files changed, 204 insertions, 66 deletions
diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue index f6b9ea5d30d..5917c96990e 100644 --- a/app/assets/javascripts/repository/components/breadcrumbs.vue +++ b/app/assets/javascripts/repository/components/breadcrumbs.vue @@ -34,7 +34,10 @@ export default { projectPath: this.projectPath, }; }, - update: data => data.project.userPermissions, + update: data => data.project?.userPermissions, + error(error) { + throw error; + }, }, }, mixins: [getRefMixin], @@ -172,7 +175,7 @@ export default { ); } - if (this.userPermissions.pushCode) { + if (this.userPermissions?.pushCode) { items.push( { type: ROW_TYPES.divider, diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue index fe1724acf89..573b0c4963e 100644 --- a/app/assets/javascripts/repository/components/last_commit.vue +++ b/app/assets/javascripts/repository/components/last_commit.vue @@ -40,16 +40,19 @@ export default { }; }, update: data => { - const pipelines = data.project.repository.tree.lastCommit.pipelines.edges; + const pipelines = data.project?.repository?.tree?.lastCommit?.pipelines?.edges; return { - ...data.project.repository.tree.lastCommit, - pipeline: pipelines.length && pipelines[0].node, + ...data.project?.repository?.tree?.lastCommit, + pipeline: pipelines?.length && pipelines[0].node, }; }, context: { isSingleRequest: true, }, + error(error) { + throw error; + }, }, }, props: { @@ -62,7 +65,7 @@ export default { data() { return { projectPath: '', - commit: {}, + commit: null, showDescription: false, }; }, @@ -79,6 +82,11 @@ export default { return this.commit.sha.substr(0, 8); }, }, + watch: { + currentPath() { + this.commit = null; + }, + }, methods: { toggleShowDescription() { this.showDescription = !this.showDescription; @@ -91,7 +99,7 @@ export default { <template> <div class="info-well d-none d-sm-flex project-last-commit commit p-3"> <gl-loading-icon v-if="isLoading" size="md" color="dark" class="m-auto" /> - <template v-else> + <template v-else-if="commit"> <user-avatar-link v-if="commit.author" :link-href="commit.author.webUrl" diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue index 92e33b013c3..7b34e9ef60d 100644 --- a/app/assets/javascripts/repository/components/tree_content.vue +++ b/app/assets/javascripts/repository/components/tree_content.vue @@ -86,7 +86,8 @@ export default { }, }) .then(({ data }) => { - if (!data) return; + if (data.errors) throw data.errors; + if (!data?.project?.repository) return; const pageInfo = this.hasNextPage(data.project.repository.tree); @@ -99,12 +100,15 @@ export default { {}, ); - if (pageInfo && pageInfo.hasNextPage) { + if (pageInfo?.hasNextPage) { this.nextPageCursor = pageInfo.endCursor; this.fetchFiles(); } }) - .catch(() => createFlash(__('An error occurred while fetching folder content.'))); + .catch(error => { + createFlash(__('An error occurred while fetching folder content.')); + throw error; + }); }, normalizeData(key, data) { return this.entries[key].concat(data.map(({ node }) => node)); diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js index 2ef0c078f13..a26acbbe301 100644 --- a/app/assets/javascripts/repository/index.js +++ b/app/assets/javascripts/repository/index.js @@ -23,7 +23,7 @@ export default function setupVueRepositoryList() { projectPath, projectShortPath, ref, - vueFileListLfsBadge: gon?.features?.vueFileListLfsBadge, + vueFileListLfsBadge: gon.features?.vueFileListLfsBadge || false, commits: [], }, }); diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb index 783c59822f1..9eaa55039c8 100644 --- a/app/controllers/admin/runners_controller.rb +++ b/app/controllers/admin/runners_controller.rb @@ -66,7 +66,7 @@ class Admin::RunnersController < Admin::ApplicationController # rubocop: disable CodeReuse/ActiveRecord def assign_builds_and_projects - @builds = runner.builds.order('id DESC').first(30) + @builds = runner.builds.order('id DESC').preload_project_and_pipeline_project.first(30) @projects = if params[:search].present? ::Project.search(params[:search]) @@ -75,7 +75,8 @@ class Admin::RunnersController < Admin::ApplicationController end @projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any? - @projects = @projects.page(params[:page]).per(30) + @projects = @projects.inc_routes + @projects = @projects.page(params[:page]).per(30).without_count end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index f16f752f85b..04919a4b9d0 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -7,14 +7,14 @@ class Import::BaseController < ApplicationController # rubocop: disable CodeReuse/ActiveRecord def find_already_added_projects(import_type) - current_user.created_projects.where(import_type: import_type).includes(:import_state) + current_user.created_projects.where(import_type: import_type).with_import_state end # rubocop: enable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord def find_jobs(import_type) current_user.created_projects - .includes(:import_state) + .with_import_state .where(import_type: import_type) .to_json(only: [:id], methods: [:import_status]) end diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb index dc72a4e4fd9..5fb7b5dccc5 100644 --- a/app/controllers/import/bitbucket_server_controller.rb +++ b/app/controllers/import/bitbucket_server_controller.rb @@ -82,7 +82,7 @@ class Import::BitbucketServerController < Import::BaseController # rubocop: disable CodeReuse/ActiveRecord def filter_added_projects(import_type, import_sources) - current_user.created_projects.where(import_type: import_type, import_source: import_sources).includes(:import_state) + current_user.created_projects.where(import_type: import_type, import_source: import_sources).with_import_state end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb index 7ba8b3ce938..9aec870c6ea 100644 --- a/app/controllers/import/manifest_controller.rb +++ b/app/controllers/import/manifest_controller.rb @@ -87,7 +87,7 @@ class Import::ManifestController < Import::BaseController group.all_projects .where(import_type: 'manifest') .where(creator_id: current_user) - .includes(:import_state) + .with_import_state end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/finders/contributed_projects_finder.rb b/app/finders/contributed_projects_finder.rb index f8c7f0c3167..a351d30229e 100644 --- a/app/finders/contributed_projects_finder.rb +++ b/app/finders/contributed_projects_finder.rb @@ -12,16 +12,14 @@ class ContributedProjectsFinder < UnionFinder # visible by this user. # # Returns an ActiveRecord::Relation. - # rubocop: disable CodeReuse/ActiveRecord def execute(current_user = nil) # Do not show contributed projects if the user profile is private. return Project.none unless can_read_profile?(current_user) segments = all_projects(current_user) - find_union(segments, Project).includes(:namespace).order_id_desc + find_union(segments, Project).with_namespace.order_id_desc end - # rubocop: enable CodeReuse/ActiveRecord private diff --git a/app/finders/personal_projects_finder.rb b/app/finders/personal_projects_finder.rb index 20f5b221a89..e7094d73905 100644 --- a/app/finders/personal_projects_finder.rb +++ b/app/finders/personal_projects_finder.rb @@ -17,15 +17,13 @@ class PersonalProjectsFinder < UnionFinder # min_access_level: integer # # Returns an ActiveRecord::Relation. - # rubocop: disable CodeReuse/ActiveRecord def execute(current_user = nil) return Project.none unless can?(current_user, :read_user_profile, @user) segments = all_projects(current_user) - find_union(segments, Project).includes(:namespace).order_updated_desc + find_union(segments, Project).with_namespace.order_updated_desc end - # rubocop: enable CodeReuse/ActiveRecord private diff --git a/app/helpers/analytics_navbar_helper.rb b/app/helpers/analytics_navbar_helper.rb new file mode 100644 index 00000000000..d9aadfaeb15 --- /dev/null +++ b/app/helpers/analytics_navbar_helper.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module AnalyticsNavbarHelper + class NavbarSubItem + attr_reader :title, :path, :link, :link_to_options + + def initialize(title:, path:, link:, link_to_options: {}) + @title = title + @path = path + @link = link + @link_to_options = link_to_options.merge(title: title) + end + end + + def project_analytics_navbar_links(project, current_user) + [ + cycle_analytics_navbar_link(project, current_user), + repository_analytics_navbar_link(project, current_user), + ci_cd_analytics_navbar_link(project, current_user) + ].compact + end + + private + + def navbar_sub_item(args) + NavbarSubItem.new(args) + end + + def cycle_analytics_navbar_link(project, current_user) + return unless Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, project) + return unless project_nav_tab?(:cycle_analytics) + + navbar_sub_item( + title: _('Cycle Analytics'), + path: 'cycle_analytics#show', + link: project_cycle_analytics_path(project), + link_to_options: { class: 'shortcuts-project-cycle-analytics' } + ) + end + + def repository_analytics_navbar_link(project, current_user) + return if Feature.disabled?(:analytics_pages_under_project_analytics_sidebar, project) + return if project.empty_repo? + + navbar_sub_item( + title: _('Repository Analytics'), + path: 'graphs#charts', + link: charts_project_graph_path(project, current_ref), + link_to_options: { class: 'shortcuts-repository-charts' } + ) + end + + def ci_cd_analytics_navbar_link(project, current_user) + return unless Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, project) + return unless project_nav_tab?(:pipelines) + return unless project.feature_available?(:builds, current_user) || !project.empty_repo? + + navbar_sub_item( + title: _('CI / CD Analytics'), + path: 'pipelines#charts', + link: charts_project_pipelines_path(project) + ) + end +end + +AnalyticsNavbarHelper.prepend_if_ee('EE::AnalyticsNavbarHelper') diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 339d68871ae..3000cfb678e 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -403,6 +403,10 @@ module ProjectsHelper nav_tabs << :operations end + if can?(current_user, :read_cycle_analytics, project) + nav_tabs << :cycle_analytics + end + tab_ability_map.each do |tab, ability| if can?(current_user, ability, project) nav_tabs << tab @@ -643,7 +647,6 @@ module ProjectsHelper projects#show projects#activity releases#index - cycle_analytics#show ] end diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 58edb327be0..0f156003a01 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -12,6 +12,7 @@ module TabHelper # :action - One or more action names to check (optional). # :path - A shorthand path, such as 'dashboard#index', to check (optional). # :html_options - Extra options to be passed to the list element (optional). + # :unless - Callable object to skip rendering the 'active' class on `li` element (optional). # block - An optional block that will become the contents of the returned # `li` element. # @@ -56,6 +57,14 @@ module TabHelper # nav_link(path: 'admin/appearances#show') { "Hello"} # # => '<li class="active">Hello</li>' # + # # Shorthand path + unless + # # Add `active` class when TreeController is requested, except the `index` action. + # nav_link(controller: 'tree', unless: -> { action_name?('index') }) { "Hello" } + # # => '<li class="active">Hello</li>' + # + # # When `TreeController#index` is requested + # # => '<li>Hello</li>' + # # Returns a list item element String def nav_link(options = {}, &block) klass = active_nav_link?(options) ? 'active' : '' @@ -73,6 +82,8 @@ module TabHelper end def active_nav_link?(options) + return false if options[:unless]&.call + if path = options.delete(:path) unless path.respond_to?(:each) path = [path] diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 369a793f3d5..d1edf3e9c03 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -172,6 +172,9 @@ module Ci scope :queued_before, ->(time) { where(arel_table[:queued_at].lt(time)) } scope :order_id_desc, -> { order('ci_builds.id DESC') } + PROJECT_ROUTE_AND_NAMESPACE_ROUTE = { project: [:project_feature, :route, { namespace: :route }] }.freeze + scope :preload_project_and_pipeline_project, -> { preload(PROJECT_ROUTE_AND_NAMESPACE_ROUTE, pipeline: PROJECT_ROUTE_AND_NAMESPACE_ROUTE) } + acts_as_taggable add_authentication_token_field :token, encrypted: :optional diff --git a/app/models/project.rb b/app/models/project.rb index 236111cba94..cd191589351 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -411,6 +411,8 @@ class Project < ApplicationRecord scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') } scope :inc_routes, -> { includes(:route, namespace: :route) } scope :with_statistics, -> { includes(:statistics) } + scope :with_namespace, -> { includes(:namespace) } + scope :with_import_state, -> { includes(:import_state) } scope :with_service, ->(service) { joins(service).eager_load(service) } scope :with_shared_runners, -> { where(shared_runners_enabled: true) } scope :with_container_registry, -> { where(container_registry_enabled: true) } diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 033c80fd8ed..8a0f44b4e93 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -100,9 +100,7 @@ module SystemNoteService end def close_after_error_tracking_resolve(issue, project, author) - body = _('resolved the corresponding error and closed the issue.') - - create_note(NoteSummary.new(issue, project, author, body, action: 'closed')) + ::SystemNotes::IssuablesService.new(noteable: issue, project: project, author: author).close_after_error_tracking_resolve end def change_status(noteable, project, author, status, source = nil) @@ -243,23 +241,6 @@ module SystemNoteService def zoom_link_removed(issue, project, author) ::SystemNotes::ZoomService.new(noteable: issue, project: project, author: author).zoom_link_removed end - - private - - def create_note(note_summary) - note = Note.create(note_summary.note.merge(system: true)) - note.system_note_metadata = SystemNoteMetadata.new(note_summary.metadata) if note_summary.metadata? - - note - end - - def url_helpers - @url_helpers ||= Gitlab::Routing.url_helpers - end - - def content_tag(*args) - ActionController::Base.helpers.content_tag(*args) - end end SystemNoteService.prepend_if_ee('EE::SystemNoteService') diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb index 6fffd2ed4bf..d7787dac4b8 100644 --- a/app/services/system_notes/issuables_service.rb +++ b/app/services/system_notes/issuables_service.rb @@ -282,6 +282,12 @@ module SystemNotes create_note(NoteSummary.new(noteable, project, author, body, action: action)) end + def close_after_error_tracking_resolve + body = _('resolved the corresponding error and closed the issue.') + + create_note(NoteSummary.new(noteable, project, author, body, action: 'closed')) + end + private def cross_reference_note_content(gfm_reference) diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml index 62be38e9dd2..f860b7a61a2 100644 --- a/app/views/admin/runners/show.html.haml +++ b/app/views/admin/runners/show.html.haml @@ -48,7 +48,7 @@ = project.full_name %td .float-right - = link_to 'Disable', [:admin, project.namespace.becomes(Namespace), project, runner_project], method: :delete, class: 'btn btn-danger btn-sm' + = link_to 'Disable', admin_namespace_project_runner_project_path(project.namespace, project, runner_project), method: :delete, class: 'btn btn-danger btn-sm' %table.table.unassigned-projects %thead @@ -70,10 +70,10 @@ = project.full_name %td .float-right - = form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f| + = form_for project.runner_projects.new, url: admin_namespace_project_runner_projects_path(project.namespace, project), method: :post do |f| = f.hidden_field :runner_id, value: @runner.id = f.submit 'Enable', class: 'btn btn-sm' - = paginate @projects, theme: "gitlab" + = paginate_without_count @projects .col-md-6 %h4 Recent jobs served by this Runner diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index 3464cc1ea07..3096b2e43fe 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -1,3 +1,5 @@ +- should_display_analytics_pages_in_sidebar = Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, @project) + .nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) } .nav-sidebar-inner-scroll - can_edit = can?(current_user, :admin_project, @project) @@ -8,7 +10,9 @@ .sidebar-context-title = @project.name %ul.sidebar-top-level-items - = nav_link(path: sidebar_projects_paths, html_options: { class: 'home' }) do + - paths = sidebar_projects_paths + - paths << 'cycle_analytics#show' unless should_display_analytics_pages_in_sidebar + = nav_link(path: paths, html_options: { class: 'home' }) do = link_to project_path(@project), class: 'shortcuts-project rspec-project-link', data: { qa_selector: 'project_link' } do .nav-icon-container = sprite_icon('home') @@ -34,15 +38,18 @@ = link_to project_releases_path(@project), title: _('Releases'), class: 'shortcuts-project-releases' do %span= _('Releases') - - if can?(current_user, :read_cycle_analytics, @project) - = nav_link(path: 'cycle_analytics#show') do - = link_to project_cycle_analytics_path(@project), title: _('Cycle Analytics'), class: 'shortcuts-project-cycle-analytics' do - %span= _('Cycle Analytics') - = render_if_exists 'layouts/nav/project_insights_link' + - unless should_display_analytics_pages_in_sidebar + - if can?(current_user, :read_cycle_analytics, @project) + = nav_link(path: 'cycle_analytics#show') do + = link_to project_cycle_analytics_path(@project), title: _('Cycle Analytics'), class: 'shortcuts-project-cycle-analytics' do + %span= _('Cycle Analytics') + + = render_if_exists 'layouts/nav/project_insights_link' + - if project_nav_tab? :files - = nav_link(controller: sidebar_repository_paths) do + = nav_link(controller: sidebar_repository_paths, unless: -> { should_display_analytics_pages_in_sidebar && current_path?('projects/graphs#charts') }) do = link_to project_tree_path(@project), class: 'shortcuts-tree qa-project-menu-repo' do .nav-icon-container = sprite_icon('doc-text') @@ -83,9 +90,10 @@ = link_to project_compare_index_path(@project, from: @repository.root_ref, to: current_ref) do = _('Compare') - = nav_link(path: 'graphs#charts') do - = link_to charts_project_graph_path(@project, current_ref) do - = _('Charts') + - unless should_display_analytics_pages_in_sidebar + = nav_link(path: 'graphs#charts') do + = link_to charts_project_graph_path(@project, current_ref) do + = _('Charts') = render_if_exists 'projects/sidebar/repository_locked_files' @@ -170,7 +178,7 @@ = number_with_delimiter(@project.open_merge_requests_count) - if project_nav_tab? :pipelines - = nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts]) do + = nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts], unless: -> { should_display_analytics_pages_in_sidebar && current_path?('projects/pipelines#charts') }) do = link_to project_pipelines_path(@project), class: 'shortcuts-pipelines qa-link-pipelines rspec-link-pipelines', data: { qa_selector: 'ci_cd_link' } do .nav-icon-container = sprite_icon('rocket') @@ -201,13 +209,13 @@ %span = _('Artifacts') - - if project_nav_tab? :pipelines + - if !should_display_analytics_pages_in_sidebar && project_nav_tab?(:pipelines) = nav_link(controller: :pipeline_schedules) do = link_to pipeline_schedules_path(@project), title: _('Schedules'), class: 'shortcuts-builds' do %span = _('Schedules') - - if @project.feature_available?(:builds, current_user) && !@project.empty_repo? + - if !should_display_analytics_pages_in_sidebar && @project.feature_available?(:builds, current_user) && !@project.empty_repo? = nav_link(path: 'pipelines#charts') do = link_to charts_project_pipelines_path(@project), title: _('Charts'), class: 'shortcuts-pipelines-charts' do %span @@ -290,7 +298,7 @@ = render_if_exists 'layouts/nav/sidebar/project_packages_link' - = render_if_exists 'layouts/nav/sidebar/project_analytics_link' # EE-specific + = render 'layouts/nav/sidebar/project_analytics_link' - if project_nav_tab? :wiki - wiki_url = project_wiki_path(@project, :home) @@ -410,11 +418,12 @@ = link_to project_network_path(@project, current_ref), title: _('Network'), class: 'shortcuts-network' do = _('Graph') - -# Shortcut to Repository > Charts (formerly, top-nav item "Graphs") - - unless @project.empty_repo? - %li.hidden - = link_to charts_project_graph_path(@project, current_ref), title: _('Charts'), class: 'shortcuts-repository-charts' do - = _('Charts') + - unless should_display_analytics_pages_in_sidebar + -# Shortcut to Repository > Charts (formerly, top-nav item "Graphs") + - unless @project.empty_repo? + %li.hidden + = link_to charts_project_graph_path(@project, current_ref), title: _('Charts'), class: 'shortcuts-repository-charts' do + = _('Charts') -# Shortcut to Issues > New Issue - if project_nav_tab?(:issues) diff --git a/app/views/layouts/nav/sidebar/_project_analytics_link.html.haml b/app/views/layouts/nav/sidebar/_project_analytics_link.html.haml new file mode 100644 index 00000000000..3eb8c024588 --- /dev/null +++ b/app/views/layouts/nav/sidebar/_project_analytics_link.html.haml @@ -0,0 +1,16 @@ +- navbar_sub_item = project_analytics_navbar_links(@project, current_user).sort_by(&:title) +- all_paths = navbar_sub_item.map(&:path) + +- if navbar_sub_item.any? + = nav_link(path: all_paths) do + = link_to navbar_sub_item.first.link, data: { qa_selector: 'project_analytics_link' } do + .nav-icon-container + = sprite_icon('chart') + %span.nav-item-name + = _('Analytics') + + %ul.sidebar-sub-level-items + - navbar_sub_item.each do |menu_item| + = nav_link(path: menu_item.path) do + = link_to(menu_item.link, menu_item.link_to_options) do + %span= menu_item.title diff --git a/app/workers/concerns/application_worker.rb b/app/workers/concerns/application_worker.rb index 62748808ff1..733156ab758 100644 --- a/app/workers/concerns/application_worker.rb +++ b/app/workers/concerns/application_worker.rb @@ -9,6 +9,7 @@ module ApplicationWorker include Sidekiq::Worker # rubocop:disable Cop/IncludeSidekiqWorker include WorkerAttributes + include WorkerContext included do set_queue diff --git a/app/workers/concerns/cronjob_queue.rb b/app/workers/concerns/cronjob_queue.rb index 0683b229381..25ee4539cab 100644 --- a/app/workers/concerns/cronjob_queue.rb +++ b/app/workers/concerns/cronjob_queue.rb @@ -8,5 +8,6 @@ module CronjobQueue included do queue_namespace :cronjob sidekiq_options retry: false + worker_context project: nil, namespace: nil, user: nil end end diff --git a/app/workers/concerns/worker_context.rb b/app/workers/concerns/worker_context.rb new file mode 100644 index 00000000000..d85565e3446 --- /dev/null +++ b/app/workers/concerns/worker_context.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module WorkerContext + extend ActiveSupport::Concern + + class_methods do + def worker_context(attributes) + @worker_context = Gitlab::ApplicationContext.new(attributes) + end + + def get_worker_context + @worker_context || superclass_context + end + + private + + def superclass_context + return unless superclass.include?(WorkerContext) + + superclass.get_worker_context + end + end + + def with_context(context, &block) + Gitlab::ApplicationContext.new(context).use(&block) + end +end |