Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-09-08 09:08:31 +00:00
parent a69bb17d1e
commit 49a897eff9
79 changed files with 374 additions and 261 deletions

View File

@ -1132,13 +1132,7 @@ Rails/SaveBang:
- 'spec/requests/api/issues/post_projects_issues_spec.rb'
- 'spec/requests/api/jobs_spec.rb'
- 'spec/requests/api/labels_spec.rb'
- 'spec/requests/api/merge_requests_spec.rb'
- 'spec/requests/api/notes_spec.rb'
- 'spec/requests/api/pipeline_schedules_spec.rb'
- 'spec/requests/api/project_import_spec.rb'
- 'spec/requests/git_http_spec.rb'
- 'spec/requests/lfs_http_spec.rb'
- 'spec/requests/profiles/notifications_controller_spec.rb'
- 'spec/requests/projects/cycle_analytics_events_spec.rb'
- 'spec/services/auth/container_registry_authentication_service_spec.rb'
- 'spec/services/auto_merge/base_service_spec.rb'

View File

@ -0,0 +1,13 @@
// This allows us to dismiss alerts that we've migrated from bootstrap
// Note: This ONLY works on alerts that are created on page load
// You can follow this effort in the following epic
// https://gitlab.com/groups/gitlab-org/-/epics/4070
export default function initAlertHandler() {
const ALERT_SELECTOR = '.gl-alert';
const CLOSE_SELECTOR = '.gl-alert-dismiss';
const dismissAlert = ({ target }) => target.closest(ALERT_SELECTOR).remove();
const closeButtons = document.querySelectorAll(`${ALERT_SELECTOR} ${CLOSE_SELECTOR}`);
closeButtons.forEach(alert => alert.addEventListener('click', dismissAlert));
}

View File

