diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-30 15:07:51 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-30 15:07:51 +0000 |
commit | 4e9acbfba3682c552b3de707c535e6257ef41054 (patch) | |
tree | 8b1fd5f89ad3f1be68d8944815b13bb7d498e4a6 | |
parent | 506d6dcd7c787ba71a8a53102f3d4fdb6adcfa5e (diff) | |
download | gitlab-ce-4e9acbfba3682c552b3de707c535e6257ef41054.tar.gz |
Add latest changes from gitlab-org/gitlab@master
58 files changed, 773 insertions, 133 deletions
diff --git a/app/assets/javascripts/mirrors/mirror_repos.js b/app/assets/javascripts/mirrors/mirror_repos.js index e5acaaf9366..5401fb7b6ec 100644 --- a/app/assets/javascripts/mirrors/mirror_repos.js +++ b/app/assets/javascripts/mirrors/mirror_repos.js @@ -22,15 +22,18 @@ export default class MirrorRepos { } initMirrorPush() { + this.$keepDivergentRefsInput = $('.js-mirror-keep-divergent-refs', this.$form); this.$passwordGroup = $('.js-password-group', this.$container); this.$password = $('.js-password', this.$passwordGroup); this.$authMethod = $('.js-auth-method', this.$form); + this.$keepDivergentRefsInput.on('change', () => this.updateKeepDivergentRefs()); this.$authMethod.on('change', () => this.togglePassword()); this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl()); this.initMirrorSSH(); this.updateProtectedBranches(); + this.updateKeepDivergentRefs(); } initMirrorSSH() { @@ -61,6 +64,16 @@ export default class MirrorRepos { $('.js-mirror-protected-hidden', this.$form).val(val); } + updateKeepDivergentRefs() { + const field = this.$keepDivergentRefsInput.get(0); + + // This field only exists after the form is switched to 'Push' mode + if (field) { + const val = field.checked ? this.$keepDivergentRefsInput.val() : '0'; + $('.js-mirror-keep-divergent-refs-hidden', this.$form).val(val); + } + } + registerUpdateListeners() { this.debouncedUpdateUrl = debounce(() => this.updateUrl(), 200); this.$urlInput.on('input', () => this.debouncedUpdateUrl()); diff --git a/app/controllers/projects/mirrors_controller.rb b/app/controllers/projects/mirrors_controller.rb index 936f89e58e7..518e6a92afa 100644 --- a/app/controllers/projects/mirrors_controller.rb +++ b/app/controllers/projects/mirrors_controller.rb @@ -77,6 +77,7 @@ class Projects::MirrorsController < Projects::ApplicationController id enabled only_protected_branches + keep_divergent_refs auth_method password ssh_known_hosts diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb index 7ff0076c3e3..03841917bbf 100644 --- a/app/models/audit_event.rb +++ b/app/models/audit_event.rb @@ -30,26 +30,12 @@ class AuditEvent < ApplicationRecord end def author_name - lazy_author.name + self.user.name end def formatted_details details.merge(details.slice(:from, :to).transform_values(&:to_s)) end - - def lazy_author - BatchLoader.for(author_id).batch(default_value: default_author_value) do |author_ids, loader| - User.where(id: author_ids).find_each do |user| - loader.call(user.id, user) - end - end - end - - private - - def default_author_value - ::Gitlab::Audit::NullAuthor.for(author_id, details[:author_name]) - end end AuditEvent.prepend_if_ee('EE::AuditEvent') diff --git a/app/models/user.rb b/app/models/user.rb index 8709bfb18fd..b147c7d4d48 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1825,7 +1825,7 @@ class User < ApplicationRecord return if restrictions.blank? if Gitlab::UntrustedRegexp.new(restrictions).match?(email) - errors.add(:email, _('is not allowed for sign-up')) + errors.add(:email, _('is not allowed. Try again with a different email address, or contact your GitLab admin.')) end end diff --git a/app/presenters/pages_domain_presenter.rb b/app/presenters/pages_domain_presenter.rb new file mode 100644 index 00000000000..6b74983d932 --- /dev/null +++ b/app/presenters/pages_domain_presenter.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class PagesDomainPresenter < Gitlab::View::Presenter::Delegated + presents :pages_domain + + def needs_verification? + Gitlab::CurrentSettings.pages_domain_verification_enabled? && unverified? + end + + def show_auto_ssl_failed_warning? + return false unless Feature.enabled?(:pages_letsencrypt_errors, pages_domain.project) + + # validations prevents auto ssl from working, so there is no need to show that warning until + return false if needs_verification? + + ::Gitlab::LetsEncrypt.enabled? && auto_ssl_failed + end +end diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb index d9e40c456aa..42ed5f17d8d 100644 --- a/app/services/audit_event_service.rb +++ b/app/services/audit_event_service.rb @@ -13,7 +13,7 @@ class AuditEventService # # @return [AuditEventService] def initialize(author, entity, details = {}) - @author = build_author(author) + @author = author @entity = entity @details = details end @@ -49,14 +49,6 @@ class AuditEventService private - def build_author(author) - if author.is_a?(User) - author - else - Gitlab::Audit::UnauthenticatedAuthor.new(name: author) - end - end - def base_payload { author_id: @author.id, diff --git a/app/services/metrics/dashboard/clone_dashboard_service.rb b/app/services/metrics/dashboard/clone_dashboard_service.rb index ee5b50aefc3..3ca25b3bd9b 100644 --- a/app/services/metrics/dashboard/clone_dashboard_service.rb +++ b/app/services/metrics/dashboard/clone_dashboard_service.rb @@ -5,9 +5,18 @@ module Metrics module Dashboard class CloneDashboardService < ::BaseService + include Stepable + ALLOWED_FILE_TYPE = '.yml' USER_DASHBOARDS_DIR = ::Metrics::Dashboard::CustomDashboardService::DASHBOARD_ROOT + steps :check_push_authorized, + :check_branch_name, + :check_file_type, + :check_dashboard_template, + :create_file, + :refresh_repository_method_caches + class << self def allowed_dashboard_templates @allowed_dashboard_templates ||= Set[::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH].freeze @@ -22,21 +31,52 @@ module Metrics end end - # rubocop:disable Cop/BanCatchThrow def execute - catch(:error) do - throw(:error, error(_(%q(You are not allowed to push into this branch. Create another branch or open a merge request.)), :forbidden)) unless push_authorized? + execute_steps + end + + private + + def check_push_authorized(result) + return error(_('You are not allowed to push into this branch. Create another branch or open a merge request.'), :forbidden) unless push_authorized? + + success(result) + end + + def check_branch_name(result) + return error(_('There was an error creating the dashboard, branch name is invalid.'), :bad_request) unless valid_branch_name? + return error(_('There was an error creating the dashboard, branch named: %{branch} already exists.') % { branch: params[:branch] }, :bad_request) unless new_or_default_branch? + + success(result) + end - result = ::Files::CreateService.new(project, current_user, dashboard_attrs).execute - throw(:error, wrap_error(result)) unless result[:status] == :success + def check_file_type(result) + return error(_('The file name should have a .yml extension'), :bad_request) unless target_file_type_valid? - repository.refresh_method_caches([:metrics_dashboard]) - success(result.merge(http_status: :created, dashboard: dashboard_details)) + success(result) + end + + def check_dashboard_template(result) + return error(_('Not found.'), :not_found) unless self.class.allowed_dashboard_templates.include?(params[:dashboard]) + + success(result) + end + + def create_file(result) + create_file_response = ::Files::CreateService.new(project, current_user, dashboard_attrs).execute + + if create_file_response[:status] == :success + success(result.merge(create_file_response)) + else + wrap_error(create_file_response) end end - # rubocop:enable Cop/BanCatchThrow - private + def refresh_repository_method_caches(result) + repository.refresh_method_caches([:metrics_dashboard]) + + success(result.merge(http_status: :created, dashboard: dashboard_details)) + end def dashboard_attrs { @@ -62,26 +102,13 @@ module Metrics Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(branch) end - # rubocop:disable Cop/BanCatchThrow def dashboard_template - @dashboard_template ||= begin - throw(:error, error(_('Not found.'), :not_found)) unless self.class.allowed_dashboard_templates.include?(params[:dashboard]) - - params[:dashboard] - end + @dashboard_template ||= params[:dashboard] end - # rubocop:enable Cop/BanCatchThrow - # rubocop:disable Cop/BanCatchThrow def branch - @branch ||= begin - throw(:error, error(_('There was an error creating the dashboard, branch name is invalid.'), :bad_request)) unless valid_branch_name? - throw(:error, error(_('There was an error creating the dashboard, branch named: %{branch} already exists.') % { branch: params[:branch] }, :bad_request)) unless new_or_default_branch? # temporary validation for first UI iteration - - params[:branch] - end + @branch ||= params[:branch] end - # rubocop:enable Cop/BanCatchThrow def new_or_default_branch? !repository.branch_exists?(params[:branch]) || project.default_branch == params[:branch] @@ -95,20 +122,22 @@ module Metrics @new_dashboard_path ||= File.join(USER_DASHBOARDS_DIR, file_name) end - # rubocop:disable Cop/BanCatchThrow def file_name - @file_name ||= begin - throw(:error, error(_('The file name should have a .yml extension'), :bad_request)) unless target_file_type_valid? - - File.basename(params[:file_name]) - end + @file_name ||= File.basename(params[:file_name]) end - # rubocop:enable Cop/BanCatchThrow def target_file_type_valid? File.extname(params[:file_name]) == ALLOWED_FILE_TYPE end + def wrap_error(result) + if result[:message] == 'A file with this name already exists' + error(_("A file with '%{file_name}' already exists in %{branch} branch") % { file_name: file_name, branch: branch }, :bad_request) + else + result + end + end + def new_dashboard_content ::Gitlab::Metrics::Dashboard::Processor .new(project, raw_dashboard, sequence, {}) @@ -119,14 +148,6 @@ module Metrics @repository ||= project.repository end - def wrap_error(result) - if result[:message] == 'A file with this name already exists' - error(_("A file with '%{file_name}' already exists in %{branch} branch") % { file_name: file_name, branch: branch }, :bad_request) - else - result - end - end - def raw_dashboard YAML.safe_load(File.read(Rails.root.join(dashboard_template))) end diff --git a/app/views/projects/mirrors/_mirror_repos_push.html.haml b/app/views/projects/mirrors/_mirror_repos_push.html.haml index b7c885b4a63..8482424a184 100644 --- a/app/views/projects/mirrors/_mirror_repos_push.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_push.html.haml @@ -1,8 +1,15 @@ - protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') +- keep_divergent_refs = Feature.enabled?(:keep_divergent_refs, @project) = f.fields_for :remote_mirrors, @project.remote_mirrors.build do |rm_f| = rm_f.hidden_field :enabled, value: '1' = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' + - if keep_divergent_refs + = rm_f.hidden_field :keep_divergent_refs, class: 'js-mirror-keep-divergent-refs-hidden' = render partial: 'projects/mirrors/ssh_host_keys', locals: { f: rm_f } = render partial: 'projects/mirrors/authentication_method', locals: { f: rm_f } + - if keep_divergent_refs + .form-check.append-bottom-10 + = check_box_tag :keep_divergent_refs, '1', false, class: 'js-mirror-keep-divergent-refs form-check-input' + = label_tag :keep_divergent_refs, 'Keep divergent refs', class: 'form-check-label' diff --git a/app/views/projects/pages/_list.html.haml b/app/views/projects/pages/_list.html.haml index 6d196b06135..0d40f375926 100644 --- a/app/views/projects/pages/_list.html.haml +++ b/app/views/projects/pages/_list.html.haml @@ -6,6 +6,7 @@ Domains (#{@domains.count}) %ul.list-group.list-group-flush.pages-domain-list{ class: ("has-verification-status" if verification_enabled) } - @domains.each do |domain| + - domain = Gitlab::View::Presenter::Factory.new(domain, current_user: current_user).fabricate! %li.pages-domain-list-item.list-group-item.d-flex.justify-content-between - if verification_enabled - tooltip, status = domain.unverified? ? [s_('GitLabPages|Unverified'), 'failed'] : [s_('GitLabPages|Verified'), 'success'] @@ -13,20 +14,27 @@ = sprite_icon("status_#{status}", size: 16 ) .domain-name = external_link(domain.url, domain.url) - - if domain.subject + - if domain.certificate %div %span.badge.badge-gray - = s_('GitLabPages|Certificate: %{subject}') % { subject: domain.subject } + = s_('GitLabPages|Certificate: %{subject}') % { subject: domain.pages_domain.subject } - if domain.expired? %span.badge.badge-danger = s_('GitLabPages|Expired') %div = link_to s_('GitLabPages|Edit'), project_pages_domain_path(@project, domain), class: "btn btn-sm btn-grouped btn-success btn-inverted" = link_to s_('GitLabPages|Remove'), project_pages_domain_path(@project, domain), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn btn-remove btn-sm btn-grouped" - - if verification_enabled && domain.unverified? + - if domain.needs_verification? %li.list-group-item.bs-callout-warning - details_link_start = "<a href='#{project_pages_domain_path(@project, domain)}'>".html_safe - details_link_end = '</a>'.html_safe = s_('GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}.').html_safe % { domain: domain.domain, link_start: details_link_start, link_end: details_link_end } + - if domain.show_auto_ssl_failed_warning? + %li.list-group-item.bs-callout-warning + - details_link_start = "<a href='#{project_pages_domain_path(@project, domain)}'>".html_safe + - details_link_end = '</a>'.html_safe + = s_("GitLabPages|Something went wrong while obtaining Let's Encrypt certificate for %{domain}. To retry visit your %{link_start}domain details%{link_end}.").html_safe % { domain: domain.domain, + link_start: details_link_start, + link_end: details_link_end } diff --git a/changelogs/unreleased/dz-scope-some-global-routes.yml b/changelogs/unreleased/dz-scope-some-global-routes.yml new file mode 100644 index 00000000000..c908c316227 --- /dev/null +++ b/changelogs/unreleased/dz-scope-some-global-routes.yml @@ -0,0 +1,5 @@ +--- +title: Move some global routes to - scope +merge_request: 27106 +author: +type: changed diff --git a/config/routes.rb b/config/routes.rb index 466555eeee8..a8b2a9b6656 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -71,6 +71,8 @@ Rails.application.routes.draw do # Health check get 'health_check(/:checks)' => 'health_check#index', as: :health_check + # Begin of the /-/ scope. + # Use this scope for all new global routes. scope path: '-' do # '/-/health' implemented by BasicHealthCheck middleware get 'liveness' => 'health#liveness' @@ -122,6 +124,10 @@ Rails.application.routes.draw do draw :country_state draw :subscription draw :analytics + + scope '/push_from_secondary/:geo_node_id' do + draw :git_http + end end if ENV['GITLAB_CHAOS_SECRET'] || Rails.env.development? || Rails.env.test? @@ -136,7 +142,24 @@ Rails.application.routes.draw do # Notification settings resources :notification_settings, only: [:create, :update] + + resources :invites, only: [:show], constraints: { id: /[A-Za-z0-9_-]+/ } do + member do + post :accept + match :decline, via: [:get, :post] + end + end + + resources :sent_notifications, only: [], constraints: { id: /\h{32}/ } do + member do + get :unsubscribe + end + end + + # Spam reports + resources :abuse_reports, only: [:new, :create] end + # End of the /-/ scope. concern :clusterable do resources :clusters, only: [:index, :new, :show, :update, :destroy] do @@ -167,22 +190,24 @@ Rails.application.routes.draw do end end - # Invites - resources :invites, only: [:show], constraints: { id: /[A-Za-z0-9_-]+/ } do - member do - post :accept - match :decline, via: [:get, :post] + # Deprecated routes. + # Will be removed as part of https://gitlab.com/gitlab-org/gitlab/-/issues/210024 + scope as: :deprecated do + resources :invites, only: [:show], constraints: { id: /[A-Za-z0-9_-]+/ } do + member do + post :accept + match :decline, via: [:get, :post] + end end - end - resources :sent_notifications, only: [], constraints: { id: /\h{32}/ } do - member do - get :unsubscribe + resources :sent_notifications, only: [], constraints: { id: /\h{32}/ } do + member do + get :unsubscribe + end end - end - # Spam reports - resources :abuse_reports, only: [:new, :create] + resources :abuse_reports, only: [:new, :create] + end resources :groups, only: [:index, :new, :create] do post :preview_markdown @@ -192,12 +217,6 @@ Rails.application.routes.draw do get '/projects/:id' => 'projects#resolve' - Gitlab.ee do - scope '/-/push_from_secondary/:geo_node_id' do - draw :git_http - end - end - draw :git_http draw :api draw :sidekiq diff --git a/db/migrate/20180102220145_add_pages_https_only_to_projects.rb b/db/migrate/20180102220145_add_pages_https_only_to_projects.rb index 75488f57fa9..7bd646cd5fd 100644 --- a/db/migrate/20180102220145_add_pages_https_only_to_projects.rb +++ b/db/migrate/20180102220145_add_pages_https_only_to_projects.rb @@ -4,6 +4,6 @@ class AddPagesHttpsOnlyToProjects < ActiveRecord::Migration[4.2] DOWNTIME = false def change - add_column :projects, :pages_https_only, :boolean + add_column :projects, :pages_https_only, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20180228172924_add_include_private_contributions_to_users.rb b/db/migrate/20180228172924_add_include_private_contributions_to_users.rb index 7921d3a14b6..58e50b2ee74 100644 --- a/db/migrate/20180228172924_add_include_private_contributions_to_users.rb +++ b/db/migrate/20180228172924_add_include_private_contributions_to_users.rb @@ -2,6 +2,6 @@ class AddIncludePrivateContributionsToUsers < ActiveRecord::Migration[4.2] DOWNTIME = false def change - add_column :users, :include_private_contributions, :boolean + add_column :users, :include_private_contributions, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20180503141722_add_remote_mirror_available_overridden_to_projects.rb b/db/migrate/20180503141722_add_remote_mirror_available_overridden_to_projects.rb index 1d99d46b7d6..aa3d9a804ab 100644 --- a/db/migrate/20180503141722_add_remote_mirror_available_overridden_to_projects.rb +++ b/db/migrate/20180503141722_add_remote_mirror_available_overridden_to_projects.rb @@ -6,7 +6,7 @@ class AddRemoteMirrorAvailableOverriddenToProjects < ActiveRecord::Migration[4.2 disable_ddl_transaction! def up - add_column(:projects, :remote_mirror_available_overridden, :boolean) unless column_exists?(:projects, :remote_mirror_available_overridden) + add_column(:projects, :remote_mirror_available_overridden, :boolean) unless column_exists?(:projects, :remote_mirror_available_overridden) # rubocop:disable Migration/AddColumnsToWideTables end def down diff --git a/db/migrate/20180722103201_add_private_profile_to_users.rb b/db/migrate/20180722103201_add_private_profile_to_users.rb index c8d917065bb..63b7a631fc8 100644 --- a/db/migrate/20180722103201_add_private_profile_to_users.rb +++ b/db/migrate/20180722103201_add_private_profile_to_users.rb @@ -5,6 +5,6 @@ class AddPrivateProfileToUsers < ActiveRecord::Migration[4.2] DOWNTIME = false def change - add_column :users, :private_profile, :boolean + add_column :users, :private_profile, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20180814153625_add_commit_email_to_users.rb b/db/migrate/20180814153625_add_commit_email_to_users.rb index 98bafc14a03..303be9b2312 100644 --- a/db/migrate/20180814153625_add_commit_email_to_users.rb +++ b/db/migrate/20180814153625_add_commit_email_to_users.rb @@ -27,7 +27,11 @@ class AddCommitEmailToUsers < ActiveRecord::Migration[4.2] # comments: # disable_ddl_transaction! + # rubocop:disable Migration/AddLimitToStringColumns + # rubocop:disable Migration/AddColumnsToWideTables def change - add_column :users, :commit_email, :string # rubocop:disable Migration/AddLimitToStringColumns + add_column :users, :commit_email, :string end + # rubocop:enable Migration/AddLimitToStringColumns + # rubocop:enable Migration/AddColumnsToWideTables end diff --git a/db/migrate/20180924190739_add_scheduled_at_to_ci_builds.rb b/db/migrate/20180924190739_add_scheduled_at_to_ci_builds.rb index cd2f8b59d41..04a784a0c90 100644 --- a/db/migrate/20180924190739_add_scheduled_at_to_ci_builds.rb +++ b/db/migrate/20180924190739_add_scheduled_at_to_ci_builds.rb @@ -4,6 +4,6 @@ class AddScheduledAtToCiBuilds < ActiveRecord::Migration[4.2] DOWNTIME = false def change - add_column :ci_builds, :scheduled_at, :datetime_with_timezone + add_column :ci_builds, :scheduled_at, :datetime_with_timezone # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20181019032408_add_repositories_table.rb b/db/migrate/20181019032408_add_repositories_table.rb index dd510b44084..5ee31b37b66 100644 --- a/db/migrate/20181019032408_add_repositories_table.rb +++ b/db/migrate/20181019032408_add_repositories_table.rb @@ -9,7 +9,7 @@ class AddRepositoriesTable < ActiveRecord::Migration[4.2] t.string :disk_path, null: false, index: { unique: true } # rubocop:disable Migration/AddLimitToStringColumns end - add_column :projects, :pool_repository_id, :bigint + add_column :projects, :pool_repository_id, :bigint # rubocop:disable Migration/AddColumnsToWideTables add_index :projects, :pool_repository_id, where: 'pool_repository_id IS NOT NULL' end end diff --git a/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb b/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb index 3083dff49b8..f6986fcdfeb 100644 --- a/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb +++ b/db/migrate/20181116141504_add_encrypted_runners_token_to_projects.rb @@ -5,7 +5,11 @@ class AddEncryptedRunnersTokenToProjects < ActiveRecord::Migration[4.2] DOWNTIME = false + # rubocop:disable Migration/AddColumnsToWideTables + # rubocop:disable Migration/AddLimitToStringColumns def change - add_column :projects, :runners_token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns + add_column :projects, :runners_token_encrypted, :string end + # rubocop:enable Migration/AddColumnsToWideTables + # rubocop:enable Migration/AddLimitToStringColumns end diff --git a/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb b/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb index 62a7421eae0..097cc59bcdc 100644 --- a/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb +++ b/db/migrate/20181129104854_add_token_encrypted_to_ci_builds.rb @@ -5,7 +5,11 @@ class AddTokenEncryptedToCiBuilds < ActiveRecord::Migration[5.0] DOWNTIME = false + # rubocop:disable Migration/AddColumnsToWideTables + # rubocop:disable Migration/AddLimitToStringColumns def change - add_column :ci_builds, :token_encrypted, :string # rubocop:disable Migration/AddLimitToStringColumns + add_column :ci_builds, :token_encrypted, :string end + # rubocop:enable Migration/AddColumnsToWideTables + # rubocop:enable Migration/AddLimitToStringColumns end diff --git a/db/migrate/20181203002526_add_project_bfg_object_map_column.rb b/db/migrate/20181203002526_add_project_bfg_object_map_column.rb index 5e6d416895c..d8c4fe1ecf6 100644 --- a/db/migrate/20181203002526_add_project_bfg_object_map_column.rb +++ b/db/migrate/20181203002526_add_project_bfg_object_map_column.rb @@ -3,7 +3,11 @@ class AddProjectBfgObjectMapColumn < ActiveRecord::Migration[5.0] DOWNTIME = false + # rubocop:disable Migration/AddColumnsToWideTables + # rubocop:disable Migration/AddLimitToStringColumns def change - add_column :projects, :bfg_object_map, :string # rubocop:disable Migration/AddLimitToStringColumns + add_column :projects, :bfg_object_map, :string end + # rubocop:enable Migration/AddColumnsToWideTables + # rubocop:enable Migration/AddLimitToStringColumns end diff --git a/db/migrate/20190312071108_add_detected_repository_languages_to_projects.rb b/db/migrate/20190312071108_add_detected_repository_languages_to_projects.rb index 5ce0ca19888..82e7ec851c9 100644 --- a/db/migrate/20190312071108_add_detected_repository_languages_to_projects.rb +++ b/db/migrate/20190312071108_add_detected_repository_languages_to_projects.rb @@ -7,6 +7,6 @@ class AddDetectedRepositoryLanguagesToProjects < ActiveRecord::Migration[5.0] DOWNTIME = false def change - add_column :projects, :detected_repository_languages, :boolean + add_column :projects, :detected_repository_languages, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20190419121952_add_bridged_pipeline_id_to_bridges.rb b/db/migrate/20190419121952_add_bridged_pipeline_id_to_bridges.rb index fac556c1897..efb59403df3 100644 --- a/db/migrate/20190419121952_add_bridged_pipeline_id_to_bridges.rb +++ b/db/migrate/20190419121952_add_bridged_pipeline_id_to_bridges.rb @@ -10,6 +10,6 @@ class AddBridgedPipelineIdToBridges < ActiveRecord::Migration[5.0] DOWNTIME = false def change - add_column :ci_builds, :upstream_pipeline_id, :integer + add_column :ci_builds, :upstream_pipeline_id, :integer # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20190715215532_add_project_emails_disabled.rb b/db/migrate/20190715215532_add_project_emails_disabled.rb index 536ea34c0fb..72dba82ef1c 100644 --- a/db/migrate/20190715215532_add_project_emails_disabled.rb +++ b/db/migrate/20190715215532_add_project_emails_disabled.rb @@ -4,6 +4,6 @@ class AddProjectEmailsDisabled < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :projects, :emails_disabled, :boolean + add_column :projects, :emails_disabled, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20190722104947_add_static_object_token_to_users.rb b/db/migrate/20190722104947_add_static_object_token_to_users.rb index 6ef85d9acaa..180e6a30b04 100644 --- a/db/migrate/20190722104947_add_static_object_token_to_users.rb +++ b/db/migrate/20190722104947_add_static_object_token_to_users.rb @@ -9,7 +9,7 @@ class AddStaticObjectTokenToUsers < ActiveRecord::Migration[5.2] disable_ddl_transaction! def up - add_column :users, :static_object_token, :string, limit: 255 + add_column :users, :static_object_token, :string, limit: 255 # rubocop:disable Migration/AddColumnsToWideTables end def down diff --git a/db/migrate/20190820163320_add_first_last_name_to_user.rb b/db/migrate/20190820163320_add_first_last_name_to_user.rb index 0ea465fc2e2..62bd1443b9d 100644 --- a/db/migrate/20190820163320_add_first_last_name_to_user.rb +++ b/db/migrate/20190820163320_add_first_last_name_to_user.rb @@ -7,8 +7,10 @@ class AddFirstLastNameToUser < ActiveRecord::Migration[5.2] # Set this constant to true if this migration requires downtime. DOWNTIME = false + # rubocop:disable Migration/AddColumnsToWideTables def change add_column(:users, :first_name, :string, null: true, limit: 255) add_column(:users, :last_name, :string, null: true, limit: 255) end + # rubocop:enable Migration/AddColumnsToWideTables end diff --git a/db/migrate/20190911115056_add_projects_max_pages_size.rb b/db/migrate/20190911115056_add_projects_max_pages_size.rb index 175c66953ed..70812e31ab8 100644 --- a/db/migrate/20190911115056_add_projects_max_pages_size.rb +++ b/db/migrate/20190911115056_add_projects_max_pages_size.rb @@ -4,6 +4,6 @@ class AddProjectsMaxPagesSize < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :projects, :max_pages_size, :integer + add_column :projects, :max_pages_size, :integer # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20190911115207_add_projects_max_artifacts_size.rb b/db/migrate/20190911115207_add_projects_max_artifacts_size.rb index 41cab7e5282..cd4574ad9c8 100644 --- a/db/migrate/20190911115207_add_projects_max_artifacts_size.rb +++ b/db/migrate/20190911115207_add_projects_max_artifacts_size.rb @@ -4,6 +4,6 @@ class AddProjectsMaxArtifactsSize < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :projects, :max_artifacts_size, :integer + add_column :projects, :max_artifacts_size, :integer # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20190912223232_add_role_to_users.rb b/db/migrate/20190912223232_add_role_to_users.rb index afbd78ed509..a6405ab896d 100644 --- a/db/migrate/20190912223232_add_role_to_users.rb +++ b/db/migrate/20190912223232_add_role_to_users.rb @@ -7,6 +7,6 @@ class AddRoleToUsers < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :users, :role, :smallint + add_column :users, :role, :smallint # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb b/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb index b9f729d7d66..f1af925c421 100644 --- a/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb +++ b/db/migrate/20190924124627_add_pull_mirror_branch_prefix_to_projects.rb @@ -4,6 +4,6 @@ class AddPullMirrorBranchPrefixToProjects < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :projects, :pull_mirror_branch_prefix, :string, limit: 50 + add_column :projects, :pull_mirror_branch_prefix, :string, limit: 50 # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20191003161031_add_mark_for_deletion_to_projects.rb b/db/migrate/20191003161031_add_mark_for_deletion_to_projects.rb index 86d581a4383..12f17c849aa 100644 --- a/db/migrate/20191003161031_add_mark_for_deletion_to_projects.rb +++ b/db/migrate/20191003161031_add_mark_for_deletion_to_projects.rb @@ -4,8 +4,10 @@ class AddMarkForDeletionToProjects < ActiveRecord::Migration[5.2] # Set this constant to true if this migration requires downtime. DOWNTIME = false + # rubocop:disable Migration/AddColumnsToWideTables def change add_column :projects, :marked_for_deletion_at, :date add_column :projects, :marked_for_deletion_by_user_id, :integer end + # rubocop:enable Migration/AddColumnsToWideTables end diff --git a/db/migrate/20191017094449_add_remove_source_branch_after_merge_to_projects.rb b/db/migrate/20191017094449_add_remove_source_branch_after_merge_to_projects.rb index 021bf7d9870..d4f84b066a3 100644 --- a/db/migrate/20191017094449_add_remove_source_branch_after_merge_to_projects.rb +++ b/db/migrate/20191017094449_add_remove_source_branch_after_merge_to_projects.rb @@ -8,7 +8,7 @@ class AddRemoveSourceBranchAfterMergeToProjects < ActiveRecord::Migration[5.1] DOWNTIME = false def up - add_column :projects, :remove_source_branch_after_merge, :boolean + add_column :projects, :remove_source_branch_after_merge, :boolean # rubocop:disable Migration/AddColumnsToWideTables end def down diff --git a/db/migrate/20191115114032_add_processed_to_ci_builds.rb b/db/migrate/20191115114032_add_processed_to_ci_builds.rb index f6f8f5e85d6..6fece99cb02 100644 --- a/db/migrate/20191115114032_add_processed_to_ci_builds.rb +++ b/db/migrate/20191115114032_add_processed_to_ci_builds.rb @@ -4,6 +4,6 @@ class AddProcessedToCiBuilds < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :ci_builds, :processed, :boolean + add_column :ci_builds, :processed, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20191129144630_add_resource_group_id_to_ci_builds.rb b/db/migrate/20191129144630_add_resource_group_id_to_ci_builds.rb index 2e696c32e7e..245df7fdcf3 100644 --- a/db/migrate/20191129144630_add_resource_group_id_to_ci_builds.rb +++ b/db/migrate/20191129144630_add_resource_group_id_to_ci_builds.rb @@ -3,6 +3,7 @@ class AddResourceGroupIdToCiBuilds < ActiveRecord::Migration[5.2] DOWNTIME = false + # rubocop:disable Migration/AddColumnsToWideTables def up unless column_exists?(:ci_builds, :resource_group_id) add_column :ci_builds, :resource_group_id, :bigint @@ -12,6 +13,7 @@ class AddResourceGroupIdToCiBuilds < ActiveRecord::Migration[5.2] add_column :ci_builds, :waiting_for_resource_at, :datetime_with_timezone end end + # rubocop:enable Migration/AddColumnsToWideTables def down if column_exists?(:ci_builds, :resource_group_id) diff --git a/db/migrate/20191208110214_add_suggestion_commit_message_to_projects.rb b/db/migrate/20191208110214_add_suggestion_commit_message_to_projects.rb index c4344cf212c..cb897edde8e 100644 --- a/db/migrate/20191208110214_add_suggestion_commit_message_to_projects.rb +++ b/db/migrate/20191208110214_add_suggestion_commit_message_to_projects.rb @@ -4,6 +4,6 @@ class AddSuggestionCommitMessageToProjects < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :projects, :suggestion_commit_message, :string, limit: 255 + add_column :projects, :suggestion_commit_message, :string, limit: 255 # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20191223124940_add_scheduling_type_to_ci_builds.rb b/db/migrate/20191223124940_add_scheduling_type_to_ci_builds.rb index 0cb42cdc328..bb849aa8a95 100644 --- a/db/migrate/20191223124940_add_scheduling_type_to_ci_builds.rb +++ b/db/migrate/20191223124940_add_scheduling_type_to_ci_builds.rb @@ -6,6 +6,6 @@ class AddSchedulingTypeToCiBuilds < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :ci_builds, :scheduling_type, :integer, limit: 2 + add_column :ci_builds, :scheduling_type, :integer, limit: 2 # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb b/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb index ac1aa2276fc..db473434205 100644 --- a/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb +++ b/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb @@ -4,6 +4,6 @@ class AddAutocloseReferencedIssuesToProjects < ActiveRecord::Migration[5.2] DOWNTIME = false def change - add_column :projects, :autoclose_referenced_issues, :boolean + add_column :projects, :autoclose_referenced_issues, :boolean # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/migrate/20200304085423_add_user_type.rb b/db/migrate/20200304085423_add_user_type.rb index 355a16897f4..3c20f2d26d8 100644 --- a/db/migrate/20200304085423_add_user_type.rb +++ b/db/migrate/20200304085423_add_user_type.rb @@ -7,7 +7,7 @@ class AddUserType < ActiveRecord::Migration[6.0] def up with_lock_retries do - add_column :users, :user_type, :integer, limit: 2 + add_column :users, :user_type, :integer, limit: 2 # rubocop:disable Migration/AddColumnsToWideTables end end diff --git a/db/post_migrate/20190424134256_drop_projects_ci_id.rb b/db/post_migrate/20190424134256_drop_projects_ci_id.rb index 44e8f316393..223e9fd4a94 100644 --- a/db/post_migrate/20190424134256_drop_projects_ci_id.rb +++ b/db/post_migrate/20190424134256_drop_projects_ci_id.rb @@ -23,7 +23,7 @@ class DropProjectsCiId < ActiveRecord::Migration[5.1] def down unless column_exists?(:projects, :ci_id) - add_column :projects, :ci_id, :integer + add_column :projects, :ci_id, :integer # rubocop:disable Migration/AddColumnsToWideTables end unless index_exists?(:projects, :ci_id) diff --git a/db/post_migrate/20190511144331_remove_users_support_type.rb b/db/post_migrate/20190511144331_remove_users_support_type.rb index 32df33432b9..e72fbb229b8 100644 --- a/db/post_migrate/20190511144331_remove_users_support_type.rb +++ b/db/post_migrate/20190511144331_remove_users_support_type.rb @@ -17,7 +17,7 @@ class RemoveUsersSupportType < ActiveRecord::Migration[5.1] end def down - add_column :users, :support_bot, :boolean + add_column :users, :support_bot, :boolean # rubocop:disable Migration/AddColumnsToWideTables add_concurrent_index :users, :support_bot add_concurrent_index :users, :state, diff --git a/db/post_migrate/20191015154408_drop_merge_requests_require_code_owner_approval_from_projects.rb b/db/post_migrate/20191015154408_drop_merge_requests_require_code_owner_approval_from_projects.rb index a1d763b7ed1..f31471c2891 100644 --- a/db/post_migrate/20191015154408_drop_merge_requests_require_code_owner_approval_from_projects.rb +++ b/db/post_migrate/20191015154408_drop_merge_requests_require_code_owner_approval_from_projects.rb @@ -15,7 +15,7 @@ class DropMergeRequestsRequireCodeOwnerApprovalFromProjects < ActiveRecord::Migr end def down - add_column :projects, :merge_requests_require_code_owner_approval, :boolean + add_column :projects, :merge_requests_require_code_owner_approval, :boolean # rubocop:disable Migration/AddColumnsToWideTables add_concurrent_index( :projects, diff --git a/doc/administration/troubleshooting/log_parsing.md b/doc/administration/troubleshooting/log_parsing.md new file mode 100644 index 00000000000..b882595ea4a --- /dev/null +++ b/doc/administration/troubleshooting/log_parsing.md @@ -0,0 +1,152 @@ +# Parsing GitLab logs with `jq` + +We recommend using log aggregation and search tools like Kibana and Splunk whenever possible, +but if they are not available you can still quickly parse +[GitLab logs](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26311) in JSON format +(the default since GitLab 12.0) using [`jq`](https://stedolan.github.io/jq/). + +## What is JQ? + +As noted in its [manual](https://stedolan.github.io/jq/manual), jq is a command-line JSON processor. The following examples +include use cases targeted for parsing GitLab log files. + +## Parsing Logs + +### General Commands + +#### Pipe colorized `jq` output into `less` + +```sh +jq . <FILE> -C | less -R +``` + +#### Search for a term and pretty-print all matching lines + +```sh +grep <TERM> <FILE> | jq . +``` + +#### Skip invalid lines of JSON + +```sh +jq -cR 'fromjson?' file.json | jq <COMMAND> +``` + +By default `jq` will error out when it encounters a line that is not valid JSON. +This skips over all invalid lines and parses the rest. + +### Parsing `production_json.log` and `api_json.log` + +#### Find all requests with a 5XX status code + +```sh +jq 'select(status >= 500)' <FILE> +``` + +#### Top 10 slowest requests + +```sh +jq -s 'sort_by(-.duration) | limit(10; .[])' <FILE> +``` + +#### Find and pretty print all requests related to a project + +```sh +grep <PROJECT_NAME> <FILE> | jq . +``` + +#### Find all requests with a total duration > 5 seconds + +```sh +jq 'select(.duration > 5000)' <FILE> +``` + +#### Find all project requests with more than 5 rugged calls + +```sh +grep <PROJECT_NAME> <FILE> | jq 'select(.rugged_calls > 5)' +``` + +#### Find all requests with a Gitaly duration > 10 seconds + +```sh +jq 'select(.gitaly_duration > 10000)' <FILE> +``` + +#### Find all requests with a queue duration > 10 seconds + +```sh +jq 'select(.queue_duration > 10000)' <FILE> +``` + +#### Top 10 requests by # of Gitaly calls + +```sh +jq -s 'map(select(.gitaly_calls != null)) | sort_by(-.gitaly_calls) | limit(10; .[])' <FILE> +``` + +### Parsing `production_json.log` + +#### Print the top three controller methods by request volume and their three longest durations + +```sh +jq -s -r 'group_by(.controller+.action) | sort_by(-length) | limit(3; .[]) | sort_by(-.duration) | "CT: \(length)\tMETHOD: \(.[0].controller)#\(.[0].action)\tDURS: \(.[0].duration), \(.[1].duration), \(.[2].duration)"' production_json.log +``` + +**Example output** + +```plaintext +CT: 2721 METHOD: SessionsController#new DURS: 844.06, 713.81, 704.66 +CT: 2435 METHOD: MetricsController#index DURS: 299.29, 284.01, 158.57 +CT: 1328 METHOD: Projects::NotesController#index DURS: 403.99, 386.29, 384.39 +``` + +### Parsing `api_json.log` + +#### Print top three routes with request count and their three longest durations + +```sh +jq -s -r 'group_by(.route) | sort_by(-length) | limit(3; .[]) | sort_by(-.duration) | "CT: \(length)\tROUTE: \(.[0].route)\tDURS: \(.[0].duration), \(.[1].duration), \(.[2].duration)"' api_json.log +``` + +**Example output** + +```plaintext +CT: 2472 ROUTE: /api/:version/internal/allowed DURS: 56402.65, 38411.43, 19500.41 +CT: 297 ROUTE: /api/:version/projects/:id/repository/tags DURS: 731.39, 685.57, 480.86 +CT: 190 ROUTE: /api/:version/projects/:id/repository/commits DURS: 1079.02, 979.68, 958.21 +``` + +### Parsing `gitaly/current` + +#### Find all Gitaly requests sent from web UI + +```sh +jq 'select(."grpc.meta.client_name" == "gitlab-web")' current +``` + +#### Find all failed Gitaly requests + +```sh +jq 'select(."grpc.code" != null and ."grpc.code" != "OK")' current +``` + +#### Find all requests that took longer than 30 seconds + +```sh +jq 'select(."grpc.time_ms" > 30000)' current +``` + +#### Print top three projects by request volume and their three longest durations + +```sh +jq -s -r 'map(select(."grpc.request.glProjectPath" != null and ."grpc.request.glProjectPath" != "" and ."grpc.time_ms" != null)) | group_by(."grpc.request.glProjectPath") | sort_by(-length) | limit(3; .[]) | sort_by(-."grpc.time_ms") | "CT: \(length)\tPROJECT: \(.[0]."grpc.request.glProjectPath")\tDURS: \(.[0]."grpc.time_ms"), \(.[1]."grpc.time_ms"), \(.[2]."grpc.time_ms")"' current +``` + +**Example output** + +```plaintext +CT: 635 PROJECT: groupA/project1 DURS: 4292.269, 4228.853, 2885.548 +CT: 462 PROJECT: groupB/project5 DURS: 4368.981, 3623.553, 361.399 +CT: 455 PROJECT: groupC/project7 DURS: 387.295, 381.874, 373.988 +``` diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md index 3c828ef1726..ed46876619d 100644 --- a/doc/install/aws/index.md +++ b/doc/install/aws/index.md @@ -115,12 +115,12 @@ RDS instances as well: 1. Follow the same steps to create all subnets: - | Name tag | Type | Availability Zone | CIDR block | - | ------------------------- | ------- | ----------------- | ---------- | - | `gitlab-public-10.0.0.0` | public | `us-west-2a` | `10.0.0.0` | - | `gitlab-private-10.0.1.0` | private | `us-west-2a` | `10.0.1.0` | - | `gitlab-public-10.0.2.0` | public | `us-west-2b` | `10.0.2.0` | - | `gitlab-private-10.0.3.0` | private | `us-west-2b` | `10.0.3.0` | + | Name tag | Type | Availability Zone | CIDR block | + | ------------------------- | ------- | ----------------- | ------------- | + | `gitlab-public-10.0.0.0` | public | `us-west-2a` | `10.0.0.0/24` | + | `gitlab-private-10.0.1.0` | private | `us-west-2a` | `10.0.1.0/24` | + | `gitlab-public-10.0.2.0` | public | `us-west-2b` | `10.0.2.0/24` | + | `gitlab-private-10.0.3.0` | private | `us-west-2b` | `10.0.3.0/24` | ### Create NAT Gateways diff --git a/doc/user/project/integrations/img/prometheus_dashboard_bar_chart_panel_type_v12.10.png b/doc/user/project/integrations/img/prometheus_dashboard_bar_chart_panel_type_v12.10.png Binary files differnew file mode 100644 index 00000000000..593e31477f4 --- /dev/null +++ b/doc/user/project/integrations/img/prometheus_dashboard_bar_chart_panel_type_v12.10.png diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md index 1ff58930a61..230b4a379b1 100644 --- a/doc/user/project/integrations/prometheus.md +++ b/doc/user/project/integrations/prometheus.md @@ -434,6 +434,35 @@ Note the following properties: ![anomaly panel type](img/prometheus_dashboard_anomaly_panel_type.png) +##### Bar chart + +To add a bar chart to a dashboard, look at the following sample dashboard file: + +```yaml +dashboard: 'Dashboard Title' +panel_groups: + - group: 'Group title' + panels: + - type: bar + title: "Http Handlers" + x_label: 'Response Size' + y_axis: + name: "Handlers" + metrics: + - id: prometheus_http_response_size_bytes_bucket + query_range: "sum(increase(prometheus_http_response_size_bytes_bucket[1d])) by (handler)" + unit: 'Bytes' +``` + +Note the following properties: + +| Property | Type | Required | Description | +| ------ | ------ | ------ | ------ | +| `type` | string | yes | Type of panel to be rendered. For bar chart types, set to `bar` | +| `query_range` | yes | yes | For bar chart, you must use a [range query] + +![bar chart panel type](img/prometheus_dashboard_bar_chart_panel_type_v12.10.png) + ##### Column chart To add a column panel type to a dashboard, look at the following sample dashboard file: diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 14cd6a7a2d1..49c1f32affc 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9723,6 +9723,9 @@ msgstr "" msgid "GitLabPages|Save" msgstr "" +msgid "GitLabPages|Something went wrong while obtaining Let's Encrypt certificate for %{domain}. To retry visit your %{link_start}domain details%{link_end}." +msgstr "" + msgid "GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it." msgstr "" @@ -24067,7 +24070,7 @@ msgstr "" msgid "is not a valid X509 certificate." msgstr "" -msgid "is not allowed for sign-up" +msgid "is not allowed. Try again with a different email address, or contact your GitLab admin." msgstr "" msgid "is not an email you own" diff --git a/package.json b/package.json index 225c8e7817b..b3c01541d0e 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@gitlab/ui": "^10.0.1", "@gitlab/visual-review-tools": "1.5.1", "@sentry/browser": "^5.10.2", - "@sourcegraph/code-host-integration": "0.0.33", + "@sourcegraph/code-host-integration": "0.0.34", "apollo-cache-inmemory": "^1.6.3", "apollo-client": "^2.6.4", "apollo-link": "^1.2.11", diff --git a/rubocop/cop/migration/add_columns_to_wide_tables.rb b/rubocop/cop/migration/add_columns_to_wide_tables.rb new file mode 100644 index 00000000000..4618e4ae890 --- /dev/null +++ b/rubocop/cop/migration/add_columns_to_wide_tables.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require_relative '../../migration_helpers' + +module RuboCop + module Cop + module Migration + # Cop that prevents adding columns to wide tables. + class AddColumnsToWideTables < RuboCop::Cop::Cop + include MigrationHelpers + + MSG = '`%s` is a wide table with several columns, addig more should be avoided unless absolutely necessary.' \ + ' Consider storing the column in a different table or creating a new one.'.freeze + + BLACKLISTED_METHODS = %i[ + add_column + add_column_with_default + add_reference + add_timestamps_with_timezone + ].freeze + + def on_send(node) + return unless in_migration?(node) + + method_name = node.children[1] + table_name = node.children[2] + + return unless offense?(method_name, table_name) + + add_offense(node, location: :selector, message: format(MSG, table_name.value)) + end + + private + + def offense?(method_name, table_name) + wide_table?(table_name) && + BLACKLISTED_METHODS.include?(method_name) + end + + def wide_table?(table_name) + table_name && table_name.type == :sym && + WIDE_TABLES.include?(table_name.value) + end + end + end + end +end diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb index b5edb502d4c..5fa6f8c2a2c 100644 --- a/rubocop/migration_helpers.rb +++ b/rubocop/migration_helpers.rb @@ -6,7 +6,7 @@ module RuboCop plan_limits ].freeze - # Blacklisted table due to: + # Blacklisted tables due to: # - size in GB (>= 10 GB on GitLab.com as of 02/2020) # - number of records BLACKLISTED_TABLES = %i[ @@ -44,6 +44,15 @@ module RuboCop web_hook_logs ].freeze + # Blacklisted tables due to: + # - number of columns (> 50 on GitLab.com as of 03/2020) + # - number of records + WIDE_TABLES = %i[ + users + projects + ci_builds + ].freeze + # Returns true if the given node originated from the db/migrate directory. def in_migration?(node) dirname(node).end_with?('db/migrate', 'db/geo/migrate') || in_post_deployment_migration?(node) diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 9b956dee089..28a238a5423 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -72,6 +72,21 @@ describe 'Projects > Settings > Repository settings' do expect(project.remote_mirrors.first.only_protected_branches).to eq(true) end + it 'creates a push mirror that keeps divergent refs', :js do + select_direction + + fill_in 'url', with: 'ssh://user@localhost/project.git' + fill_in 'Password', with: 'password' + check 'Keep divergent refs' + + Sidekiq::Testing.fake! do + click_button 'Mirror repository' + end + + expect(page).to have_content('Mirroring settings were successfully updated') + expect(project.reload.remote_mirrors.first.keep_divergent_refs).to eq(true) + end + it 'generates an SSH public key on submission', :js do fill_in 'url', with: 'ssh://user@localhost/project.git' select 'SSH public key', from: 'Authentication method' @@ -110,6 +125,20 @@ describe 'Projects > Settings > Repository settings' do end end + # Removal: https://gitlab.com/gitlab-org/gitlab/-/issues/208828 + context 'with the `keep_divergent_refs` feature flag disabled' do + before do + stub_feature_flags(keep_divergent_refs: { enabled: false, thing: project }) + end + + it 'hides the "Keep divergent refs" option' do + visit project_settings_repository_path(project) + + expect(page).not_to have_selector('#keep_divergent_refs') + expect(page).not_to have_text('Keep divergent refs') + end + end + context 'repository cleanup settings' do let(:object_map_file) { Rails.root.join('spec', 'fixtures', 'bfg_object_map.txt') } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b7abcb31321..608e3a6e938 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -529,7 +529,7 @@ describe User, :do_not_mock_admin_mode do user = build(:user, email: 'info@gitlab.com') expect(user).not_to be_valid - expect(user.errors.messages[:email].first).to eq(_('is not allowed for sign-up')) + expect(user.errors.messages[:email].first).to eq(_('is not allowed. Try again with a different email address, or contact your GitLab admin.')) end it 'does accept a valid email address' do diff --git a/spec/presenters/pages_domain_presenter_spec.rb b/spec/presenters/pages_domain_presenter_spec.rb new file mode 100644 index 00000000000..1cae3a8c9be --- /dev/null +++ b/spec/presenters/pages_domain_presenter_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe PagesDomainPresenter do + using RSpec::Parameterized::TableSyntax + include LetsEncryptHelpers + + let(:presenter) { Gitlab::View::Presenter::Factory.new(domain).fabricate! } + + describe 'needs_validation?' do + where(:pages_verification_enabled, :traits, :expected) do + false | :unverified | false + false | [] | false + true | :unverified | true + true | [] | false + end + + with_them do + before do + stub_application_setting(pages_domain_verification_enabled: pages_verification_enabled) + end + + let(:domain) { create(:pages_domain, *traits) } + + it { expect(presenter.needs_verification?).to eq(expected) } + end + end + + describe 'show_auto_ssl_failed_warning?' do + subject { presenter.show_auto_ssl_failed_warning? } + + let(:domain) { create(:pages_domain) } + + before do + stub_lets_encrypt_settings + end + + it { is_expected.to eq(false) } + + context "when we failed to obtain Let's Encrypt's certificate" do + before do + domain.update!(auto_ssl_failed: true) + end + + it { is_expected.to eq(true) } + + context 'when lets_encrypt_error feature flag is disabled' do + before do + stub_feature_flags(pages_letsencrypt_errors: false) + end + + it { is_expected.to eq(false) } + end + + context "when Let's Encrypt integration is disabled" do + before do + allow(::Gitlab::LetsEncrypt).to receive(:enabled?).and_return false + end + + it { is_expected.to eq(false) } + end + + context "when domain is unverified" do + before do + domain.update!(verified_at: nil) + end + + it { is_expected.to eq(false) } + end + end + end +end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index ff002469e3c..61599f0876f 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -313,3 +313,34 @@ describe HealthCheckController, 'routing' do expect(get('/health_check/email')).to route_to('health_check#index', checks: 'email') end end + +describe InvitesController, 'routing' do + let_it_be(:member) { create(:project_member, :invited) } + + it 'to #show' do + expect(get("/-/invites/#{member.invite_token}")).to route_to('invites#show', id: member.invite_token) + end + + it 'to legacy route' do + expect(get("/invites/#{member.invite_token}")).to route_to('invites#show', id: member.invite_token) + end +end + +describe AbuseReportsController, 'routing' do + let_it_be(:user) { create(:user) } + + it 'to #new' do + expect(get("/-/abuse_reports/new?user_id=#{user.id}")).to route_to('abuse_reports#new', user_id: user.id.to_s) + end + + it 'to legacy route' do + expect(get("/abuse_reports/new?user_id=#{user.id}")).to route_to('abuse_reports#new', user_id: user.id.to_s) + end +end + +describe SentNotificationsController, 'routing' do + it 'to #unsubscribe' do + expect(get("/-/sent_notifications/4bee17d4a63ed60cf5db53417e9aeb4c/unsubscribe")) + .to route_to('sent_notifications#unsubscribe', id: '4bee17d4a63ed60cf5db53417e9aeb4c') + end +end diff --git a/spec/rubocop/cop/migration/add_columns_to_wide_tables_spec.rb b/spec/rubocop/cop/migration/add_columns_to_wide_tables_spec.rb new file mode 100644 index 00000000000..f0c64740e63 --- /dev/null +++ b/spec/rubocop/cop/migration/add_columns_to_wide_tables_spec.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'rubocop' + +require_relative '../../../../rubocop/cop/migration/add_columns_to_wide_tables' + +describe RuboCop::Cop::Migration::AddColumnsToWideTables do + include CopHelper + + let(:cop) { described_class.new } + + context 'outside of a migration' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY) + def up + add_column(:users, :another_column, :string) + end + RUBY + end + end + + context 'in a migration' do + before do + allow(cop).to receive(:in_migration?).and_return(true) + end + + context 'with wide tables' do + it 'registers an offense when adding a column to a wide table' do + offense = '`projects` is a wide table with several columns, addig more should be avoided unless absolutely necessary. Consider storing the column in a different table or creating a new one.' + + expect_offense(<<~RUBY) + def up + add_column(:projects, :another_column, :integer) + ^^^^^^^^^^ #{offense} + end + RUBY + end + + it 'registers an offense when adding a column with default to a wide table' do + offense = '`users` is a wide table with several columns, addig more should be avoided unless absolutely necessary. Consider storing the column in a different table or creating a new one.' + + expect_offense(<<~RUBY) + def up + add_column_with_default(:users, :another_column, :boolean, default: false) + ^^^^^^^^^^^^^^^^^^^^^^^ #{offense} + end + RUBY + end + + it 'registers an offense when adding a reference' do + offense = '`ci_builds` is a wide table with several columns, addig more should be avoided unless absolutely necessary. Consider storing the column in a different table or creating a new one.' + + expect_offense(<<~RUBY) + def up + add_reference(:ci_builds, :issue, :boolean, index: true) + ^^^^^^^^^^^^^ #{offense} + end + RUBY + end + + it 'registers an offense when adding timestamps' do + offense = '`projects` is a wide table with several columns, addig more should be avoided unless absolutely necessary. Consider storing the column in a different table or creating a new one.' + + expect_offense(<<~RUBY) + def up + add_timestamps_with_timezone(:projects, null: false) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{offense} + end + RUBY + end + + it 'register no offense when using other method' do + expect_no_offenses(<<~RUBY) + def up + add_concurrent_index(:projects, :new_index) + end + RUBY + end + end + + context 'with a regular table' do + it 'registers no offense for notes' do + expect_no_offenses(<<~RUBY) + def up + add_column(:notes, :another_column, :boolean) + end + RUBY + end + end + end +end diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb index 6f7250037cd..b386159541a 100644 --- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb @@ -29,7 +29,7 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor end context 'user does not have push right to repository' do - it_behaves_like 'misconfigured dashboard service response', :forbidden, %q(You are not allowed to push into this branch. Create another branch or open a merge request.) + it_behaves_like 'misconfigured dashboard service response with stepable', :forbidden, 'You are not allowed to push into this branch. Create another branch or open a merge request.' end context 'with rights to push to the repository' do @@ -40,19 +40,19 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor context 'wrong target file extension' do let(:file_name) { 'custom_dashboard.txt' } - it_behaves_like 'misconfigured dashboard service response', :bad_request, 'The file name should have a .yml extension' + it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'The file name should have a .yml extension' end context 'wrong source dashboard file' do let(:dashboard) { 'config/prometheus/common_metrics_123.yml' } - it_behaves_like 'misconfigured dashboard service response', :not_found, 'Not found.' + it_behaves_like 'misconfigured dashboard service response with stepable', :not_found, 'Not found.' end context 'path traversal attack attempt' do let(:dashboard) { 'config/prometheus/../database.yml' } - it_behaves_like 'misconfigured dashboard service response', :not_found, 'Not found.' + it_behaves_like 'misconfigured dashboard service response with stepable', :not_found, 'Not found.' end context 'path traversal attack attempt on target file' do @@ -92,7 +92,7 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor project.repository.add_branch(user, branch, 'master') end - it_behaves_like 'misconfigured dashboard service response', :bad_request, "There was an error creating the dashboard, branch named: existing_branch already exists." + it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'There was an error creating the dashboard, branch named: existing_branch already exists.' # temporary not available function for first iteration # follow up issue https://gitlab.com/gitlab-org/gitlab/issues/196237 which @@ -111,7 +111,7 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor context 'blank branch name' do let(:branch) { '' } - it_behaves_like 'misconfigured dashboard service response', :bad_request, 'There was an error creating the dashboard, branch name is invalid.' + it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'There was an error creating the dashboard, branch name is invalid.' end context 'dashboard file already exists' do @@ -129,7 +129,7 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor ).execute end - it_behaves_like 'misconfigured dashboard service response', :bad_request, "A file with 'custom_dashboard.yml' already exists in custom_dashboard branch" + it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, "A file with 'custom_dashboard.yml' already exists in custom_dashboard branch" end it 'extends dashboard template path to absolute url' do diff --git a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb index 48e4b4a18fd..bcd69b9e4f6 100644 --- a/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb +++ b/spec/support/shared_examples/services/metrics/dashboard_shared_examples.rb @@ -107,3 +107,14 @@ RSpec.shared_examples 'valid dashboard update process' do service_call end end + +RSpec.shared_examples 'misconfigured dashboard service response with stepable' do |status_code, message = nil| + it 'returns an appropriate message and status code', :aggregate_failures do + result = service_call + + expect(result.keys).to contain_exactly(:message, :http_status, :status, :last_step) + expect(result[:status]).to eq(:error) + expect(result[:http_status]).to eq(status_code) + expect(result[:message]).to eq(message) if message + end +end diff --git a/spec/views/projects/pages/show.html.haml_spec.rb b/spec/views/projects/pages/show.html.haml_spec.rb new file mode 100644 index 00000000000..80410e7bc32 --- /dev/null +++ b/spec/views/projects/pages/show.html.haml_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'projects/pages/show' do + include LetsEncryptHelpers + + let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + let(:domain) { create(:pages_domain, project: project) } + + before do + allow(project).to receive(:pages_deployed?).and_return(true) + stub_pages_setting(external_https: true) + stub_lets_encrypt_settings + project.add_maintainer(user) + + assign(:project, project) + allow(view).to receive(:current_user).and_return(user) + assign(:domains, [domain]) + end + + describe 'validation warning' do + let(:warning_message) do + "#{domain.domain} is not verified. To learn how to verify ownership, "\ + "visit your domain details." + end + + it "doesn't show auto ssl error warning" do + render + + expect(rendered).not_to have_content(warning_message) + end + + context "when domain is not verified" do + before do + domain.update!(verified_at: nil) + end + + it 'shows auto ssl error warning' do + render + + expect(rendered).to have_content(warning_message) + end + end + end + + describe "warning about failed Let's Encrypt" do + let(:error_message) do + "Something went wrong while obtaining Let's Encrypt certificate for #{domain.domain}. "\ + "To retry visit your domain details." + end + + it "doesn't show auto ssl error warning" do + render + + expect(rendered).not_to have_content(error_message) + end + + context "when we failed to obtain Let's Encrypt's certificate" do + before do + domain.update!(auto_ssl_failed: true) + end + + it 'shows auto ssl error warning' do + render + + expect(rendered).to have_content(error_message) + end + end + end +end diff --git a/yarn.lock b/yarn.lock index 4886a3651d1..d78aee490e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1036,10 +1036,10 @@ "@sentry/types" "5.10.0" tslib "^1.9.3" -"@sourcegraph/code-host-integration@0.0.33": - version "0.0.33" - resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.33.tgz#133f11535be0cc937fbadc6a6951ee9fd21fbe1d" - integrity sha512-J49ljHsSIe8KD5+ke9C3ugGO9T6R2M96miiGEZFRHJQ7FXyKi/zP5N4BFVweHjE+b15BLSicoaAnnyg4nhIBIw== +"@sourcegraph/code-host-integration@0.0.34": + version "0.0.34" + resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.34.tgz#c8f94854d64fe035926bbda7bed3a538a7259d03" + integrity sha512-TAa5kU/zPb9PfB4HIhaEDhKKdW5Fx9YVx9WWMOwz9elD0y9FZoAXDO1o4Pz1cm1IP/VZwd8csypAWgfxsAmfzw== "@types/anymatch@*": version "1.3.0" |