diff options
| author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 15:10:08 +0000 |
|---|---|---|
| committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 15:10:08 +0000 |
| commit | ec4abad65d774cfc94110577589d44de5da825de (patch) | |
| tree | c51897390fa0a749bcd414d1ee1c2007fa9c3ec7 | |
| parent | 111e0ef1fa06e79adf73a34ebd14f71bfeb99bff (diff) | |
| download | gitlab-ce-ec4abad65d774cfc94110577589d44de5da825de.tar.gz | |
Add latest changes from gitlab-org/gitlab@master
55 files changed, 598 insertions, 174 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index e2d9a2df4a7..ad5db8cde46 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -b82b2da71ab8ad5e61e4f162b99e64a7ab78ca7f +77d6f6e6bee63c41438ec5c186c10fa17b91fd7c @@ -480,7 +480,7 @@ end gem 'spamcheck', '~> 0.1.0' # Gitaly GRPC protocol definitions -gem 'gitaly', '~> 13.12.0.pre.rc1' +gem 'gitaly', '~> 14.0.0.pre.rc2' # KAS GRPC protocol definitions gem 'kas-grpc', '~> 0.0.2' diff --git a/Gemfile.lock b/Gemfile.lock index 5cd2431a7d1..ef31d72a5dd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -454,7 +454,7 @@ GEM rails (>= 3.2.0) git (1.7.0) rchardet (~> 1.8) - gitaly (13.12.0.pre.rc1) + gitaly (14.0.0.pre.rc2) grpc (~> 1.0) github-markup (1.7.0) gitlab (4.16.1) @@ -1483,7 +1483,7 @@ DEPENDENCIES gettext (~> 3.3) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly (~> 13.12.0.pre.rc1) + gitaly (~> 14.0.0.pre.rc2) github-markup (~> 1.7.0) gitlab-chronic (~> 0.10.5) gitlab-dangerfiles (~> 2.1.2) diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue index 3dbac0d146c..bda6b340871 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/base_token.vue @@ -184,7 +184,7 @@ export default { <gl-dropdown-divider /> </template> <slot - v-if="preloadedTokenValues.length" + v-if="preloadedTokenValues.length && !searchKey" name="token-values-list" :token-values="preloadedTokenValues" ></slot> 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 index 154b8c31e8b..1ea50281204 100644 --- a/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_variant.scss +++ b/app/assets/stylesheets/framework/contextual_sidebar_refactoring/contextual_sidebar_variant.scss @@ -13,13 +13,49 @@ $top-level-item-color: $purple-900; box-shadow: none; } +&.gl-dark .nav-sidebar .sidebar-sub-level-items { + box-shadow: none; + border: 1px solid $border-color; +} + +&.gl-dark .sidebar-top-level-items .context-header a .avatar-container.rect-avatar .avatar.s32 { + color: $white; +} + &.gl-dark .nav-sidebar li a, &.gl-dark .toggle-sidebar-button .collapse-text, &.gl-dark .toggle-sidebar-button .icon-chevron-double-lg-left, &.gl-dark .toggle-sidebar-button .icon-chevron-double-lg-right, &.gl-dark .sidebar-top-level-items .context-header a .sidebar-context-title, -&.gl-dark .nav-sidebar-inner-scroll > div.context-header a .sidebar-context-title { +&.gl-dark .nav-sidebar-inner-scroll > div.context-header a .sidebar-context-title, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item a, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item a:hover, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item.active a, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item .fly-out-top-item-container { + color: $gray-darkest; +} + +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item a, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item a:hover, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item.active a, +&.gl-dark .nav-sidebar a.has-sub-items + .sidebar-sub-level-items .fly-out-top-item .fly-out-top-item-container { + @include gl-mt-0; +} + +&.gl-dark .nav-sidebar a:not(.has-sub-items) + .sidebar-sub-level-items .fly-out-top-item a, +&.gl-dark .nav-sidebar a:not(.has-sub-items) + .sidebar-sub-level-items .fly-out-top-item a:hover, +&.gl-dark .nav-sidebar a:not(.has-sub-items) + .sidebar-sub-level-items .fly-out-top-item.active a, +&.gl-dark .nav-sidebar a:not(.has-sub-items) + .sidebar-sub-level-items .fly-out-top-item .fly-out-top-item-container { + background: $white; color: $gray-darkest; + + &::before { + border-right-color: $white; + } +} + +&.gl-dark .nav-sidebar .sidebar-sub-level-items { + background-color: $white; } &.ui-indigo .nav-sidebar li.active:not(.fly-out-top-item) > a { @@ -183,7 +219,7 @@ $top-level-item-color: $purple-900; .avatar.s32 { @extend .rect-avatar.s32; - color: $gray-900; + //color: $gray-900; box-shadow: $avatar-box-shadow; } } @@ -226,7 +262,7 @@ $top-level-item-color: $purple-900; color: $white; @if $has-sub-items { - @include gl-mt-n2; + @include gl-mt-0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @else { @@ -244,13 +280,13 @@ $top-level-item-color: $purple-900; content: ''; display: block; top: 50%; - left: $gl-spacing-scale-3/-2; - margin-top: -$gl-spacing-scale-3; + left: -$gl-spacing-scale-2; + margin-top: -$gl-spacing-scale-2; width: 0; height: 0; - border-top: $gl-spacing-scale-3 solid transparent; - border-bottom: $gl-spacing-scale-3 solid transparent; - border-right: $gl-spacing-scale-3 solid $black; + border-top: $gl-spacing-scale-2 solid transparent; + border-bottom: $gl-spacing-scale-2 solid transparent; + border-right: $gl-spacing-scale-2 solid $black; } } } @@ -356,6 +392,8 @@ $top-level-item-color: $purple-900; } a.has-sub-items + .sidebar-sub-level-items { + @include gl-mt-n2; + .fly-out-top-item { @include fly-out-top-item($has-sub-items: true); } diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss index c6f0b3a2ba7..00a6ee579d8 100644 --- a/app/assets/stylesheets/startup/startup-dark.scss +++ b/app/assets/stylesheets/startup/startup-dark.scss @@ -1240,6 +1240,18 @@ input { body.sidebar-refactoring.gl-dark .nav-sidebar li.active { box-shadow: none; } +body.sidebar-refactoring.gl-dark .nav-sidebar .sidebar-sub-level-items { + box-shadow: none; + border: 1px solid #404040; +} +body.sidebar-refactoring.gl-dark + .sidebar-top-level-items + .context-header + a + .avatar-container.rect-avatar + .avatar.s32 { + color: #333; +} body.sidebar-refactoring.gl-dark .nav-sidebar li a, body.sidebar-refactoring.gl-dark .toggle-sidebar-button .collapse-text, body.sidebar-refactoring.gl-dark @@ -1257,9 +1269,91 @@ body.sidebar-refactoring.gl-dark .nav-sidebar-inner-scroll > div.context-header a - .sidebar-context-title { + .sidebar-context-title, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items + .fly-out-top-item + a, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items + .fly-out-top-item.active + a, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items + .fly-out-top-item + .fly-out-top-item-container { + color: #c4c4c4; +} +body.sidebar-refactoring.gl-dark + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items + .fly-out-top-item + a, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items + .fly-out-top-item.active + a, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items + .fly-out-top-item + .fly-out-top-item-container { + margin-top: 0; +} +body.sidebar-refactoring.gl-dark + .nav-sidebar + a:not(.has-sub-items) + + .sidebar-sub-level-items + .fly-out-top-item + a, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a:not(.has-sub-items) + + .sidebar-sub-level-items + .fly-out-top-item.active + a, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a:not(.has-sub-items) + + .sidebar-sub-level-items + .fly-out-top-item + .fly-out-top-item-container { + background: #333; color: #c4c4c4; } +body.sidebar-refactoring.gl-dark + .nav-sidebar + a:not(.has-sub-items) + + .sidebar-sub-level-items + .fly-out-top-item + a::before, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a:not(.has-sub-items) + + .sidebar-sub-level-items + .fly-out-top-item.active + a::before, +body.sidebar-refactoring.gl-dark + .nav-sidebar + a:not(.has-sub-items) + + .sidebar-sub-level-items + .fly-out-top-item + .fly-out-top-item-container::before { + border-right-color: #333; +} +body.sidebar-refactoring.gl-dark .nav-sidebar .sidebar-sub-level-items { + background-color: #333; +} body.sidebar-refactoring.ui-indigo .nav-sidebar li.active:not(.fly-out-top-item) @@ -1482,12 +1576,18 @@ body.sidebar-refactoring display: block; top: 50%; left: -0.25rem; - margin-top: -0.5rem; + margin-top: -0.25rem; width: 0; height: 0; - border-top: 0.5rem solid transparent; - border-bottom: 0.5rem solid transparent; - border-right: 0.5rem solid #fff; + border-top: 0.25rem solid transparent; + border-bottom: 0.25rem solid transparent; + border-right: 0.25rem solid #fff; +} +body.sidebar-refactoring + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items { + margin-top: -0.25rem; } body.sidebar-refactoring .nav-sidebar @@ -1523,7 +1623,7 @@ body.sidebar-refactoring font-size: 0.75rem; background-color: #2f2a6b; color: #333; - margin-top: -0.25rem; + margin-top: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -1691,7 +1791,6 @@ body.sidebar-refactoring a .avatar-container.rect-avatar .avatar.s32 { - color: #fafafa; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); } body.sidebar-refactoring @@ -1732,7 +1831,6 @@ body.sidebar-refactoring a .avatar-container.rect-avatar .avatar.s32 { - color: #fafafa; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08); } body.sidebar-refactoring diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss index a05e27b6af0..4605b6de563 100644 --- a/app/assets/stylesheets/startup/startup-general.scss +++ b/app/assets/stylesheets/startup/startup-general.scss @@ -1444,12 +1444,18 @@ body.sidebar-refactoring display: block; top: 50%; left: -0.25rem; - margin-top: -0.5rem; + margin-top: -0.25rem; width: 0; height: 0; - border-top: 0.5rem solid transparent; - border-bottom: 0.5rem solid transparent; - border-right: 0.5rem solid #000; + border-top: 0.25rem solid transparent; + border-bottom: 0.25rem solid transparent; + border-right: 0.25rem solid #000; +} +body.sidebar-refactoring + .nav-sidebar + a.has-sub-items + + .sidebar-sub-level-items { + margin-top: -0.25rem; } body.sidebar-refactoring .nav-sidebar @@ -1485,7 +1491,7 @@ body.sidebar-refactoring font-size: 0.75rem; background-color: #2f2a6b; color: #fff; - margin-top: -0.25rem; + margin-top: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -1653,7 +1659,6 @@ body.sidebar-refactoring a .avatar-container.rect-avatar .avatar.s32 { - color: #303030; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08); } body.sidebar-refactoring @@ -1694,7 +1699,6 @@ body.sidebar-refactoring a .avatar-container.rect-avatar .avatar.s32 { - color: #303030; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08); } body.sidebar-refactoring diff --git a/app/controllers/admin/cohorts_controller.rb b/app/controllers/admin/cohorts_controller.rb index c29b5224b09..8163f062b62 100644 --- a/app/controllers/admin/cohorts_controller.rb +++ b/app/controllers/admin/cohorts_controller.rb @@ -1,11 +1,28 @@ # frozen_string_literal: true class Admin::CohortsController < Admin::ApplicationController + include Analytics::UniqueVisitsHelper + feature_category :devops_reports - # Backwards compatibility. Remove it and routing in 14.0 - # @see https://gitlab.com/gitlab-org/gitlab/-/issues/299303 def index - redirect_to cohorts_admin_users_path + @cohorts = load_cohorts + track_cohorts_visit + end + + private + + def load_cohorts + cohorts_results = Rails.cache.fetch('cohorts', expires_in: 1.day) do + CohortsService.new.execute + end + + CohortsSerializer.new.represent(cohorts_results) + end + + def track_cohorts_visit + if request.format.html? && request.headers['DNT'] != '1' + track_visit('i_analytics_cohorts') + end end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index e397ecbadaf..700acc46d8d 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -2,9 +2,8 @@ class Admin::UsersController < Admin::ApplicationController include RoutableActions - include Analytics::UniqueVisitsHelper - before_action :user, except: [:index, :cohorts, :new, :create] + before_action :user, except: [:index, :new, :create] before_action :check_impersonation_availability, only: :impersonate before_action :ensure_destroy_prerequisites_met, only: [:destroy] before_action :check_ban_user_feature_flag, only: [:ban] @@ -14,7 +13,7 @@ class Admin::UsersController < Admin::ApplicationController PAGINATION_WITH_COUNT_LIMIT = 1000 def index - return redirect_to cohorts_admin_users_path if params[:tab] == 'cohorts' + return redirect_to admin_cohorts_path if params[:tab] == 'cohorts' @users = User.filter_items(params[:filter]).order_name_asc @users = @users.search_with_secondary_emails(params[:search_query]) if params[:search_query].present? @@ -24,11 +23,6 @@ class Admin::UsersController < Admin::ApplicationController @users = @users.without_count if paginate_without_count? end - def cohorts - @cohorts = load_cohorts - track_cohorts_visit - end - def show end @@ -376,20 +370,6 @@ class Admin::UsersController < Admin::ApplicationController def log_impersonation_event Gitlab::AppLogger.info(_("User %{current_user_username} has started impersonating %{username}") % { current_user_username: current_user.username, username: user.username }) end - - def load_cohorts - cohorts_results = Rails.cache.fetch('cohorts', expires_in: 1.day) do - CohortsService.new.execute - end - - CohortsSerializer.new.represent(cohorts_results) - end - - def track_cohorts_visit - if request.format.html? && request.headers['DNT'] != '1' - track_visit('i_analytics_cohorts') - end - end end Admin::UsersController.prepend_mod_with('Admin::UsersController') diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb index c3ca90ca0ad..a700f104150 100644 --- a/app/models/remote_mirror.rb +++ b/app/models/remote_mirror.rb @@ -100,10 +100,11 @@ class RemoteMirror < ApplicationRecord update_status == 'started' end - def update_repository + def update_repository(inmemory_remote:) Gitlab::Git::RemoteMirror.new( project.repository.raw, remote_name, + inmemory_remote ? remote_url : nil, **options_for_update ).update end diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb index 9f4f6133d92..eac84337967 100644 --- a/app/services/projects/update_remote_mirror_service.rb +++ b/app/services/projects/update_remote_mirror_service.rb @@ -39,12 +39,16 @@ module Projects def update_mirror(remote_mirror) remote_mirror.update_start! - remote_mirror.ensure_remote! # LFS objects must be sent first, or the push has dangling pointers send_lfs_objects!(remote_mirror) - response = remote_mirror.update_repository + response = if Feature.enabled?(:update_remote_mirror_inmemory, project, default_enabled: :yaml) + remote_mirror.update_repository(inmemory_remote: true) + else + remote_mirror.ensure_remote! + remote_mirror.update_repository(inmemory_remote: false) + end if response.divergent_refs.any? message = "Some refs have diverged and have not been updated on the remote:" diff --git a/app/views/admin/users/_cohorts.html.haml b/app/views/admin/cohorts/_cohorts.html.haml index 25b30adc5be..25b30adc5be 100644 --- a/app/views/admin/users/_cohorts.html.haml +++ b/app/views/admin/cohorts/_cohorts.html.haml diff --git a/app/views/admin/users/_cohorts_table.html.haml b/app/views/admin/cohorts/_cohorts_table.html.haml index a92cfb5851a..a92cfb5851a 100644 --- a/app/views/admin/users/_cohorts_table.html.haml +++ b/app/views/admin/cohorts/_cohorts_table.html.haml diff --git a/app/views/admin/users/cohorts.html.haml b/app/views/admin/cohorts/index.html.haml index 3f3d22fa410..7ba4cd6d733 100644 --- a/app/views/admin/users/cohorts.html.haml +++ b/app/views/admin/cohorts/index.html.haml @@ -1,6 +1,6 @@ - page_title _("Users") -= render 'tabs' += render 'admin/users/tabs' .tab-content .tab-pane.active diff --git a/app/views/admin/users/_tabs.html.haml b/app/views/admin/users/_tabs.html.haml index 1a3239897eb..90f06eeaf3f 100644 --- a/app/views/admin/users/_tabs.html.haml +++ b/app/views/admin/users/_tabs.html.haml @@ -3,5 +3,5 @@ %a.nav-link{ href: admin_users_path, class: active_when(current_page?(admin_users_path)), role: 'tab' } = s_('AdminUsers|Users') %li.nav-item{ role: 'presentation' } - %a.nav-link{ href: cohorts_admin_users_path, class: active_when(current_page?(cohorts_admin_users_path)), role: 'tab' } + %a.nav-link{ href: admin_cohorts_path, class: active_when(current_page?(admin_cohorts_path)), role: 'tab' } = s_('AdminUsers|Cohorts') diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 7a80c4e0ba9..21c3d7cb7e2 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -10,14 +10,14 @@ %span.sidebar-context-title = _('Admin Area') %ul.sidebar-top-level-items{ data: { qa_selector: 'admin_sidebar_overview_submenu_content' } } - = nav_link(controller: %w(dashboard admin admin/projects users groups jobs runners gitaly_servers), html_options: {class: 'home'}) do + = nav_link(controller: %w(dashboard admin admin/projects users groups jobs runners gitaly_servers cohorts), html_options: {class: 'home'}) do = link_to admin_root_path, class: 'has-sub-items' do .nav-icon-container = sprite_icon('overview') %span.nav-item-name = _('Overview') %ul.sidebar-sub-level-items - = nav_link(controller: %w(dashboard admin admin/projects users groups jobs runners gitaly_servers), html_options: { class: "fly-out-top-item" } ) do + = nav_link(controller: %w(dashboard admin admin/projects users groups jobs runners gitaly_servers cohorts), html_options: { class: "fly-out-top-item" } ) do = link_to admin_root_path do %strong.fly-out-top-item-name = _('Overview') @@ -30,7 +30,7 @@ = link_to admin_projects_path, title: _('Projects') do %span = _('Projects') - = nav_link(controller: :users) do + = nav_link(controller: %w(users cohorts)) do = link_to admin_users_path, title: _('Users'), data: { qa_selector: 'users_overview_link' } do %span = _('Users') diff --git a/config/feature_flags/development/update_remote_mirror_inmemory.yml b/config/feature_flags/development/update_remote_mirror_inmemory.yml new file mode 100644 index 00000000000..e1d347ffa7e --- /dev/null +++ b/config/feature_flags/development/update_remote_mirror_inmemory.yml @@ -0,0 +1,8 @@ +--- +name: update_remote_mirror_inmemory +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63962 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/333517 +milestone: '14.0' +type: development +group: group::gitaly +default_enabled: false diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 7bd24ac5f5b..4d25f24a104 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -10,12 +10,6 @@ namespace :admin do end end - collection do - scope '/-/' do - get :cohorts - end - end - member do get :projects get :keys diff --git a/db/migrate/20210608103230_add_issue_id_to_test_report.rb b/db/migrate/20210608103230_add_issue_id_to_test_report.rb new file mode 100644 index 00000000000..f4e723d0af8 --- /dev/null +++ b/db/migrate/20210608103230_add_issue_id_to_test_report.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIssueIdToTestReport < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + def up + with_lock_retries do + add_column :requirements_management_test_reports, :issue_id, :bigint, null: true + end + end + + def down + with_lock_retries do + remove_column :requirements_management_test_reports, :issue_id + end + end +end diff --git a/db/migrate/20210608103235_add_issue_index_to_test_report.rb b/db/migrate/20210608103235_add_issue_index_to_test_report.rb new file mode 100644 index 00000000000..41f1970b2a9 --- /dev/null +++ b/db/migrate/20210608103235_add_issue_index_to_test_report.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIssueIndexToTestReport < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + INDEX_NAME = 'index_requirements_management_test_reports_on_issue_id' + + def up + add_concurrent_index :requirements_management_test_reports, :issue_id, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :requirements_management_test_reports, INDEX_NAME + end +end diff --git a/db/migrate/20210608110752_change_column_null_test_report_requirement.rb b/db/migrate/20210608110752_change_column_null_test_report_requirement.rb new file mode 100644 index 00000000000..44a614a34ce --- /dev/null +++ b/db/migrate/20210608110752_change_column_null_test_report_requirement.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class ChangeColumnNullTestReportRequirement < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + TARGET_TABLE = :requirements_management_test_reports + + def up + with_lock_retries do + change_column_null TARGET_TABLE, :requirement_id, true + end + end + + def down + # no-op as it's difficult to revert + end +end diff --git a/db/migrate/20210608110760_add_requirement_test_reports_foreign_key.rb b/db/migrate/20210608110760_add_requirement_test_reports_foreign_key.rb new file mode 100644 index 00000000000..e256bce6ae0 --- /dev/null +++ b/db/migrate/20210608110760_add_requirement_test_reports_foreign_key.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class AddRequirementTestReportsForeignKey < ActiveRecord::Migration[6.1] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + TARGET_TABLE = :requirements_management_test_reports + CONSTRAINT_NAME = 'requirements_test_reports_requirement_id_xor_issue_id' + + def up + add_concurrent_foreign_key TARGET_TABLE, :issues, column: :issue_id + + add_check_constraint(TARGET_TABLE, 'num_nonnulls(requirement_id, issue_id) = 1', CONSTRAINT_NAME) + end + + def down + remove_check_constraint TARGET_TABLE, CONSTRAINT_NAME + + with_lock_retries do + remove_foreign_key_if_exists(TARGET_TABLE, column: :issue_id) + end + end +end diff --git a/db/schema_migrations/20210608103230 b/db/schema_migrations/20210608103230 new file mode 100644 index 00000000000..541faa3aab7 --- /dev/null +++ b/db/schema_migrations/20210608103230 @@ -0,0 +1 @@ +12d8de65d287cf29fa2761264c42eb42e7fe2a5b36c279e623d93897503b5313
\ No newline at end of file diff --git a/db/schema_migrations/20210608103235 b/db/schema_migrations/20210608103235 new file mode 100644 index 00000000000..601c374e620 --- /dev/null +++ b/db/schema_migrations/20210608103235 @@ -0,0 +1 @@ +fc503b8e9672eb5638d2cb3468c8df4d9c0d998332909351121ace04d3f7214a
\ No newline at end of file diff --git a/db/schema_migrations/20210608110752 b/db/schema_migrations/20210608110752 new file mode 100644 index 00000000000..5c4a1f16971 --- /dev/null +++ b/db/schema_migrations/20210608110752 @@ -0,0 +1 @@ +cbe4cff5937f3ba39a4aeeed78dcc6dc6ece212b01b16bfcd61ccf4a20427dcc
\ No newline at end of file diff --git a/db/schema_migrations/20210608110760 b/db/schema_migrations/20210608110760 new file mode 100644 index 00000000000..46ace509e0d --- /dev/null +++ b/db/schema_migrations/20210608110760 @@ -0,0 +1 @@ +b84505713afce3bf0673329a3a4eaf85a00d4f8948f56d43d365d6cc47ef629c
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index fcac180738c..fa72d72cb9d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -17498,10 +17498,12 @@ ALTER SEQUENCE requirements_id_seq OWNED BY requirements.id; CREATE TABLE requirements_management_test_reports ( id bigint NOT NULL, created_at timestamp with time zone NOT NULL, - requirement_id bigint NOT NULL, + requirement_id bigint, author_id bigint, state smallint NOT NULL, - build_id bigint + build_id bigint, + issue_id bigint, + CONSTRAINT requirements_test_reports_requirement_id_xor_issue_id CHECK ((num_nonnulls(requirement_id, issue_id) = 1)) ); CREATE SEQUENCE requirements_management_test_reports_id_seq @@ -24489,6 +24491,8 @@ CREATE INDEX index_requirements_management_test_reports_on_author_id ON requirem CREATE INDEX index_requirements_management_test_reports_on_build_id ON requirements_management_test_reports USING btree (build_id); +CREATE INDEX index_requirements_management_test_reports_on_issue_id ON requirements_management_test_reports USING btree (issue_id); + CREATE INDEX index_requirements_management_test_reports_on_requirement_id ON requirements_management_test_reports USING btree (requirement_id); CREATE INDEX index_requirements_on_author_id ON requirements USING btree (author_id); @@ -25826,6 +25830,9 @@ ALTER TABLE ONLY vulnerabilities ALTER TABLE ONLY bulk_import_entities ADD CONSTRAINT fk_88c725229f FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY requirements_management_test_reports + ADD CONSTRAINT fk_88f30752fc FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE; + ALTER TABLE ONLY issues ADD CONSTRAINT fk_899c8f3231 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; diff --git a/doc/administration/database_load_balancing.md b/doc/administration/database_load_balancing.md index 9c1ed9b3477..e9f989c96ea 100644 --- a/doc/administration/database_load_balancing.md +++ b/doc/administration/database_load_balancing.md @@ -113,7 +113,7 @@ Some background jobs can use database replicas to read application state. This allows to offload the primary database. Load balancing is disabled by default in Sidekiq. When enabled, we can define -[the data consistency](../development/sidekiq_style_guide.md#job-data-consistency) +[the data consistency](../development/sidekiq_style_guide.md#job-data-consistency-strategies) requirements for a specific job. To enable it, define the `ENABLE_LOAD_BALANCING_FOR_SIDEKIQ` variable to the environment, as shown below. diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md index cf542a9da0b..40d51f90b5a 100644 --- a/doc/api/group_milestones.md +++ b/doc/api/group_milestones.md @@ -144,6 +144,11 @@ Parameters: | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `milestone_id` | integer | yes | The ID of a group milestone | +Currently, this API endpoint doesn't return issues from any subgroups. +If you want to get all the milestones' issues, you can instead use the +[List issues API](issues.md#list-issues) and filter for a +particular milestone (for example, `GET /issues?milestone=1.0.0&state=opened`). + ## Get all merge requests assigned to a single milestone Gets all merge requests assigned to a single group milestone. diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 870605c82f4..844ef2156d9 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -842,6 +842,70 @@ Keep in mind, this means your app will not batch queries. Once subscriptions are mature, this process can be replaced by using them and we can remove the separate link library and return to batching queries. +#### Subscriptions + +We use [subscriptions](https://www.apollographql.com/docs/react/data/subscriptions/) to receive real-time updates from GraphQL API via websockets. Currently, the number of existing subscriptions is limited, you can check a list of available ones in [GraphqiQL explorer](https://gitlab.com/-/graphql-explorer) + +**NOTE:** +We cannot test subscriptions using GraphiQL, because they require an ActionCable client, which GraphiQL does not support at the moment. + +Subscriptions don't require any additional configuration of Apollo Client instance, you can use them in the application right away. To distinguish subscriptions from queries and mutations, we recommend naming them with `.subscription.graphql` extension: + +```graphql +// ~/sidebar/queries/issuable_assignees.subscription.graphql + +subscription issuableAssigneesUpdated($issuableId: IssuableID!) { + issuableAssigneesUpdated(issuableId: $issuableId) { + ... on Issue { + assignees { + nodes { + ...User + status { + availability + } + } + } + } + } +} +``` + +When using GraphQL subscriptions in Vue application, we recommend updating existing Apollo query results with [subscribeToMore](https://apollo.vuejs.org/guide/apollo/subscriptions.html#subscribe-to-more) option: + +```javascript +import issuableAssigneesSubscription from '~/sidebar/queries/issuable_assignees.subscription.graphql' + +apollo: { + issuable: { + query() { + return assigneesQueries[this.issuableType].query; + }, + subscribeToMore: { + // Specify the subscription that will update the query + document() { + return issuableAssigneesSubscription; + }, + variables() { + return { + issuableId: convertToGraphQLId(this.issuableClass, this.issuableId), + }; + }, + // Describe how subscription should update the query + updateQuery(prev, { subscriptionData }) { + if (prev && subscriptionData?.data?.issuableAssigneesUpdated) { + const data = produce(prev, (draftData) => { + draftData.workspace.issuable.assignees.nodes = + subscriptionData.data.issuableAssigneesUpdated.assignees.nodes; + }); + return data; + } + return prev; + }, + }, + }, +}, +``` + ### Testing #### Generating the GraphQL schema diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md index c87870b088c..7bc3ecf002f 100644 --- a/doc/development/sidekiq_style_guide.md +++ b/doc/development/sidekiq_style_guide.md @@ -155,7 +155,7 @@ A job scheduled for an idempotent worker is [deduplicated](#deduplication) when an unstarted job with the same arguments is already in the queue. WARNING: -For [data consistency jobs](#job-data-consistency), the deduplication is not compatible with the +For [data consistency jobs](#job-data-consistency-strategies), the deduplication is not compatible with the `data_consistency` attribute set to `:sticky` or `:delayed`. The reason for this is that deduplication always takes into account the latest binary replication pointer into account, not the first one. There is an [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/325291) to improve this. @@ -462,18 +462,56 @@ If we expect an increase of **less than 5%**, then no further action is needed. Otherwise, please ping `@gitlab-org/scalability` on the merge request and ask for a review. -## Job data consistency +## Job data consistency strategies -In order to utilize [Sidekiq read-only database replicas capabilities](../administration/database_load_balancing.md#enable-the-load-balancer-for-sidekiq), -set the `data_consistency` attribute of the job to `:always`, `:sticky`, or `:delayed`. +In GitLab 13.11 and earlier, Sidekiq workers would always send database queries to the primary +database node, +both for reads and writes. This ensured that data integrity +is both guaranteed and immediate, since in a single-node scenario it is impossible to encounter +stale reads even for workers that read their own writes. +If a worker writes to the primary, but reads from a replica, however, the possibility +of reading a stale record is non-zero due to replicas potentially lagging behind the primary. + +When the number of jobs that rely on the database increases, ensuring immediate data consistency +can put unsustainable load on the primary database server. We therefore added the ability to use +[database load-balancing in Sidekiq workers](../administration/database_load_balancing.md#enable-the-load-balancer-for-sidekiq). +By configuring a worker's `data_consistency` field, we can then allow the scheduler to target read replicas +under several strategies outlined below. + +## Trading immediacy for reduced primary load + +Not requiring immediate data consistency allows developers to decide to either: + +- Ensure immediately consistent reads, but increase load on the primary database. +- Prefer read replicas to add relief to the primary, but increase the likelihood of stale reads that have to be retried. + +By default, any worker has a data consistency requirement of `:always`, so, as before, all +database operations target the primary. To allow for reads to be served from replicas instead, we +added two additional consistency modes: `:sticky` and `:delayed`. + +When you declare either `:sticky` or `:delayed` consistency, workers become eligible for database +load-balancing. In both cases, jobs are enqueued with a short delay. +This minimizes the likelihood of replication lag after a write. + +The difference is in what happens when there is replication lag after the delay: `sticky` workers +switch over to the primary right away, whereas `delayed` workers fail fast and are retried once. +If they still encounter replication lag, they also switch to the primary instead. +**If your worker never performs any writes, it is strongly advised to apply one of these consistency settings, +since it will never need to rely on the primary database node.** + +The table below shows the `data_consistency` attribute and its values, ordered by the degree to which +they prefer read replicas and will wait for replicas to catch up: | **Data Consistency** | **Description** | |--------------|-----------------------------| -| `:always` | The job is required to use the primary database (default). | -| `:sticky` | The job uses a replica as long as possible. It switches to primary either on write or long replication lag. It should be used on jobs that require to be executed as fast as possible. | -| `:delayed` | The job always uses replica, but switches to primary on write. The job is delayed if there's a long replication lag. If the replica is not up-to-date with the next retry, it switches to the primary. It should be used on jobs where we are fine to delay the execution of a given job due to their importance such as expire caches, execute hooks, etc. | +| `:always` | The job is required to use the primary database (default). It should be used for workers that primarily perform writes or that have very strict requirements around reading their writes without suffering any form of delay. | +| `:sticky` | The job prefers replicas, but switches to the primary for writes or when encountering replication lag. It should be used for jobs that require to be executed as fast as possible but can sustain a small initial queuing delay. | +| `:delayed` | The job prefers replicas, but switches to the primary for writes. When encountering replication lag before the job starts, the job is retried once. If the replica is still not up to date on the next retry, it switches to the primary. It should be used for jobs where delaying execution further typically does not matter, such as cache expiration or web hooks execution. | + +In all cases workers read either from a replica that is fully caught up, +or from the primary node, so data consistency is always ensured. -To set a data consistency for a job, use the `data_consistency` class method: +To set a data consistency for a worker, use the `data_consistency` class method: ```ruby class DelayedWorker @@ -499,8 +537,8 @@ When `feature_flag` is disabled, the job defaults to `:always`, which means that The `feature_flag` property does not allow the use of [feature gates based on actors](../development/feature_flags/index.md). This means that the feature flag cannot be toggled only for particular -projects, groups, or users, but instead, you can safely use [percentage of time rollout](../development/feature_flags/index.md). -Note that since we check the feature flag on both Sidekiq client and server, rolling out a 10% of the time, +projects, groups, or users, but instead, you can safely use [percentage of time rollout](../development/feature_flags/index.md). +Note that since we check the feature flag on both Sidekiq client and server, rolling out a 10% of the time, will likely results in 1% (0.1 [from client]*0.1 [from server]) of effective jobs using replicas. Example: @@ -515,15 +553,6 @@ class DelayedWorker end ``` -### Delayed job execution - -Scheduling workers that utilize [Sidekiq read-only database replicas capabilities](#job-data-consistency), -(workers with `data_consistency` attribute set to `:sticky` or `:delayed`), -by calling `SomeWorker.perform_async` results in a worker performing in the future (1 second in the future). - -This way, the replica has a chance to catch up, and the job will likely use the replica. -For workers with `data_consistency` set to `:delayed`, it can also reduce the number of retried jobs. - ## Jobs with External Dependencies Most background jobs in the GitLab application communicate with other GitLab diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md index 5deb71698ff..e637408328d 100644 --- a/doc/user/admin_area/settings/email.md +++ b/doc/user/admin_area/settings/email.md @@ -20,8 +20,9 @@ The logo in the header of some emails can be customized, see the [logo customiza The additional text appears at the bottom of any email and can be used for legal/auditing/compliance reasons. -1. Go to **Admin Area > Settings > Preferences** (`/admin/application_settings/preferences`). -1. Expand the **Email** section. +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Preferences** (`/admin/application_settings/preferences`). +1. Expand **Email**. 1. Enter your text in the **Additional text** field. 1. Click **Save**. @@ -34,8 +35,9 @@ This configuration option sets the email hostname for [private commit emails](.. In order to change this option: -1. Go to **Admin Area > Settings > Preferences** (`/admin/application_settings/preferences`). -1. Expand the **Email** section. +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Preferences** (`/admin/application_settings/preferences`). +1. Expand **Email**. 1. Enter the desired hostname in the **Custom hostname (for private commit emails)** field. 1. Select **Save changes**. diff --git a/doc/user/admin_area/settings/img/file_template_admin_area.png b/doc/user/admin_area/settings/img/file_template_admin_area.png Binary files differdeleted file mode 100644 index 269d997e1d9..00000000000 --- a/doc/user/admin_area/settings/img/file_template_admin_area.png +++ /dev/null diff --git a/doc/user/admin_area/settings/img/file_template_admin_area_v14_0.png b/doc/user/admin_area/settings/img/file_template_admin_area_v14_0.png Binary files differnew file mode 100644 index 00000000000..33fce8a2b77 --- /dev/null +++ b/doc/user/admin_area/settings/img/file_template_admin_area_v14_0.png diff --git a/doc/user/admin_area/settings/instance_template_repository.md b/doc/user/admin_area/settings/instance_template_repository.md index c8a4c2866ca..8a796435ef8 100644 --- a/doc/user/admin_area/settings/instance_template_repository.md +++ b/doc/user/admin_area/settings/instance_template_repository.md @@ -23,7 +23,7 @@ To select a project to serve as the custom template repository: 1. In the left sidebar, select **Settings > Templates**. 1. Select the project: -  +  1. Add custom templates to the selected repository. diff --git a/doc/user/admin_area/settings/rate_limit_on_issues_creation.md b/doc/user/admin_area/settings/rate_limit_on_issues_creation.md index 3acfb636a13..ef2b8ad80cd 100644 --- a/doc/user/admin_area/settings/rate_limit_on_issues_creation.md +++ b/doc/user/admin_area/settings/rate_limit_on_issues_creation.md @@ -10,7 +10,13 @@ info: To determine the technical writer assigned to the Stage/Group associated w > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28129) in GitLab 12.10. This setting allows you to rate limit the requests to the issue creation endpoint. -You can change its value in **Admin Area > Settings > Network > Issues Rate Limits**. +To can change its value: + +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Network**. +1. Expand **Issues Rate Limits**. +1. Under **Max requests per minute per user**, enter the new value. +1. Select **Save changes**. For example, if you set a limit of 300, requests using the [Projects::IssuesController#create](https://gitlab.com/gitlab-org/gitlab/raw/master/app/controllers/projects/issues_controller.rb) diff --git a/doc/user/admin_area/settings/rate_limit_on_notes_creation.md b/doc/user/admin_area/settings/rate_limit_on_notes_creation.md index 67a97d26b34..193f39542cf 100644 --- a/doc/user/admin_area/settings/rate_limit_on_notes_creation.md +++ b/doc/user/admin_area/settings/rate_limit_on_notes_creation.md @@ -13,9 +13,11 @@ This setting allows you to rate limit the requests to the note creation endpoint To change the note creation rate limit: -1. Go to **Admin Area > Settings > Network**. -1. Expand the **Notes Rate Limits** section. -1. Enter the new value. +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Network**. +1. Expand **Notes Rate Limits**. +1. Under **Max requests per minute per user**, enter the new value. +1. Optional. Under **List of users to be excluded from the limit**, list users to be excluded fromt the limit. 1. Select **Save changes**. This limit is: diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index 8e83ade5608..323a064c3e4 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -11,10 +11,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w WARNING: Versions of GitLab prior to 14.0 used Clair as the default container scanning engine. GitLab 14.0 -replaces Clair with Trivy and removes Clair from the product. If you run container scanning with the -default settings, GitLab switches you seamlessly and automatically to Trivy in GitLab 14.0. However, -if you customized the variables in your container scanning job, you should review the -[migration guide](#migrating-from-clair-to-trivy) and make any necessary updates. +removes Clair from the product and replaces it with two new scanners. If you +run container scanning with the default settings, GitLab switches you seamlessly and automatically +to Trivy in GitLab 14.0. However, if you customized the variables in your container scanning job, +you should review the [migration guide](#change-scanners) +and make any necessary updates. Your application's Docker image may itself be based on Docker images that contain known vulnerabilities. By including an extra job in your pipeline that scans for those vulnerabilities and @@ -23,6 +24,7 @@ displays them in a merge request, you can use GitLab to audit your Docker-based GitLab provides integration with open-source tools for vulnerability static analysis in containers: - [Trivy](https://github.com/aquasecurity/trivy) +- [Grype](https://github.com/anchore/grype) To integrate GitLab with security scanners other than those listed here, see [Security scanner integration](../../../development/integrations/secure.md). @@ -79,8 +81,10 @@ Other changes: - GitLab 13.9 [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322656) integration with [Trivy](https://github.com/aquasecurity/trivy) by upgrading `CS_MAJOR_VERSION` from `3` to `4`. - GitLab 14.0 [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61850) - integration with [Trivy](https://github.com/aquasecurity/trivy) - as the default for container scanning. + an integration with [Trivy](https://github.com/aquasecurity/trivy) + as the default for container scanning, and also [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326279) + an integration with [Grype](https://github.com/anchore/grype) + as an alternative scanner. To include the `Container-Scanning.gitlab-ci.yml` template (GitLab 11.9 and later), add the following to your `.gitlab-ci.yml` file: @@ -151,7 +155,7 @@ You can [configure](#customizing-the-container-scanning-settings) analyzers by u | `ADDITIONAL_CA_CERT_BUNDLE` | `""` | Bundle of CA certs that you want to trust. See [Using a custom SSL CA certificate authority](#using-a-custom-ssl-ca-certificate-authority) for more details. | All | | `CI_APPLICATION_REPOSITORY` | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` | Docker repository URL for the image to be scanned. | All | | `CI_APPLICATION_TAG` | `$CI_COMMIT_SHA` | Docker repository tag for the image to be scanned. | All | -| `CS_ANALYZER_IMAGE` | `$SECURE_ANALYZERS_PREFIX/$CS_PROJECT:$CS_MAJOR_VERSION` | Docker image of the analyzer. | All | +| `CS_ANALYZER_IMAGE` | `registry.gitlab.com/security-products/container-scanning:4` | Docker image of the analyzer. | All | | `CS_DOCKER_INSECURE` | `"false"` | Allow access to secure Docker registries using HTTPS without validating the certificates. | All | | `CS_REGISTRY_INSECURE` | `"false"` | Allow access to insecure registries (HTTP only). Should only be set to `true` when testing the image locally. | Trivy. The registry must listen on port `80/tcp`. | | `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are Unknown, Low, Medium, High, and Critical. | Trivy | @@ -165,6 +169,7 @@ You can [configure](#customizing-the-container-scanning-settings) analyzers by u Support depends on the scanner: +- [Grype](https://github.com/anchore/grype#grype) - [Trivy](https://aquasecurity.github.io/trivy/latest/vuln-detection/os/) (Default). ### Overriding the container scanning template @@ -189,7 +194,18 @@ GitLab 13.0 and later doesn't support [`only` and `except`](../../../ci/yaml/REA When overriding the template, you must use [`rules`](../../../ci/yaml/README.md#rules) instead. -### Migrating from Clair to Trivy +### Change scanners + +The container-scanning analyzer can use different scanners, depending on the value of the +`CS_ANALYZER_IMAGE` configuration variable. + +The following options are available: + +| Scanner name | `CS_ANALYZER_IMAGE` | +| ------------ | ------------------- | +| Default ([Trivy](https://github.com/aquasecurity/trivy)) | `registry.gitlab.com/security-products/container-scanning:4` | +| [Grype](https://github.com/anchore/grype) | `registry.gitlab.com/security-products/container-scanning/grype:4` | +| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:4` | If you're migrating from a GitLab 13.x release to a GitLab 14.x release and have customized the `container_scanning` job or its CI variables, you might need to perform these migration steps in @@ -214,17 +230,16 @@ your CI file: complete list of supported variables, see [available variables](#available-cicd-variables). 1. Make any [necessary customizations](#customizing-the-container-scanning-settings) - to the `Trivy` scanner. We recommend that you minimize such customizations, as they might require + to the chosen scanner. We recommend that you minimize such customizations, as they might require changes in future GitLab major releases. 1. Trigger a new run of a pipeline that includes the `container_scanning` job. Inspect the job output and ensure that the log messages do not mention Clair. -**Troubleshooting** - +NOTE: Prior to the GitLab 14.0 release, any variable defined under the scope `container_scanning` is not -considered for the Trivy scanner. Verify that all variables for Trivy are -either defined as a global variable, or under `container_scanning`. +considered for scanners other than Clair. In GitLab 14.0 and later, all variables can be defined +either as a global variable or under `container_scanning`. ### Using a custom SSL CA certificate authority @@ -362,14 +377,17 @@ Support for custom certificate authorities was introduced in the following versi | Scanner | Version | | -------- | ------- | | `Trivy` | [4.0.0](https://gitlab.com/gitlab-org/security-products/analyzers/container-scanning/-/releases/4.0.0) | +| `Grype` | [4.3.0](https://gitlab.com/gitlab-org/security-products/analyzers/container-scanning/-/releases/4.3.0) | #### Make GitLab container scanning analyzer images available inside your Docker registry -For container scanning, import the following default images from `registry.gitlab.com` into your +For container scanning, import the following images from `registry.gitlab.com` into your [local Docker container registry](../../packages/container_registry/index.md): ```plaintext -registry.gitlab.com/security-products/container-scanning +registry.gitlab.com/security-products/container-scanning:4 +registry.gitlab.com/security-products/container-scanning/grype:4 +registry.gitlab.com/security-products/container-scanning/trivy:4 ``` The process for importing Docker images into a local offline Docker registry depends on @@ -410,13 +428,13 @@ following `.gitlab-yml.ci` example as a template. ```yaml variables: SOURCE_IMAGE: registry.gitlab.com/security-products/container-scanning:4 - TARGET_IMAGE: $CI_REGISTRY/$CI_PROJECT_PATH/gitlab-container-scanning + TARGET_IMAGE: $CI_REGISTRY/namespace/gitlab-container-scanning image: docker:stable update-scanner-image: services: - - docker:19-dind + - docker:dind script: - docker pull $SOURCE_IMAGE - docker tag $SOURCE_IMAGE $TARGET_IMAGE diff --git a/doc/user/project/description_templates.md b/doc/user/project/description_templates.md index d2897c7310e..711d7f561e4 100644 --- a/doc/user/project/description_templates.md +++ b/doc/user/project/description_templates.md @@ -116,12 +116,13 @@ Only instance administrators can set instance-level templates. To set the instance-level description template repository: -1. Select the **Admin Area** icon (**{admin}**). -1. Go to **Settings > Templates**. +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Templates**. +1. Expand **Templates** 1. From the dropdown, select your template project as the template repository at instance level. 1. Select **Save changes**. - + Learn more about [instance template repository](../admin_area/settings/instance_template_repository.md). diff --git a/doc/user/project/time_tracking.md b/doc/user/project/time_tracking.md index 3c9b0341661..b7fd14ae74b 100644 --- a/doc/user/project/time_tracking.md +++ b/doc/user/project/time_tracking.md @@ -109,8 +109,15 @@ Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h. > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29469/) in GitLab 12.1. -In GitLab self-managed instances, the display of time units can be limited to -hours through the option in **Admin Area > Settings > Preferences** under **Localization**. +In GitLab self-managed instances, you can limit the display of time units to +hours. +To do so: + +1. On the top bar, select **Menu >** **{admin}** **Admin**. +1. On the left sidebar, select **Settings > Preferences**. +1. Expand **Localization**. +1. Under **Time tracking**, select the **Limit display of time tracking units to hours** checkbox. +1. Select **Save changes**. With this option enabled, `75h` is displayed instead of `1w 4d 3h`. diff --git a/lib/gitlab/git/remote_mirror.rb b/lib/gitlab/git/remote_mirror.rb index d9f51a7e844..eb368af199d 100644 --- a/lib/gitlab/git/remote_mirror.rb +++ b/lib/gitlab/git/remote_mirror.rb @@ -5,11 +5,12 @@ module Gitlab class RemoteMirror include Gitlab::Git::WrapsGitalyErrors - attr_reader :repository, :ref_name, :only_branches_matching, :ssh_key, :known_hosts, :keep_divergent_refs + attr_reader :repository, :ref_name, :remote_url, :only_branches_matching, :ssh_key, :known_hosts, :keep_divergent_refs - def initialize(repository, ref_name, only_branches_matching: [], ssh_key: nil, known_hosts: nil, keep_divergent_refs: false) + def initialize(repository, ref_name, remote_url, only_branches_matching: [], ssh_key: nil, known_hosts: nil, keep_divergent_refs: false) @repository = repository @ref_name = ref_name + @remote_url = remote_url @only_branches_matching = only_branches_matching @ssh_key = ssh_key @known_hosts = known_hosts @@ -20,6 +21,7 @@ module Gitlab wrapped_gitaly_errors do repository.gitaly_remote_client.update_remote_mirror( ref_name, + remote_url, only_branches_matching, ssh_key: ssh_key, known_hosts: known_hosts, diff --git a/lib/gitlab/gitaly_client/remote_service.rb b/lib/gitlab/gitaly_client/remote_service.rb index 1f360385111..487127b7b74 100644 --- a/lib/gitlab/gitaly_client/remote_service.rb +++ b/lib/gitlab/gitaly_client/remote_service.rb @@ -55,13 +55,18 @@ module Gitlab encode_utf8(response.ref) end - def update_remote_mirror(ref_name, only_branches_matching, ssh_key: nil, known_hosts: nil, keep_divergent_refs: false) + def update_remote_mirror(ref_name, remote_url, only_branches_matching, ssh_key: nil, known_hosts: nil, keep_divergent_refs: false) req_enum = Enumerator.new do |y| first_request = Gitaly::UpdateRemoteMirrorRequest.new( - repository: @gitaly_repo, - ref_name: ref_name + repository: @gitaly_repo ) + if remote_url + first_request.remote = Gitaly::UpdateRemoteMirrorRequest::Remote.new(url: remote_url) + else + first_request.ref_name = ref_name + end + first_request.ssh_key = ssh_key if ssh_key.present? first_request.known_hosts = known_hosts if known_hosts.present? first_request.keep_divergent_refs = keep_divergent_refs diff --git a/spec/controllers/admin/cohorts_controller_spec.rb b/spec/controllers/admin/cohorts_controller_spec.rb index ba5406f25ab..d271276a3e4 100644 --- a/spec/controllers/admin/cohorts_controller_spec.rb +++ b/spec/controllers/admin/cohorts_controller_spec.rb @@ -9,9 +9,9 @@ RSpec.describe Admin::CohortsController do sign_in(user) end - it 'redirects to Overview->Users' do - get :index - - expect(response).to redirect_to(cohorts_admin_users_path) + describe 'GET #index' do + it_behaves_like 'tracking unique visits', :index do + let(:target_id) { 'i_analytics_cohorts' } + end end end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index da57e5f8a92..6dc5c38cb76 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -54,12 +54,6 @@ RSpec.describe Admin::UsersController do end end - describe 'GET #cohorts' do - it_behaves_like 'tracking unique visits', :cohorts do - let(:target_id) { 'i_analytics_cohorts' } - end - end - describe 'GET :id' do it 'finds a user case-insensitively' do user = create(:user, username: 'CaseSensitive') diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 6d5944002a1..2b627707ff2 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -15,7 +15,7 @@ RSpec.describe "Admin::Users" do let(:active_tab_selector) { '.nav-link.active' } it 'links to the Users tab' do - visit cohorts_admin_users_path + visit admin_cohorts_path within tabs_selector do click_link 'Users' @@ -35,14 +35,14 @@ RSpec.describe "Admin::Users" do expect(page).to have_selector active_tab_selector, text: 'Cohorts' end - expect(page).to have_current_path(cohorts_admin_users_path) + expect(page).to have_current_path(admin_cohorts_path) expect(page).to have_selector active_tab_selector, text: 'Cohorts' end it 'redirects legacy route' do visit admin_users_path(tab: 'cohorts') - expect(page).to have_current_path(cohorts_admin_users_path) + expect(page).to have_current_path(admin_cohorts_path) end end diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb index d555519eb43..85eb956033b 100644 --- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb +++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb @@ -25,8 +25,6 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', } end - let_it_be(:runner) { create(:ci_runner, :online) } - before do stub_application_setting(auto_devops_enabled: false) stub_ci_pipeline_yaml_file(YAML.dump(config)) diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js index 19fda1433e0..951b050495c 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js @@ -290,6 +290,14 @@ describe('AuthorToken', () => { expect(firstSuggestion).toContain('Administrator'); expect(firstSuggestion).toContain('@root'); }); + + it('does not show current user while searching', async () => { + wrapper.findComponent(BaseToken).vm.handleInput({ data: 'foo' }); + + await wrapper.vm.$nextTick(); + + expect(wrapper.findComponent(GlFilteredSearchSuggestion).exists()).toBe(false); + }); }); }); }); diff --git a/spec/lib/gitlab/git/remote_mirror_spec.rb b/spec/lib/gitlab/git/remote_mirror_spec.rb index 92504b7aafe..0954879f6bd 100644 --- a/spec/lib/gitlab/git/remote_mirror_spec.rb +++ b/spec/lib/gitlab/git/remote_mirror_spec.rb @@ -7,16 +7,29 @@ RSpec.describe Gitlab::Git::RemoteMirror do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:ref_name) { 'foo' } + let(:url) { 'https://example.com' } let(:options) { { only_branches_matching: ['master'], ssh_key: 'KEY', known_hosts: 'KNOWN HOSTS', keep_divergent_refs: true } } - subject(:remote_mirror) { described_class.new(repository, ref_name, **options) } + subject(:remote_mirror) { described_class.new(repository, ref_name, url, **options) } - it 'delegates to the Gitaly client' do - expect(repository.gitaly_remote_client) - .to receive(:update_remote_mirror) - .with(ref_name, ['master'], ssh_key: 'KEY', known_hosts: 'KNOWN HOSTS', keep_divergent_refs: true) + shared_examples 'an update' do + it 'delegates to the Gitaly client' do + expect(repository.gitaly_remote_client) + .to receive(:update_remote_mirror) + .with(ref_name, url, ['master'], ssh_key: 'KEY', known_hosts: 'KNOWN HOSTS', keep_divergent_refs: true) + + remote_mirror.update # rubocop:disable Rails/SaveBang + end + end + + context 'with url' do + it_behaves_like 'an update' + end + + context 'without url' do + let(:url) { nil } - remote_mirror.update # rubocop:disable Rails/SaveBang + it_behaves_like 'an update' end it 'wraps gitaly errors' do diff --git a/spec/lib/gitlab/gitaly_client/remote_service_spec.rb b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb index df9dde324a5..2ec5f70be76 100644 --- a/spec/lib/gitlab/gitaly_client/remote_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb @@ -67,13 +67,29 @@ RSpec.describe Gitlab::GitalyClient::RemoteService do let(:ssh_key) { 'KEY' } let(:known_hosts) { 'KNOWN HOSTS' } - it 'sends an update_remote_mirror message' do - expect_any_instance_of(Gitaly::RemoteService::Stub) - .to receive(:update_remote_mirror) - .with(kind_of(Enumerator), kind_of(Hash)) - .and_return(double(:update_remote_mirror_response)) + shared_examples 'an update' do + it 'sends an update_remote_mirror message' do + expect_any_instance_of(Gitaly::RemoteService::Stub) + .to receive(:update_remote_mirror) + .with(array_including(gitaly_request_with_params(expected_params)), kind_of(Hash)) + .and_return(double(:update_remote_mirror_response)) + + client.update_remote_mirror(ref_name, url, only_branches_matching, ssh_key: ssh_key, known_hosts: known_hosts, keep_divergent_refs: true) + end + end + + context 'with remote name' do + let(:url) { nil } + let(:expected_params) { { ref_name: ref_name } } + + it_behaves_like 'an update' + end + + context 'with remote URL' do + let(:url) { 'http:://git.example.com/my-repo.git' } + let(:expected_params) { { remote: Gitaly::UpdateRemoteMirrorRequest::Remote.new(url: url) } } - client.update_remote_mirror(ref_name, only_branches_matching, ssh_key: ssh_key, known_hosts: known_hosts, keep_divergent_refs: true) + it_behaves_like 'an update' end end diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb index d6951b5926e..a64b01967ef 100644 --- a/spec/models/remote_mirror_spec.rb +++ b/spec/models/remote_mirror_spec.rb @@ -157,19 +157,34 @@ RSpec.describe RemoteMirror, :mailer do end describe '#update_repository' do - it 'performs update including options' do - git_remote_mirror = stub_const('Gitlab::Git::RemoteMirror', spy) - mirror = build(:remote_mirror) - - expect(mirror).to receive(:options_for_update).and_return(keep_divergent_refs: true) - mirror.update_repository - - expect(git_remote_mirror).to have_received(:new).with( - mirror.project.repository.raw, - mirror.remote_name, - keep_divergent_refs: true - ) - expect(git_remote_mirror).to have_received(:update) + shared_examples 'an update' do + it 'performs update including options' do + git_remote_mirror = stub_const('Gitlab::Git::RemoteMirror', spy) + mirror = build(:remote_mirror) + + expect(mirror).to receive(:options_for_update).and_return(keep_divergent_refs: true) + mirror.update_repository(inmemory_remote: inmemory) + + expect(git_remote_mirror).to have_received(:new).with( + mirror.project.repository.raw, + mirror.remote_name, + inmemory ? mirror.url : nil, + keep_divergent_refs: true + ) + expect(git_remote_mirror).to have_received(:update) + end + end + + context 'with inmemory remote' do + let(:inmemory) { true } + + it_behaves_like 'an update' + end + + context 'with on-disk remote' do + let(:inmemory) { false } + + it_behaves_like 'an update' end end diff --git a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb index 7fd32288893..b3b8e34dd8e 100644 --- a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb +++ b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb @@ -53,8 +53,6 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do end context 'when sidekiq processes the job', :sidekiq_inline do - let_it_be(:runner) { create(:ci_runner, :online) } - it 'transitions to pending status and triggers a downstream pipeline' do pipeline = create_pipeline! diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 052727401dd..3316f8c3d9b 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -7,7 +7,6 @@ RSpec.describe Ci::CreatePipelineService do let_it_be(:project, reload: true) { create(:project, :repository) } let_it_be(:user, reload: true) { project.owner } - let_it_be(:runner) { create(:ci_runner, :online, tag_list: %w[postgres mysql ruby]) } let(:ref_name) { 'refs/heads/master' } diff --git a/spec/services/ci/pipeline_processing/shared_processing_service.rb b/spec/services/ci/pipeline_processing/shared_processing_service.rb index 34d9b60217f..13c924a3089 100644 --- a/spec/services/ci/pipeline_processing/shared_processing_service.rb +++ b/spec/services/ci/pipeline_processing/shared_processing_service.rb @@ -859,8 +859,6 @@ RSpec.shared_examples 'Pipeline Processing Service' do end context 'when a bridge job has parallel:matrix config', :sidekiq_inline do - let_it_be(:runner) { create(:ci_runner, :online) } - let(:parent_config) do <<-EOY test: diff --git a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb index 9c8e6fd3292..572808cd2db 100644 --- a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb +++ b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb @@ -3,7 +3,6 @@ RSpec.shared_context 'Pipeline Processing Service Tests With Yaml' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.owner } - let_it_be(:runner) { create(:ci_runner, :online) } where(:test_file_path) do Dir.glob(Rails.root.join('spec/services/ci/pipeline_processing/test_cases/*.yml')) diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb index 96dbfe8e0b7..feb70ddaa46 100644 --- a/spec/services/projects/update_remote_mirror_service_spec.rb +++ b/spec/services/projects/update_remote_mirror_service_spec.rb @@ -13,21 +13,36 @@ RSpec.describe Projects::UpdateRemoteMirrorService do describe '#execute' do let(:retries) { 0 } + let(:inmemory) { true } subject(:execute!) { service.execute(remote_mirror, retries) } before do + stub_feature_flags(update_remote_mirror_inmemory: inmemory) project.repository.add_branch(project.owner, 'existing-branch', 'master') allow(remote_mirror) .to receive(:update_repository) + .with(inmemory_remote: inmemory) .and_return(double(divergent_refs: [])) end - it 'ensures the remote exists' do - expect(remote_mirror).to receive(:ensure_remote!) + context 'with in-memory remote disabled' do + let(:inmemory) { false } - execute! + it 'ensures the remote exists' do + expect(remote_mirror).to receive(:ensure_remote!) + + execute! + end + end + + context 'with in-memory remote enabled' do + it 'does not ensure the remote exists' do + expect(remote_mirror).not_to receive(:ensure_remote!) + + execute! + end end it 'does not fetch the remote repository' do |
