Commit 6315ed96 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent fedf978f
# Make sure to update all the similar conditions in other CI config files if you modify these conditions # Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-default: &if-default .if-not-canonical-namespace: &if-not-canonical-namespace
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG' if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/'
# Make sure to update all the similar conditions in other CI config files if you modify these conditions # Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-default-ee: &if-default-ee .if-not-ee: &if-not-ee
if: '($CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG) && $CI_PROJECT_NAME =~ /^gitlab(-ee)?$/' if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/'
# Make sure to update all the similar conditions in other CI config files if you modify these conditions # Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-master: &if-master .if-master-refs: &if-master-refs
if: '$CI_COMMIT_REF_NAME == "master"' if: '$CI_COMMIT_REF_NAME == "master"'
# Make sure to update all the similar conditions in other CI config files if you modify these conditions
.if-default-refs: &if-default-refs
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG'
# Make sure to update all the similar patterns in other CI config files if you modify these patterns # Make sure to update all the similar patterns in other CI config files if you modify these patterns
.code-backstage-patterns: &code-backstage-patterns .code-backstage-patterns: &code-backstage-patterns
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
...@@ -33,6 +37,32 @@ ...@@ -33,6 +37,32 @@
- "{,ee/}spec/**/*" - "{,ee/}spec/**/*"
- "doc/README.md" # Some RSpec test rely on this file - "doc/README.md" # Some RSpec test rely on this file
# Make sure to update all the similar patterns in other CI config files if you modify these patterns
.code-backstage-patterns-qa: &code-backstage-patterns-qa
- ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,scss-lint}.yml"
- ".csscomb.json"
- "Dockerfile.assets"
- "*_VERSION"
- "Gemfile{,.lock}"
- "Rakefile"
- "{babel.config,jest.config}.js"
- "config.ru"
- "{package.json,yarn.lock}"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# Backstage changes
- "Dangerfile"
- "danger/**/*"
- "{,ee/}fixtures/**/*"
- "{,ee/}rubocop/**/*"
- "{,ee/}spec/**/*"
- "doc/README.md" # Some RSpec test rely on this file
# QA changes
- ".dockerignore"
- "qa/**/*"
.assets-compile-cache: .assets-compile-cache:
cache: cache:
paths: paths:
...@@ -46,10 +76,8 @@ ...@@ -46,10 +76,8 @@
extends: extends:
- .default-tags - .default-tags
- .default-retry - .default-retry
- .default-only
- .default-before_script - .default-before_script
- .assets-compile-cache - .assets-compile-cache
- .only:changes-code-backstage-qa
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-19.03.1 image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-19.03.1
stage: prepare stage: prepare
services: services:
...@@ -80,24 +108,29 @@ ...@@ -80,24 +108,29 @@
- time scripts/build_assets_image - time scripts/build_assets_image
- scripts/clean-old-cached-assets - scripts/clean-old-cached-assets
- rm -f /etc/apt/sources.list.d/google*.list # We don't need to update Chrome here - rm -f /etc/apt/sources.list.d/google*.list # We don't need to update Chrome here
only:
variables:
- $CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE =~ /^gitlab-org($|\/)/ # Matches the gitlab-org group and its subgroups
- $CI_SERVER_HOST == "dev.gitlab.org"
tags: tags:
- gitlab-org - gitlab-org
- docker - docker
gitlab:assets:compile pull-push-cache: gitlab:assets:compile pull-push-cache:
extends: .gitlab:assets:compile-metadata extends: .gitlab:assets:compile-metadata
only: rules:
refs: - <<: *if-not-canonical-namespace
- master when: never
- <<: *if-master-refs
changes: *code-backstage-patterns-qa
when: on_success
cache: cache:
policy: pull-push policy: pull-push
gitlab:assets:compile pull-cache: gitlab:assets:compile pull-cache:
extends: .gitlab:assets:compile-metadata extends: .gitlab:assets:compile-metadata
rules:
- <<: *if-not-canonical-namespace
when: never
- <<: *if-default-refs
changes: *code-backstage-patterns-qa
when: on_success
cache: cache:
policy: pull policy: pull
...@@ -105,10 +138,8 @@ gitlab:assets:compile pull-cache: ...@@ -105,10 +138,8 @@ gitlab:assets:compile pull-cache:
extends: extends:
- .default-tags - .default-tags
- .default-retry - .default-retry
- .default-only
- .default-before_script - .default-before_script
- .assets-compile-cache - .assets-compile-cache
- .only:changes-code-backstage-qa
stage: prepare stage: prepare
script: script:
- node --version - node --version
...@@ -130,28 +161,46 @@ gitlab:assets:compile pull-cache: ...@@ -130,28 +161,46 @@ gitlab:assets:compile pull-cache:
compile-assets pull-push-cache: compile-assets pull-push-cache:
extends: .compile-assets-metadata extends: .compile-assets-metadata
only: rules:
refs: - <<: *if-master-refs
- master changes: *code-backstage-patterns-qa
when: on_success
cache: cache:
policy: pull-push policy: pull-push
compile-assets pull-push-cache foss: compile-assets pull-push-cache foss:
extends: [".compile-assets-metadata", ".only-ee-as-if-foss"] extends:
only: - .compile-assets-metadata
refs: - .as-if-foss
- master rules:
- <<: *if-not-ee
when: never
- <<: *if-master-refs
changes: *code-backstage-patterns-qa
when: on_success
cache: cache:
policy: pull-push policy: pull-push
key: "assets-compile:v8:foss" key: "assets-compile:v8:foss"
compile-assets pull-cache: compile-assets pull-cache:
extends: .compile-assets-metadata extends: .compile-assets-metadata
rules:
- <<: *if-default-refs
changes: *code-backstage-patterns-qa
when: on_success
cache: cache:
policy: pull policy: pull
compile-assets pull-cache foss: compile-assets pull-cache foss:
extends: [".compile-assets-metadata", ".only-ee-as-if-foss"] extends:
- .compile-assets-metadata
- .as-if-foss
rules:
- <<: *if-not-ee
when: never
- <<: *if-default-refs
changes: *code-backstage-patterns-qa
when: on_success
cache: cache:
policy: pull policy: pull
key: "assets-compile:v8:foss" key: "assets-compile:v8:foss"
...@@ -240,7 +289,7 @@ jest-foss: ...@@ -240,7 +289,7 @@ jest-foss:
- .default-cache - .default-cache
stage: test stage: test
rules: rules:
- <<: *if-master - <<: *if-master-refs
when: on_success when: on_success
dependencies: [] dependencies: []
cache: cache:
...@@ -274,7 +323,7 @@ webpack-dev-server: ...@@ -274,7 +323,7 @@ webpack-dev-server:
- .default-cache - .default-cache
stage: test stage: test
rules: rules:
- <<: *if-default - <<: *if-default-refs
changes: *code-backstage-patterns changes: *code-backstage-patterns
when: on_success when: on_success
needs: ["setup-test-env", "compile-assets pull-cache"] needs: ["setup-test-env", "compile-assets pull-cache"]
......
...@@ -230,7 +230,11 @@ ...@@ -230,7 +230,11 @@
- $CI_PROJECT_NAME == "gitlab" - $CI_PROJECT_NAME == "gitlab"
- $CI_PROJECT_NAME == "gitlab-ee" # Support former project name for forks/mirrors - $CI_PROJECT_NAME == "gitlab-ee" # Support former project name for forks/mirrors
.only-ee-as-if-foss: .as-if-foss:
extends: .only-ee
variables: variables:
FOSS_ONLY: '1' FOSS_ONLY: '1'
.only-ee-as-if-foss:
extends:
- .only-ee
- .as-if-foss
import Cookies from 'js-cookie';
const handleOnDismiss = ({ currentTarget }) => {
currentTarget.removeEventListener('click', handleOnDismiss);
const {
dataset: { id },
} = currentTarget;
Cookies.set(`hide_broadcast_notification_message_${id}`, true);
const notification = document.querySelector(`.js-broadcast-notification-${id}`);
notification.parentNode.removeChild(notification);
};
export default () => {
const dismissButton = document.querySelector('.js-dismiss-current-broadcast-notification');
if (dismissButton) {
dismissButton.addEventListener('click', handleOnDismiss);
}
};
...@@ -35,6 +35,7 @@ import initPerformanceBar from './performance_bar'; ...@@ -35,6 +35,7 @@ import initPerformanceBar from './performance_bar';
import initSearchAutocomplete from './search_autocomplete'; import initSearchAutocomplete from './search_autocomplete';
import GlFieldErrors from './gl_field_errors'; import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers'; import initUserPopovers from './user_popovers';
import initBroadcastNotifications from './broadcast_notification';
import { initUserTracking } from './tracking'; import { initUserTracking } from './tracking';
import { __ } from './locale'; import { __ } from './locale';
...@@ -105,6 +106,7 @@ function deferredInitialisation() { ...@@ -105,6 +106,7 @@ function deferredInitialisation() {
initUsagePingConsent(); initUsagePingConsent();
initUserPopovers(); initUserPopovers();
initUserTracking(); initUserTracking();
initBroadcastNotifications();
if (document.querySelector('.search')) initSearchAutocomplete(); if (document.querySelector('.search')) initSearchAutocomplete();
......
...@@ -6,19 +6,16 @@ module BroadcastMessagesHelper ...@@ -6,19 +6,16 @@ module BroadcastMessagesHelper
end end
def current_broadcast_notification_message def current_broadcast_notification_message
BroadcastMessage.current_notification_messages(request.path).last not_hidden_messages = BroadcastMessage.current_notification_messages(request.path).select do |message|
cookies["hide_broadcast_notification_message_#{message.id}"].blank?
end
not_hidden_messages.last
end end
def broadcast_message(message, opts = {}) def broadcast_message(message, opts = {})
return unless message.present? return unless message.present?
classes = "broadcast-#{message.broadcast_type}-message #{opts[:preview] && 'preview'}" render "shared/broadcast_message", { message: message, opts: opts }
content_tag :div, dir: 'auto', class: classes, style: broadcast_message_style(message) do
concat sprite_icon('bullhorn', size: 16, css_class: 'vertical-align-text-top')
concat ' '
concat render_broadcast_message(message)
end
end end
def broadcast_message_style(broadcast_message) def broadcast_message_style(broadcast_message)
......
...@@ -27,7 +27,8 @@ module Ci ...@@ -27,7 +27,8 @@ module Ci
license_management: 'gl-license-management-report.json', license_management: 'gl-license-management-report.json',
license_scanning: 'gl-license-scanning-report.json', license_scanning: 'gl-license-scanning-report.json',
performance: 'performance.json', performance: 'performance.json',
metrics: 'metrics.txt' metrics: 'metrics.txt',
lsif: 'lsif.sqlite3'
}.freeze }.freeze
INTERNAL_TYPES = { INTERNAL_TYPES = {
...@@ -52,7 +53,8 @@ module Ci ...@@ -52,7 +53,8 @@ module Ci
dast: :raw, dast: :raw,
license_management: :raw, license_management: :raw,
license_scanning: :raw, license_scanning: :raw,
performance: :raw performance: :raw,
lsif: :raw
}.freeze }.freeze
TYPE_AND_FORMAT_PAIRS = INTERNAL_TYPES.merge(REPORT_TYPES).freeze TYPE_AND_FORMAT_PAIRS = INTERNAL_TYPES.merge(REPORT_TYPES).freeze
...@@ -114,7 +116,8 @@ module Ci ...@@ -114,7 +116,8 @@ module Ci
performance: 11, ## EE-specific performance: 11, ## EE-specific
metrics: 12, ## EE-specific metrics: 12, ## EE-specific
metrics_referee: 13, ## runner referees metrics_referee: 13, ## runner referees
network_referee: 14 ## runner referees network_referee: 14, ## runner referees
lsif: 15 # LSIF dump for code navigation
} }
enum file_format: { enum file_format: {
......
...@@ -27,7 +27,7 @@ module AtomicInternalId ...@@ -27,7 +27,7 @@ module AtomicInternalId
extend ActiveSupport::Concern extend ActiveSupport::Concern
class_methods do class_methods do
def has_internal_id(column, scope:, init:, ensure_if: nil, track_if: nil, presence: true) # rubocop:disable Naming/PredicateName def has_internal_id(column, scope:, init:, ensure_if: nil, track_if: nil, presence: true, backfill: false) # rubocop:disable Naming/PredicateName
# We require init here to retain the ability to recalculate in the absence of a # We require init here to retain the ability to recalculate in the absence of a
# InternalId record (we may delete records in `internal_ids` for example). # InternalId record (we may delete records in `internal_ids` for example).
raise "has_internal_id requires a init block, none given." unless init raise "has_internal_id requires a init block, none given." unless init
...@@ -38,6 +38,8 @@ module AtomicInternalId ...@@ -38,6 +38,8 @@ module AtomicInternalId
validates column, presence: presence validates column, presence: presence
define_method("ensure_#{scope}_#{column}!") do define_method("ensure_#{scope}_#{column}!") do
return if backfill && self.class.where(column => nil).exists?
scope_value = internal_id_read_scope(scope) scope_value = internal_id_read_scope(scope)
value = read_attribute(column) value = read_attribute(column)
return value unless scope_value return value unless scope_value
......
...@@ -21,7 +21,7 @@ class InternalId < ApplicationRecord ...@@ -21,7 +21,7 @@ class InternalId < ApplicationRecord
belongs_to :project belongs_to :project
belongs_to :namespace belongs_to :namespace
enum usage: { issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4, ci_pipelines: 5 } enum usage: { issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4, ci_pipelines: 5, operations_feature_flags: 6 }
validates :usage, presence: true validates :usage, presence: true
......
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusDashboard
include ActiveModel::Model
attr_accessor :dashboard, :panel_groups
validates :dashboard, presence: true
validates :panel_groups, presence: true
def self.from_json(json_content)
dashboard = new(
dashboard: json_content['dashboard'],
panel_groups: json_content['panel_groups'].map { |group| PrometheusPanelGroup.from_json(group) }
)
dashboard.tap(&:validate!)
end
def to_yaml
self.as_json(only: valid_attributes).to_yaml
end
private
def valid_attributes
%w(panel_groups panels metrics group priority type title y_label weight id unit label query query_range dashboard)
end
end
end
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusMetric
include ActiveModel::Model
attr_accessor :id, :unit, :label, :query, :query_range
validates :unit, presence: true
validates :query, presence: true, unless: :query_range
validates :query_range, presence: true, unless: :query
def self.from_json(json_content)
metric = PrometheusMetric.new(
id: json_content['id'],
unit: json_content['unit'],
label: json_content['label'],
query: json_content['query'],
query_range: json_content['query_range']
)
metric.tap(&:validate!)
end
end
end
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusPanel
include ActiveModel::Model
attr_accessor :type, :title, :y_label, :weight, :metrics
validates :title, presence: true
validates :metrics, presence: true
def self.from_json(json_content)
panel = new(
type: json_content['type'],
title: json_content['title'],
y_label: json_content['y_label'],
weight: json_content['weight'],
metrics: json_content['metrics'].map { |metric| PrometheusMetric.from_json(metric) }
)
panel.tap(&:validate!)
end
end
end
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusPanelGroup
include ActiveModel::Model
attr_accessor :group, :priority, :panels
validates :group, presence: true
validates :panels, presence: true
def self.from_json(json_content)
panel_group = new(
group: json_content['group'],
priority: json_content['priority'],
panels: json_content['panels'].map { |panel| PrometheusPanel.from_json(panel) }
)
panel_group.tap(&:validate!)
end
end
end
...@@ -927,22 +927,12 @@ class Repository ...@@ -927,22 +927,12 @@ class Repository
def ancestor?(ancestor_id, descendant_id) def ancestor?(ancestor_id, descendant_id)
return false if ancestor_id.nil? || descendant_id.nil? return false if ancestor_id.nil? || descendant_id.nil?
counter = Gitlab::Metrics.counter(
:repository_ancestor_calls_total,
'The number of times we call Repository#ancestor with valid arguments')
cache_hit = true
cache_key = "ancestor:#{ancestor_id}:#{descendant_id}" cache_key = "ancestor:#{ancestor_id}:#{descendant_id}"
result = request_store_cache.fetch(cache_key) do request_store_cache.fetch(cache_key) do
cache.fetch(cache_key) do cache.fetch(cache_key) do
cache_hit = false
raw_repository.ancestor?(ancestor_id, descendant_id) raw_repository.ancestor?(ancestor_id, descendant_id)
end end
end end
counter.increment(cache_hit: cache_hit.to_s)
result
end end
def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil, prune: true) def fetch_as_mirror(url, forced: false, refmap: :all_refs, remote_name: nil, prune: true)
......
%div{ class: "broadcast-#{message.broadcast_type}-message #{opts[:preview] && 'preview'} js-broadcast-notification-#{message.id} d-flex",
style: broadcast_message_style(message), dir: 'auto' }
%div
= sprite_icon('bullhorn', size: 16, css_class: 'vertical-align-text-top')
= render_broadcast_message(message)
- if message.notification? && opts[:preview].blank?
%button.js-dismiss-current-broadcast-notification.btn.btn-link.text-dark.pl-2.pr-2{ 'aria-label' => _('Close'), :type => 'button', data: { id: message.id } }
%i.fa.fa-times
---
title: Migrate epic, epic notes mentions to respective DB table
merge_request: 22333
author:
type: changed
---
title: Add validation for custom PrometheusDashboard
merge_request: 22893
author:
type: added
---
title: Add support for lsif artifact report
merge_request: 23672
author:
type: added
---
title: Add iid to operations_feature_flags and backfill
merge_request: 22175
author:
type: added
---
title: Eliminate statement timeouts when namespace is blank
merge_request: 23839
author:
type: fixed
...@@ -120,9 +120,7 @@ Rails.application.routes.draw do ...@@ -120,9 +120,7 @@ Rails.application.routes.draw do
draw :country draw :country
draw :country_state draw :country_state
draw :subscription draw :subscription
end
Gitlab.ee do
constraints(-> (*) { Gitlab::Analytics.any_features_enabled? }) do constraints(-> (*) { Gitlab::Analytics.any_features_enabled? }) do
draw :analytics draw :analytics
end end
...@@ -168,11 +166,6 @@ Rails.application.routes.draw do ...@@ -168,11 +166,6 @@ Rails.application.routes.draw do
end end
end end
draw :api
draw :sidekiq
draw :help
draw :snippets
# Invites # Invites
resources :invites, only: [:show], constraints: { id: /[A-Za-z0-9_-]+/ } do resources :invites, only: [:show], constraints: { id: /[A-Za-z0-9_-]+/ } do
member do member do
...@@ -193,6 +186,25 @@ Rails.application.routes.draw do ...@@ -193,6 +186,25 @@ Rails.application.routes.draw do
# Notification settings # Notification settings
resources :notification_settings, only: [:create, :update] resources :notification_settings, only: [:create, :update]
resources :groups, only: [:index, :new, :create] do
post :preview_markdown
end
resources :projects, only: [:index, :new, :create]
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
draw :help
draw :snippets
draw :google_api draw :google_api
draw :import draw :import
draw :uploads draw :uploads
......
# frozen_string_literal: true # frozen_string_literal: true
# rubocop: disable Cop/PutGroupRoutesUnderScope
resources :groups, only: [:index, :new, :create] do
post :preview_markdown
end
# rubocop: enable Cop/PutGroupRoutesUnderScope
constraints(::Constraints::GroupUrlConstrainer.new) do constraints(::Constraints::GroupUrlConstrainer.new) do
scope(path: 'groups/*id', scope(path: 'groups/*id',
controller: :groups, controller: :groups,
......
# frozen_string_literal: true # frozen_string_literal: true
# rubocop: disable Cop/PutProjectRoutesUnderScope
resources :projects, only: [:index, :new, :create]
draw :git_http
get '/projects/:id' => 'projects#resolve'
# rubocop: enable Cop/PutProjectRoutesUnderScope
constraints(::Constraints::ProjectUrlConstrainer.new) do constraints(::Constraints::ProjectUrlConstrainer.new) do
# If the route has a wildcard segment, the segment has a regex constraint, # If the route has a wildcard segment, the segment has a regex constraint,
# the segment is potentially followed by _another_ wildcard segment, and # the segment is potentially followed by _another_ wildcard segment, and
......
...@@ -7,9 +7,13 @@ class AddMergeTrainEnabledToCiCdSettings < ActiveRecord::Migration[5.1] ...@@ -7,9 +7,13 @@ class AddMergeTrainEnabledToCiCdSettings < ActiveRecord::Migration[5.1]
disable_ddl_transaction! disable_ddl_transaction!
# rubocop:disable Migration/UpdateLargeTable
# rubocop:disable Migration/AddColumnWithDefault
def up def up
add_column_with_default :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: false # rubocop:disable Migration/AddColumnWithDefault add_column_with_default :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: false
end end
# rubocop:enable Migration/UpdateLargeTable
# rubocop:enable Migration/AddColumnWithDefault
def down def down
remove_column :project_ci_cd_settings, :merge_trains_enabled remove_column :project_ci_cd_settings, :merge_trains_enabled
......
# frozen_string_literal: true
class AddIidToOperationsFeatureFlags < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
add_column :operations_feature_flags, :iid, :integer
end
def down
remove_column :operations_feature_flags, :iid
end
end
# frozen_string_literal: true
class AddIndexOnOperationsFeatureFlagsIid < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :operations_feature_flags, [:project_id, :iid], unique: true
end
def down
remove_concurrent_index :operations_feature_flags, [:project_id, :iid]
end
end
# frozen_string_literal: true
class MigrateEpicMentionsToDb < ActiveRecord::Migration[5.2]
DOWNTIME = false
disable_ddl_transaction!
DELAY = 2.minutes.to_i
BATCH_SIZE = 10000
MIGRATION = 'UserMentions::CreateResourceUserMention'
JOIN = "LEFT JOIN epic_user_mentions on epics.id = epic_user_mentions.epic_id"
QUERY_CONDITIONS = "(description like '%@%' OR title like '%@%') AND epic_user_mentions.epic_id is null"
class Epic < ActiveRecord::Base
include EachBatch
self.table_name = 'epics'
end
def up
return unless Gitlab.ee?
Epic
.joins(JOIN)
.where(QUERY_CONDITIONS)
.each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck(Arel.sql('MIN(epics.id)'), Arel.sql('MAX(epics.id)')).first
BackgroundMigrationWorker.perform_in(index * DELAY, MIGRATION, ['Epic', JOIN, QUERY_CONDITIONS, false, *range])
end
end
def down
# no-op
end
end
# frozen_string_literal: true
class MigrateEpicNotesMentionsToDb < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
DELAY = 2.minutes.to_i
BATCH_SIZE = 10000
MIGRATION = 'UserMentions::CreateResourceUserMention'
INDEX_NAME = 'epic_mentions_temp_index'
INDEX_CONDITION = "note LIKE '%@%'::text AND notes.noteable_type = 'Epic'"
QUERY_CONDITIONS = "#{INDEX_CONDITION} AND epic_user_mentions.epic_id IS NULL"
JOIN = 'LEFT JOIN epic_user_mentions ON notes.id = epic_user_mentions.note_id'
class Note < ActiveRecord::Base
include EachBatch
self.table_name = 'notes'
end
def up
return unless Gitlab.ee?
# create temporary index for notes with mentions, may take well over 1h
add_concurrent_index(:notes, :id, where: INDEX_CONDITION, name: INDEX_NAME)
Note
.joins(JOIN)
.where(QUERY_CONDITIONS)
.each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck(Arel.sql('MIN(notes.id)'), Arel.sql('MAX(notes.id)')).first
BackgroundMigrationWorker.perform_in(index * DELAY, MIGRATION, ['Epic', JOIN, QUERY_CONDITIONS, true, *range])
end
end
def down
# no-op
# temporary index is to be dropped in a different migration in an upcoming release:
# https://gitlab.com/gitlab-org/gitlab/issues/196842
end
end
...@@ -12,6 +12,6 @@ class DropProjectCiCdSettingsMergeTrainsEnabled < ActiveRecord::Migration[5.2] ...@@ -12,6 +12,6 @@ class DropProjectCiCdSettingsMergeTrainsEnabled < ActiveRecord::Migration[5.2]
end end
def down def down
add_column_with_default :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: true add_column_with_default :project_ci_cd_settings, :merge_trains_enabled, :boolean, default: false, allow_null: true # rubocop:disable Migration/UpdateLargeTable
end end
end end
# frozen_string_literal: true
class BackfillOperationsFeatureFlagsIid < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
###
# This should update about 700 rows on gitlab.com
# Execution time is predicted to take less than a second based on #database-lab results
# https://gitlab.com/gitlab-org/gitlab/merge_requests/22175#migration-performance
###
def up
execute('LOCK operations_feature_flags IN ACCESS EXCLUSIVE MODE')
backfill_iids('operations_feature_flags')
change_column_null :operations_feature_flags, :iid, false
end
def down
change_column_null :operations_feature_flags, :iid, true
end
end
# frozen_string_literal: true
class DeleteInternalIdsWhereFeatureFlagsUsage < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sql = <<~SQL
DELETE FROM internal_ids WHERE usage = 6
SQL
execute(sql)
end
def down
# no-op
end
end
...@@ -2778,6 +2778,7 @@ ActiveRecord::Schema.define(version: 2020_01_27_090233) do ...@@ -2778,6 +2778,7 @@ ActiveRecord::Schema.define(version: 2020_01_27_090233) do
t.index ["commit_id"], name: "index_notes_on_commit_id" t.index ["commit_id"], name: "index_notes_on_commit_id"
t.index ["created_at"], name: "index_notes_on_created_at" t.index ["created_at"], name: "index_notes_on_created_at"
t.index ["discussion_id"], name: "index_notes_on_discussion_id" t.index ["discussion_id"], name: "index_notes_on_discussion_id"
t.index ["id"], name: "epic_mentions_temp_index", where: "((note ~~ '%@%'::text) AND ((noteable_type)::text = 'Epic'::text))"
t.index ["line_code"], name: "index_notes_on_line_code" t.index ["line_code"], name: "index_notes_on_line_code"
t.index ["note"], name: "index_notes_on_note_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["note"], name: "index_notes_on_note_trigram", opclass: :gin_trgm_ops, using: :gin
t.index ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type" t.index ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type"
...@@ -2881,6 +2882,8 @@ ActiveRecord::Schema.define(version: 2020_01_27_090233) do ...@@ -2881,6 +2882,8 @@ ActiveRecord::Schema.define(version: 2020_01_27_090233) do
t.datetime_with_timezone "updated_at", null: false t.datetime_with_timezone "updated_at", null: false
t.string "name", null: false t.string "name", null: false
t.text "description" t.text "description"
t.integer "iid", null: false
t.index ["project_id", "iid"], name: "index_operations_feature_flags_on_project_id_and_iid", unique: true
t.index ["project_id", "name"], name: "index_operations_feature_flags_on_project_id_and_name", unique: true t.index ["project_id", "name"], name: "index_operations_feature_flags_on_project_id_and_name", unique: true
end end
......
...@@ -327,7 +327,7 @@ On different cloud vendors a best effort like for like can be used. ...@@ -327,7 +327,7 @@ On different cloud vendors a best effort like for like can be used.
| Service | Nodes | Configuration | GCP type | | Service | Nodes | Configuration | GCP type |
| ----------------------------|-------|-----------------------|---------------| | ----------------------------|-------|-----------------------|---------------|
| GitLab Rails[^1] | 15 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | | GitLab Rails[^1] | 15 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
| PostgreSQL | 3 | 8 vCPU, 30GB Memory | n1-standard-8 | | PostgreSQL | 3 | 16 vCPU, 60GB Memory | n1-standard-16 |
| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | | PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
| Gitaly[^2] [^7] | X | 64 vCPU, 240GB Memory | n1-standard-64 | | Gitaly[^2] [^7] | X | 64 vCPU, 240GB Memory | n1-standard-64 |
| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | | Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
......
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
module UserMentions
class CreateResourceUserMention
# Resources that have mentions to be migrated:
# issue, merge_request, epic, commit, snippet, design
BULK_INSERT_SIZE = 5000
ISOLATION_MODULE = 'Gitlab::BackgroundMigration::UserMentions::Models'
def perform(resource_model, join, conditions, with_notes, start_id, end_id)
resource_model = "#{ISOLATION_MODULE}::#{resource_model}".constantize if resource_model.is_a?(String)
model = with_notes ? "#{ISOLATION_MODULE}::Note".constantize : resource_model
resource_user_mention_model = resource_model.user_mention_model
records = model.joins(join).where(conditions).where(id: start_id..end_id)
records.in_groups_of(BULK_INSERT_SIZE, false).each do |records|
mentions = []
records.each do |record|
mentions << record.build_mention_values
end
no_quote_columns = [:note_id]
no_quote_columns << resource_user_mention_model.resource_foreign_key
Gitlab::Database.bulk_insert(
resource_user_mention_model.table_name,
mentions,
return_ids: true,
disable_quote: no_quote_columns,
on_conflict: :do_nothing
)
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
module UserMentions
module Models
class Epic < ActiveRecord::Base
include IsolatedMentionable
include CacheMarkdownField
attr_mentionable :title, pipeline: :single_line
attr_mentionable :description
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description, issuable_state_filter_enabled: true
self.table_name = 'epics'
belongs_to :author, class_name: "User"
belongs_to :project
belongs_to :group
def self.user_mention_model
Gitlab::BackgroundMigration::UserMentions::Models::EpicUserMention
end
def user_mention_model
self.class.user_mention_model
end
def project
nil
end
def mentionable_params
{ group: group, label_url_method: :group_epics_url }
end
def user_mention_resource_id
id
end
def user_mention_note_id
'NULL'
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
module UserMentions
module Models
class EpicUserMention < ActiveRecord::Base
self.table_name = 'epic_user_mentions'
def self.resource_foreign_key
:epic_id
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
module UserMentions
module Models
# == IsolatedMentionable concern
#
# Shortcutted for isolation version of Mentionable to be used in mentions migrations
#
module IsolatedMentionable
extend ::ActiveSupport::Concern
class_methods do
# Indicate which attributes of the Mentionable to search for GFM references.
def attr_mentionable(attr, options = {})
attr = attr.to_s
mentionable_attrs << [attr, options]
end
end
included do
# Accessor for attributes marked mentionable.
cattr_accessor :mentionable_attrs, instance_accessor: false do
[]
end
if self < Participable
participant -> (user, ext) { all_references(user, extractor: ext) }
end
end
def all_references(current_user = nil, extractor: nil)
# Use custom extractor if it's passed in the function parameters.
if extractor
extractors[current_user] = extractor
else
extractor = extractors[current_user] ||= ::Gitlab::ReferenceExtractor.new(project, current_user)
extractor.reset_memoized_values
end
self.class.mentionable_attrs.each do |attr, options|
text = __send__(attr) # rubocop:disable GitlabSecurity/PublicSend
options = options.merge(
cache_key: [self, attr],
author: author,
skip_project_check: skip_project_check?
).merge(mentionable_params)
cached_html = self.try(:updated_cached_html_for, attr.to_sym)
options[:rendered] = cached_html if cached_html
extractor.analyze(text, options)
end
extractor
end
def extractors
@extractors ||= {}
end
def skip_project_check?
false
end
def build_mention_values
refs = all_references(author)
{
"#{self.user_mention_model.resource_foreign_key}": user_mention_resource_id,
note_id: user_mention_note_id,
mentioned_users_ids: array_to_sql(refs.mentioned_users.pluck(:id)),
mentioned_projects_ids: array_to_sql(refs.mentioned_projects.pluck(:id)),
mentioned_groups_ids: array_to_sql(refs.mentioned_groups.pluck(:id))
}
end
def array_to_sql(ids_array)
return unless ids_array.present?
'{' + ids_array.join(", ") + '}'
end
private
def mentionable_params
{}
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
module UserMentions
module Models
class Note < ActiveRecord::Base
include IsolatedMentionable
include CacheMarkdownField
self.table_name = 'notes'
self.inheritance_column = :_type_disabled
attr_mentionable :note, pipeline: :note
cache_markdown_field :note, pipeline: :note, issuable_state_filter_enabled: true
belongs_to :author, class_name: "User"
belongs_to :noteable, polymorphic: true
belongs_to :project
def user_mention_model
"#{CreateResourceUserMention::ISOLATION_MODULE}::#{noteable.class}".constantize.user_mention_model
end
def for_personal_snippet?
noteable.class.name == 'PersonalSnippet'
end
def for_project_noteable?
!for_personal_snippet?
end
def skip_project_check?
!for_project_noteable?
end
def for_epic?
noteable.class.name == 'Epic'
end
def user_mention_resource_id
noteable_id || commit_id
end
def user_mention_note_id
id
end
private
def mentionable_params
return super unless for_epic?
super.merge(banzai_context_params)
end
def banzai_context_params
{ group: noteable.group, label_url_method: :group_epics_url }
end
end
end
end
end
end
...@@ -11,7 +11,7 @@ module Gitlab ...@@ -11,7 +11,7 @@ module Gitlab
include ::Gitlab::Config::Entry::Validatable include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable include ::Gitlab::Config::Entry::Attributable
ALLOWED_KEYS = %i[junit codequality sast dependency_scanning container_scanning dast performance license_management license_scanning metrics].freeze ALLOWED_KEYS = %i[junit codequality sast dependency_scanning container_scanning dast performance license_management license_scanning metrics lsif].freeze
attributes ALLOWED_KEYS attributes ALLOWED_KEYS
...@@ -30,6 +30,7 @@ module Gitlab ...@@ -30,6 +30,7 @@ module Gitlab
validates :license_management, array_of_strings_or_string: true validates :license_management, array_of_strings_or_string: true
validates :license_scanning, array_of_strings_or_string: true validates :license_scanning, array_of_strings_or_string: true
validates :metrics, array_of_strings_or_string: true validates :metrics, array_of_strings_or_string: true
validates :lsif, array_of_strings_or_string: true
end end
end end
......
...@@ -1119,6 +1119,20 @@ into similar problems in the future (e.g. when new tables are created). ...@@ -1119,6 +1119,20 @@ into similar problems in the future (e.g. when new tables are created).
SQL SQL
end end
# Note this should only be used with very small tables
def backfill_iids(table)
sql = <<-END
UPDATE #{table}
SET iid = #{table}_with_calculated_iid.iid_num
FROM (
SELECT id, ROW_NUMBER() OVER (PARTITION BY project_id ORDER BY id ASC) AS iid_num FROM #{table}
) AS #{table}_with_calculated_iid
WHERE #{table}.id = #{table}_with_calculated_iid.id
END
execute(sql)
end
private private
def tables_match?(target_table, foreign_key_table) def tables_match?(target_table, foreign_key_table)
......
...@@ -47,11 +47,7 @@ module Gitlab ...@@ -47,11 +47,7 @@ module Gitlab
private private
def cache def cache
@cache ||= if Feature.enabled?(:hset_redis_diff_caching, project, default_enabled: true) @cache ||= Gitlab::Diff::HighlightCache.new(self)
Gitlab::Diff::HighlightCache.new(self)
else
Gitlab::Diff::DeprecatedHighlightCache.new(self)
end
end end
end end
end end
......
...@@ -50,8 +50,8 @@ module Gitlab ...@@ -50,8 +50,8 @@ module Gitlab
@project = project @project = project
@protocol = protocol @protocol = protocol
@authentication_abilities = authentication_abilities @authentication_abilities = authentication_abilities
@namespace_path = namespace_path @namespace_path = namespace_path || project&.namespace&.full_path
@project_path = project_path @project_path = project_path || project&.path
@redirected_path = redirected_path @redirected_path = redirected_path
@auth_result_type = auth_result_type @auth_result_type = auth_result_type
end end
...@@ -60,6 +60,7 @@ module Gitlab ...@@ -60,6 +60,7 @@ module Gitlab
@logger = Checks::TimedLogger.new(timeout: INTERNAL_TIMEOUT, header: LOG_HEADER) @logger = Checks::TimedLogger.new(timeout: INTERNAL_TIMEOUT, header: LOG_HEADER)
@changes = changes @changes = changes
check_namespace!
check_protocol! check_protocol!
check_valid_actor! check_valid_actor!
check_active_user! check_active_user!
...@@ -136,6 +137,12 @@ module Gitlab ...@@ -136,6 +137,12 @@ module Gitlab
end end
end end
def check_namespace!
return if namespace_path.present?
raise NotFoundError, ERROR_MESSAGES[:project_not_found]
end
def check_active_user! def check_active_user!
return unless user return unless user
......
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
context 'Manage', :orchestrated, :oauth, quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/196517' do # This test is skipped instead of quarantine because continuously running
# this test may cause the user to hit GitHub's rate limits thus blocking the user.
# Related issue: https://gitlab.com/gitlab-org/gitlab/issues/196517
context 'Manage', :orchestrated, :oauth, :skip do
describe 'OAuth login' do describe 'OAuth login' do
it 'User logs in to GitLab with GitHub OAuth' do it 'User logs in to GitLab with GitHub OAuth' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
......
...@@ -34,6 +34,7 @@ module RuboCop ...@@ -34,6 +34,7 @@ module RuboCop
namespaces namespaces
notes notes
projects projects
project_ci_cd_settings
routes routes
users users
].freeze ].freeze
......
...@@ -1129,8 +1129,9 @@ describe Projects::IssuesController do ...@@ -1129,8 +1129,9 @@ describe Projects::IssuesController do
sign_in(user) sign_in(user)
end end
it "rejects a developer to destroy an issue" do it "does not delete the issue, returning :not_found" do
delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe 'Broadcast Messages' do
let!(:broadcast_message) { create(:broadcast_message, broadcast_type: 'notification', message: 'SampleMessage') }
it 'shows broadcast message' do
visit root_path
expect(page).to have_content 'SampleMessage'
end
it 'hides broadcast message after dismiss', :js do
visit root_path
find('.js-dismiss-current-broadcast-notification').click
expect(page).not_to have_content 'SampleMessage'
end
it 'broadcast message is still hidden after refresh', :js do
visit root_path
find('.js-dismiss-current-broadcast-notification').click
visit root_path
expect(page).not_to have_content 'SampleMessage'
end
end
...@@ -3,6 +3,29 @@ ...@@ -3,6 +3,29 @@
require 'spec_helper' require 'spec_helper'
describe BroadcastMessagesHelper do describe BroadcastMessagesHelper do
describe 'current_broadcast_notification_message' do
subject { helper.current_broadcast_notification_message }
context 'with available broadcast notification messages' do
let!(:broadcast_message_1) { create(:broadcast_message, broadcast_type: 'notification', starts_at: Time.now - 1.day) }
let!(:broadcast_message_2) { create(:broadcast_message, broadcast_type: 'notification', starts_at: Time.now) }
it { is_expected.to eq broadcast_message_2 }
context 'when last broadcast message is hidden' do
before do
helper.request.cookies["hide_broadcast_notification_message_#{broadcast_message_2.id}"] = 'true'
end
it { is_expected.to eq broadcast_message_1 }
end
end
context 'without broadcast notification messages' do
it { is_expected.to be_nil }
end
end
describe 'broadcast_message' do describe 'broadcast_message' do
let(:current_broadcast_message) { BroadcastMessage.new(message: 'Current Message') } let(:current_broadcast_message) { BroadcastMessage.new(message: 'Current Message') }
......
...@@ -43,6 +43,7 @@ describe Gitlab::Ci::Config::Entry::Reports do ...@@ -43,6 +43,7 @@ describe Gitlab::Ci::Config::Entry::Reports do
:license_management | 'gl-license-management-report.json' :license_management | 'gl-license-management-report.json'
:license_scanning | 'gl-license-scanning-report.json' :license_scanning | 'gl-license-scanning-report.json'
:performance | 'performance.json' :performance | 'performance.json'
:lsif | 'lsif.sqlite3'
end end
with_them do with_them do
......
...@@ -38,21 +38,6 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do ...@@ -38,21 +38,6 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
let(:diffable) { merge_request.merge_request_diff } let(:diffable) { merge_request.merge_request_diff }
end end
context 'using Gitlab::Diff::DeprecatedHighlightCache' do
before do
stub_feature_flags(hset_redis_diff_caching: false)
end
it 'uses a different cache key if diff line keys change' do
mr_diff = described_class.new(merge_request.merge_request_diff, diff_options: nil)
key = mr_diff.cache_key
stub_const('Gitlab::Diff::Line::SERIALIZE_KEYS', [:foo])
expect(mr_diff.cache_key).not_to eq(key)
end
end
it_behaves_like 'diff statistics' do it_behaves_like 'diff statistics' do
let(:collection_default_args) do let(:collection_default_args) do
{ diff_options: {} } { diff_options: {} }
......
...@@ -75,6 +75,32 @@ describe Gitlab::GitAccess do ...@@ -75,6 +75,32 @@ describe Gitlab::GitAccess do
end end
end end
describe '#check_namespace!' do
context 'when namespace exists' do
before do
project.add_maintainer(user)
end
it 'allows push and pull access' do
aggregate_failures do
expect { push_access_check }.not_to raise_error
expect { pull_access_check }.not_to raise_error
end
end
end
context 'when namespace does not exist' do
let(:namespace_path) { nil }
it 'does not allow push and pull access' do
aggregate_failures do
expect { push_access_check }.to raise_not_found
expect { pull_access_check }.to raise_not_found
end
end
end
end
describe '#check_project_accessibility!' do describe '#check_project_accessibility!' do
context 'when the project exists' do context 'when the project exists' do
context 'when actor exists' do context 'when actor exists' do
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200117194850_backfill_operations_feature_flags_iid.rb')
describe BackfillOperationsFeatureFlagsIid, :migration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:flags) { table(:operations_feature_flags) }
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
project = projects.create!(namespace_id: namespace.id)
project
end
it 'migrates successfully when there are no flags in the database' do
setup
disable_migrations_output { migrate! }
expect(flags.count).to eq(0)
end
it 'migrates successfully with a row in the table in both FOSS and EE' do
project = setup
flags.create!(project_id: project.id, active: true, name: 'test_flag')
disable_migrations_output { migrate! }
expect(flags.count).to eq(1)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200117194900_delete_internal_ids_where_feature_flags_usage')
describe DeleteInternalIdsWhereFeatureFlagsUsage, :migration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:internal_ids) { table(:internal_ids) }
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
project = projects.create!(namespace_id: namespace.id)
project
end
it 'deletes feature flag rows from the internal_ids table' do
project = setup
internal_ids.create!(project_id: project.id, usage: 6, last_value: 1)
disable_migrations_output { migrate! }
expect(internal_ids.count).to eq(0)
end
it 'does not delete issue rows from the internal_ids table' do
project = setup
internal_ids.create!(project_id: project.id, usage: 0, last_value: 1)
disable_migrations_output { migrate! }
expect(internal_ids.count).to eq(1)
end
it 'does not delete merge request rows from the internal_ids table' do
project = setup
internal_ids.create!(project_id: project.id, usage: 1, last_value: 1)
disable_migrations_output { migrate! }
expect(internal_ids.count).to eq(1)
end
end
...@@ -2450,15 +2450,6 @@ describe Repository do ...@@ -2450,15 +2450,6 @@ describe Repository do
2.times { repository.ancestor?(commit.id, ancestor.id) } 2.times { repository.ancestor?(commit.id, ancestor.id) }
end end
it 'increments a counter with cache hits' do
counter = Gitlab::Metrics.counter(:repository_ancestor_calls_total, 'Repository ancestor calls')
expect do
2.times { repository.ancestor?(commit.id, ancestor.id) }
end.to change { counter.get(cache_hit: 'true') }.by(1)
.and change { counter.get(cache_hit: 'false') }.by(1)
end
it 'returns the value from the request store' do it 'returns the value from the request store' do
repository.__send__(:request_store_cache).write(cache_key, "it's apparent") repository.__send__(:request_store_cache).write(cache_key, "it's apparent")
......
...@@ -33,7 +33,7 @@ describe Ci::RetryBuildService do ...@@ -33,7 +33,7 @@ describe Ci::RetryBuildService do
job_artifacts_sast job_artifacts_dependency_scanning job_artifacts_sast job_artifacts_dependency_scanning
job_artifacts_container_scanning job_artifacts_dast job_artifacts_container_scanning job_artifacts_dast
job_artifacts_license_management job_artifacts_license_scanning job_artifacts_license_management job_artifacts_license_scanning
job_artifacts_performance job_artifacts_performance job_artifacts_lsif
job_artifacts_codequality job_artifacts_metrics scheduled_at job_artifacts_codequality job_artifacts_metrics scheduled_at
job_variables waiting_for_resource_at job_artifacts_metrics_referee job_variables waiting_for_resource_at job_artifacts_metrics_referee
job_artifacts_network_referee].freeze job_artifacts_network_referee].freeze
......
...@@ -33,34 +33,13 @@ describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_cachin ...@@ -33,34 +33,13 @@ describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_cachin
end end
context 'cache clearing' do context 'cache clearing' do
context 'using Gitlab::Diff::DeprecatedHighlightCache' do it 'clears the cache for older diffs on the merge request' do
before do old_diff = merge_request.merge_request_diff
stub_feature_flags(hset_redis_diff_caching: false) old_cache_key = old_diff.diffs_collection.cache_key
end
it 'clears the cache for older diffs on the merge request' do expect_any_instance_of(Redis).to receive(:del).with(old_cache_key).and_call_original
old_diff = merge_request.merge_request_diff
old_cache_key = old_diff.diffs_collection.cache_key
expect(Rails.cache).to receive(:delete).with(old_cache_key).and_call_original subject.execute
subject.execute
end
end
context 'using Gitlab::Diff::HighlightCache' do
before do
stub_feature_flags(hset_redis_diff_caching: true)
end
it 'clears the cache for older diffs on the merge request' do
old_diff = merge_request.merge_request_diff
old_cache_key = old_diff.diffs_collection.cache_key
expect_any_instance_of(Redis).to receive(:del).with(old_cache_key).and_call_original
subject.execute
end
end end
it 'avoids N+1 queries', :request_store do it 'avoids N+1 queries', :request_store do
......
...@@ -87,28 +87,10 @@ describe Notes::CreateService do ...@@ -87,28 +87,10 @@ describe Notes::CreateService do
.to receive(:unfolded_diff?) { true } .to receive(:unfolded_diff?) { true }
end end
context 'using Gitlab::Diff::DeprecatedHighlightCache' do it 'clears noteable diff cache when it was unfolded for the note position' do
before do expect_any_instance_of(Gitlab::Diff::HighlightCache).to receive(:clear)
stub_feature_flags(hset_redis_diff_caching: false)
end
it 'clears noteable diff cache when it was unfolded for the note position' do
expect_any_instance_of(Gitlab::Diff::DeprecatedHighlightCache).to receive(:clear)
described_class.new(project_with_repo, user, new_opts).execute
end
end
context 'using Gitlab::Diff::HighlightCache' do described_class.new(project_with_repo, user, new_opts).execute
before do
stub_feature_flags(hset_redis_diff_caching: true)
end
it 'clears noteable diff cache when it was unfolded for the note position' do
expect_any_instance_of(Gitlab::Diff::HighlightCache).to receive(:clear)
described_class.new(project_with_repo, user, new_opts).execute
end
end end
it 'does not clear cache when note is not the first of the discussion' do it 'does not clear cache when note is not the first of the discussion' do
......
...@@ -229,16 +229,17 @@ RSpec.shared_examples 'mentions in description' do |mentionable_type| ...@@ -229,16 +229,17 @@ RSpec.shared_examples 'mentions in description' do |mentionable_type|
context 'when mentionable description contains mentions' do context 'when mentionable description contains mentions' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:mentionable_desc) { "#{user.to_reference} some description #{group.to_reference(full: true)} and @all" } let(:mentionable_desc) { "#{user.to_reference} #{user2.to_reference} #{user.to_reference} some description #{group.to_reference(full: true)} and #{user2.to_reference} @all" }
let(:mentionable) { create(mentionable_type, description: mentionable_desc) } let(:mentionable) { create(mentionable_type, description: mentionable_desc) }
it 'stores mentions' do it 'stores mentions' do
add_member(user) add_member(user)
expect(mentionable.user_mentions.count).to eq 1 expect(mentionable.user_mentions.count).to eq 1
expect(mentionable.referenced_users).to match_array([user]) expect(mentionable.referenced_users).to match_array([user, user2])
expect(mentionable.referenced_projects(user)).to match_array([mentionable.project].compact) # epic.project is nil, and we want empty [] expect(mentionable.referenced_projects(user)).to match_array([mentionable.project].compact) # epic.project is nil, and we want empty []
expect(mentionable.referenced_groups(user)).to match_array([group]) expect(mentionable.referenced_groups(user)).to match_array([group])
end end
...@@ -249,8 +250,9 @@ end ...@@ -249,8 +250,9 @@ end
RSpec.shared_examples 'mentions in notes' do |mentionable_type| RSpec.shared_examples 'mentions in notes' do |mentionable_type|
context 'when mentionable notes contain mentions' do context 'when mentionable notes contain mentions' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:note_desc) { "#{user.to_reference} and #{group.to_reference(full: true)} and @all" } let(:note_desc) { "#{user.to_reference} #{user2.to_reference} #{user.to_reference} and #{group.to_reference(full: true)} and #{user2.to_reference} @all" }
let!(:mentionable) { note.noteable } let!(:mentionable) { note.noteable }
before do before do
...@@ -261,7 +263,7 @@ RSpec.shared_examples 'mentions in notes' do |mentionable_type| ...@@ -261,7 +263,7 @@ RSpec.shared_examples 'mentions in notes' do |mentionable_type|
it 'returns all mentionable mentions' do it 'returns all mentionable mentions' do
expect(mentionable.user_mentions.count).to eq 1 expect(mentionable.user_mentions.count).to eq 1
expect(mentionable.referenced_users).to eq [user] expect(mentionable.referenced_users).to eq [user, user2]
expect(mentionable.referenced_projects(user)).to eq [mentionable.project].compact # epic.project is nil, and we want empty [] expect(mentionable.referenced_projects(user)).to eq [mentionable.project].compact # epic.project is nil, and we want empty []
expect(mentionable.referenced_groups(user)).to eq [group] expect(mentionable.referenced_groups(user)).to eq [group]
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment