diff options
46 files changed, 375 insertions, 91 deletions
@@ -47,7 +47,7 @@ gem 'responders', '~> 3.0' # rubocop:todo Gemfile/MissingFeatureCategory gem 'sprockets', '~> 3.7.0' # rubocop:todo Gemfile/MissingFeatureCategory -gem 'view_component', '~> 3.6.0' # rubocop:todo Gemfile/MissingFeatureCategory +gem 'view_component', '~> 3.7.0' # rubocop:todo Gemfile/MissingFeatureCategory # Supported DBs gem 'pg', '~> 1.5.4' # rubocop:todo Gemfile/MissingFeatureCategory diff --git a/Gemfile.checksum b/Gemfile.checksum index fa57b6abfbc..85e476f88f1 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -678,7 +678,7 @@ {"name":"validates_hostname","version":"1.0.13","platform":"ruby","checksum":"eac40178cc0b4f727df9cc6a5cb5bc2550718ad8d9bb3728df9aba6354bdda19"}, {"name":"version_gem","version":"1.1.0","platform":"ruby","checksum":"6b009518020db57f51ec7b410213fae2bf692baea9f1b51770db97fbc93d9a80"}, {"name":"version_sorter","version":"2.3.0","platform":"ruby","checksum":"2147f2a1a3804fbb8f60d268b7d7c1ec717e6dd727ffe2c165b4e05e82efe1da"}, -{"name":"view_component","version":"3.6.0","platform":"ruby","checksum":"7aa45c11b4fd51583bd63b10fbc6b1a87f088182e4f026e5f4f6a9211e5a42a3"}, +{"name":"view_component","version":"3.7.0","platform":"ruby","checksum":"648909bde6c188621d607732d64a82515b03e69761c8098a0fe4336166d7e403"}, {"name":"virtus","version":"2.0.0","platform":"ruby","checksum":"8841dae4eb7fcc097320ba5ea516bf1839e5d056c61ee27138aa4bddd6e3d1c2"}, {"name":"vite_rails","version":"3.0.15","platform":"ruby","checksum":"b8ec528aedf7e24b54f222b449cd9250810ea2456d5f8dd4ef87f06b475cf860"}, {"name":"vite_ruby","version":"3.3.4","platform":"ruby","checksum":"025e438385a6dc2320c8c148dff453f5bb1d4f056ce69c3386f47d4c388ad80c"}, diff --git a/Gemfile.lock b/Gemfile.lock index 29cdca969fc..601cfd70894 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -152,7 +152,7 @@ PATH PATH remote: vendor/gems/sidekiq-reliable-fetch specs: - gitlab-sidekiq-fetcher (0.9.0) + gitlab-sidekiq-fetcher (0.10.0) json (>= 2.5) sidekiq (~> 6.1) @@ -1670,7 +1670,7 @@ GEM activesupport (>= 3.0) version_gem (1.1.0) version_sorter (2.3.0) - view_component (3.6.0) + view_component (3.7.0) activesupport (>= 5.2.0, < 8.0) concurrent-ruby (~> 1.0) method_source (~> 1.0) @@ -2038,7 +2038,7 @@ DEPENDENCIES valid_email (~> 0.1) validates_hostname (~> 1.0.13) version_sorter (~> 2.3) - view_component (~> 3.6.0) + view_component (~> 3.7.0) vite_rails vmstat (~> 2.3.0) warning (~> 1.3.0) diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js index 430022f9a9b..d368c76b6cc 100644 --- a/app/assets/javascripts/pages/users/user_tabs.js +++ b/app/assets/javascripts/pages/users/user_tabs.js @@ -194,7 +194,7 @@ export default class UserTabs { this.loadActivityCalendar(); UserTabs.renderMostRecentBlocks('#js-overview .activities-block', { - requestParams: { limit: 10 }, + requestParams: { limit: 15 }, }); UserTabs.renderMostRecentBlocks('#js-overview .projects-block', { requestParams: { limit: 10, skip_pagination: true, skip_namespace: true, compact_mode: true }, diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 2722893d04c..8e0fab04ab2 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -10,16 +10,13 @@ $icon-size-diff: $avatar-icon-size - $system-note-icon-size; $system-note-icon-m-top: $avatar-m-top + $icon-size-diff - 1.3rem; $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio; -@mixin vertical-line($left) { - &::before { - content: ''; - border-left: 2px solid var(--gray-50, $gray-50); - position: absolute; - top: 16px; - bottom: 0; - left: calc(#{$left} - 1px); - height: calc(100% + 20px); - } +@mixin vertical-line($top, $left) { + content: ''; + position: absolute; + width: 2px; + left: $left; + top: $top; + height: calc(100% - #{$top}); } @mixin outline-comment() { @@ -32,12 +29,7 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio; .limited-width-notes { .main-notes-list::before, .timeline-entry:last-child::before { - content: ''; - position: absolute; - width: 2px; - left: 15px; - top: 15px; - height: calc(100% - 15px); + @include vertical-line(15px, 15px); } .main-notes-list::before { @@ -1143,6 +1135,24 @@ $system-note-icon-m-left: $avatar-m-left + $icon-size-diff / $avatar-m-ratio; } } +.user-activity-content { + &::before { + @include vertical-line(80px, 25px); + background: var(--gray-50, $gray-50); + } + + .system-note-image { + @include gl--flex-center; + top: 14px; + width: 22px; + height: 22px; + + svg { + fill: $gray-600 !important; + } + } +} + //This needs to be deleted when Snippet/Commit comments are convered to Vue // See https://gitlab.com/gitlab-org/gitlab-foss/issues/53918#note_117038785 .unstyled-comments { diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb index 4f228ced542..f78a28c89dd 100644 --- a/app/controllers/repositories/git_http_controller.rb +++ b/app/controllers/repositories/git_http_controller.rb @@ -106,7 +106,8 @@ module Repositories def access_actor return user if user - return :ci if ci? + + :ci if ci? end def access_check diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 5f1145c95f6..769af0d9ef9 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -13,7 +13,10 @@ module EventsHelper 'deleted' => 'remove', 'destroyed' => 'remove', 'imported' => 'import', - 'joined' => 'users' + 'joined' => 'users', + 'approved' => 'check', + 'added' => 'upload', + 'removed' => 'remove' }.freeze def localized_action_name_map @@ -242,7 +245,7 @@ module EventsHelper def event_wiki_title_html(event) capture do - concat content_tag(:span, _('wiki page'), class: "event-target-type gl-mr-2") + concat content_tag(:span, _('wiki page'), class: "event-target-type gl-mr-2 #{user_profile_activity_classes}") concat link_to( event.target_title, event_wiki_page_target_url(event), @@ -254,7 +257,7 @@ module EventsHelper def event_design_title_html(event) capture do - concat content_tag(:span, _('design'), class: "event-target-type gl-mr-2") + concat content_tag(:span, _('design'), class: "event-target-type gl-mr-2 #{user_profile_activity_classes}") concat link_to( event.design.reference_link_text, design_url(event.design), @@ -271,7 +274,7 @@ module EventsHelper def event_note_title_html(event) if event.note_target capture do - concat content_tag(:span, event.note_target_type_name, class: "event-target-type gl-mr-2") + concat content_tag(:span, event.note_target_type_name, class: "event-target-type gl-mr-2 #{user_profile_activity_classes}") concat link_to(event.note_target_reference, event_note_target_url(event), title: event.target_title, class: 'has-tooltip event-target-link gl-mr-2') end else @@ -303,19 +306,16 @@ module EventsHelper end def icon_for_profile_event(event) - if current_path?('users#show') - content_tag :div, class: "system-note-image #{event.action_name.parameterize}-icon" do - icon_for_event(event.action_name) - end - else - content_tag :div, class: 'system-note-image user-avatar' do - author_avatar(event, size: 32) - end - end + base_class = 'system-note-image' + + classes = current_path?('users#activity') ? "#{event.action_name.parameterize}-icon gl-rounded-full gl-bg-gray-50 gl-line-height-0" : "user-avatar" + content = current_path?('users#activity') ? icon_for_event(event.action_name, size: 14) : author_avatar(event, size: 32) + + tag.div(class: "#{base_class} #{classes}") { content } end def inline_event_icon(event) - unless current_path?('users#show') + unless current_path?('users#activity') content_tag :span, class: "system-note-image-inline d-none d-sm-flex gl-mr-2 #{event.action_name.parameterize}-icon align-self-center" do next design_event_icon(event.action, size: 14) if event.design? @@ -325,13 +325,19 @@ module EventsHelper end def event_user_info(event) - content_tag(:div, class: "event-user-info") do - concat content_tag(:span, link_to_author(event), class: "author-name") - concat " ".html_safe - concat content_tag(:span, event.author.to_reference, class: "username") + return if current_path?('users#activity') + + tag.div(class: 'event-user-info') do + concat tag.span(link_to_author(event), class: 'author-name') + concat ' '.html_safe + concat tag.span(event.author.to_reference, class: 'username') end end + def user_profile_activity_classes + current_path?('users#activity') ? ' gl-font-weight-semibold gl-text-black-normal' : '' + end + private def design_url(design, opts = {}) diff --git a/app/models/user.rb b/app/models/user.rb index bc256ef0f31..7177f1981eb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -48,7 +48,7 @@ class User < MainClusterwide::ApplicationRecord # Associations with dependent: option cross_database_ignore_tables( - %w[namespaces projects project_authorizations issues merge_requests merge_requests issues issues merge_requests], + %w[namespaces projects project_authorizations issues merge_requests merge_requests issues issues merge_requests events], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424285', on: :destroy ) diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index a3be188854d..c28fe7c8330 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,7 +1,7 @@ - event = event.present - if event.visible_to_user?(current_user) - .event-item + .event-item{ class: current_path?('users#activity') ? 'user-profile-activity gl-border-bottom-0 gl-pl-7! gl-pb-3' : '' } .event-item-timestamp.gl-font-sm #{time_ago_with_tooltip(event.created_at)} diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml index 7ef3461a7fb..78ce24c429a 100644 --- a/app/views/events/event/_common.html.haml +++ b/app/views/events/event/_common.html.haml @@ -5,9 +5,9 @@ .event-title.d-flex.flex-wrap = inline_event_icon(event) - if event.target - %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name } + %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name + user_profile_activity_classes } = localized_action_name(event) - %span.event-target-type.gl-mr-2= event.target_type_name + %span.event-target-type.gl-mr-2{ class: user_profile_activity_classes }= event.target_type_name = link_to event_target_path(event), class: 'has-tooltip event-target-link gl-mr-2', title: event.target_title do = event.target.reference_link_text - unless event.milestone? diff --git a/app/views/events/event/_design.html.haml b/app/views/events/event/_design.html.haml index c1fa1aaca50..945c7465ea8 100644 --- a/app/views/events/event/_design.html.haml +++ b/app/views/events/event/_design.html.haml @@ -4,7 +4,7 @@ .event-title.d-flex.flex-wrap = inline_event_icon(event) - %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name } + %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name + user_profile_activity_classes } = event.action_name = event_design_title_html(event) = render "events/event_scope", event: event diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 53c59474d83..5bbece84e40 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -6,7 +6,7 @@ .event-title.d-flex.flex-wrap = inline_event_icon(event) - %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name } + %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name + user_profile_activity_classes } = event.action_name = event_note_title_html(event) - title = note_target_title(event.target) diff --git a/app/views/events/event/_wiki.html.haml b/app/views/events/event/_wiki.html.haml index cbd5ebcae12..a48c34f80d8 100644 --- a/app/views/events/event/_wiki.html.haml +++ b/app/views/events/event/_wiki.html.haml @@ -4,7 +4,7 @@ .event-title.d-flex.flex-wrap = inline_event_icon(event) - %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name } + %span.event-type.d-inline-block.gl-mr-2{ class: event.action_name + user_profile_activity_classes } = event.action_name = event_wiki_title_html(event) = render "events/event_scope", event: event diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml index 3649f72c956..597e7c37388 100644 --- a/app/views/users/_overview.html.haml +++ b/app/views/users/_overview.html.haml @@ -1,4 +1,4 @@ -- activity_pane_class = Feature.enabled?(:security_auto_fix) && @user.bot? ? "col-12" : "col-md-12 col-lg-6" +- activity_pane_class = Feature.enabled?(:security_auto_fix) && @user.bot? ? "col-12" : "col-md-12 col-lg-6 gl-align-self-start" .row.d-none.d-sm-flex .col-12.calendar-block.gl-my-3 @@ -33,7 +33,7 @@ %h4.gl-flex-grow-1 = Feature.enabled?(:security_auto_fix) && @user.bot? ? s_('UserProfile|Bot activity') : s_('UserProfile|Activity') = link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all" - .overview-content-list{ data: { href: user_activity_path, testid: 'user-activity-content' } } + .overview-content-list.user-activity-content{ data: { href: user_activity_path, testid: 'user-activity-content' } } = gl_loading_icon(size: 'md', css_class: 'loading') - unless Feature.enabled?(:security_auto_fix) && @user.bot? diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 16b69a4298b..c4a55a7d7ed 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -171,13 +171,15 @@ - if profile_tab?(:activity) #activity.tab-pane - .flash-container - - if can?(current_user, :read_cross_project) - %h4.prepend-top-20 - = s_('UserProfile|Most Recent Activity') - .content_list{ data: { href: user_activity_path } } - .loading - = gl_loading_icon(size: 'md') + .row + .col-12 + .flash-container + - if can?(current_user, :read_cross_project) + %h4.prepend-top-20 + = s_('UserProfile|Most Recent Activity') + .content_list.user-activity-content{ data: { href: user_activity_path } } + .loading + = gl_loading_icon(size: 'md') - unless @user.bot? - if profile_tab?(:groups) #groups.tab-pane diff --git a/app/workers/concerns/gitlab/github_import/stage_methods.rb b/app/workers/concerns/gitlab/github_import/stage_methods.rb index 1414ff8d6bd..5c63c667a03 100644 --- a/app/workers/concerns/gitlab/github_import/stage_methods.rb +++ b/app/workers/concerns/gitlab/github_import/stage_methods.rb @@ -5,6 +5,8 @@ module Gitlab module StageMethods extend ActiveSupport::Concern + MAX_RETRIES_AFTER_INTERRUPTION = 20 + included do include ApplicationWorker @@ -18,6 +20,29 @@ module Gitlab end end + class_methods do + # We can increase the number of times a GitHubImport::Stage worker is retried + # after being interrupted if the importer it executes can restart exactly + # from where it left off. + # + # It is not safe to call this method if the importer loops over its data from + # the beginning when restarted, even if it skips data that is already imported + # inside the loop, as there is a possibility the importer will never reach + # the end of the loop. + # + # Examples of stage workers that call this method are ones that execute services that: + # + # - Continue paging an endpoint from where it left off: + # https://gitlab.com/gitlab-org/gitlab/-/blob/487521cc/lib/gitlab/github_import/parallel_scheduling.rb#L114-117 + # - Continue their loop from where it left off: + # https://gitlab.com/gitlab-org/gitlab/-/blob/024235ec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer.rb#L15 + def resumes_work_when_interrupted! + return unless Feature.enabled?(:github_importer_raise_max_interruptions) + + sidekiq_options max_retries_after_interruption: MAX_RETRIES_AFTER_INTERRUPTION + end + end + # project_id - The ID of the GitLab project to import the data into. def perform(project_id) info(project_id, message: 'starting stage') diff --git a/app/workers/gitlab/github_import/stage/import_attachments_worker.rb b/app/workers/gitlab/github_import/stage/import_attachments_worker.rb index f9952f04e99..6f8190fc7e6 100644 --- a/app/workers/gitlab/github_import/stage/import_attachments_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_attachments_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_issue_events_worker.rb b/app/workers/gitlab/github_import/stage/import_issue_events_worker.rb index c80412d941b..77d286dc466 100644 --- a/app/workers/gitlab/github_import/stage/import_issue_events_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_issue_events_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb b/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb index 592b789cc94..e70f10e3ce9 100644 --- a/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_lfs_objects_worker.rb b/app/workers/gitlab/github_import/stage/import_lfs_objects_worker.rb index e89a850c991..9db72de59b7 100644 --- a/app/workers/gitlab/github_import/stage/import_lfs_objects_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_lfs_objects_worker.rb @@ -11,6 +11,11 @@ module Gitlab include GithubImport::Queue include StageMethods + # Importer::LfsObjectsImporter can resume work when interrupted as + # it uses Projects::LfsPointers::LfsObjectDownloadListService which excludes LFS objects that already exist. + # https://gitlab.com/gitlab-org/gitlab/-/blob/eabf0800/app/services/projects/lfs_pointers/lfs_object_download_list_service.rb#L69-71 + resumes_work_when_interrupted! + def perform(project_id) return unless (project = find_project(project_id)) diff --git a/app/workers/gitlab/github_import/stage/import_notes_worker.rb b/app/workers/gitlab/github_import/stage/import_notes_worker.rb index c1fdb76d03e..8e88034ba15 100644 --- a/app/workers/gitlab/github_import/stage/import_notes_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_notes_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb index 889f938318f..376581c633f 100644 --- a/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb index 44cd7cdb9d1..f2907006d9c 100644 --- a/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker.rb index 9947a89b92c..5c516555387 100644 --- a/app/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb index 9bdf3a31776..50527dfa2d8 100644 --- a/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb +++ b/app/workers/gitlab/github_import/stage/import_pull_requests_worker.rb @@ -11,6 +11,8 @@ module Gitlab include GithubImport::Queue include StageMethods + resumes_work_when_interrupted! + # client - An instance of Gitlab::GithubImport::Client. # project - An instance of Project. def import(client, project) diff --git a/config/feature_flags/development/github_importer_raise_max_interruptions.yml b/config/feature_flags/development/github_importer_raise_max_interruptions.yml new file mode 100644 index 00000000000..3cbcc10865f --- /dev/null +++ b/config/feature_flags/development/github_importer_raise_max_interruptions.yml @@ -0,0 +1,8 @@ +--- +name: github_importer_raise_max_interruptions +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/134949 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/429306 +milestone: '16.6' +type: development +group: group::import and integrate +default_enabled: false diff --git a/config/initializers/active_record_renamed_table.rb b/config/initializers/active_record_renamed_table.rb index 948ef8790c8..5a9e30d2fb5 100644 --- a/config/initializers/active_record_renamed_table.rb +++ b/config/initializers/active_record_renamed_table.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true ActiveSupport.on_load(:active_record) do - ActiveRecord::ConnectionAdapters::SchemaCache.prepend(Gitlab::Database::SchemaCacheWithRenamedTable) + if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('7.1') + ActiveRecord::ConnectionAdapters::SchemaCache.prepend(Gitlab::Database::SchemaCacheWithRenamedTable) + else + ActiveRecord::ConnectionAdapters::SchemaCache.prepend(Gitlab::Database::SchemaCacheWithRenamedTableLegacy) + end end diff --git a/db/docs/events.yml b/db/docs/events.yml index 04d90a24ec9..4e493fefea3 100644 --- a/db/docs/events.yml +++ b/db/docs/events.yml @@ -14,4 +14,4 @@ feature_categories: description: Stores events created by users interacting with various product features introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/a847501fd2ffc1c4becc7d0d352d80168d9b3568 milestone: "2.2" -gitlab_schema: gitlab_main +gitlab_schema: gitlab_main_cell diff --git a/db/docs/internal_ids.yml b/db/docs/internal_ids.yml index 5109a51802c..53e83142780 100644 --- a/db/docs/internal_ids.yml +++ b/db/docs/internal_ids.yml @@ -7,4 +7,4 @@ feature_categories: description: Keeps track of counters scoped to a certain context, e.g. a project-wide counter for issues. introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17580 milestone: '10.7' -gitlab_schema: gitlab_main +gitlab_schema: gitlab_main_cell diff --git a/db/docs/namespace_commit_emails.yml b/db/docs/namespace_commit_emails.yml index c19ff1c577b..c5afcfaaebd 100644 --- a/db/docs/namespace_commit_emails.yml +++ b/db/docs/namespace_commit_emails.yml @@ -7,4 +7,4 @@ feature_categories: description: User default email for commits from the GitLab UI introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101832 milestone: '15.6' -gitlab_schema: gitlab_main +gitlab_schema: gitlab_main_cell diff --git a/db/docs/topics.yml b/db/docs/topics.yml index dcf988c58eb..42fc6a9f4e3 100644 --- a/db/docs/topics.yml +++ b/db/docs/topics.yml @@ -7,4 +7,4 @@ feature_categories: description: Stores topics that can be assigned to projects introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67574 milestone: '14.3' -gitlab_schema: gitlab_main +gitlab_schema: gitlab_main_cell diff --git a/doc/install/docker.md b/doc/install/docker.md index ac15b5490ce..0ba41e06b65 100644 --- a/doc/install/docker.md +++ b/doc/install/docker.md @@ -35,7 +35,10 @@ to community resources (such as IRC or forums) to seek help from other users. ## Prerequisites -Docker is required. See the [official installation documentation](https://docs.docker.com/get-docker/). +To use the GitLab Docker images: + +- You must install Docker. +- You must use a valid externally-accessible hostname. Do not use `localhost`. ## Set up the volumes location diff --git a/lib/gitlab/database/schema_cache_with_renamed_table.rb b/lib/gitlab/database/schema_cache_with_renamed_table.rb index 6da76803f7c..1a64bcbcf10 100644 --- a/lib/gitlab/database/schema_cache_with_renamed_table.rb +++ b/lib/gitlab/database/schema_cache_with_renamed_table.rb @@ -17,20 +17,20 @@ module Gitlab clear_renamed_tables_cache! end - def primary_keys(table_name) - super(underlying_table(table_name)) + def primary_keys(connection, table_name) + super(connection, underlying_table(table_name)) end - def columns(table_name) - super(underlying_table(table_name)) + def columns(connection, table_name) + super(connection, underlying_table(table_name)) end - def columns_hash(table_name) - super(underlying_table(table_name)) + def columns_hash(connection, table_name) + super(connection, underlying_table(table_name)) end - def indexes(table_name) - super(underlying_table(table_name)) + def indexes(connection, table_name) + super(connection, underlying_table(table_name)) end private @@ -40,7 +40,7 @@ module Gitlab end def renamed_tables_cache - @renamed_tables ||= Gitlab::Database::TABLES_TO_BE_RENAMED.select do |old_name, new_name| + @renamed_tables ||= Gitlab::Database::TABLES_TO_BE_RENAMED.select do |old_name, _new_name| connection.view_exists?(old_name) end end diff --git a/lib/gitlab/database/schema_cache_with_renamed_table_legacy.rb b/lib/gitlab/database/schema_cache_with_renamed_table_legacy.rb new file mode 100644 index 00000000000..acc9bbd0aff --- /dev/null +++ b/lib/gitlab/database/schema_cache_with_renamed_table_legacy.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Gitlab + module Database + # This is a legacy extension targeted at Rails versions prior to 7.1 + # In Rails 7.1, the method parameters have been changed to (connection, table_name) + module SchemaCacheWithRenamedTableLegacy + # Override methods in ActiveRecord::ConnectionAdapters::SchemaCache + + def clear! + super + + clear_renamed_tables_cache! + end + + def clear_data_source_cache!(name) + super(name) + + clear_renamed_tables_cache! + end + + def primary_keys(table_name) + super(underlying_table(table_name)) + end + + def columns(table_name) + super(underlying_table(table_name)) + end + + def columns_hash(table_name) + super(underlying_table(table_name)) + end + + def indexes(table_name) + super(underlying_table(table_name)) + end + + private + + def underlying_table(table_name) + renamed_tables_cache.fetch(table_name, table_name) + end + + def renamed_tables_cache + @renamed_tables ||= Gitlab::Database::TABLES_TO_BE_RENAMED.select do |old_name, _new_name| + connection.view_exists?(old_name) + end + end + + def clear_renamed_tables_cache! + @renamed_tables = nil # rubocop:disable Gitlab/ModuleWithInstanceVariables + end + end + end +end diff --git a/lib/gitlab/identifier.rb b/lib/gitlab/identifier.rb index 08d44184bb6..720f8748cba 100644 --- a/lib/gitlab/identifier.rb +++ b/lib/gitlab/identifier.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Detect user based on identifier like +# Detect user or keys based on identifier like # key-13 or user-36 module Gitlab module Identifier @@ -35,6 +35,13 @@ module Gitlab end end + # Tries to identify a deploy key using a SSH key identifier (e.g. "key-123"). + def identify_using_deploy_key(identifier) + key_id = identifier.gsub("key-", "") + + DeployKey.find_by_id(key_id) + end + def identify_with_cache(category, key) if identification_cache[category].key?(key) identification_cache[category][key] diff --git a/package.json b/package.json index 7bff6132996..e589a965a1c 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@cubejs-client/core": "^0.34.9", "@cubejs-client/vue": "^0.34.9", "@floating-ui/dom": "^1.2.9", - "@gitlab/application-sdk-browser": "^0.2.8", + "@gitlab/application-sdk-browser": "^0.2.9", "@gitlab/at.js": "1.5.7", "@gitlab/cluster-client": "^2.1.0", "@gitlab/favicon-overlay": "2.0.0", diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb index 906ad51d841..1da61ecb868 100644 --- a/spec/features/users/overview_spec.rb +++ b/spec/features/users/overview_spec.rb @@ -60,15 +60,15 @@ RSpec.describe 'Overview tab on a user profile', :js, feature_category: :user_pr end end - describe 'user has 11 activities' do + describe 'user has 15 activities' do before do - 11.times { push_code_contribution } + 16.times { push_code_contribution } end include_context 'visit overview tab' - it 'displays 10 entries in the list of activities' do - expect(find('#js-overview')).to have_selector('.event-item', count: 10) + it 'displays 15 entries in the list of activities' do + expect(find('#js-overview')).to have_selector('.event-item', count: 15) end it 'shows a link to the activity list' do diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index 7e6c0a9086a..d19df3d1395 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -41,6 +41,69 @@ RSpec.describe EventsHelper, factory_default: :keep, feature_category: :user_pro end end + describe '#icon_for_profile_event' do + let(:event) { build(:event, :joined) } + let(:users_activity_page?) { true } + + before do + allow(helper).to receive(:current_path?).and_call_original + allow(helper).to receive(:current_path?).with('users#activity').and_return(users_activity_page?) + end + + context 'when on users activity page' do + it 'gives an icon with specialized classes' do + result = helper.icon_for_profile_event(event) + + expect(result).to include('joined-icon') + expect(result).to include('<svg') + end + + context 'with an unsupported event action_name' do + let(:event) { build(:event, :expired) } + + it 'does not have an icon' do + result = helper.icon_for_profile_event(event) + + expect(result).not_to include('<svg') + end + end + end + + context 'when not on users activity page' do + let(:users_activity_page?) { false } + + it 'gives an icon with specialized classes' do + result = helper.icon_for_profile_event(event) + + expect(result).not_to include('joined-icon') + expect(result).not_to include('<svg') + expect(result).to include('<img') + end + end + end + + describe '#event_user_info' do + let(:event) { build(:event) } + let(:users_activity_page?) { true } + + before do + allow(helper).to receive(:current_path?).and_call_original + allow(helper).to receive(:current_path?).with('users#activity').and_return(users_activity_page?) + end + + subject { helper.event_user_info(event) } + + context 'when on users activity page' do + it { is_expected.to be_nil } + end + + context 'when not on users activity page' do + let(:users_activity_page?) { false } + + it { is_expected.to include('<div') } + end + end + describe '#event_target_path' do subject { helper.event_target_path(event.present) } @@ -270,12 +333,26 @@ RSpec.describe EventsHelper, factory_default: :keep, feature_category: :user_pro describe '#event_wiki_title_html' do let(:event) { create(:wiki_page_event) } + let(:url) { helper.event_wiki_page_target_url(event) } + let(:title) { event.target_title } it 'produces a suitable title chunk' do - url = helper.event_wiki_page_target_url(event) - title = event.target_title html = [ - "<span class=\"event-target-type gl-mr-2\">wiki page</span>", + "<span class=\"event-target-type gl-mr-2 \">wiki page</span>", + "<a title=\"#{title}\" class=\"has-tooltip event-target-link gl-mr-2\" href=\"#{url}\">", + title, + "</a>" + ].join + + expect(helper.event_wiki_title_html(event)).to eq(html) + end + + it 'produces a suitable title chunk on the user profile' do + allow(helper).to receive(:user_profile_activity_classes).and_return( + 'gl-font-weight-semibold gl-text-black-normal') + + html = [ + "<span class=\"event-target-type gl-mr-2 gl-font-weight-semibold gl-text-black-normal\">wiki page</span>", "<a title=\"#{title}\" class=\"has-tooltip event-target-link gl-mr-2\" href=\"#{url}\">", title, "</a>" @@ -443,5 +520,28 @@ RSpec.describe EventsHelper, factory_default: :keep, feature_category: :user_pro end end end + + describe '#user_profile_activity_classes' do + let(:users_activity_page?) { true } + + before do + allow(helper).to receive(:current_path?).and_call_original + allow(helper).to receive(:current_path?).with('users#activity').and_return(users_activity_page?) + end + + context 'when on the user activity page' do + it 'returns the expected class names' do + expect(helper.user_profile_activity_classes).to eq(' gl-font-weight-semibold gl-text-black-normal') + end + end + + context 'when not on the user activity page' do + let(:users_activity_page?) { false } + + it 'returns an empty string' do + expect(helper.user_profile_activity_classes).to eq('') + end + end + end end # rubocop:enable RSpec/FactoryBot/AvoidCreate diff --git a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb index f1271f2434c..a81ccf9583a 100644 --- a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb @@ -443,10 +443,10 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers, describe '#ensure_batched_background_migration_is_finished' do let(:job_class_name) { 'CopyColumnUsingBackgroundMigrationJob' } - let(:table_name) { 'events' } + let(:table_name) { '_test_table' } let(:column_name) { :id } let(:job_arguments) { [["id"], ["id_convert_to_bigint"], nil] } - let(:gitlab_schema) { Gitlab::Database::GitlabSchema.table_schema!(table_name) } + let(:gitlab_schema) { :gitlab_main } let(:configuration) do { @@ -484,7 +484,7 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers, "\n\n" \ "Finalize it manually by running the following command in a `bash` or `sh` shell:" \ "\n\n" \ - "\tsudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,events,id,'[[\"id\"]\\,[\"id_convert_to_bigint\"]\\,null]']" \ + "\tsudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,_test_table,id,'[[\"id\"]\\,[\"id_convert_to_bigint\"]\\,null]']" \ "\n\n" \ "For more information, check the documentation" \ "\n\n" \ diff --git a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb index a6f21fe7438..4c7c56631fc 100644 --- a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb +++ b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb @@ -11,6 +11,7 @@ RSpec.describe 'cross-database foreign keys' do # should be added as a comment along with the name of the column. let!(:allowed_cross_database_foreign_keys) do [ + 'events.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429803 'gitlab_subscriptions.hosted_plan_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422012 'group_import_states.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421210 'identities.saml_provider_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422010 @@ -22,6 +23,8 @@ RSpec.describe 'cross-database foreign keys' do 'merge_requests.updated_by_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080 'merge_requests.merge_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080 'merge_requests.author_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422080 + 'namespace_commit_emails.email_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429804 + 'namespace_commit_emails.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429804 'path_locks.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429380 'project_authorizations.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/422044 'security_orchestration_policy_configurations.bot_user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/429438 diff --git a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb index 898606845a2..fa782967441 100644 --- a/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb +++ b/spec/workers/concerns/gitlab/github_import/stage_methods_spec.rb @@ -185,4 +185,30 @@ RSpec.describe Gitlab::GithubImport::StageMethods, feature_category: :importers expect(worker.find_project(-1)).to be_nil end end + + describe '.resumes_work_when_interrupted!' do + subject(:sidekiq_options) { worker.class.sidekiq_options } + + it 'does not set the `max_retries_after_interruption` if not called' do + is_expected.not_to have_key('max_retries_after_interruption') + end + + it 'sets the `max_retries_after_interruption`' do + worker.class.resumes_work_when_interrupted! + + is_expected.to include('max_retries_after_interruption' => 20) + end + + context 'when the flag is disabled' do + before do + stub_feature_flags(github_importer_raise_max_interruptions: false) + end + + it 'does not set `max_retries_after_interruption`' do + worker.class.resumes_work_when_interrupted! + + is_expected.not_to have_key('max_retries_after_interruption') + end + end + end end diff --git a/vendor/gems/sidekiq-reliable-fetch/Gemfile.lock b/vendor/gems/sidekiq-reliable-fetch/Gemfile.lock index 57767ee8c3b..aeb163db018 100644 --- a/vendor/gems/sidekiq-reliable-fetch/Gemfile.lock +++ b/vendor/gems/sidekiq-reliable-fetch/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - gitlab-sidekiq-fetcher (0.9.0) + gitlab-sidekiq-fetcher (0.10.0) json (>= 2.5) sidekiq (~> 6.1) diff --git a/vendor/gems/sidekiq-reliable-fetch/gitlab-sidekiq-fetcher.gemspec b/vendor/gems/sidekiq-reliable-fetch/gitlab-sidekiq-fetcher.gemspec index 0d0e5e3f6fa..b656267003a 100644 --- a/vendor/gems/sidekiq-reliable-fetch/gitlab-sidekiq-fetcher.gemspec +++ b/vendor/gems/sidekiq-reliable-fetch/gitlab-sidekiq-fetcher.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = 'gitlab-sidekiq-fetcher' - s.version = '0.9.0' + s.version = '0.10.0' s.authors = ['TEA', 'GitLab'] s.email = 'valery@gitlab.com' s.license = 'LGPL-3.0' diff --git a/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/base_reliable_fetch.rb b/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/base_reliable_fetch.rb index 39b98a0109f..006aad87abe 100644 --- a/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/base_reliable_fetch.rb +++ b/vendor/gems/sidekiq-reliable-fetch/lib/sidekiq/base_reliable_fetch.rb @@ -230,7 +230,7 @@ module Sidekiq max_retries_after_interruption = nil max_retries_after_interruption ||= begin - Object.const_get(worker_class).sidekiq_options[:max_retries_after_interruption] + Object.const_get(worker_class).sidekiq_options['max_retries_after_interruption'] rescue NameError end diff --git a/vendor/gems/sidekiq-reliable-fetch/spec/base_reliable_fetch_spec.rb b/vendor/gems/sidekiq-reliable-fetch/spec/base_reliable_fetch_spec.rb index cdc4409f0d5..32e62925aaf 100644 --- a/vendor/gems/sidekiq-reliable-fetch/spec/base_reliable_fetch_spec.rb +++ b/vendor/gems/sidekiq-reliable-fetch/spec/base_reliable_fetch_spec.rb @@ -76,6 +76,19 @@ describe Sidekiq::BaseReliableFetch do expect(queue2.size).to eq 1 expect(Sidekiq::InterruptedSet.new.size).to eq 0 end + + it 'does not put jobs into interrupted queue if it is disabled on the worker' do + stub_const('Bob', double(sidekiq_options: { 'max_retries_after_interruption' => -1 })) + + uow = described_class::UnitOfWork + interrupted_job = Sidekiq.dump_json(class: 'Bob', args: [1, 2, 'foo'], interrupted_count: 3) + jobs = [ uow.new('queue:foo', interrupted_job), uow.new('queue:foo', job), uow.new('queue:bar', job) ] + described_class.new(options).bulk_requeue(jobs, nil) + + expect(queue1.size).to eq 2 + expect(queue2.size).to eq 1 + expect(Sidekiq::InterruptedSet.new.size).to eq 0 + end end it 'sets heartbeat' do diff --git a/yarn.lock b/yarn.lock index 673a80a7597..222e074ac54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1211,10 +1211,10 @@ dependencies: "@floating-ui/core" "^1.2.6" -"@gitlab/application-sdk-browser@^0.2.8": - version "0.2.8" - resolved "https://registry.yarnpkg.com/@gitlab/application-sdk-browser/-/application-sdk-browser-0.2.8.tgz#d4c824e44f033a4af5a11e63e18350de6b7c9228" - integrity sha512-jVE11bWHrMHVc4B+t/QD2z1rzUP1rgSP15hHDiM48219I3uahmA5ZMeuYqldaJzimTMEEkV+bdWIA4eNiJXVFA== +"@gitlab/application-sdk-browser@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@gitlab/application-sdk-browser/-/application-sdk-browser-0.2.9.tgz#fc9069350452ce73b7409affd1615ee4d62ed728" + integrity sha512-FnUbsyan/LTh2I9NWcfnfYLAp928FnXN4rlcitMIU2FKhhFXcVDtDaOolECBLtMM+c12teWIDn6eRzYtEd23TA== dependencies: "@snowplow/browser-plugin-client-hints" "^3.9.0" "@snowplow/browser-plugin-error-tracking" "^3.9.0" |