diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-24 09:10:31 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-24 09:10:31 +0000 |
commit | 0a35aa97051a1255e0bd8f12f30afd25ead228ff (patch) | |
tree | 90bdfdd0d28f19d844c11c92945ab67346866045 /app | |
parent | f6df57b3011cb21c504878daf5d7b6678e07078a (diff) | |
download | gitlab-ce-0a35aa97051a1255e0bd8f12f30afd25ead228ff.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
16 files changed, 115 insertions, 420 deletions
diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js index 82fc816fe9e..e1749331d90 100644 --- a/app/assets/javascripts/locale/sprintf.js +++ b/app/assets/javascripts/locale/sprintf.js @@ -15,8 +15,10 @@ export default (input, parameters, escapeParameters = true) => { let output = input; if (parameters) { - Object.keys(parameters).forEach((parameterName) => { - const parameterValue = parameters[parameterName]; + const mappedParameters = new Map(Object.entries(parameters)); + + mappedParameters.forEach((key, parameterName) => { + const parameterValue = mappedParameters.get(parameterName); const escapedParameterValue = escapeParameters ? escape(parameterValue) : parameterValue; output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), escapedParameterValue); }); diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 603747aa490..3126c690514 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -39,7 +39,7 @@ @import 'framework/selects'; @import 'framework/sidebar'; @import 'framework/contextual_sidebar_header'; -@import 'framework/contextual_sidebar_refactoring/contextual_sidebar'; +@import 'framework/contextual_sidebar'; @import 'framework/tables'; @import 'framework/notes'; @import 'framework/tabs'; diff --git a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_base.scss b/app/assets/stylesheets/framework/contextual_sidebar.scss index 3d9b555c8d5..6299d4b236f 100644 --- a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_base.scss +++ b/app/assets/stylesheets/framework/contextual_sidebar.scss @@ -175,6 +175,10 @@ overflow: auto; } +.with-performance-bar .nav-sidebar { + top: $header-height + $performance-bar-height; +} + .sidebar-sub-level-items { display: none; padding-bottom: 8px; diff --git a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar.scss b/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar.scss deleted file mode 100644 index 905ac260203..00000000000 --- a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar.scss +++ /dev/null @@ -1,7 +0,0 @@ -body:not(.sidebar-refactoring) { - @import 'contextual_sidebar_base'; -} - -body.sidebar-refactoring { - @import 'contextual_sidebar_variant'; -} diff --git a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_variant.scss b/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_variant.scss deleted file mode 100644 index 03e92a27f75..00000000000 --- a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_variant.scss +++ /dev/null @@ -1,383 +0,0 @@ -.page-with-contextual-sidebar { - transition: padding-left $sidebar-transition-duration; - - @include media-breakpoint-up(md) { - padding-left: $contextual-sidebar-collapsed-width; - } - - @include media-breakpoint-up(xl) { - padding-left: $contextual-sidebar-width; - } - - .issues-bulk-update.right-sidebar.right-sidebar-expanded .issuable-sidebar-header { - padding: 10px 0 15px; - } -} - -.page-with-icon-sidebar { - @include media-breakpoint-up(md) { - padding-left: $contextual-sidebar-collapsed-width; - } -} - -.settings-avatar { - background-color: $white; - - svg { - fill: $gl-text-color-secondary; - margin: auto; - } -} - -@mixin collapse-contextual-sidebar-content { - - @include context-header-collapsed; - - .sidebar-top-level-items > li { - .sidebar-sub-level-items { - &:not(.flyout-list) { - display: none; - } - } - } - - .nav-icon-container { - margin-right: 0; - } - - .toggle-sidebar-button { - padding: 16px; - width: $contextual-sidebar-collapsed-width - 1px; - - .collapse-text, - .icon-chevron-double-lg-left { - display: none; - } - - .icon-chevron-double-lg-right { - display: block; - margin: 0; - } - } -} - -.nav-sidebar { - transition: width $sidebar-transition-duration, left $sidebar-transition-duration; - position: fixed; - z-index: 600; - width: $contextual-sidebar-width; - top: $header-height; - bottom: 0; - left: 0; - background: linear-gradient($purple-200, $orange-200); - box-shadow: inset -1px 0 0 $border-color; - transform: translate3d(0, 0, 0); - - &:not(.sidebar-collapsed-desktop) { - @media (min-width: map-get($grid-breakpoints, sm)) and (max-width: map-get($grid-breakpoints, sm)) { - box-shadow: inset -1px 0 0 $border-color, 2px 1px 3px $dropdown-shadow-color; - } - } - - @mixin collapse-contextual-sidebar { - width: $contextual-sidebar-collapsed-width; - - .nav-sidebar-inner-scroll { - overflow-x: hidden; - } - - .badge.badge-pill:not(.fly-out-badge), - .nav-item-name { - @include gl-sr-only; - } - - .sidebar-top-level-items > li > a { - min-height: 45px; - } - - .fly-out-top-item { - display: block; - } - - .avatar-container { - margin: 0 auto; - } - } - - &.sidebar-collapsed-desktop { - @include collapse-contextual-sidebar; - } - - &.sidebar-expanded-mobile { - left: 0; - } - - a { - text-decoration: none; - } - - ul { - padding-left: 0; - list-style: none; - } - - li { - white-space: nowrap; - - a { - transition: padding $sidebar-transition-duration; - display: flex; - align-items: center; - padding: 12px $gl-padding; - color: $gl-text-color-secondary; - } - - .nav-item-name { - flex: 1; - } - - &.active { - > a { - font-weight: $gl-font-weight-bold; - } - } - } - - @include media-breakpoint-down(sm) { - left: (-$contextual-sidebar-width); - } - - .nav-icon-container { - display: flex; - margin-right: 8px; - } - - .fly-out-top-item { - display: none; - } - - svg { - height: 16px; - width: 16px; - } - - @media (min-width: map-get($grid-breakpoints, md)) and (max-width: map-get($grid-breakpoints, xl) - 1px) { - &:not(.sidebar-expanded-mobile) { - @include collapse-contextual-sidebar; - @include collapse-contextual-sidebar-content; - } - } -} - -.nav-sidebar-inner-scroll { - height: 100%; - width: 100%; - overflow: auto; -} - -.sidebar-sub-level-items { - display: none; - padding-bottom: 8px; - - > li { - a { - padding: 8px 16px 8px 40px; - - &:hover, - &:focus { - background: $link-active-background; - color: $gl-text-color; - } - } - - &.active { - a { - &, - &:hover, - &:focus { - background: $link-active-background; - } - } - } - } -} - -.sidebar-top-level-items { - margin-bottom: 60px; - - > li { - > a { - @include media-breakpoint-up(sm) { - margin-right: 1px; - } - - &:hover { - color: $gl-text-color; - } - } - - &.is-showing-fly-out { - > a { - margin-right: 1px; - } - - .sidebar-sub-level-items { - @include media-breakpoint-up(sm) { - position: fixed; - top: 0; - left: 0; - min-width: 150px; - margin-top: -1px; - padding: 4px 1px; - background-color: $white; - box-shadow: 2px 1px 3px $dropdown-shadow-color; - border: 1px solid $gray-darker; - border-left: 0; - border-radius: 0 3px 3px 0; - - &::before { - content: ''; - position: absolute; - top: -30px; - bottom: -30px; - left: -10px; - right: -30px; - z-index: -1; - } - - &.is-above { - margin-top: 1px; - } - - .divider { - height: 1px; - margin: 4px -1px; - padding: 0; - background-color: $dropdown-divider-bg; - } - - > .active { - box-shadow: none; - - > a { - background-color: transparent; - } - } - - a { - padding: 8px 16px; - color: $gl-text-color; - - &:hover, - &:focus { - background-color: $gray-darker; - } - } - } - } - } - - .badge.badge-pill { - background-color: $inactive-badge-background; - color: $gl-text-color-secondary; - } - - &.active { - background: $link-active-background; - - > a { - margin-left: 4px; - // Subtract width of left border on active element - padding-left: $gl-padding-12; - } - - .badge.badge-pill { - font-weight: $gl-font-weight-bold; - } - - .sidebar-sub-level-items:not(.is-fly-out-only) { - display: block; - } - } - - &.active > a:hover, - &.is-over > a { - background-color: $link-hover-background; - } - } -} - -// Collapsed nav - -.toggle-sidebar-button, -.close-nav-button { - @include side-panel-toggle; -} - -.toggle-sidebar-button, -.close-nav-button { - position: fixed; - bottom: 0; - width: $contextual-sidebar-width - 1px; - border-top: 1px solid $border-color; - - svg { - margin-right: 8px; - } - - .icon-chevron-double-lg-right { - display: none; - } -} - -.collapse-text { - white-space: nowrap; - overflow: hidden; -} - -.sidebar-collapsed-desktop { - @include collapse-contextual-sidebar-content; -} - -.fly-out-top-item { - > a { - display: flex; - } - - .fly-out-badge { - margin-left: 8px; - } -} - -.fly-out-top-item-name { - flex: 1; -} - -// Mobile nav - -.close-nav-button { - display: none; -} - -@include media-breakpoint-down(sm) { - .close-nav-button { - display: flex; - } - - .toggle-sidebar-button { - display: none; - } - - .mobile-overlay { - display: none; - - &.mobile-nav-open { - display: block; - position: fixed; - background-color: $black-transparent; - height: 100%; - width: 100%; - z-index: $zindex-dropdown-menu; - } - } -} diff --git a/app/assets/stylesheets/performance_bar.scss b/app/assets/stylesheets/performance_bar.scss index 62736c7de5f..bcc3c35e00e 100644 --- a/app/assets/stylesheets/performance_bar.scss +++ b/app/assets/stylesheets/performance_bar.scss @@ -135,7 +135,3 @@ #modal-peek-pg-queries-content { color: $black; } - -.with-performance-bar .nav-sidebar { - top: $header-height + $performance-bar-height !important; -} diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb index 16eaab4c7c8..25c6167185a 100644 --- a/app/helpers/nav/top_nav_helper.rb +++ b/app/helpers/nav/top_nav_helper.rb @@ -44,6 +44,13 @@ module Nav **snippets_menu_item_attrs ) end + + builder.add_secondary_menu_item( + id: 'help', + title: _('Help'), + icon: 'question-o', + href: help_path + ) end def build_view_model(builder:, project:, group:) diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index b5171dfbebd..3a6b9ed2cfc 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -12,6 +12,7 @@ module NavHelper def page_with_sidebar_class class_name = page_gutter_class class_name << 'page-with-contextual-sidebar' if defined?(@left_sidebar) && @left_sidebar + class_name << 'sidebar-refactoring' if Feature.enabled?(:sidebar_refactor, current_user, default_enabled: :yaml) class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @left_sidebar class_name -= ['right-sidebar-expanded'] if defined?(@right_sidebar) && !@right_sidebar diff --git a/app/models/concerns/packages/debian/component_file.rb b/app/models/concerns/packages/debian/component_file.rb index c41635a0d16..9cf66c756a0 100644 --- a/app/models/concerns/packages/debian/component_file.rb +++ b/app/models/concerns/packages/debian/component_file.rb @@ -50,6 +50,8 @@ module Packages scope :with_file_type, ->(file_type) { where(file_type: file_type) } + scope :with_architecture, ->(architecture) { where(architecture: architecture) } + scope :with_architecture_name, ->(architecture_name) do left_outer_joins(:architecture) .where("packages_debian_#{container_type}_architectures" => { name: architecture_name }) @@ -60,7 +62,7 @@ module Packages scope :preload_distribution, -> { includes(component: :distribution) } - scope :created_before, ->(reference) { where("#{table_name}.created_at < ?", reference) } + scope :updated_before, ->(reference) { where("#{table_name}.updated_at < ?", reference) } mount_file_store_uploader Packages::Debian::ComponentFileUploader diff --git a/app/services/packages/debian/generate_distribution_service.rb b/app/services/packages/debian/generate_distribution_service.rb index 67348af1a49..651325c49a0 100644 --- a/app/services/packages/debian/generate_distribution_service.rb +++ b/app/services/packages/debian/generate_distribution_service.rb @@ -6,6 +6,8 @@ module Packages include Gitlab::Utils::StrongMemoize include ExclusiveLeaseGuard + ONE_HOUR = 1.hour.freeze + # used by ExclusiveLeaseGuard DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze @@ -62,7 +64,7 @@ module Packages def initialize(distribution) @distribution = distribution - @last_generated_at = nil + @oldest_kept_generated_at = nil @md5sum = [] @sha256 = [] end @@ -70,7 +72,10 @@ module Packages def execute try_obtain_lease do @distribution.transaction do - @last_generated_at = @distribution.component_files.maximum(:created_at) + # We consider `apt-get update` can take at most one hour + # We keep all generations younger than one hour + # and the previous generation + @oldest_kept_generated_at = @distribution.component_files.updated_before(release_date - ONE_HOUR).maximum(:updated_at) generate_component_files generate_release destroy_old_component_files @@ -96,7 +101,7 @@ module Packages .with_debian_file_type(package_file_type) .find_each .map(&method(:package_stanza_from_fields)) - create_component_file(component, component_file_type, architecture, package_file_type, paragraphs.join("\n")) + reuse_or_create_component_file(component, component_file_type, architecture, paragraphs.join("\n")) end def package_stanza_from_fields(package_file) @@ -127,17 +132,32 @@ module Packages end end - def create_component_file(component, component_file_type, architecture, package_file_type, content) - component_file = component.files.create!( - file_type: component_file_type, - architecture: architecture, - compression_type: nil, - file: CarrierWaveStringFile.new(content), - file_md5: Digest::MD5.hexdigest(content), - file_sha256: Digest::SHA256.hexdigest(content) - ) - @md5sum.append(" #{component_file.file_md5} #{component_file.size.to_s.rjust(8)} #{component_file.relative_path}") - @sha256.append(" #{component_file.file_sha256} #{component_file.size.to_s.rjust(8)} #{component_file.relative_path}") + def reuse_or_create_component_file(component, component_file_type, architecture, content) + file_md5 = Digest::MD5.hexdigest(content) + file_sha256 = Digest::SHA256.hexdigest(content) + component_file = component.files + .with_file_type(component_file_type) + .with_architecture(architecture) + .with_compression_type(nil) + .with_file_sha256(file_sha256) + .last + + if component_file + component_file.touch(time: release_date) + else + component_file = component.files.create!( + updated_at: release_date, + file_type: component_file_type, + architecture: architecture, + compression_type: nil, + file: CarrierWaveStringFile.new(content), + file_md5: file_md5, + file_sha256: file_sha256 + ) + end + + @md5sum.append(" #{file_md5} #{component_file.size.to_s.rjust(8)} #{component_file.relative_path}") + @sha256.append(" #{file_sha256} #{component_file.size.to_s.rjust(8)} #{component_file.relative_path}") end def generate_release @@ -187,10 +207,9 @@ module Packages end def destroy_old_component_files - # Only keep the last generation and one hour before - return if @last_generated_at.nil? + return if @oldest_kept_generated_at.nil? - @distribution.component_files.created_before(@last_generated_at - 1.hour).destroy_all # rubocop:disable Cop/DestroyAll + @distribution.component_files.updated_before(@oldest_kept_generated_at).destroy_all # rubocop:disable Cop/DestroyAll end # used by ExclusiveLeaseGuard diff --git a/app/services/packages/debian/process_changes_service.rb b/app/services/packages/debian/process_changes_service.rb index 881ad2c46f4..b6e81012656 100644 --- a/app/services/packages/debian/process_changes_service.rb +++ b/app/services/packages/debian/process_changes_service.rb @@ -25,6 +25,8 @@ module Packages update_files_metadata update_changes_metadata end + + ::Packages::Debian::GenerateDistributionWorker.perform_async(:project, package.debian_distribution.id) end end diff --git a/app/views/layouts/_startup_css.haml b/app/views/layouts/_startup_css.haml index d50ebf49482..7d3cfe28007 100644 --- a/app/views/layouts/_startup_css.haml +++ b/app/views/layouts/_startup_css.haml @@ -2,5 +2,4 @@ %style = Rails.application.assets_manifest.find_sources("themes/#{user_application_theme_css_filename}.css").first.to_s.html_safe if user_application_theme_css_filename - - if sidebar_refactor_disabled? - = Rails.application.assets_manifest.find_sources("startup/startup-#{startup_filename}.css").first.to_s.html_safe + = Rails.application.assets_manifest.find_sources("startup/startup-#{startup_filename}.css").first.to_s.html_safe diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 47c092e199a..58408ec822c 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,12 +1,10 @@ - page_classes = page_class << @html_class - page_classes = page_classes.flatten.compact -- body_classes = [user_application_theme, user_tab_width, @body_class, client_class_list] -- body_classes << 'sidebar-refactoring' if sidebar_refactor_enabled? !!! 5 %html{ lang: I18n.locale, class: page_classes } = render "layouts/head" - %body{ class: body_classes, data: body_data } + %body{ class: "#{user_application_theme} #{user_tab_width} #{@body_class} #{client_class_list}", data: body_data } = render "layouts/init_auto_complete" if @gfm_form = render "layouts/init_client_detection_flags" = render 'peek/bar' diff --git a/app/views/shared/members/_invite_group.html.haml b/app/views/shared/members/_invite_group.html.haml index d59f2950df6..58f658ce9c3 100644 --- a/app/views/shared/members/_invite_group.html.haml +++ b/app/views/shared/members/_invite_group.html.haml @@ -9,6 +9,8 @@ .form-group = label_tag group_link_field, _("Select a group to invite"), class: "label-bold" = groups_select_tag(group_link_field, data: { skip_groups: @skip_groups }, class: 'input-clamp qa-group-select-field', required: true) + .form-text.text-muted.gl-mb-3 + = _('Group sharing provides access to all group members (including members who inherited group membership from a parent group).') .form-group = label_tag group_access_field, _("Max access level"), class: "label-bold" .select-wrapper diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index af84230a1d1..4357bf301b0 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -1326,6 +1326,15 @@ :weight: 1 :idempotent: :tags: [] +- :name: package_repositories:packages_debian_generate_distribution + :worker_name: Packages::Debian::GenerateDistributionWorker + :feature_category: :package_registry + :has_external_dependencies: + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: package_repositories:packages_debian_process_changes :worker_name: Packages::Debian::ProcessChangesWorker :feature_category: :package_registry diff --git a/app/workers/packages/debian/generate_distribution_worker.rb b/app/workers/packages/debian/generate_distribution_worker.rb new file mode 100644 index 00000000000..68fdd80ffb1 --- /dev/null +++ b/app/workers/packages/debian/generate_distribution_worker.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Packages + module Debian + class GenerateDistributionWorker # rubocop:disable Scalability/IdempotentWorker + include ApplicationWorker + include Gitlab::Utils::StrongMemoize + + # The worker is idempotent, by reusing component files with the same file_sha256. + # + # See GenerateDistributionService#find_or_create_component_file + deduplicate :until_executed + idempotent! + + queue_namespace :package_repositories + feature_category :package_registry + + loggable_arguments 0 + + def perform(container_type, distribution_id) + @container_type = container_type + @distribution_id = distribution_id + + return unless distribution + + ::Packages::Debian::GenerateDistributionService.new(distribution).execute + end + + private + + def container_class + return ::Packages::Debian::GroupDistribution if @container_type == :group + + ::Packages::Debian::ProjectDistribution + end + + def distribution + strong_memoize(:distribution) do + container_class.find_by_id(@distribution_id) + end + end + end + end +end |