@ -96,10 +96,11 @@ export default {
showAssigneeListDetails() {
return this.list.type === 'assignee' && (this.list.isExpanded || !this.isSwimlanesHeader);
},
issuesCount() {
return this.list.issuesSize;
},
issuesTooltipLabel() {
const { issuesSize } = this.list;
return n__(`%d issue`, `%d issues`, issuesSize);
return n__(`%d issue`, `%d issues`, this.issuesCount);
},
chevronTooltip() {
return this.list.isExpanded ? s__('Boards|Collapse') : s__('Boards|Expand');
@ -299,7 +300,7 @@ export default {
<gl-tooltip :target="() => $refs.issueCount" :title="issuesTooltipLabel" />
<span ref="issueCount" class="issue-count-badge-count">
<gl-icon class="gl-mr-2" name="issues" />
<issue-count :issues-size="list.issuesSize" :max-issue-count="list.maxIssueCount" />
<issue-count :issues-size="issuesCount" :max-issue-count="list.maxIssueCount" />
</span>
<!-- The following is only true in EE. -->
<template v-if="weightFeatureAvailable">

View File

@ -161,7 +161,12 @@ export default () => {
}
},
methods: {
...mapActions(['setInitialBoardData', 'setFilters', 'fetchEpicsSwimlanes']),
...mapActions([
'setInitialBoardData',
'setFilters',
'fetchEpicsSwimlanes',
'fetchIssuesForAllLists',
]),
updateTokens() {
this.filterManager.updateTokens();
},
@ -169,6 +174,7 @@ export default () => {
this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)));
if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) {
this.fetchEpicsSwimlanes(false);
this.fetchIssuesForAllLists();
}
},
updateDetailIssue(newIssue, multiSelect = false) {

View File

@ -1,18 +0,0 @@
#import "./issue.fragment.graphql"
query GroupListIssues($fullPath: ID!, $boardId: ID!) {
group(fullPath: $fullPath) {
board(id: $boardId) {
lists {
nodes {
id
issues {
nodes {
...IssueNode
}
}
}
}
}
}
}

View File

@ -0,0 +1,38 @@
#import "./issue.fragment.graphql"
query ListIssues(
$fullPath: ID!
$boardId: ID!
$filters: BoardIssueInput
$isGroup: Boolean = false
$isProject: Boolean = false
) {
group(fullPath: $fullPath) @include(if: $isGroup) {
board(id: $boardId) {
lists {
nodes {
id
issues(filters: $filters) {
nodes {
...IssueNode
}
}
}
}
}
}
project(fullPath: $fullPath) @include(if: $isProject) {
board(id: $boardId) {
lists {
nodes {
id
issues(filters: $filters) {
nodes {
...IssueNode
}
}
}
}
}
}
}

View File

@ -1,18 +0,0 @@
#import "./issue.fragment.graphql"
query ProjectListIssues($fullPath: ID!, $boardId: ID!) {
project(fullPath: $fullPath) {
board(id: $boardId) {
lists {
nodes {
id
issues {
nodes {
...IssueNode
}
}
}
}
}
}
}

View File

@ -1,5 +1,5 @@
import Cookies from 'js-cookie';
import { sortBy } from 'lodash';
import { sortBy, pick } from 'lodash';
import createFlash from '~/flash';
import { __ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
@ -10,8 +10,7 @@ import * as types from './mutation_types';
import { formatListIssues, fullBoardId } from '../boards_util';
import boardStore from '~/boards/stores/boards_store';
import groupListsIssuesQuery from '../queries/group_lists_issues.query.graphql';
import projectListsIssuesQuery from '../queries/project_lists_issues.query.graphql';
import listsIssuesQuery from '../queries/lists_issues.query.graphql';
import projectBoardQuery from '../queries/project_board.query.graphql';
import groupBoardQuery from '../queries/group_board.query.graphql';
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
@ -38,7 +37,14 @@ export default {
},
setFilters: ({ commit }, filters) => {
const { scope, utf8, state, ...filterParams } = filters;
const filterParams = pick(filters, [
'assigneeUsername',
'authorUsername',
'labelName',
'milestoneTitle',
'releaseTag',
'search',
]);
commit(types.SET_FILTERS, filterParams);
},
@ -197,19 +203,20 @@ export default {
fetchIssuesForAllLists: ({ state, commit }) => {
commit(types.REQUEST_ISSUES_FOR_ALL_LISTS);
const { endpoints, boardType } = state;
const { endpoints, boardType, filterParams } = state;
const { fullPath, boardId } = endpoints;
const query = boardType === BoardType.group ? groupListsIssuesQuery : projectListsIssuesQuery;
const variables = {
fullPath,
boardId: fullBoardId(boardId),
filters: filterParams,
isGroup: boardType === BoardType.group,
isProject: boardType === BoardType.project,
};
return gqlClient
.query({
query,
query: listsIssuesQuery,
variables,
})
.then(({ data }) => {

View File

@ -24,6 +24,7 @@ import { deprecatedCreateFlash as Flash, removeFlashClickListener } from './flas
import initTodoToggle from './header';
import initImporterStatus from './importer_status';
import initLayoutNav from './layout_nav';
import initAlertHandler from './alert_handler';
import './feature_highlight/feature_highlight_options';
import LazyLoader from './lazy_loader';
import initLogoAnimation from './logo';
@ -167,6 +168,7 @@ document.addEventListener('DOMContentLoaded', () => {
initUserTracking();
initLayoutNav();
initAlertHandler();
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';

View File

@ -252,7 +252,8 @@
}
}
.cross-project-reference {
.cross-project-reference,
.sidebar-mr-source-branch {
color: inherit;
span {
@ -389,7 +390,8 @@
border-bottom: 0;
overflow: hidden;
&:hover {
&.with-sub-blocks .sub-block:hover,
&:not(.with-sub-blocks):hover {
background-color: $gray-100;
}

View File

@ -234,8 +234,7 @@ class IssuableFinder
end
def attempt_project_search_optimizations?
params[:attempt_project_search_optimizations] &&
Feature.enabled?(:attempt_project_search_optimizations, default_enabled: true)
params[:attempt_project_search_optimizations]
end
def count_key(value)

View File

@ -75,8 +75,8 @@ module Timebox
scope :within_timeframe, -> (start_date, end_date) do
where('start_date is not NULL or due_date is not NULL')
.where('start_date is NULL or start_date <= ?', end_date)
.where('due_date is NULL or due_date >= ?', start_date)
.where('start_date is NULL or start_date <= ?', end_date)
.where('due_date is NULL or due_date >= ?', start_date)
end
strip_attributes :title
@ -195,6 +195,10 @@ module Timebox
end
end
def weight_available?
resource_parent&.feature_available?(:issue_weights)
end
private
def timebox_format_reference(format = :iid)

View File

@ -6,7 +6,7 @@
.merge-request-details.issuable-details
= render "projects/merge_requests/mr_box"
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, source_branch: @merge_request.source_branch
#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } }

View File

@ -89,7 +89,7 @@
.loading.hide
.spinner.spinner-md
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees
= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, source_branch: @merge_request.source_branch
- if @merge_request.can_be_reverted?(current_user)
= render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title

View File

@ -151,15 +151,24 @@
.js-sidebar-subscriptions-entry-point
- project_ref = issuable_sidebar[:reference]
.block.project-reference
.sidebar-collapsed-icon.dont-change-state
= clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
.cross-project-reference.hide-collapsed
%span
= _('Reference:')
%cite{ title: project_ref }
= project_ref
= clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
.block.with-sub-blocks
.project-reference.sub-block
.sidebar-collapsed-icon.dont-change-state
= clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
.cross-project-reference.hide-collapsed
%span
= _('Reference:')
%cite{ title: project_ref }
= project_ref
= clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
- if issuable_type == 'merge_request'
.sidebar-source-branch.sub-block
.sidebar-collapsed-icon.dont-change-state
= clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
.sidebar-mr-source-branch.hide-collapsed
%span
= _('Source branch: %{source_branch_open}${source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<cite class='ref-name' title='#{source_branch}'>".html_safe, source_branch_close: "</cite>".html_safe, source_branch: source_branch }
= clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
- if issuable_sidebar.dig(:current_user, :can_move)
.block.js-sidebar-move-issue-block

View File

@ -27,6 +27,6 @@ module NewIssuable
# rubocop: enable CodeReuse/ActiveRecord
def log_error(record_class, record_id)
Rails.logger.error("#{self.class}: couldn't find #{record_class} with ID=#{record_id}, skipping job") # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error("#{self.class}: couldn't find #{record_class} with ID=#{record_id}, skipping job")
end
end

View File

@ -41,16 +41,14 @@ module ObjectStorage
end
end
# rubocop:disable Gitlab/RailsLogger
def report!(results)
success, failures = results.partition(&:success?)
Rails.logger.info header(success, failures)
Rails.logger.warn failures(failures)
Gitlab::AppLogger.info header(success, failures)
Gitlab::AppLogger.warn failures(failures)
raise MigrationFailures.new(failures.map(&:error)) if failures.any?
end
# rubocop:enable Gitlab/RailsLogger
def header(success, failures)
_("Migrated %{success_count}/%{total_count} files.") % { success_count: success.count, total_count: success.count + failures.count }
@ -104,7 +102,7 @@ module ObjectStorage
report!(results)
rescue SanityCheckError => e
# do not retry: the job is insane
Rails.logger.warn "#{self.class}: Sanity check error (#{e.message})" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.warn "#{self.class}: Sanity check error (#{e.message})"
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -34,7 +34,7 @@ class RepositoryForkWorker # rubocop:disable Scalability/IdempotentWorker
def start_fork(project)
return true if start(project.import_state)
Rails.logger.info("Project #{project.full_path} was in inconsistent state (#{project.import_status}) while forking.") # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info("Project #{project.full_path} was in inconsistent state (#{project.import_status}) while forking.")
false
end

View File

@ -31,11 +31,10 @@ class RunPipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker
private
# rubocop:disable Gitlab/RailsLogger
def error(schedule, error)
failed_creation_counter.increment
Rails.logger.error "Failed to create a scheduled pipeline. " \
Gitlab::AppLogger.error "Failed to create a scheduled pipeline. " \
"schedule_id: #{schedule.id} message: #{error.message}"
Gitlab::ErrorTracking
@ -43,7 +42,6 @@ class RunPipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker
issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/41231',
schedule_id: schedule.id)
end
# rubocop:enable Gitlab/RailsLogger
def failed_creation_counter
@failed_creation_counter ||=

View File

@ -17,7 +17,7 @@ class StuckCiJobsWorker # rubocop:disable Scalability/IdempotentWorker
def perform
return unless try_obtain_lease
Rails.logger.info "#{self.class}: Cleaning stuck builds" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info "#{self.class}: Cleaning stuck builds" # rubocop:disable Gitlab/RailsLogger
drop :running, BUILD_RUNNING_OUTDATED_TIMEOUT, 'ci_builds.updated_at < ?', :stuck_or_timeout_failure
drop :pending, BUILD_PENDING_OUTDATED_TIMEOUT, 'ci_builds.updated_at < ?', :stuck_or_timeout_failure
@ -69,7 +69,7 @@ class StuckCiJobsWorker # rubocop:disable Scalability/IdempotentWorker
# rubocop: enable CodeReuse/ActiveRecord
def drop_build(type, build, status, timeout, reason)
Rails.logger.info "#{self.class}: Dropping #{type} build #{build.id} for runner #{build.runner_id} (status: #{status}, timeout: #{timeout}, reason: #{reason})" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info "#{self.class}: Dropping #{type} build #{build.id} for runner #{build.runner_id} (status: #{status}, timeout: #{timeout}, reason: #{reason})"
Gitlab::OptimisticLocking.retry_lock(build, 3) do |b|
b.drop(reason)
end

View File

@ -7,7 +7,7 @@ class StuckMergeJobsWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :source_code_management
def self.logger
Rails.logger # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger
end
# rubocop: disable CodeReuse/ActiveRecord

View File

@ -11,7 +11,7 @@ class TrendingProjectsWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :source_code_management
def perform
Rails.logger.info('Refreshing trending projects') # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info('Refreshing trending projects')
TrendingProject.refresh!
end

View File

@ -10,6 +10,6 @@ class UploadChecksumWorker # rubocop:disable Scalability/IdempotentWorker
upload.calculate_checksum!
upload.save!
rescue ActiveRecord::RecordNotFound
Rails.logger.error("UploadChecksumWorker: couldn't find upload #{upload_id}, skipping") # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error("UploadChecksumWorker: couldn't find upload #{upload_id}, skipping")
end
end

View File

@ -0,0 +1,5 @@
---
title: Add index to resource_iteration_events for add actions
merge_request: 41280
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Display Merge Request's source branch name in sidebar
merge_request: 34901
author: Ethan Reesor (@firelizzard)
type: added

View File

@ -0,0 +1,5 @@
---
title: Adds an alert handler for bootstrap migration
merge_request: 41323
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Use applogger in app/workers/*
merge_request: 41046
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Use applogger in lib/gitlab
merge_request: 41063
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Use applogger in lib/gitlab/database
merge_request: 41068
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Use applogger in lib/gitlab/
merge_request: 41075
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Use applogger in ee/app/models, helpers and workers
merge_request: 41048
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Use applogger
merge_request: 41055
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Remove attempt_project_search_optimizations feature flag
merge_request: 41550
author: gaga5lala
type: other

View File

@ -0,0 +1,5 @@
---
title: Fix Rails/SaveBang offenses for 3 files
merge_request: 41392
author: Rajendra Kadam
type: other

View File

@ -0,0 +1,5 @@
---
title: Fix Rails/SaveBang offenses for 3 files
merge_request: 41395
author: Rajendra Kadam
type: other

43
danger/pajamas/Dangerfile Normal file
View File

@ -0,0 +1,43 @@
# frozen_string_literal: true
PATTERNS = %w[
createFlash
gl-deprecated-button
loading-button
pagination-button
gl-deprecated-dropdown
gl-deprecated-dropdown-divider
gl-deprecated-dropdown-header
gl-deprecated-dropdown-item
initDeprecatedJQueryDropdown
].freeze
def get_added_lines(files)
lines = []
files.each do |file|
lines += helper.changed_lines(file).select { |line| %r{^[+]}.match?(line) }
end
lines
end
changed_vue_haml_files = helper.changed_files(/.vue$|.haml$/)
return if changed_vue_haml_files.empty?
changed_lines_in_mr = get_added_lines(changed_vue_haml_files)
has_deprecated_components = changed_lines_in_mr.select { |i| i[/#{PATTERNS.join("|")}/] }
deprecated_components_in_mr = PATTERNS.select { |s| has_deprecated_components.join(" ")[s] }
return if deprecated_components_in_mr.empty?
warn "This merge request contains deprecated components. Please consider using Pajamas components instead."
markdown(<<~MARKDOWN)
## Deprecated components
The following components are deprecated:
* #{deprecated_components_in_mr.join("\n* ")}
Please consider using [Pajamas components](https://design.gitlab.com/components/status/) instead.
MARKDOWN

View File

@ -14,8 +14,9 @@ SPECIALIZATIONS = {
}.freeze
labels_to_add = helper.changes_by_category.each_with_object([]) do |(category, _changes), memo|
label = SPECIALIZATIONS.fetch(category, category.to_s)
memo << label unless gitlab.mr_labels.include?(label)
label = SPECIALIZATIONS[category]
memo << label if label && !gitlab.mr_labels.include?(label)
end
if labels_to_add.any?

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddIndexToResourceIterationEventsAddEvents < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
INDEX_NAME = 'index_resource_iteration_events_on_iteration_id_and_add_action'
ADD_ACTION = '1'
def up
# Index add iteration events
add_concurrent_index :resource_iteration_events, :iteration_id, where: "action = #{ADD_ACTION}", name: INDEX_NAME
end
def down
remove_concurrent_index :resource_iteration_events, :iteration_id, name: INDEX_NAME
end
end

View File

@ -1,25 +0,0 @@
# frozen_string_literal: true
class UpdateLocationFingerprintForCsFindings < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
BATCH_SIZE = 1_000
INTERVAL = 2.minutes
# 815_565 records
def up
# no-op
# There was a bug introduced with this migration for gitlab.com
# We created new migration to mitigate that VERISON=20200907123723
# and change this one to no-op to prevent running migration twice
end
def down
# no-op
# intentionally blank
end
end

View File

@ -1,33 +0,0 @@
# frozen_string_literal: true
class FixUpdateLocationFingerprintForCsFindings < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
BATCH_SIZE = 1_000
INTERVAL = 2.minutes
# 815_565 records
def up
return unless Gitlab.ee?
migration = Gitlab::BackgroundMigration::UpdateLocationFingerprintForCsFindings
migration_name = migration.to_s.demodulize
Gitlab::BackgroundMigration.steal(migration_name)
relation = migration::Finding.container_scanning
queue_background_migration_jobs_by_range_at_intervals(relation,
migration_name,
INTERVAL,
batch_size: BATCH_SIZE)
end
def down
# no-op
# intentionally blank
end
end

View File

@ -1 +0,0 @@
e24f8495b7458ce57e148017ef6cae901e7f3997fca247afeff524a43e739431

View File

@ -0,0 +1 @@
e6c3d5352feed1adc82b14218a6f47fa55df9e0add8a59228d128e4e7f39614b

View File

@ -1 +0,0 @@
74f6adf29b9293537d653b993ab0e2f31af2ab5a8581ca631e8a87fc589ca284

View File

@ -20817,6 +20817,8 @@ CREATE INDEX index_resource_iteration_events_on_merge_request_id ON public.resou
CREATE INDEX index_resource_iteration_events_on_user_id ON public.resource_iteration_events USING btree (user_id);
CREATE INDEX index_resource_iterationn_events_on_iteration_id_and_add_action ON public.resource_iteration_events USING btree (iteration_id) WHERE (action = 1);
CREATE INDEX index_resource_label_events_issue_id_label_id_action ON public.resource_label_events USING btree (issue_id, label_id, action);
CREATE INDEX index_resource_label_events_on_epic_id ON public.resource_label_events USING btree (epic_id);

View File

@ -1922,7 +1922,9 @@ test:
```
The following example will skip the `build` job if a change is detected in any file
in the root directory of the repository with a `.md` extension:
in the root directory of the repository with a `.md` extension. This mean that if you change multiple files,
but only one file is a `.md` file, the `build` job will still be skipped and will
not run for the other files.
```yaml
build:

View File

@ -10,7 +10,7 @@ module Gitlab
.includes(project: [:route, :group, namespace: [:owner]]).find_each do |statistics|
statistics.refresh!(only: [:wiki_size])
rescue => e
Rails.logger.error "Failed to update wiki statistics. id: #{statistics.id} message: #{e.message}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error "Failed to update wiki statistics. id: #{statistics.id} message: #{e.message}"
end
end
end

View File

@ -25,7 +25,7 @@ module Gitlab
certificate_valid_not_after: domain.x509&.not_after&.iso8601
)
rescue => e
Rails.logger.error "Failed to update pages domain certificate valid time. id: #{domain.id}, message: #{e.message}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error "Failed to update pages domain certificate valid time. id: #{domain.id}, message: #{e.message}"
end
end
end

View File

@ -1,13 +0,0 @@
# frozen_string_literal: true
# rubocop:disable Style/Documentation
module Gitlab
module BackgroundMigration
class UpdateLocationFingerprintForCsFindings
def perform(start_id, stop_id)
end
end
end
end
Gitlab::BackgroundMigration::UpdateLocationFingerprintForCsFindings.prepend_if_ee('EE::Gitlab::BackgroundMigration::UpdateLocationFingerprintForCsFindings')

View File

@ -18,7 +18,7 @@ module Gitlab
@limit = limit
@dry_run = dry_run
@niceness = (niceness || DEFAULT_NICENESS).downcase
@logger = logger || Rails.logger # rubocop:disable Gitlab/RailsLogger
@logger = logger || Gitlab::AppLogger
@total_found = @total_cleaned = 0
new_batch!

View File

@ -22,7 +22,7 @@ module Gitlab
attr_reader :batch_size, :dry_run
attr_accessor :artifact_files
def initialize(batch_size:, dry_run: true, logger: Rails.logger) # rubocop:disable Gitlab/RailsLogger
def initialize(batch_size:, dry_run: true, logger: Gitlab::AppLogger)
@batch_size = batch_size
@dry_run = dry_run
@logger = logger

View File

@ -12,7 +12,7 @@ module Gitlab
def initialize(project, dry_run: true, logger: nil, limit: nil)
@project = project
@dry_run = dry_run
@logger = logger || Rails.logger # rubocop:disable Gitlab/RailsLogger
@logger = logger || Gitlab::AppLogger
@limit = limit
end

View File

@ -49,7 +49,7 @@ module Gitlab
cmd = %W[#{ionice} -c Idle] + cmd if ionice
log_msg = "find command: \"#{cmd.join(' ')}\""
Rails.logger.info log_msg # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info log_msg
cmd
end

View File

@ -8,7 +8,7 @@ module Gitlab
attr_reader :logger
def initialize(logger: nil)
@logger = logger || Rails.logger # rubocop:disable Gitlab/RailsLogger
@logger = logger || Gitlab::AppLogger
end
def run!(dry_run: true)

View File

@ -7,7 +7,7 @@ module Gitlab
BATCH_SIZE = 100
def initialize(logger: nil)
@logger = logger || Rails.logger # rubocop:disable Gitlab/RailsLogger
@logger = logger || Gitlab::AppLogger
end
def run!(dry_run: false)

View File

@ -87,7 +87,7 @@ module Gitlab
options = options.merge({ algorithm: :concurrently })
if index_exists?(table_name, column_name, options)
Rails.logger.warn "Index not created because it already exists (this may be due to an aborted migration or similar): table_name: #{table_name}, column_name: #{column_name}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.warn "Index not created because it already exists (this may be due to an aborted migration or similar): table_name: #{table_name}, column_name: #{column_name}"
return
end
@ -113,7 +113,7 @@ module Gitlab
options = options.merge({ algorithm: :concurrently })
unless index_exists?(table_name, column_name, options)
Rails.logger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, column_name: #{column_name}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, column_name: #{column_name}"
return
end
@ -143,7 +143,7 @@ module Gitlab
options = options.merge({ algorithm: :concurrently })
unless index_exists_by_name?(table_name, index_name)
Rails.logger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, index_name: #{index_name}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.warn "Index not removed because it does not exist (this may be due to an aborted migration or similar): table_name: #{table_name}, index_name: #{index_name}"
return
end
@ -163,7 +163,6 @@ module Gitlab
# defaults to "CASCADE".
# name - The name of the foreign key.
#
# rubocop:disable Gitlab/RailsLogger
def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade, name: nil, validate: true)
# Transactions would result in ALTER TABLE locks being held for the
# duration of the transaction, defeating the purpose of this method.
@ -183,7 +182,7 @@ module Gitlab
"source: #{source}, target: #{target}, column: #{options[:column]}, "\
"name: #{options[:name]}, on_delete: #{options[:on_delete]}"
Rails.logger.warn warning_message
Gitlab::AppLogger.warn warning_message
else
# Using NOT VALID allows us to create a key without immediately
# validating it. This means we keep the ALTER TABLE lock only for a
@ -217,7 +216,6 @@ module Gitlab
end
end
end
# rubocop:enable Gitlab/RailsLogger
def validate_foreign_key(source, column, name: nil)
fk_name = name || concurrent_foreign_key_name(source, column)
@ -1085,7 +1083,6 @@ into similar problems in the future (e.g. when new tables are created).
# Should be unique per table (not per column)
# validate - Whether to validate the constraint in this call
#
# rubocop:disable Gitlab/RailsLogger
def add_check_constraint(table, check, constraint_name, validate: true)
validate_check_constraint_name!(constraint_name)
@ -1102,7 +1099,7 @@ into similar problems in the future (e.g. when new tables are created).
table: #{table}, check: #{check}, constraint name: #{constraint_name}
MESSAGE
Rails.logger.warn warning_message
Gitlab::AppLogger.warn warning_message
else
# Only add the constraint without validating it
# Even though it is fast, ADD CONSTRAINT requires an EXCLUSIVE lock
@ -1187,7 +1184,7 @@ into similar problems in the future (e.g. when new tables are created).
column #{table}.#{column} is already defined as `NOT NULL`
MESSAGE
Rails.logger.warn warning_message
Gitlab::AppLogger.warn warning_message
end
end

View File

@ -31,7 +31,7 @@ module Gitlab
current_keys << specified_key
else
Rails.logger.warn "foreign key not added because it already exists: #{specified_key}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.warn "foreign key not added because it already exists: #{specified_key}"
current_keys
end
end
@ -56,7 +56,7 @@ module Gitlab
existing_key.delete
current_keys.delete(existing_key)
else
Rails.logger.warn "foreign key not removed because it doesn't exist: #{specified_key}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.warn "foreign key not removed because it doesn't exist: #{specified_key}"
end
current_keys

View File

@ -202,10 +202,8 @@ module Gitlab
def create_range_partitioned_copy(source_table_name, partitioned_table_name, partition_column, primary_key)
if table_exists?(partitioned_table_name)
# rubocop:disable Gitlab/RailsLogger
Rails.logger.warn "Partitioned table not created because it already exists" \
Gitlab::AppLogger.warn "Partitioned table not created because it already exists" \
" (this may be due to an aborted migration or similar): table_name: #{partitioned_table_name} "
# rubocop:enable Gitlab/RailsLogger
return
end
@ -258,10 +256,8 @@ module Gitlab
def create_range_partition_safely(partition_name, table_name, lower_bound, upper_bound)
if table_exists?(table_for_range_partition(partition_name))
# rubocop:disable Gitlab/RailsLogger
Rails.logger.warn "Partition not created because it already exists" \
Gitlab::AppLogger.warn "Partition not created because it already exists" \
" (this may be due to an aborted migration or similar): partition_name: #{partition_name}"
# rubocop:enable Gitlab/RailsLogger
return
end
@ -282,10 +278,8 @@ module Gitlab
def create_sync_function(name, partitioned_table_name, unique_key)
if function_exists?(name)
# rubocop:disable Gitlab/RailsLogger
Rails.logger.warn "Partitioning sync function not created because it already exists" \
Gitlab::AppLogger.warn "Partitioning sync function not created because it already exists" \
" (this may be due to an aborted migration or similar): function name: #{name}"
# rubocop:enable Gitlab/RailsLogger
return
end
@ -317,10 +311,8 @@ module Gitlab
def create_sync_trigger(table_name, trigger_name, function_name)
if trigger_exists?(table_name, trigger_name)
# rubocop:disable Gitlab/RailsLogger
Rails.logger.warn "Partitioning sync trigger not created because it already exists" \
Gitlab::AppLogger.warn "Partitioning sync trigger not created because it already exists" \
" (this may be due to an aborted migration or similar): trigger name: #{trigger_name}"
# rubocop:enable Gitlab/RailsLogger
return
end

View File

@ -71,7 +71,7 @@ module Gitlab
unless gitlab_shell.mv_namespace(repository_storage, old_full_path, new_full_path)
message = "Exception moving on shard #{repository_storage} from #{old_full_path} to #{new_full_path}"
Rails.logger.error message # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error message
end
end
end

View File

@ -56,7 +56,7 @@ module Gitlab
unless gitlab_shell.mv_repository(project.repository_storage,
old_path,
new_path)
Rails.logger.error "Error moving #{old_path} to #{new_path}" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error "Error moving #{old_path} to #{new_path}"
end
end

View File

@ -42,7 +42,7 @@ module Gitlab
def puma_stats
Puma.stats
rescue NoMethodError
Rails.logger.info "PumaSampler: stats are not available yet, waiting for Puma to boot" # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info "PumaSampler: stats are not available yet, waiting for Puma to boot"
nil
end

View File

@ -36,7 +36,7 @@ module Gitlab
def call
if disallowed_request? && Gitlab::Database.read_only?
Rails.logger.debug('GitLab ReadOnly: preventing possible non read-only operation') # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.debug('GitLab ReadOnly: preventing possible non read-only operation')
if json_request?
return [403, { 'Content-Type' => APPLICATION_JSON }, [{ 'message' => ERROR_MESSAGE }.to_json]]

View File

@ -48,7 +48,7 @@ module Gitlab
attr_reader :logger
def initialize(logger: Rails.logger) # rubocop:disable Gitlab/RailsLogger
def initialize(logger: Gitlab::AppLogger)
@logger = logger
end

View File

@ -13,6 +13,7 @@ class GitlabDanger
commit_messages
telemetry
utility_css
pajamas
].freeze
CI_ONLY_RULES ||= %w[

View File

@ -41,7 +41,7 @@ module Mattermost
begin
yield self
rescue Errno::ECONNREFUSED => e
Rails.logger.error(e.message + "\n" + e.backtrace.join("\n")) # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.error(e.message + "\n" + e.backtrace.join("\n"))
raise Mattermost::NoSessionError
ensure
destroy

View File

@ -19,7 +19,7 @@ module MicrosoftTeams
result = true if response
rescue Gitlab::HTTP::Error, StandardError => error
Rails.logger.info("#{self.class.name}: Error while connecting to #{@webhook}: #{error.message}") # rubocop:disable Gitlab/RailsLogger
Gitlab::AppLogger.info("#{self.class.name}: Error while connecting to #{@webhook}: #{error.message}")
end
result

View File

@ -452,7 +452,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@ -773,6 +773,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
msgid "%{timebox_type} does not support burnup charts"
msgstr ""
msgid "%{timebox_type} must have a start and due date"
msgstr ""
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@ -15857,18 +15863,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
msgid "Milestone does not support burnup charts"
msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
msgid "Milestone must have a start and due date"
msgstr ""
msgid "MilestoneSidebar|Closed:"
msgstr ""
@ -23484,6 +23484,9 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
msgid "Source branch: %{source_branch_open}${source_branch}%{source_branch_close}"
msgstr ""
msgid "Source code"
msgstr ""

View File

@ -1004,36 +1004,22 @@ RSpec.describe IssuesFinder do
end
end
context 'when attempt_group_search_optimizations is unset and attempt_project_search_optimizations is set' do
let(:params) { { search: 'foo', attempt_project_search_optimizations: true } }
context 'when all conditions are met' do
context "uses group search optimization" do
let(:params) { { search: 'foo', attempt_group_search_optimizations: true } }
context 'and the corresponding feature flag is disabled' do
before do
stub_feature_flags(attempt_project_search_optimizations: false)
end
it 'returns false' do
expect(finder.use_cte_for_search?).to be_falsey
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
end
end
context 'and the corresponding feature flag is enabled' do
before do
stub_feature_flags(attempt_project_search_optimizations: true)
end
context "uses project search optimization" do
let(:params) { { search: 'foo', attempt_project_search_optimizations: true } }
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
end
end
end
context 'when all conditions are met' do
let(:params) { { search: 'foo', attempt_group_search_optimizations: true } }
it 'returns true' do
expect(finder.use_cte_for_search?).to be_truthy
end
end
end
end

View File

@ -0,0 +1,46 @@
import { setHTMLFixture } from 'helpers/fixtures';
import initAlertHandler from '~/alert_handler';
describe('Alert Handler', () => {
const ALERT_SELECTOR = 'gl-alert';
const CLOSE_SELECTOR = 'gl-alert-dismiss';
const ALERT_HTML = `<div class="${ALERT_SELECTOR}"><button class="${CLOSE_SELECTOR}">Dismiss</button></div>`;
const findFirstAlert = () => document.querySelector(`.${ALERT_SELECTOR}`);
const findAllAlerts = () => document.querySelectorAll(`.${ALERT_SELECTOR}`);
const findFirstCloseButton = () => document.querySelector(`.${CLOSE_SELECTOR}`);
describe('initAlertHandler', () => {
describe('with one alert', () => {
beforeEach(() => {
setHTMLFixture(ALERT_HTML);
initAlertHandler();
});
it('should render the alert', () => {
expect(findFirstAlert()).toExist();
});
it('should dismiss the alert on click', () => {
findFirstCloseButton().click();
expect(findFirstAlert()).not.toExist();
});
});
describe('with two alerts', () => {
beforeEach(() => {
setHTMLFixture(ALERT_HTML + ALERT_HTML);
initAlertHandler();
});
it('should render two alerts', () => {
expect(findAllAlerts()).toHaveLength(2);
});
it('should dismiss only one alert on click', () => {
findFirstCloseButton().click();
expect(findAllAlerts()).toHaveLength(1);
});
});
});
});

View File

@ -9,7 +9,7 @@ RSpec.describe GitlabDanger do
describe '.local_warning_message' do
it 'returns an informational message with rules that can run' do
expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changes_size, documentation, frozen_string, duplicate_yarn_dependencies, prettier, eslint, karma, database, commit_messages, telemetry, utility_css')
expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changes_size, documentation, frozen_string, duplicate_yarn_dependencies, prettier, eslint, karma, database, commit_messages, telemetry, utility_css, pajamas')
end
end

View File

@ -912,7 +912,7 @@ RSpec.describe API::MergeRequests do
let(:parent_group) { create(:group) }
before do
group.update(parent_id: parent_group.id)
group.update!(parent_id: parent_group.id)
merge_request_merged.reload
end
@ -1027,7 +1027,7 @@ RSpec.describe API::MergeRequests do
let(:non_member) { create(:user) }
before do
merge_request.update(author: non_member)
merge_request.update!(author: non_member)
end
it 'exposes first_contribution as true' do
@ -1084,8 +1084,8 @@ RSpec.describe API::MergeRequests do
let(:merge_request) { create(:merge_request, :simple, author: user, source_project: project, source_branch: 'markdown', title: "Test") }
before do
merge_request.update(head_pipeline: create(:ci_pipeline))
merge_request.project.project_feature.update(builds_access_level: 10)
merge_request.update!(head_pipeline: create(:ci_pipeline))
merge_request.project.project_feature.update!(builds_access_level: 10)
end
context 'when user can read the pipeline' do
@ -1691,7 +1691,7 @@ RSpec.describe API::MergeRequests do
end
it 'returns 403 when target project has disabled merge requests' do
project.project_feature.update(merge_requests_access_level: 0)
project.project_feature.update!(merge_requests_access_level: 0)
post api("/projects/#{forked_project.id}/merge_requests", user2),
params: {
@ -2146,7 +2146,7 @@ RSpec.describe API::MergeRequests do
let(:source_branch) { merge_request.source_branch }
before do
merge_request.update(merge_params: { 'force_remove_source_branch' => true })
merge_request.update!(merge_params: { 'force_remove_source_branch' => true })
end
it 'removes the source branch' do
@ -2173,7 +2173,7 @@ RSpec.describe API::MergeRequests do
let(:merge_request) { create(:merge_request, :rebased, source_project: project, squash: true) }
before do
project.update(merge_requests_ff_only_enabled: true)
project.update!(merge_requests_ff_only_enabled: true)
end
it "records the squash commit SHA and returns it in the response" do
@ -2263,7 +2263,7 @@ RSpec.describe API::MergeRequests do
describe "PUT /projects/:id/merge_requests/:merge_request_iid" do
context 'updates force_remove_source_branch properly' do
it 'sets to false' do
merge_request.update(merge_params: { 'force_remove_source_branch' => true } )
merge_request.update!(merge_params: { 'force_remove_source_branch' => true } )
expect(merge_request.force_remove_source_branch?).to be_truthy
@ -2275,7 +2275,7 @@ RSpec.describe API::MergeRequests do
end
it 'sets to true' do
merge_request.update(merge_params: { 'force_remove_source_branch' => false } )
merge_request.update!(merge_params: { 'force_remove_source_branch' => false } )
expect(merge_request.force_remove_source_branch?).to be_falsey
@ -2760,7 +2760,7 @@ RSpec.describe API::MergeRequests do
merge_request
merge_request.created_at += 1.hour
merge_request.updated_at += 30.minutes
merge_request.save
merge_request.save!
merge_request
end
@ -2768,7 +2768,7 @@ RSpec.describe API::MergeRequests do
merge_request_closed
merge_request_closed.created_at -= 1.hour
merge_request_closed.updated_at -= 30.minutes
merge_request_closed.save
merge_request_closed.save!
merge_request_closed
end
end

View File

@ -81,7 +81,7 @@ RSpec.describe API::Notes do
context "issue is confidential" do
before do
ext_issue.update(confidential: true)
ext_issue.update!(confidential: true)
end
it "returns 404" do
@ -183,7 +183,7 @@ RSpec.describe API::Notes do
context "when issue is confidential" do
before do
issue.update(confidential: true)
issue.update!(confidential: true)
end
it "returns 404" do

View File

@ -763,7 +763,7 @@ RSpec.describe 'Git HTTP requests' do
context 'and build created by' do
before do
build.update(user: user)
build.update!(user: user)
project.add_reporter(user)
end

View File

@ -786,7 +786,7 @@ RSpec.describe 'Git LFS API and storage' do
let(:authorization) { authorize_deploy_key }
let(:update_user_permissions) do
project.deploy_keys_projects.create(deploy_key: key, can_push: true)
project.deploy_keys_projects.create!(deploy_key: key, can_push: true)
end
it_behaves_like 'pushes new LFS objects', renew_authorization: false
@ -991,7 +991,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'and workhorse requests upload finalize for a new LFS object' do
before do
lfs_object.destroy
lfs_object.destroy!
end
context 'with object storage disabled' do
@ -1009,7 +1009,7 @@ RSpec.describe 'Git LFS API and storage' do
end
let(:tmp_object) do
fog_connection.directories.new(key: 'lfs-objects').files.create(
fog_connection.directories.new(key: 'lfs-objects').files.create( # rubocop: disable Rails/SaveBang
key: 'tmp/uploads/12312300',
body: 'content'
)
@ -1080,7 +1080,7 @@ RSpec.describe 'Git LFS API and storage' do
context 'without the lfs object' do
before do
lfs_object.destroy
lfs_object.destroy!
end
it 'rejects slashes in the tempfile name (path traversal)' do

View File

@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe 'view user notifications' do
let(:user) do
create(:user) do |user|
user.emails.create(email: 'original@example.com', confirmed_at: Time.current)
user.emails.create(email: 'new@example.com', confirmed_at: Time.current)
user.emails.create!(email: 'original@example.com', confirmed_at: Time.current)
user.emails.create!(email: 'new@example.com', confirmed_at: Time.current)
user.notification_email = 'original@example.com'
user.save!
end

View File

@ -42,10 +42,6 @@ RSpec.shared_examples 'issuables list meta-data' do |issuable_type, action = nil
let(:result_issuable) { issuables.first }
let(:search) { result_issuable.title }
before do
stub_feature_flags(attempt_project_search_optimizations: true)
end
# .simple_sorts is the same across all Sortable classes
sorts = ::Issue.simple_sorts.keys + %w[popularity priority label_priority]
sorts.each do |sort|

View File

@ -63,7 +63,7 @@ RSpec.shared_examples 'uploads migration worker' do
if success > 0
it 'outputs the reports' do
expect(Rails.logger).to receive(:info).with(%r{Migrated #{success}/#{total} files})
expect(Gitlab::AppLogger).to receive(:info).with(%r{Migrated #{success}/#{total} files})
perform(uploads)
end
@ -71,7 +71,7 @@ RSpec.shared_examples 'uploads migration worker' do
if failures > 0
it 'outputs upload failures' do
expect(Rails.logger).to receive(:warn).with(/Error .* I am a teapot/)
expect(Gitlab::AppLogger).to receive(:warn).with(/Error .* I am a teapot/)
perform(uploads)
end

View File

@ -15,7 +15,7 @@ RSpec.describe NewIssueWorker do
end
it 'logs an error' do
expect(Rails.logger).to receive(:error).with('NewIssueWorker: couldn\'t find Issue with ID=99, skipping job')
expect(Gitlab::AppLogger).to receive(:error).with('NewIssueWorker: couldn\'t find Issue with ID=99, skipping job')
worker.perform(99, create(:user).id)
end
@ -32,7 +32,7 @@ RSpec.describe NewIssueWorker do
it 'logs an error' do
issue = create(:issue)
expect(Rails.logger).to receive(:error).with('NewIssueWorker: couldn\'t find User with ID=99, skipping job')
expect(Gitlab::AppLogger).to receive(:error).with('NewIssueWorker: couldn\'t find User with ID=99, skipping job')
worker.perform(issue.id, 99)
end

View File

@ -17,7 +17,7 @@ RSpec.describe NewMergeRequestWorker do
it 'logs an error' do
user = create(:user)
expect(Rails.logger).to receive(:error).with('NewMergeRequestWorker: couldn\'t find MergeRequest with ID=99, skipping job')
expect(Gitlab::AppLogger).to receive(:error).with('NewMergeRequestWorker: couldn\'t find MergeRequest with ID=99, skipping job')
worker.perform(99, user.id)
end
@ -34,7 +34,7 @@ RSpec.describe NewMergeRequestWorker do
it 'logs an error' do
merge_request = create(:merge_request)
expect(Rails.logger).to receive(:error).with('NewMergeRequestWorker: couldn\'t find User with ID=99, skipping job')
expect(Gitlab::AppLogger).to receive(:error).with('NewMergeRequestWorker: couldn\'t find User with ID=99, skipping job')
worker.perform(merge_request.id, 99)
end

View File

@ -59,7 +59,7 @@ RSpec.describe RunPipelineScheduleWorker do
end
it 'logging a pipeline error' do
expect(Rails.logger)
expect(Gitlab::AppLogger)
.to receive(:error)
.with(a_string_matching('ActiveRecord::StatementInvalid'))
.and_call_original