Commit 5d75b2b9 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 6f2065c4
...@@ -425,7 +425,7 @@ gem 'gitlab-mail_room', '~> 0.0.3', require: 'mail_room' ...@@ -425,7 +425,7 @@ gem 'gitlab-mail_room', '~> 0.0.3', require: 'mail_room'
gem 'email_reply_trimmer', '~> 0.1' gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text' gem 'html2text'
gem 'ruby-prof', '~> 1.0.0' gem 'ruby-prof', '~> 1.3.0'
gem 'stackprof', '~> 0.2.15', require: false gem 'stackprof', '~> 0.2.15', require: false
gem 'rbtrace', '~> 0.4', require: false gem 'rbtrace', '~> 0.4', require: false
gem 'memory_profiler', '~> 0.9', require: false gem 'memory_profiler', '~> 0.9', require: false
......
...@@ -951,7 +951,7 @@ GEM ...@@ -951,7 +951,7 @@ GEM
i18n i18n
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-prof (1.0.0) ruby-prof (1.3.1)
ruby-progressbar (1.10.1) ruby-progressbar (1.10.1)
ruby-saml (1.7.2) ruby-saml (1.7.2)
nokogiri (>= 1.5.10) nokogiri (>= 1.5.10)
...@@ -1358,7 +1358,7 @@ DEPENDENCIES ...@@ -1358,7 +1358,7 @@ DEPENDENCIES
rubocop-performance (~> 1.4.1) rubocop-performance (~> 1.4.1)
rubocop-rspec (~> 1.37.0) rubocop-rspec (~> 1.37.0)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 1.0.0) ruby-prof (~> 1.3.0)
ruby-progressbar ruby-progressbar
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
rubyzip (~> 2.0.0) rubyzip (~> 2.0.0)
......
...@@ -68,6 +68,9 @@ module BulkInsertSafe ...@@ -68,6 +68,9 @@ module BulkInsertSafe
# @param [Boolean] validate Whether validations should run on [items] # @param [Boolean] validate Whether validations should run on [items]
# @param [Integer] batch_size How many items should at most be inserted at once # @param [Integer] batch_size How many items should at most be inserted at once
# @param [Boolean] skip_duplicates Marks duplicates as allowed, and skips inserting them # @param [Boolean] skip_duplicates Marks duplicates as allowed, and skips inserting them
# @param [Symbol] returns Pass :ids to return an array with the primary key values
# for all inserted records or nil to omit the underlying
# RETURNING SQL clause entirely.
# @param [Proc] handle_attributes Block that will receive each item attribute hash # @param [Proc] handle_attributes Block that will receive each item attribute hash
# prior to insertion for further processing # prior to insertion for further processing
# #
...@@ -78,10 +81,11 @@ module BulkInsertSafe ...@@ -78,10 +81,11 @@ module BulkInsertSafe
# #
# @return true if operation succeeded, throws otherwise. # @return true if operation succeeded, throws otherwise.
# #
def bulk_insert!(items, validate: true, skip_duplicates: false, batch_size: DEFAULT_BATCH_SIZE, &handle_attributes) def bulk_insert!(items, validate: true, skip_duplicates: false, returns: nil, batch_size: DEFAULT_BATCH_SIZE, &handle_attributes)
_bulk_insert_all!(items, _bulk_insert_all!(items,
validate: validate, validate: validate,
on_duplicate: skip_duplicates ? :skip : :raise, on_duplicate: skip_duplicates ? :skip : :raise,
returns: returns,
unique_by: nil, unique_by: nil,
batch_size: batch_size, batch_size: batch_size,
&handle_attributes) &handle_attributes)
...@@ -94,6 +98,9 @@ module BulkInsertSafe ...@@ -94,6 +98,9 @@ module BulkInsertSafe
# @param [Boolean] validate Whether validations should run on [items] # @param [Boolean] validate Whether validations should run on [items]
# @param [Integer] batch_size How many items should at most be inserted at once # @param [Integer] batch_size How many items should at most be inserted at once
# @param [Symbol/Array] unique_by Defines index or columns to use to consider item duplicate # @param [Symbol/Array] unique_by Defines index or columns to use to consider item duplicate
# @param [Symbol] returns Pass :ids to return an array with the primary key values
# for all inserted or updated records or nil to omit the
# underlying RETURNING SQL clause entirely.
# @param [Proc] handle_attributes Block that will receive each item attribute hash # @param [Proc] handle_attributes Block that will receive each item attribute hash
# prior to insertion for further processing # prior to insertion for further processing
# #
...@@ -109,10 +116,11 @@ module BulkInsertSafe ...@@ -109,10 +116,11 @@ module BulkInsertSafe
# #
# @return true if operation succeeded, throws otherwise. # @return true if operation succeeded, throws otherwise.
# #
def bulk_upsert!(items, unique_by:, validate: true, batch_size: DEFAULT_BATCH_SIZE, &handle_attributes) def bulk_upsert!(items, unique_by:, returns: nil, validate: true, batch_size: DEFAULT_BATCH_SIZE, &handle_attributes)
_bulk_insert_all!(items, _bulk_insert_all!(items,
validate: validate, validate: validate,
on_duplicate: :update, on_duplicate: :update,
returns: returns,
unique_by: unique_by, unique_by: unique_by,
batch_size: batch_size, batch_size: batch_size,
&handle_attributes) &handle_attributes)
...@@ -120,21 +128,30 @@ module BulkInsertSafe ...@@ -120,21 +128,30 @@ module BulkInsertSafe
private private
def _bulk_insert_all!(items, on_duplicate:, unique_by:, validate:, batch_size:, &handle_attributes) def _bulk_insert_all!(items, on_duplicate:, returns:, unique_by:, validate:, batch_size:, &handle_attributes)
return true if items.empty? return [] if items.empty?
returning =
case returns
when :ids
[primary_key]
when nil
false
else
raise ArgumentError, "returns needs to be :ids or nil"
end
transaction do transaction do
items.each_slice(batch_size) do |item_batch| items.each_slice(batch_size).flat_map do |item_batch|
attributes = _bulk_insert_item_attributes( attributes = _bulk_insert_item_attributes(
item_batch, validate, &handle_attributes) item_batch, validate, &handle_attributes)
ActiveRecord::InsertAll ActiveRecord::InsertAll
.new(self, attributes, on_duplicate: on_duplicate, unique_by: unique_by) .new(self, attributes, on_duplicate: on_duplicate, returning: returning, unique_by: unique_by)
.execute .execute
.pluck(primary_key)
end end
end end
true
end end
def _bulk_insert_item_attributes(items, validate_items) def _bulk_insert_item_attributes(items, validate_items)
......
...@@ -58,7 +58,7 @@ module Projects ...@@ -58,7 +58,7 @@ module Projects
end end
def tree_saver_class def tree_saver_class
if ::Feature.enabled?(:streaming_serializer, project) if ::Feature.enabled?(:streaming_serializer, project, default_enabled: true)
Gitlab::ImportExport::Project::TreeSaver Gitlab::ImportExport::Project::TreeSaver
else else
# Once we remove :streaming_serializer feature flag, Project::LegacyTreeSaver should be removed as well # Once we remove :streaming_serializer feature flag, Project::LegacyTreeSaver should be removed as well
......
# frozen_string_literal: true
module Projects
module Prometheus
module Alerts
class NotifyService < BaseService
include Gitlab::Utils::StrongMemoize
include IncidentManagement::Settings
def execute(token)
return false unless valid_payload_size?
return false unless valid_version?
return false unless valid_alert_manager_token?(token)
persist_events
send_alert_email if send_email?
process_incident_issues if process_issues?
true
end
private
def valid_payload_size?
Gitlab::Utils::DeepSize.new(params).valid?
end
def send_email?
incident_management_setting.send_email && firings.any?
end
def firings
@firings ||= alerts_by_status('firing')
end
def alerts_by_status(status)
alerts.select { |alert| alert['status'] == status }
end
def alerts
params['alerts']
end
def valid_version?
params['version'] == '4'
end
def valid_alert_manager_token?(token)
valid_for_manual?(token) || valid_for_managed?(token)
end
def valid_for_manual?(token)
prometheus = project.find_or_initialize_service('prometheus')
return false unless prometheus.manual_configuration?
if setting = project.alerting_setting
compare_token(token, setting.token)
else
token.nil?
end
end
def valid_for_managed?(token)
prometheus_application = available_prometheus_application(project)
return false unless prometheus_application
if token
compare_token(token, prometheus_application.alert_manager_token)
else
prometheus_application.alert_manager_token.nil?
end
end
def available_prometheus_application(project)
alert_id = gitlab_alert_id
return unless alert_id
alert = find_alert(project, alert_id)
return unless alert
cluster = alert.environment.deployment_platform&.cluster
return unless cluster&.enabled?
return unless cluster.application_prometheus_available?
cluster.application_prometheus
end
def find_alert(project, metric)
Projects::Prometheus::AlertsFinder
.new(project: project, metric: metric)
.execute
.first
end
def gitlab_alert_id
alerts&.first&.dig('labels', 'gitlab_alert_id')
end
def compare_token(expected, actual)
return unless expected && actual
ActiveSupport::SecurityUtils.secure_compare(expected, actual)
end
def send_alert_email
notification_service
.async
.prometheus_alerts_fired(project, firings)
end
def process_incident_issues
alerts.each do |alert|
IncidentManagement::ProcessPrometheusAlertWorker
.perform_async(project.id, alert.to_h)
end
end
def persist_events
CreateEventsService.new(project, nil, params).execute
end
end
end
end
end
---
title: Enable streaming serializer feature flag by default.
merge_request: 27813
author:
type: performance
---
title: Add support for Okta as a SCIM provider
merge_request: 25649
author:
type: added
# frozen_string_literal: true
# Patch to use COPY in db/structure.sql when populating schema_migrations table
# This is intended to reduce potential for merge conflicts in db/structure.sql
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(Gitlab::Database::PostgresqlAdapter::SchemaVersionsCopyMixin)
...@@ -11775,1023 +11775,1024 @@ ALTER TABLE ONLY public.timelogs ...@@ -11775,1023 +11775,1024 @@ ALTER TABLE ONLY public.timelogs
ALTER TABLE ONLY public.timelogs ALTER TABLE ONLY public.timelogs
ADD CONSTRAINT fk_timelogs_merge_requests_merge_request_id FOREIGN KEY (merge_request_id) REFERENCES public.merge_requests(id) ON DELETE CASCADE; ADD CONSTRAINT fk_timelogs_merge_requests_merge_request_id FOREIGN KEY (merge_request_id) REFERENCES public.merge_requests(id) ON DELETE CASCADE;
INSERT INTO "schema_migrations" (version) VALUES COPY "schema_migrations" (version) FROM STDIN;
('20171230123729'), 20171230123729
('20180101160629'), 20180101160629
('20180101160630'), 20180101160630
('20180102220145'), 20180102220145
('20180103123548'), 20180103123548
('20180104131052'), 20180104131052
('20180105212544'), 20180105212544
('20180109183319'), 20180109183319
('20180113220114'), 20180113220114
('20180115094742'), 20180115094742
('20180115113902'), 20180115113902
('20180115201419'), 20180115201419
('20180116193854'), 20180116193854
('20180119121225'), 20180119121225
('20180119135717'), 20180119135717
('20180119160751'), 20180119160751
('20180122154930'), 20180122154930
('20180122162010'), 20180122162010
('20180125214301'), 20180125214301
('20180129193323'), 20180129193323
('20180201102129'), 20180201102129
('20180201110056'), 20180201110056
('20180201145907'), 20180201145907
('20180204200836'), 20180204200836
('20180206200543'), 20180206200543
('20180208183958'), 20180208183958
('20180209115333'), 20180209115333
('20180209165249'), 20180209165249
('20180212030105'), 20180212030105
('20180212101828'), 20180212101828
('20180212101928'), 20180212101928
('20180212102028'), 20180212102028
('20180213131630'), 20180213131630
('20180214093516'), 20180214093516
('20180214155405'), 20180214155405
('20180215181245'), 20180215181245
('20180216120000'), 20180216120000
('20180216120010'), 20180216120010
('20180216120020'), 20180216120020
('20180216120030'), 20180216120030
('20180216120040'), 20180216120040
('20180216120050'), 20180216120050
('20180216121020'), 20180216121020
('20180216121030'), 20180216121030
('20180219153455'), 20180219153455
('20180220150310'), 20180220150310
('20180221151752'), 20180221151752
('20180222043024'), 20180222043024
('20180223120443'), 20180223120443
('20180223124427'), 20180223124427
('20180223144945'), 20180223144945
('20180226050030'), 20180226050030
('20180227182112'), 20180227182112
('20180228172924'), 20180228172924
('20180301010859'), 20180301010859
('20180301084653'), 20180301084653
('20180302152117'), 20180302152117
('20180305095250'), 20180305095250
('20180305100050'), 20180305100050
('20180305144721'), 20180305144721
('20180306074045'), 20180306074045
('20180306134842'), 20180306134842
('20180306164012'), 20180306164012
('20180307012445'), 20180307012445
('20180308052825'), 20180308052825
('20180308125206'), 20180308125206
('20180309121820'), 20180309121820
('20180309160427'), 20180309160427
('20180314100728'), 20180314100728
('20180314145917'), 20180314145917
('20180315160435'), 20180315160435
('20180319190020'), 20180319190020
('20180320182229'), 20180320182229
('20180323150945'), 20180323150945
('20180326202229'), 20180326202229
('20180327101207'), 20180327101207
('20180330121048'), 20180330121048
('20180403035759'), 20180403035759
('20180405101928'), 20180405101928
('20180405142733'), 20180405142733
('20180408143354'), 20180408143354
('20180408143355'), 20180408143355
('20180409170809'), 20180409170809
('20180413022611'), 20180413022611
('20180416155103'), 20180416155103
('20180417090132'), 20180417090132
('20180417101040'), 20180417101040
('20180417101940'), 20180417101940
('20180418053107'), 20180418053107
('20180420010016'), 20180420010016
('20180420010616'), 20180420010616
('20180420080616'), 20180420080616
('20180423204600'), 20180423204600
('20180424090541'), 20180424090541
('20180424134533'), 20180424134533
('20180424151928'), 20180424151928
('20180424160449'), 20180424160449
('20180425075446'), 20180425075446
('20180425131009'), 20180425131009
('20180425205249'), 20180425205249
('20180426102016'), 20180426102016
('20180430101916'), 20180430101916
('20180430143705'), 20180430143705
('20180502122856'), 20180502122856
('20180503131624'), 20180503131624
('20180503141722'), 20180503141722
('20180503150427'), 20180503150427
('20180503175053'), 20180503175053
('20180503175054'), 20180503175054
('20180503193542'), 20180503193542
('20180503193953'), 20180503193953
('20180503200320'), 20180503200320
('20180504195842'), 20180504195842
('20180507083701'), 20180507083701
('20180508055821'), 20180508055821
('20180508100222'), 20180508100222
('20180508102840'), 20180508102840
('20180508135515'), 20180508135515
('20180511090724'), 20180511090724
('20180511131058'), 20180511131058
('20180511174224'), 20180511174224
('20180512061621'), 20180512061621
('20180514161336'), 20180514161336
('20180515005612'), 20180515005612
('20180515121227'), 20180515121227
('20180517082340'), 20180517082340
('20180523042841'), 20180523042841
('20180523125103'), 20180523125103
('20180524132016'), 20180524132016
('20180529093006'), 20180529093006
('20180529152628'), 20180529152628
('20180530135500'), 20180530135500
('20180531185349'), 20180531185349
('20180531220618'), 20180531220618
('20180601213245'), 20180601213245
('20180603190921'), 20180603190921
('20180604123514'), 20180604123514
('20180607071808'), 20180607071808
('20180608091413'), 20180608091413
('20180608110058'), 20180608110058
('20180608201435'), 20180608201435
('20180612103626'), 20180612103626
('20180613081317'), 20180613081317
('20180625113853'), 20180625113853
('20180626125654'), 20180626125654
('20180628124813'), 20180628124813
('20180629153018'), 20180629153018
('20180629191052'), 20180629191052
('20180702120647'), 20180702120647
('20180702124358'), 20180702124358
('20180702134423'), 20180702134423
('20180704145007'), 20180704145007
('20180704204006'), 20180704204006
('20180705160945'), 20180705160945
('20180706223200'), 20180706223200
('20180710162338'), 20180710162338
('20180711103851'), 20180711103851
('20180711103922'), 20180711103922
('20180713092803'), 20180713092803
('20180717125853'), 20180717125853
('20180718005113'), 20180718005113
('20180720023512'), 20180720023512
('20180722103201'), 20180722103201
('20180723135214'), 20180723135214
('20180726172057'), 20180726172057
('20180807153545'), 20180807153545
('20180808162000'), 20180808162000
('20180809195358'), 20180809195358
('20180813101999'), 20180813101999
('20180813102000'), 20180813102000
('20180814153625'), 20180814153625
('20180815040323'), 20180815040323
('20180815160409'), 20180815160409
('20180815170510'), 20180815170510
('20180815175440'), 20180815175440
('20180816161409'), 20180816161409
('20180816193530'), 20180816193530
('20180824202952'), 20180824202952
('20180826111825'), 20180826111825
('20180831164905'), 20180831164905
('20180831164907'), 20180831164907
('20180831164908'), 20180831164908
('20180831164909'), 20180831164909
('20180831164910'), 20180831164910
('20180901171833'), 20180901171833
('20180901200537'), 20180901200537
('20180902070406'), 20180902070406
('20180906101639'), 20180906101639
('20180907015926'), 20180907015926
('20180910115836'), 20180910115836
('20180910153412'), 20180910153412
('20180910153413'), 20180910153413
('20180912111628'), 20180912111628
('20180913142237'), 20180913142237
('20180914162043'), 20180914162043
('20180914201132'), 20180914201132
('20180916011959'), 20180916011959
('20180917172041'), 20180917172041
('20180924141949'), 20180924141949
('20180924190739'), 20180924190739
('20180924201039'), 20180924201039
('20180925200829'), 20180925200829
('20180927073410'), 20180927073410
('20181002172433'), 20181002172433
('20181005110927'), 20181005110927
('20181005125926'), 20181005125926
('20181006004100'), 20181006004100
('20181008145341'), 20181008145341
('20181008145359'), 20181008145359
('20181008200441'), 20181008200441
('20181009190428'), 20181009190428
('20181010133639'), 20181010133639
('20181010235606'), 20181010235606
('20181013005024'), 20181013005024
('20181014203236'), 20181014203236
('20181015155839'), 20181015155839
('20181016141739'), 20181016141739
('20181016152238'), 20181016152238
('20181017001059'), 20181017001059
('20181019032400'), 20181019032400
('20181019032408'), 20181019032408
('20181019105553'), 20181019105553
('20181022135539'), 20181022135539
('20181022173835'), 20181022173835
('20181023104858'), 20181023104858
('20181023144439'), 20181023144439
('20181025115728'), 20181025115728
('20181026091631'), 20181026091631
('20181026143227'), 20181026143227
('20181027114222'), 20181027114222
('20181028120717'), 20181028120717
('20181030135124'), 20181030135124
('20181030154446'), 20181030154446
('20181031145139'), 20181031145139
('20181031190558'), 20181031190558
('20181031190559'), 20181031190559
('20181101091005'), 20181101091005
('20181101091124'), 20181101091124
('20181101144347'), 20181101144347
('20181101191341'), 20181101191341
('20181105201455'), 20181105201455
('20181106135939'), 20181106135939
('20181107054254'), 20181107054254
('20181108091549'), 20181108091549
('20181112103239'), 20181112103239
('20181115140140'), 20181115140140
('20181116050532'), 20181116050532
('20181116141415'), 20181116141415
('20181116141504'), 20181116141504
('20181119081539'), 20181119081539
('20181119132520'), 20181119132520
('20181120082911'), 20181120082911
('20181120091639'), 20181120091639
('20181120151656'), 20181120151656
('20181121101842'), 20181121101842
('20181121101843'), 20181121101843
('20181121111200'), 20181121111200
('20181122160027'), 20181122160027
('20181123042307'), 20181123042307
('20181123135036'), 20181123135036
('20181123144235'), 20181123144235
('20181126150622'), 20181126150622
('20181126153547'), 20181126153547
('20181128123704'), 20181128123704
('20181129104854'), 20181129104854
('20181129104944'), 20181129104944
('20181130102132'), 20181130102132
('20181203002526'), 20181203002526
('20181205171941'), 20181205171941
('20181211092510'), 20181211092510
('20181211092514'), 20181211092514
('20181212104941'), 20181212104941
('20181212171634'), 20181212171634
('20181219130552'), 20181219130552
('20181219145520'), 20181219145520
('20181219145521'), 20181219145521
('20181228175414'), 20181228175414
('20190102152410'), 20190102152410
('20190103140724'), 20190103140724
('20190104182041'), 20190104182041
('20190107151020'), 20190107151020
('20190108192941'), 20190108192941
('20190109153125'), 20190109153125
('20190114172110'), 20190114172110
('20190115054215'), 20190115054215
('20190115054216'), 20190115054216
('20190115092821'), 20190115092821
('20190116234221'), 20190116234221
('20190124200344'), 20190124200344
('20190130091630'), 20190130091630
('20190131122559'), 20190131122559
('20190204115450'), 20190204115450
('20190206193120'), 20190206193120
('20190211131150'), 20190211131150
('20190214112022'), 20190214112022
('20190215154930'), 20190215154930
('20190218134158'), 20190218134158
('20190218134209'), 20190218134209
('20190219201635'), 20190219201635
('20190220142344'), 20190220142344
('20190220150130'), 20190220150130
('20190222051615'), 20190222051615
('20190225152525'), 20190225152525
('20190225160300'), 20190225160300
('20190225160301'), 20190225160301
('20190228192410'), 20190228192410
('20190301081611'), 20190301081611
('20190301182457'), 20190301182457
('20190312071108'), 20190312071108
('20190312113229'), 20190312113229
('20190312113634'), 20190312113634
('20190313092516'), 20190313092516
('20190315191339'), 20190315191339
('20190320174702'), 20190320174702
('20190322132835'), 20190322132835
('20190322164830'), 20190322164830
('20190325080727'), 20190325080727
('20190325105715'), 20190325105715
('20190325111602'), 20190325111602
('20190325165127'), 20190325165127
('20190326164045'), 20190326164045
('20190327163904'), 20190327163904
('20190329085614'), 20190329085614
('20190402150158'), 20190402150158
('20190402224749'), 20190402224749
('20190403161806'), 20190403161806
('20190404143330'), 20190404143330
('20190404231137'), 20190404231137
('20190408163745'), 20190408163745
('20190409224933'), 20190409224933
('20190410173409'), 20190410173409
('20190412155659'), 20190412155659
('20190412183653'), 20190412183653
('20190414185432'), 20190414185432
('20190415030217'), 20190415030217
('20190415095825'), 20190415095825
('20190415172035'), 20190415172035
('20190416185130'), 20190416185130
('20190416213556'), 20190416213556
('20190416213615'), 20190416213615
('20190416213631'), 20190416213631
('20190418132125'), 20190418132125
('20190418132750'), 20190418132750
('20190418182545'), 20190418182545
('20190419121952'), 20190419121952
('20190419123057'), 20190419123057
('20190422082247'), 20190422082247
('20190423124640'), 20190423124640
('20190424134256'), 20190424134256
('20190426180107'), 20190426180107
('20190429082448'), 20190429082448
('20190430131225'), 20190430131225
('20190430142025'), 20190430142025
('20190506135337'), 20190506135337
('20190506135400'), 20190506135400
('20190511144331'), 20190511144331
('20190513174947'), 20190513174947
('20190514105711'), 20190514105711
('20190515125613'), 20190515125613
('20190516011213'), 20190516011213
('20190516151857'), 20190516151857
('20190516155724'), 20190516155724
('20190517153211'), 20190517153211
('20190520200123'), 20190520200123
('20190520201748'), 20190520201748
('20190521174505'), 20190521174505
('20190522143720'), 20190522143720
('20190523112344'), 20190523112344
('20190524062810'), 20190524062810
('20190524071727'), 20190524071727
('20190524073827'), 20190524073827
('20190527011309'), 20190527011309
('20190527194830'), 20190527194830
('20190527194900'), 20190527194900
('20190528173628'), 20190528173628
('20190528180441'), 20190528180441
('20190529142545'), 20190529142545
('20190530042141'), 20190530042141
('20190530154715'), 20190530154715
('20190531153110'), 20190531153110
('20190602014139'), 20190602014139
('20190603124955'), 20190603124955
('20190604091310'), 20190604091310
('20190604184643'), 20190604184643
('20190605104727'), 20190605104727
('20190605184422'), 20190605184422
('20190606014128'), 20190606014128
('20190606034427'), 20190606034427
('20190606054649'), 20190606054649
('20190606054742'), 20190606054742
('20190606054832'), 20190606054832
('20190606163724'), 20190606163724
('20190606175050'), 20190606175050
('20190606202100'), 20190606202100
('20190607085356'), 20190607085356
('20190607145325'), 20190607145325
('20190607190856'), 20190607190856
('20190607205656'), 20190607205656
('20190610142825'), 20190610142825
('20190611090827'), 20190611090827
('20190611100201'), 20190611100201
('20190611100202'), 20190611100202
('20190611161641'), 20190611161641
('20190611161642'), 20190611161642
('20190612111201'), 20190612111201
('20190612111404'), 20190612111404
('20190613030606'), 20190613030606
('20190613044655'), 20190613044655
('20190613073003'), 20190613073003
('20190613231640'), 20190613231640
('20190617123615'), 20190617123615
('20190618171120'), 20190618171120
('20190619175843'), 20190619175843
('20190620105427'), 20190620105427
('20190620112608'), 20190620112608
('20190621022810'), 20190621022810
('20190621151636'), 20190621151636
('20190623212503'), 20190623212503
('20190624123615'), 20190624123615
('20190625115224'), 20190625115224
('20190625184066'), 20190625184066
('20190626175626'), 20190626175626
('20190627051902'), 20190627051902
('20190627100221'), 20190627100221
('20190627122264'), 20190627122264
('20190628145246'), 20190628145246
('20190628185000'), 20190628185000
('20190628185004'), 20190628185004
('20190628191740'), 20190628191740
('20190702173936'), 20190702173936
('20190703043358'), 20190703043358
('20190703130053'), 20190703130053
('20190703171157'), 20190703171157
('20190703171555'), 20190703171555
('20190703185326'), 20190703185326
('20190709204413'), 20190709204413
('20190709220014'), 20190709220014
('20190709220143'), 20190709220143
('20190710151229'), 20190710151229
('20190711124721'), 20190711124721
('20190711200053'), 20190711200053
('20190711200508'), 20190711200508
('20190711201818'), 20190711201818
('20190712040400'), 20190712040400
('20190712040412'), 20190712040412
('20190712064021'), 20190712064021
('20190715042813'), 20190715042813
('20190715043944'), 20190715043944
('20190715043954'), 20190715043954
('20190715044501'), 20190715044501
('20190715114644'), 20190715114644
('20190715140740'), 20190715140740
('20190715142138'), 20190715142138
('20190715173819'), 20190715173819
('20190715193142'), 20190715193142
('20190715215532'), 20190715215532
('20190715215549'), 20190715215549
('20190716144222'), 20190716144222
('20190719122333'), 20190719122333
('20190719174505'), 20190719174505
('20190722104947'), 20190722104947
('20190722132830'), 20190722132830
('20190722144316'), 20190722144316
('20190723105753'), 20190723105753
('20190723153247'), 20190723153247
('20190724112147'), 20190724112147
('20190725012225'), 20190725012225
('20190725080128'), 20190725080128
('20190725183432'), 20190725183432
('20190726101050'), 20190726101050
('20190726101133'), 20190726101133
('20190729062536'), 20190729062536
('20190729090456'), 20190729090456
('20190729180447'), 20190729180447
('20190731084415'), 20190731084415
('20190801060809'), 20190801060809
('20190801114109'), 20190801114109
('20190801142441'), 20190801142441
('20190801193427'), 20190801193427
('20190802012622'), 20190802012622
('20190802091750'), 20190802091750
('20190802195602'), 20190802195602
('20190802235445'), 20190802235445
('20190805140353'), 20190805140353
('20190806071559'), 20190806071559
('20190807023052'), 20190807023052
('20190808152507'), 20190808152507
('20190809072552'), 20190809072552
('20190812070645'), 20190812070645
('20190814205640'), 20190814205640
('20190815093936'), 20190815093936
('20190815093949'), 20190815093949
('20190816151221'), 20190816151221
('20190819131155'), 20190819131155
('20190819231552'), 20190819231552
('20190820163320'), 20190820163320
('20190821040941'), 20190821040941
('20190822175441'), 20190822175441
('20190822181528'), 20190822181528
('20190822185441'), 20190822185441
('20190823055948'), 20190823055948
('20190826090628'), 20190826090628
('20190826100605'), 20190826100605
('20190827102026'), 20190827102026
('20190827222124'), 20190827222124
('20190828083843'), 20190828083843
('20190828110802'), 20190828110802
('20190828170945'), 20190828170945
('20190828172831'), 20190828172831
('20190829131130'), 20190829131130
('20190830075508'), 20190830075508
('20190830080123'), 20190830080123
('20190830080626'), 20190830080626
('20190830140240'), 20190830140240
('20190901174200'), 20190901174200
('20190902131045'), 20190902131045
('20190902152329'), 20190902152329
('20190902160015'), 20190902160015
('20190903150358'), 20190903150358
('20190903150435'), 20190903150435
('20190904173203'), 20190904173203
('20190904205212'), 20190904205212
('20190905022045'), 20190905022045
('20190905074652'), 20190905074652
('20190905091812'), 20190905091812
('20190905091831'), 20190905091831
('20190905140605'), 20190905140605
('20190905223800'), 20190905223800
('20190905223900'), 20190905223900
('20190906104555'), 20190906104555
('20190907184714'), 20190907184714
('20190909045845'), 20190909045845
('20190909141517'), 20190909141517
('20190910000130'), 20190910000130
('20190910103144'), 20190910103144
('20190910114843'), 20190910114843
('20190910125852'), 20190910125852
('20190910211526'), 20190910211526
('20190910212256'), 20190910212256
('20190911115056'), 20190911115056
('20190911115109'), 20190911115109
('20190911115207'), 20190911115207
('20190911115222'), 20190911115222
('20190911251732'), 20190911251732
('20190912061145'), 20190912061145
('20190912223232'), 20190912223232
('20190913174707'), 20190913174707
('20190913175827'), 20190913175827
('20190914223900'), 20190914223900
('20190917173107'), 20190917173107
('20190918025618'), 20190918025618
('20190918102042'), 20190918102042
('20190918104212'), 20190918104212
('20190918104222'), 20190918104222
('20190918104731'), 20190918104731
('20190918121135'), 20190918121135
('20190919040324'), 20190919040324
('20190919091300'), 20190919091300
('20190919104119'), 20190919104119
('20190919162036'), 20190919162036
('20190919183411'), 20190919183411
('20190920122420'), 20190920122420
('20190920194925'), 20190920194925
('20190920224341'), 20190920224341
('20190924124627'), 20190924124627
('20190924152703'), 20190924152703
('20190925055714'), 20190925055714
('20190925055902'), 20190925055902
('20190926041216'), 20190926041216
('20190926180443'), 20190926180443
('20190926225633'), 20190926225633
('20190927055500'), 20190927055500
('20190927055540'), 20190927055540
('20190927074328'), 20190927074328
('20190929180751'), 20190929180751
('20190929180813'), 20190929180813
('20190929180827'), 20190929180827
('20190930025655'), 20190930025655
('20190930063627'), 20190930063627
('20190930082942'), 20190930082942
('20190930153535'), 20190930153535
('20191001040549'), 20191001040549
('20191001170300'), 20191001170300
('20191002031332'), 20191002031332
('20191002123516'), 20191002123516
('20191003015155'), 20191003015155
('20191003060227'), 20191003060227
('20191003064615'), 20191003064615
('20191003130045'), 20191003130045
('20191003150045'), 20191003150045
('20191003161031'), 20191003161031
('20191003161032'), 20191003161032
('20191003195218'), 20191003195218
('20191003195620'), 20191003195620
('20191003200045'), 20191003200045
('20191003250045'), 20191003250045
('20191003300045'), 20191003300045
('20191003350045'), 20191003350045
('20191004080818'), 20191004080818
('20191004081520'), 20191004081520
('20191004133612'), 20191004133612
('20191004151428'), 20191004151428
('20191007163701'), 20191007163701
('20191007163736'), 20191007163736
('20191008013056'), 20191008013056
('20191008142331'), 20191008142331
('20191008143850'), 20191008143850
('20191008180203'), 20191008180203
('20191008200204'), 20191008200204
('20191009100244'), 20191009100244
('20191009110124'), 20191009110124
('20191009110757'), 20191009110757
('20191009222222'), 20191009222222
('20191010174846'), 20191010174846
('20191011084019'), 20191011084019
('20191013100213'), 20191013100213
('20191014025629'), 20191014025629
('20191014030134'), 20191014030134
('20191014030730'), 20191014030730
('20191014084150'), 20191014084150
('20191014123159'), 20191014123159
('20191014132931'), 20191014132931
('20191015154408'), 20191015154408
('20191016072826'), 20191016072826
('20191016133352'), 20191016133352
('20191016220135'), 20191016220135
('20191017001326'), 20191017001326
('20191017045817'), 20191017045817
('20191017094449'), 20191017094449
('20191017134513'), 20191017134513
('20191017180026'), 20191017180026
('20191017191341'), 20191017191341
('20191021101942'), 20191021101942
('20191022113635'), 20191022113635
('20191023093207'), 20191023093207
('20191023132005'), 20191023132005
('20191023152913'), 20191023152913
('20191024134020'), 20191024134020
('20191025092748'), 20191025092748
('20191026041447'), 20191026041447
('20191026120008'), 20191026120008
('20191026120112'), 20191026120112
('20191026124116'), 20191026124116
('20191028130054'), 20191028130054
('20191028162543'), 20191028162543
('20191028184740'), 20191028184740
('20191029095537'), 20191029095537
('20191029125305'), 20191029125305
('20191029191901'), 20191029191901
('20191030135044'), 20191030135044
('20191030152934'), 20191030152934
('20191030193050'), 20191030193050
('20191030223057'), 20191030223057
('20191031095636'), 20191031095636
('20191031112603'), 20191031112603
('20191101092917'), 20191101092917
('20191103202505'), 20191103202505
('20191104142124'), 20191104142124
('20191104205020'), 20191104205020
('20191105094558'), 20191105094558
('20191105094625'), 20191105094625
('20191105134413'), 20191105134413
('20191105140942'), 20191105140942
('20191105155113'), 20191105155113
('20191105193652'), 20191105193652
('20191106144901'), 20191106144901
('20191106150931'), 20191106150931
('20191107064946'), 20191107064946
('20191107173446'), 20191107173446
('20191107220314'), 20191107220314
('20191108031900'), 20191108031900
('20191108202723'), 20191108202723
('20191111115229'), 20191111115229
('20191111115431'), 20191111115431
('20191111121500'), 20191111121500
('20191111165017'), 20191111165017
('20191111175230'), 20191111175230
('20191112023159'), 20191112023159
('20191112090226'), 20191112090226
('20191112105448'), 20191112105448
('20191112115247'), 20191112115247
('20191112115317'), 20191112115317
('20191112214305'), 20191112214305
('20191112221821'), 20191112221821
('20191112232338'), 20191112232338
('20191114132259'), 20191114132259
('20191114173508'), 20191114173508
('20191114173602'), 20191114173602
('20191114173624'), 20191114173624
('20191114201118'), 20191114201118
('20191114204343'), 20191114204343
('20191115001123'), 20191115001123
('20191115001843'), 20191115001843
('20191115091425'), 20191115091425
('20191115114032'), 20191115114032
('20191115115043'), 20191115115043
('20191115115522'), 20191115115522
('20191118053631'), 20191118053631
('20191118155702'), 20191118155702
('20191118173522'), 20191118173522
('20191118182722'), 20191118182722
('20191118211629'), 20191118211629
('20191119023952'), 20191119023952
('20191119220425'), 20191119220425
('20191119221041'), 20191119221041
('20191119231621'), 20191119231621
('20191120084627'), 20191120084627
('20191120115530'), 20191120115530
('20191120200015'), 20191120200015
('20191121111621'), 20191121111621
('20191121121947'), 20191121121947
('20191121122856'), 20191121122856
('20191121161018'), 20191121161018
('20191121193110'), 20191121193110
('20191122135327'), 20191122135327
('20191122161519'), 20191122161519
('20191123062354'), 20191123062354
('20191123081456'), 20191123081456
('20191124150431'), 20191124150431
('20191125024005'), 20191125024005
('20191125114345'), 20191125114345
('20191125133353'), 20191125133353
('20191125140458'), 20191125140458
('20191126134210'), 20191126134210
('20191127030005'), 20191127030005
('20191127151619'), 20191127151619
('20191127151629'), 20191127151629
('20191127163053'), 20191127163053
('20191127221608'), 20191127221608
('20191128145231'), 20191128145231
('20191128145232'), 20191128145232
('20191128145233'), 20191128145233
('20191128162854'), 20191128162854
('20191129134844'), 20191129134844
('20191129144630'), 20191129144630
('20191129144631'), 20191129144631
('20191202031812'), 20191202031812
('20191202181924'), 20191202181924
('20191203121729'), 20191203121729
('20191204070713'), 20191204070713
('20191204093410'), 20191204093410
('20191204114127'), 20191204114127
('20191204192726'), 20191204192726
('20191205060723'), 20191205060723
('20191205084057'), 20191205084057
('20191205094702'), 20191205094702
('20191205145647'), 20191205145647
('20191205212923'), 20191205212923
('20191205212924'), 20191205212924
('20191206014412'), 20191206014412
('20191206022133'), 20191206022133
('20191206122926'), 20191206122926
('20191207104000'), 20191207104000
('20191208071111'), 20191208071111
('20191208071112'), 20191208071112
('20191208110214'), 20191208110214
('20191209143606'), 20191209143606
('20191209215316'), 20191209215316
('20191210211253'), 20191210211253
('20191212140117'), 20191212140117
('20191212162434'), 20191212162434
('20191213104838'), 20191213104838
('20191213120427'), 20191213120427
('20191213143656'), 20191213143656
('20191213184609'), 20191213184609
('20191214175727'), 20191214175727
('20191216074800'), 20191216074800
('20191216074802'), 20191216074802
('20191216074803'), 20191216074803
('20191216094119'), 20191216094119
('20191216183531'), 20191216183531
('20191216183532'), 20191216183532
('20191217165641'), 20191217165641
('20191217212348'), 20191217212348
('20191218084115'), 20191218084115
('20191218122457'), 20191218122457
('20191218124915'), 20191218124915
('20191218125015'), 20191218125015
('20191218190253'), 20191218190253
('20191218225624'), 20191218225624
('20191223124940'), 20191223124940
('20191225071320'), 20191225071320
('20191227140254'), 20191227140254
('20191229140154'), 20191229140154
('20200102140148'), 20200102140148
('20200102170221'), 20200102170221
('20200103190741'), 20200103190741
('20200103192859'), 20200103192859
('20200103192914'), 20200103192914
('20200103195205'), 20200103195205
('20200104113850'), 20200104113850
('20200106071113'), 20200106071113
('20200106085831'), 20200106085831
('20200107172020'), 20200107172020
('20200108100603'), 20200108100603
('20200108155731'), 20200108155731
('20200108233040'), 20200108233040
('20200109030418'), 20200109030418
('20200109085206'), 20200109085206
('20200109233938'), 20200109233938
('20200110089001'), 20200110089001
('20200110090153'), 20200110090153
('20200110121314'), 20200110121314
('20200110144316'), 20200110144316
('20200110203532'), 20200110203532
('20200113133352'), 20200113133352
('20200113151354'), 20200113151354
('20200114112932'), 20200114112932
('20200114113341'), 20200114113341
('20200114140305'), 20200114140305
('20200114204949'), 20200114204949
('20200115135132'), 20200115135132
('20200115135234'), 20200115135234
('20200116051619'), 20200116051619
('20200116175538'), 20200116175538
('20200117112554'), 20200117112554
('20200117194830'), 20200117194830
('20200117194840'), 20200117194840
('20200117194850'), 20200117194850
('20200117194900'), 20200117194900
('20200120083607'), 20200120083607
('20200121132641'), 20200121132641
('20200121192942'), 20200121192942
('20200121194000'), 20200121194000
('20200121194048'), 20200121194048
('20200121194154'), 20200121194154
('20200121200203'), 20200121200203
('20200122123016'), 20200122123016
('20200122144759'), 20200122144759
('20200122161638'), 20200122161638
('20200123040535'), 20200123040535
('20200123045415'), 20200123045415
('20200123090839'), 20200123090839
('20200123091422'), 20200123091422
('20200123091622'), 20200123091622
('20200123091734'), 20200123091734
('20200123091854'), 20200123091854
('20200123155929'), 20200123155929
('20200124053531'), 20200124053531
('20200124110831'), 20200124110831
('20200124143014'), 20200124143014
('20200127090233'), 20200127090233
('20200127111840'), 20200127111840
('20200128105731'), 20200128105731
('20200128132510'), 20200128132510
('20200128133510'), 20200128133510
('20200128134110'), 20200128134110
('20200128141125'), 20200128141125
('20200128184209'), 20200128184209
('20200128210353'), 20200128210353
('20200129034515'), 20200129034515
('20200129035446'), 20200129035446
('20200129035708'), 20200129035708
('20200129133716'), 20200129133716
('20200129172428'), 20200129172428
('20200130134335'), 20200130134335
('20200130145430'), 20200130145430
('20200130161817'), 20200130161817
('20200131140428'), 20200131140428
('20200131181354'), 20200131181354
('20200131191754'), 20200131191754
('20200202100932'), 20200202100932
('20200203015140'), 20200203015140
('20200203025400'), 20200203025400
('20200203025602'), 20200203025602
('20200203025619'), 20200203025619
('20200203025744'), 20200203025744
('20200203025801'), 20200203025801
('20200203025821'), 20200203025821
('20200203104214'), 20200203104214
('20200203173508'), 20200203173508
('20200203183508'), 20200203183508
('20200203232433'), 20200203232433
('20200204070729'), 20200204070729
('20200204113223'), 20200204113223
('20200204113224'), 20200204113224
('20200204131054'), 20200204131054
('20200204131831'), 20200204131831
('20200205143231'), 20200205143231
('20200206091544'), 20200206091544
('20200206112850'), 20200206112850
('20200206135203'), 20200206135203
('20200206141511'), 20200206141511
('20200207062728'), 20200207062728
('20200207090921'), 20200207090921
('20200207132752'), 20200207132752
('20200207151640'), 20200207151640
('20200207182131'), 20200207182131
('20200207184023'), 20200207184023
('20200207185149'), 20200207185149
('20200209131152'), 20200209131152
('20200210062432'), 20200210062432
('20200210092405'), 20200210092405
('20200210135504'), 20200210135504
('20200210184410'), 20200210184410
('20200210184420'), 20200210184420
('20200211152410'), 20200211152410
('20200211155000'), 20200211155000
('20200211155100'), 20200211155100
('20200211155539'), 20200211155539
('20200211174946'), 20200211174946
('20200212014653'), 20200212014653
('20200212052620'), 20200212052620
('20200212133945'), 20200212133945
('20200212134201'), 20200212134201
('20200213093702'), 20200213093702
('20200213155311'), 20200213155311
('20200213204737'), 20200213204737
('20200213220159'), 20200213220159
('20200213220211'), 20200213220211
('20200214025454'), 20200214025454
('20200214034836'), 20200214034836
('20200214085940'), 20200214085940
('20200214214934'), 20200214214934
('20200215222507'), 20200215222507
('20200215225103'), 20200215225103
('20200217223651'), 20200217223651
('20200217225719'), 20200217225719
('20200219105209'), 20200219105209
('20200219133859'), 20200219133859
('20200219135440'), 20200219135440
('20200219141307'), 20200219141307
('20200219142522'), 20200219142522
('20200219183456'), 20200219183456
('20200219184219'), 20200219184219
('20200219193058'), 20200219193058
('20200219193117'), 20200219193117
('20200220180944'), 20200220180944
('20200221023320'), 20200221023320
('20200221074028'), 20200221074028
('20200221100514'), 20200221100514
('20200221105436'), 20200221105436
('20200221142216'), 20200221142216
('20200221144534'), 20200221144534
('20200222055543'), 20200222055543
('20200224020219'), 20200224020219
('20200224163804'), 20200224163804
('20200224185814'), 20200224185814
('20200225111018'), 20200225111018
('20200225123228'), 20200225123228
('20200226100614'), 20200226100614
('20200226100624'), 20200226100624
('20200226100634'), 20200226100634
('20200226162156'), 20200226162156
('20200226162239'), 20200226162239
('20200226162634'), 20200226162634
('20200226162723'), 20200226162723
('20200227140242'), 20200227140242
('20200227164113'), 20200227164113
('20200227165129'), 20200227165129
('20200228160542'), 20200228160542
('20200302142052'), 20200302142052
('20200302152516'), 20200302152516
('20200303055348'), 20200303055348
('20200303074328'), 20200303074328
('20200304085423'), 20200304085423
('20200304090155'), 20200304090155
('20200304121828'), 20200304121828
('20200304121844'), 20200304121844
('20200304124406'), 20200304124406
('20200304160800'), 20200304160800
('20200304160801'), 20200304160801
('20200304160823'), 20200304160823
('20200304211738'), 20200304211738
('20200305121159'), 20200305121159
('20200305151736'), 20200305151736
('20200306095654'), 20200306095654
('20200306160521'), 20200306160521
('20200306170211'), 20200306170211
('20200306170321'), 20200306170321
('20200306170531'), 20200306170531
('20200306192548'), 20200306192548
('20200306193236'), 20200306193236
('20200309140540'), 20200309140540
('20200309162244'), 20200309162244
('20200309195209'), 20200309195209
('20200309195710'), 20200309195710
('20200310075115'), 20200310075115
('20200310123229'), 20200310123229
('20200310132654'), 20200310132654
('20200310133822'), 20200310133822
('20200310135818'), 20200310135818
('20200310135823'), 20200310135823
('20200310145304'), 20200310145304
('20200311074438'), 20200311074438
('20200311082301'), 20200311082301
('20200311084025'), 20200311084025
('20200311093210'), 20200311093210
('20200311094020'), 20200311094020
('20200311141053'), 20200311141053
('20200311141943'), 20200311141943
('20200311154110'), 20200311154110
('20200311165635'), 20200311165635
('20200311192351'), 20200311192351
('20200311214912'), 20200311214912
('20200312125121'), 20200312125121
('20200312160532'), 20200312160532
('20200312163407'), 20200312163407
('20200313101649'), 20200313101649
('20200313123934'), 20200313123934
('20200316111759'), 20200316111759
('20200316162648'), 20200316162648
('20200316173312'), 20200316173312
('20200317142110'), 20200317142110
('20200318140400'), 20200318140400
('20200318152134'), 20200318152134
('20200318162148'), 20200318162148
('20200318163148'), 20200318163148
('20200318164448'), 20200318164448
('20200318165448'), 20200318165448
('20200318175008'), 20200318175008
('20200319123041'), 20200319123041
('20200319203901'), 20200319203901
('20200320112455'), 20200320112455
('20200320123839'), 20200320123839
('20200323075043'), 20200323075043
('20200323122201'), 20200323122201
('20200324115359'); 20200324115359
\.
...@@ -14,7 +14,7 @@ tasks such as: ...@@ -14,7 +14,7 @@ tasks such as:
To request access to Chatops on GitLab.com: To request access to Chatops on GitLab.com:
1. Log into <https://ops.gitlab.net/users/sign_in> **using the same username** as for GitLab.com (you may have to rename it). 1. Log into <https://ops.gitlab.net/users/sign_in> **using the same username** as for GitLab.com (you may have to rename it).
1. Ask in the [#production](https://gitlab.slack.com/messages/production) channel to add you by running `/chatops run member add <username> gitlab-com/chatops --ops`. 1. Ask in the [#production](https://gitlab.slack.com/messages/production) channel for an existing member to add you to the `chatops` project in Ops. They can do it by running `/chatops run member add <username> gitlab-com/chatops --ops` command in that channel.
NOTE: **Note:** If you had to change your username for GitLab.com on the first step, make sure [to reflect this information](https://gitlab.com/gitlab-com/www-gitlab-com#adding-yourself-to-the-team-page) on [the team page](https://about.gitlab.com/company/team/). NOTE: **Note:** If you had to change your username for GitLab.com on the first step, make sure [to reflect this information](https://gitlab.com/gitlab-com/www-gitlab-com#adding-yourself-to-the-team-page) on [the team page](https://about.gitlab.com/company/team/).
......
...@@ -150,6 +150,10 @@ module API ...@@ -150,6 +150,10 @@ module API
authorize! :download_code, release authorize! :download_code, release
end end
def authorize_create_evidence!
# This is a separate method so that EE can extend its behaviour
end
def release def release
@release ||= user_project.releases.find_by_tag(params[:tag]) @release ||= user_project.releases.find_by_tag(params[:tag])
end end
......
# frozen_string_literal: true
module Gitlab
module Database
module PostgresqlAdapter
module SchemaVersionsCopyMixin
extend ActiveSupport::Concern
def dump_schema_information # :nodoc:
versions = schema_migration.all_versions
copy_versions_sql(versions) if versions.any?
end
private
def copy_versions_sql(versions)
sm_table = quote_table_name(schema_migration.table_name)
sql = +"COPY #{sm_table} (version) FROM STDIN;\n"
sql << versions.map { |v| Integer(v) }.sort.join("\n")
sql << "\n\\.\n"
sql
end
end
end
end
end
...@@ -168,9 +168,9 @@ module Gitlab ...@@ -168,9 +168,9 @@ module Gitlab
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def self.print_by_total_time(result, options = {}) def self.print_by_total_time(result, options = {})
default_options = { sort_method: :total_time } default_options = { sort_method: :total_time, filter_by: :total_time }
Gitlab::Profiler::TotalTimeFlatPrinter.new(result).print(STDOUT, default_options.merge(options)) RubyProf::FlatPrinter.new(result).print(STDOUT, default_options.merge(options))
end end
end end
end end
# frozen_string_literal: true
module Gitlab
module Profiler
class TotalTimeFlatPrinter < RubyProf::FlatPrinter
def max_percent
@options[:max_percent] || 100
end
# Copied from:
# <https://github.com/ruby-prof/ruby-prof/blob/master/lib/ruby-prof/printers/flat_printer.rb>
#
# The changes are just to filter by total time, not self time, and add a
# max_percent option as well.
def print_methods(thread)
total_time = thread.total_time
methods = thread.methods.sort_by(&sort_method).reverse
sum = 0
methods.each do |method|
total_percent = (method.total_time / total_time) * 100
next if total_percent < min_percent
next if total_percent > max_percent
sum += method.self_time
@output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%-30s %s\n" % [
method.self_time / total_time * 100, # %self
method.total_time, # total
method.self_time, # self
method.wait_time, # wait
method.children_time, # children
method.called, # calls
method.recursive? ? "*" : " ", # cycle
method.full_name, # method_name
method_location(method) # location
]
end
end
end
end
end
...@@ -4,75 +4,110 @@ require 'toml-rb' ...@@ -4,75 +4,110 @@ require 'toml-rb'
module Gitlab module Gitlab
module SetupHelper module SetupHelper
class << self def create_configuration(dir, storage_paths, force: false)
# We cannot create config.toml files for all possible Gitaly configuations. generate_configuration(
# For instance, if Gitaly is running on another machine then it makes no configuration_toml(dir, storage_paths),
# sense to write a config.toml file on the current machine. This method will get_config_path(dir),
# only generate a configuration for the most common and simplest case: when force: force
# we have exactly one Gitaly process and we are sure it is running locally )
# because it uses a Unix socket. end
# For development and testing purposes, an extra storage is added to gitaly,
# which is not known to Rails, but must be explicitly stubbed. # rubocop:disable Rails/Output
def gitaly_configuration_toml(gitaly_dir, storage_paths, gitaly_ruby: true) def generate_configuration(toml_data, config_path, force: false)
storages = [] FileUtils.rm_f(config_path) if force
address = nil
File.open(config_path, File::WRONLY | File::CREAT | File::EXCL) do |f|
Gitlab.config.repositories.storages.each do |key, val| f.puts toml_data
if address end
if address != val['gitaly_address'] rescue Errno::EEXIST
raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address." puts 'Skipping config.toml generation:'
puts 'A configuration file already exists.'
rescue ArgumentError => e
puts 'Skipping config.toml generation:'
puts e.message
end
# rubocop:enable Rails/Output
module Gitaly
extend Gitlab::SetupHelper
class << self
# We cannot create config.toml files for all possible Gitaly configuations.
# For instance, if Gitaly is running on another machine then it makes no
# sense to write a config.toml file on the current machine. This method will
# only generate a configuration for the most common and simplest case: when
# we have exactly one Gitaly process and we are sure it is running locally
# because it uses a Unix socket.
# For development and testing purposes, an extra storage is added to gitaly,
# which is not known to Rails, but must be explicitly stubbed.
def configuration_toml(gitaly_dir, storage_paths, gitaly_ruby: true)
storages = []
address = nil
Gitlab.config.repositories.storages.each do |key, val|
if address
if address != val['gitaly_address']
raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address."
end
elsif URI(val['gitaly_address']).scheme != 'unix'
raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses."
else
address = val['gitaly_address']
end end
elsif URI(val['gitaly_address']).scheme != 'unix'
raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses." storages << { name: key, path: storage_paths[key] }
else
address = val['gitaly_address']
end end
storages << { name: key, path: storage_paths[key] } config = { socket_path: address.sub(/\Aunix:/, '') }
end
if Rails.env.test? if Rails.env.test?
storage_path = Rails.root.join('tmp', 'tests', 'second_storage').to_s storage_path = Rails.root.join('tmp', 'tests', 'second_storage').to_s
storages << { name: 'test_second_storage', path: storage_path } storages << { name: 'test_second_storage', path: storage_path }
end
config[:auth] = { token: 'secret' }
# Compared to production, tests run in constrained environments. This
# number is meant to grow with the number of concurrent rails requests /
# sidekiq jobs, and concurrency will be low anyway in test.
config[:git] = { catfile_cache_size: 5 }
end
config = { socket_path: address.sub(/\Aunix:/, ''), storage: storages } config[:storage] = storages
config[:auth] = { token: 'secret' } if Rails.env.test?
internal_socket_dir = File.join(gitaly_dir, 'internal_sockets') internal_socket_dir = File.join(gitaly_dir, 'internal_sockets')
FileUtils.mkdir(internal_socket_dir) unless File.exist?(internal_socket_dir) FileUtils.mkdir(internal_socket_dir) unless File.exist?(internal_socket_dir)
config[:internal_socket_dir] = internal_socket_dir config[:internal_socket_dir] = internal_socket_dir
config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path } config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
config[:bin_dir] = Gitlab.config.gitaly.client_path config[:bin_dir] = Gitlab.config.gitaly.client_path
if Rails.env.test? TomlRB.dump(config)
# Compared to production, tests run in constrained environments. This
# number is meant to grow with the number of concurrent rails requests /
# sidekiq jobs, and concurrency will be low anyway in test.
config[:git] = { catfile_cache_size: 5 }
end end
TomlRB.dump(config) private
def get_config_path(dir)
File.join(dir, 'config.toml')
end
end end
end
module Praefect
extend Gitlab::SetupHelper
class << self
def configuration_toml(gitaly_dir, storage_paths)
nodes = [{ storage: 'default', address: "unix:#{gitaly_dir}/gitaly.socket", primary: true, token: 'secret' }]
config = { socket_path: "#{gitaly_dir}/praefect.socket", virtual_storage_name: 'default', token: 'secret', node: nodes }
config[:token] = 'secret' if Rails.env.test?
TomlRB.dump(config)
end
# rubocop:disable Rails/Output private
def create_gitaly_configuration(dir, storage_paths, force: false)
config_path = File.join(dir, 'config.toml')
FileUtils.rm_f(config_path) if force
File.open(config_path, File::WRONLY | File::CREAT | File::EXCL) do |f| def get_config_path(dir)
f.puts gitaly_configuration_toml(dir, storage_paths) File.join(dir, 'praefect.config.toml')
end end
rescue Errno::EEXIST
puts "Skipping config.toml generation:"
puts "A configuration file already exists."
rescue ArgumentError => e
puts "Skipping config.toml generation:"
puts e.message
end end
# rubocop:enable Rails/Output
end end
end end
end end
...@@ -27,7 +27,7 @@ Usage: rake "gitlab:gitaly:install[/installation/dir,/storage/path]") ...@@ -27,7 +27,7 @@ Usage: rake "gitlab:gitaly:install[/installation/dir,/storage/path]")
end end
storage_paths = { 'default' => args.storage_path } storage_paths = { 'default' => args.storage_path }
Gitlab::SetupHelper.create_gitaly_configuration(args.dir, storage_paths) Gitlab::SetupHelper::Gitaly.create_configuration(args.dir, storage_paths)
Dir.chdir(args.dir) do Dir.chdir(args.dir) do
# In CI we run scripts/gitaly-test-build instead of this command # In CI we run scripts/gitaly-test-build instead of this command
unless ENV['CI'].present? unless ENV['CI'].present?
......
...@@ -48,7 +48,7 @@ class UploadedFile ...@@ -48,7 +48,7 @@ class UploadedFile
return if path.blank? && remote_id.blank? return if path.blank? && remote_id.blank?
file_path = nil file_path = nil
if path if path.present?
file_path = File.realpath(path) file_path = File.realpath(path)
paths = Array(upload_paths) << Dir.tmpdir paths = Array(upload_paths) << Dir.tmpdir
......
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
context 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/36817', type: :bug } do context 'Create', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/30226', type: :bug } do
describe 'Merge request rebasing' do describe 'Merge request rebasing' do
it 'user rebases source branch of merge request' do it 'user rebases source branch of merge request' do
Flow::Login.sign_in Flow::Login.sign_in
......
...@@ -17,13 +17,16 @@ class GitalyTestBuild ...@@ -17,13 +17,16 @@ class GitalyTestBuild
check_gitaly_config! check_gitaly_config!
# Starting gitaly further validates its configuration # Starting gitaly further validates its configuration
pid = start_gitaly gitaly_pid = start_gitaly
Process.kill('TERM', pid) praefect_pid = start_praefect
Process.kill('TERM', gitaly_pid)
Process.kill('TERM', praefect_pid)
# Make the 'gitaly' executable look newer than 'GITALY_SERVER_VERSION'. # Make the 'gitaly' executable look newer than 'GITALY_SERVER_VERSION'.
# Without this a gitaly executable created in the setup-test-env job # Without this a gitaly executable created in the setup-test-env job
# will look stale compared to GITALY_SERVER_VERSION. # will look stale compared to GITALY_SERVER_VERSION.
FileUtils.touch(File.join(tmp_tests_gitaly_dir, 'gitaly'), mtime: Time.now + (1 << 24)) FileUtils.touch(File.join(tmp_tests_gitaly_dir, 'gitaly'), mtime: Time.now + (1 << 24))
FileUtils.touch(File.join(tmp_tests_gitaly_dir, 'praefect'), mtime: Time.now + (1 << 24))
end end
end end
......
...@@ -13,10 +13,9 @@ class GitalyTestSpawn ...@@ -13,10 +13,9 @@ class GitalyTestSpawn
# # Uncomment line below to see all gitaly logs merged into CI trace # # Uncomment line below to see all gitaly logs merged into CI trace
# spawn('sleep 1; tail -f log/gitaly-test.log') # spawn('sleep 1; tail -f log/gitaly-test.log')
pid = start_gitaly
# In local development this pid file is used by rspec. # In local development this pid file is used by rspec.
IO.write(File.expand_path('../tmp/tests/gitaly.pid', __dir__), pid) IO.write(File.expand_path('../tmp/tests/gitaly.pid', __dir__), start_gitaly)
IO.write(File.expand_path('../tmp/tests/praefect.pid', __dir__), start_praefect)
end end
end end
......
...@@ -37,16 +37,31 @@ module GitalyTest ...@@ -37,16 +37,31 @@ module GitalyTest
env_hash env_hash
end end
def config_path def config_path(service)
File.join(tmp_tests_gitaly_dir, 'config.toml') case service
when :gitaly
File.join(tmp_tests_gitaly_dir, 'config.toml')
when :praefect
File.join(tmp_tests_gitaly_dir, 'praefect.config.toml')
end
end end
def start_gitaly def start_gitaly
args = %W[#{tmp_tests_gitaly_dir}/gitaly #{config_path}] start(:gitaly)
pid = spawn(env, *args, [:out, :err] => 'log/gitaly-test.log') end
def start_praefect
start(:praefect)
end
def start(service)
args = ["#{tmp_tests_gitaly_dir}/#{service}"]
args.push("-config") if service == :praefect
args.push(config_path(service))
pid = spawn(env, *args, [:out, :err] => "log/#{service}-test.log")
begin begin
try_connect! try_connect!(service)
rescue rescue
Process.kill('TERM', pid) Process.kill('TERM', pid)
raise raise
...@@ -68,11 +83,11 @@ module GitalyTest ...@@ -68,11 +83,11 @@ module GitalyTest
abort 'bundle check failed' unless system(env, 'bundle', 'check', chdir: File.dirname(gemfile)) abort 'bundle check failed' unless system(env, 'bundle', 'check', chdir: File.dirname(gemfile))
end end
def read_socket_path def read_socket_path(service)
# This code needs to work in an environment where we cannot use bundler, # This code needs to work in an environment where we cannot use bundler,
# so we cannot easily use the toml-rb gem. This ad-hoc parser should be # so we cannot easily use the toml-rb gem. This ad-hoc parser should be
# good enough. # good enough.
config_text = IO.read(config_path) config_text = IO.read(config_path(service))
config_text.lines.each do |line| config_text.lines.each do |line|
match_data = line.match(/^\s*socket_path\s*=\s*"([^"]*)"$/) match_data = line.match(/^\s*socket_path\s*=\s*"([^"]*)"$/)
...@@ -80,14 +95,14 @@ module GitalyTest ...@@ -80,14 +95,14 @@ module GitalyTest
return match_data[1] if match_data return match_data[1] if match_data
end end
raise "failed to find socket_path in #{config_path}" raise "failed to find socket_path in #{config_path(service)}"
end end
def try_connect! def try_connect!(service)
print "Trying to connect to gitaly: " print "Trying to connect to #{service}: "
timeout = 20 timeout = 20
delay = 0.1 delay = 0.1
socket = read_socket_path socket = read_socket_path(service)
Integer(timeout / delay).times do Integer(timeout / delay).times do
UNIXSocket.new(socket) UNIXSocket.new(socket)
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Database::PostgresqlAdapter::SchemaVersionsCopyMixin do
let(:schema_migration) { double('schem_migration', table_name: table_name, all_versions: versions) }
let(:versions) { %w(5 2 1000 200 4 93 2) }
let(:table_name) { "schema_migrations" }
let(:instance) do
Object.new.extend(described_class)
end
before do
allow(instance).to receive(:schema_migration).and_return(schema_migration)
allow(instance).to receive(:quote_table_name).with(table_name).and_return("\"#{table_name}\"")
end
subject { instance.dump_schema_information }
it 'uses COPY FROM STDIN' do
expect(subject.split("\n").first).to match(/COPY "schema_migrations" \(version\) FROM STDIN;/)
end
it 'contains a sorted list of versions by their numeric value' do
version_lines = subject.split("\n")[1..-2].map(&:to_i)
expect(version_lines).to eq(versions.map(&:to_i).sort)
end
it 'contains a end-of-data marker' do
expect(subject).to end_with("\\.\n")
end
context 'with non-Integer versions' do
let(:versions) { %w(5 2 4 abc) }
it 'raises an error' do
expect { subject }.to raise_error(/invalid value for Integer/)
end
end
end
...@@ -59,6 +59,16 @@ describe UploadedFile do ...@@ -59,6 +59,16 @@ describe UploadedFile do
expect(subject.sha256).to eq('sha256') expect(subject.sha256).to eq('sha256')
expect(subject.remote_id).to eq('remote_id') expect(subject.remote_id).to eq('remote_id')
end end
it 'handles a blank path' do
params['file.path'] = ''
# Not a real file, so can't determine size itself
params['file.size'] = 1.byte
expect { described_class.from_params(params, :file, upload_path) }
.not_to raise_error
end
end end
end end
......
...@@ -129,10 +129,37 @@ describe BulkInsertSafe do ...@@ -129,10 +129,37 @@ describe BulkInsertSafe do
end.not_to change { described_class.count } end.not_to change { described_class.count }
end end
it 'does nothing and returns true when items are empty' do it 'does nothing and returns an empty array when items are empty' do
expect(described_class.bulk_insert!([])).to be(true) expect(described_class.bulk_insert!([])).to eq([])
expect(described_class.count).to eq(0) expect(described_class.count).to eq(0)
end end
context 'with returns option set' do
context 'when is set to :ids' do
it 'return an array with the primary key values for all inserted records' do
items = described_class.valid_list(1)
expect(described_class.bulk_insert!(items, returns: :ids)).to contain_exactly(a_kind_of(Integer))
end
end
context 'when is set to nil' do
it 'returns an empty array' do
items = described_class.valid_list(1)
expect(described_class.bulk_insert!(items, returns: nil)).to eq([])
end
end
context 'when is set to anything else' do
it 'raises an error' do
items = described_class.valid_list(1)
expect { described_class.bulk_insert!([items], returns: [:id, :name]) }
.to raise_error(ArgumentError, "returns needs to be :ids or nil")
end
end
end
end end
context 'when duplicate items are to be inserted' do context 'when duplicate items are to be inserted' do
......
...@@ -6,6 +6,7 @@ describe API::Releases do ...@@ -6,6 +6,7 @@ describe API::Releases do
let(:project) { create(:project, :repository, :private) } let(:project) { create(:project, :repository, :private) }
let(:maintainer) { create(:user) } let(:maintainer) { create(:user) }
let(:reporter) { create(:user) } let(:reporter) { create(:user) }
let(:developer) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:non_project_member) { create(:user) } let(:non_project_member) { create(:user) }
let(:commit) { create(:commit, project: project) } let(:commit) { create(:commit, project: project) }
...@@ -15,6 +16,7 @@ describe API::Releases do ...@@ -15,6 +16,7 @@ describe API::Releases do
project.add_maintainer(maintainer) project.add_maintainer(maintainer)
project.add_reporter(reporter) project.add_reporter(reporter)
project.add_guest(guest) project.add_guest(guest)
project.add_developer(developer)
project.repository.add_tag(maintainer, 'v0.1', commit.id) project.repository.add_tag(maintainer, 'v0.1', commit.id)
project.repository.add_tag(maintainer, 'v0.2', commit.id) project.repository.add_tag(maintainer, 'v0.2', commit.id)
...@@ -248,6 +250,24 @@ describe API::Releases do ...@@ -248,6 +250,24 @@ describe API::Releases do
.to match_array(release.sources.map(&:url)) .to match_array(release.sources.map(&:url))
end end
context 'with evidence' do
let!(:evidence) { create(:evidence, release: release) }
it 'returns the evidence' do
get api("/projects/#{project.id}/releases/v0.1", maintainer)
expect(json_response['evidences'].count).to eq(1)
end
it '#collected_at' do
Timecop.freeze(Time.now.round) do
get api("/projects/#{project.id}/releases/v0.1", maintainer)
expect(json_response['evidences'].first['collected_at'].to_datetime.to_i).to be_within(1.minute).of(release.evidences.first.created_at.to_i)
end
end
end
context 'when release has link asset' do context 'when release has link asset' do
let!(:link) do let!(:link) do
create(:release_link, create(:release_link,
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::Prometheus::Alerts::NotifyService do
let_it_be(:project, reload: true) { create(:project) }
let(:service) { described_class.new(project, nil, payload) }
let(:token_input) { 'token' }
let!(:setting) do
create(:project_incident_management_setting, project: project, send_email: true, create_issue: true)
end
let(:subject) { service.execute(token_input) }
before do
# We use `let_it_be(:project)` so we make sure to clear caches
project.clear_memoization(:licensed_feature_available)
end
shared_examples 'sends notification email' do
let(:notification_service) { spy }
it 'sends a notification for firing alerts only' do
expect(NotificationService)
.to receive(:new)
.and_return(notification_service)
expect(notification_service)
.to receive_message_chain(:async, :prometheus_alerts_fired)
expect(subject).to eq(true)
end
end
shared_examples 'processes incident issues' do |amount|
let(:create_incident_service) { spy }
it 'processes issues' do
expect(IncidentManagement::ProcessPrometheusAlertWorker)
.to receive(:perform_async)
.with(project.id, kind_of(Hash))
.exactly(amount).times
Sidekiq::Testing.inline! do
expect(subject).to eq(true)
end
end
end
shared_examples 'does not process incident issues' do
it 'does not process issues' do
expect(IncidentManagement::ProcessPrometheusAlertWorker)
.not_to receive(:perform_async)
expect(subject).to eq(true)
end
end
shared_examples 'persists events' do
let(:create_events_service) { spy }
it 'persists events' do
expect(Projects::Prometheus::Alerts::CreateEventsService)
.to receive(:new)
.and_return(create_events_service)
expect(create_events_service)
.to receive(:execute)
expect(subject).to eq(true)
end
end
shared_examples 'notifies alerts' do
it_behaves_like 'sends notification email'
it_behaves_like 'persists events'
end
shared_examples 'no notifications' do
let(:notification_service) { spy }
let(:create_events_service) { spy }
it 'does not notify' do
expect(notification_service).not_to receive(:async)
expect(create_events_service).not_to receive(:execute)
expect(subject).to eq(false)
end
end
context 'with valid payload' do
let(:alert_firing) { create(:prometheus_alert, project: project) }
let(:alert_resolved) { create(:prometheus_alert, project: project) }
let(:payload_raw) { payload_for(firing: [alert_firing], resolved: [alert_resolved]) }
let(:payload) { ActionController::Parameters.new(payload_raw).permit! }
let(:payload_alert_firing) { payload_raw['alerts'].first }
let(:token) { 'token' }
context 'with project specific cluster' do
using RSpec::Parameterized::TableSyntax
where(:cluster_enabled, :status, :configured_token, :token_input, :result) do
true | :installed | token | token | :success
true | :installed | nil | nil | :success
true | :updated | token | token | :success
true | :updating | token | token | :failure
true | :installed | token | 'x' | :failure
true | :installed | nil | token | :failure
true | :installed | token | nil | :failure
true | nil | token | token | :failure
false | :installed | token | token | :failure
end
with_them do
before do
cluster = create(:cluster, :provided_by_user,
projects: [project],
enabled: cluster_enabled)
if status
create(:clusters_applications_prometheus, status,
cluster: cluster,
alert_manager_token: configured_token)
end
end
case result = params[:result]
when :success
it_behaves_like 'notifies alerts'
when :failure
it_behaves_like 'no notifications'
else
raise "invalid result: #{result.inspect}"
end
end
end
context 'without project specific cluster' do
let!(:cluster) { create(:cluster, enabled: true) }
it_behaves_like 'no notifications'
end
context 'with manual prometheus installation' do
using RSpec::Parameterized::TableSyntax
where(:alerting_setting, :configured_token, :token_input, :result) do
true | token | token | :success
true | token | 'x' | :failure
true | token | nil | :failure
false | nil | nil | :success
false | nil | token | :failure
end
with_them do
let(:alert_manager_token) { token_input }
before do
create(:prometheus_service, project: project)
if alerting_setting
create(:project_alerting_setting,
project: project,
token: configured_token)
end
end
case result = params[:result]
when :success
it_behaves_like 'notifies alerts'
when :failure
it_behaves_like 'no notifications'
else
raise "invalid result: #{result.inspect}"
end
end
end
context 'alert emails' do
before do
create(:prometheus_service, project: project)
create(:project_alerting_setting, project: project, token: token)
end
context 'when incident_management_setting does not exist' do
let!(:setting) { nil }
it_behaves_like 'persists events'
it 'does not send notification email', :sidekiq_might_not_need_inline do
expect_any_instance_of(NotificationService)
.not_to receive(:async)
expect(subject).to eq(true)
end
end
context 'when incident_management_setting.send_email is true' do
it_behaves_like 'notifies alerts'
end
context 'incident_management_setting.send_email is false' do
let!(:setting) do
create(:project_incident_management_setting, send_email: false, project: project)
end
it_behaves_like 'persists events'
it 'does not send notification' do
expect(NotificationService).not_to receive(:new)
expect(subject).to eq(true)
end
end
end
context 'process incident issues' do
before do
create(:prometheus_service, project: project)
create(:project_alerting_setting, project: project, token: token)
end
context 'with create_issue setting enabled' do
before do
setting.update!(create_issue: true)
end
it_behaves_like 'processes incident issues', 2
context 'multiple firing alerts' do
let(:payload_raw) do
payload_for(firing: [alert_firing, alert_firing], resolved: [])
end
it_behaves_like 'processes incident issues', 2
end
context 'without firing alerts' do
let(:payload_raw) do
payload_for(firing: [], resolved: [alert_resolved])
end
it_behaves_like 'processes incident issues', 1
end
end
context 'with create_issue setting disabled' do
before do
setting.update!(create_issue: false)
end
it_behaves_like 'does not process incident issues'
end
end
end
context 'with invalid payload' do
context 'without version' do
let(:payload) { {} }
it_behaves_like 'no notifications'
end
context 'when version is not "4"' do
let(:payload) { { 'version' => '5' } }
it_behaves_like 'no notifications'
end
context 'with missing alerts' do
let(:payload) { { 'version' => '4' } }
it_behaves_like 'no notifications'
end
context 'when the payload is too big' do
let(:payload) { { 'the-payload-is-too-big' => true } }
let(:deep_size_object) { instance_double(Gitlab::Utils::DeepSize, valid?: false) }
before do
allow(Gitlab::Utils::DeepSize).to receive(:new).and_return(deep_size_object)
end
it_behaves_like 'no notifications'
it 'does not process issues' do
expect(IncidentManagement::ProcessPrometheusAlertWorker)
.not_to receive(:perform_async)
subject
end
end
end
private
def payload_for(firing: [], resolved: [])
status = firing.any? ? 'firing' : 'resolved'
alerts = firing + resolved
alert_name = alerts.first.title
prometheus_metric_id = alerts.first.prometheus_metric_id.to_s
alerts_map = \
firing.map { |alert| map_alert_payload('firing', alert) } +
resolved.map { |alert| map_alert_payload('resolved', alert) }
# See https://prometheus.io/docs/alerting/configuration/#%3Cwebhook_config%3E
{
'version' => '4',
'receiver' => 'gitlab',
'status' => status,
'alerts' => alerts_map,
'groupLabels' => {
'alertname' => alert_name
},
'commonLabels' => {
'alertname' => alert_name,
'gitlab' => 'hook',
'gitlab_alert_id' => prometheus_metric_id
},
'commonAnnotations' => {},
'externalURL' => '',
'groupKey' => "{}:{alertname=\'#{alert_name}\'}"
}
end
def map_alert_payload(status, alert)
{
'status' => status,
'labels' => {
'alertname' => alert.title,
'gitlab' => 'hook',
'gitlab_alert_id' => alert.prometheus_metric_id.to_s
},
'annotations' => {},
'startsAt' => '2018-09-24T08:57:31.095725221Z',
'endsAt' => '0001-01-01T00:00:00Z',
'generatorURL' => 'http://prometheus-prometheus-server-URL'
}
end
end
# frozen_string_literal: true # frozen_string_literal: true
require 'rspec/mocks' require 'rspec/mocks'
require 'toml-rb'
module TestEnv module TestEnv
extend ActiveSupport::Concern extend ActiveSupport::Concern
...@@ -87,7 +86,7 @@ module TestEnv ...@@ -87,7 +86,7 @@ module TestEnv
'conflict-resolvable-fork' => '404fa3f' 'conflict-resolvable-fork' => '404fa3f'
}.freeze }.freeze
TMP_TEST_PATH = Rails.root.join('tmp', 'tests', '**') TMP_TEST_PATH = Rails.root.join('tmp', 'tests').freeze
REPOS_STORAGE = 'default'.freeze REPOS_STORAGE = 'default'.freeze
SECOND_STORAGE_PATH = Rails.root.join('tmp', 'tests', 'second_storage') SECOND_STORAGE_PATH = Rails.root.join('tmp', 'tests', 'second_storage')
...@@ -140,7 +139,7 @@ module TestEnv ...@@ -140,7 +139,7 @@ module TestEnv
# #
# Keeps gitlab-shell and gitlab-test # Keeps gitlab-shell and gitlab-test
def clean_test_path def clean_test_path
Dir[TMP_TEST_PATH].each do |entry| Dir[File.join(TMP_TEST_PATH, '**')].each do |entry|
unless test_dirs.include?(File.basename(entry)) unless test_dirs.include?(File.basename(entry))
FileUtils.rm_rf(entry) FileUtils.rm_rf(entry)
end end
...@@ -164,7 +163,8 @@ module TestEnv ...@@ -164,7 +163,8 @@ module TestEnv
install_dir: gitaly_dir, install_dir: gitaly_dir,
version: Gitlab::GitalyClient.expected_server_version, version: Gitlab::GitalyClient.expected_server_version,
task: "gitlab:gitaly:install[#{install_gitaly_args}]") do task: "gitlab:gitaly:install[#{install_gitaly_args}]") do
Gitlab::SetupHelper.create_gitaly_configuration(gitaly_dir, { 'default' => repos_path }, force: true) Gitlab::SetupHelper::Gitaly.create_configuration(gitaly_dir, { 'default' => repos_path }, force: true)
Gitlab::SetupHelper::Praefect.create_configuration(gitaly_dir, { 'praefect' => repos_path }, force: true)
start_gitaly(gitaly_dir) start_gitaly(gitaly_dir)
end end
end end
...@@ -192,17 +192,38 @@ module TestEnv ...@@ -192,17 +192,38 @@ module TestEnv
end end
end end
@gitaly_pid = Integer(File.read('tmp/tests/gitaly.pid')) gitaly_pid = Integer(File.read(TMP_TEST_PATH.join('gitaly.pid')))
praefect_pid = Integer(File.read(TMP_TEST_PATH.join('praefect.pid')))
Kernel.at_exit { stop_gitaly } Kernel.at_exit { stop(gitaly_pid) }
Kernel.at_exit { stop(praefect_pid) }
wait_gitaly wait('gitaly')
wait('praefect')
end end
def wait_gitaly def stop(pid)
Process.kill('KILL', pid)
rescue Errno::ESRCH
# The process can already be gone if the test run was INTerrupted.
end
def gitaly_url
ENV.fetch('GITALY_REPO_URL', nil)
end
def socket_path(service)
TMP_TEST_PATH.join('gitaly', "#{service}.socket").to_s
end
def praefect_socket_path
"unix:" + socket_path(:praefect)
end
def wait(service)
sleep_time = 10 sleep_time = 10
sleep_interval = 0.1 sleep_interval = 0.1
socket = Gitlab::GitalyClient.address('default').sub('unix:', '') socket = socket_path(service)
Integer(sleep_time / sleep_interval).times do Integer(sleep_time / sleep_interval).times do
Socket.unix(socket) Socket.unix(socket)
...@@ -211,19 +232,7 @@ module TestEnv ...@@ -211,19 +232,7 @@ module TestEnv
sleep sleep_interval sleep sleep_interval
end end
raise "could not connect to gitaly at #{socket.inspect} after #{sleep_time} seconds" raise "could not connect to #{service} at #{socket.inspect} after #{sleep_time} seconds"
end
def stop_gitaly
return unless @gitaly_pid
Process.kill('KILL', @gitaly_pid)
rescue Errno::ESRCH
# The process can already be gone if the test run was INTerrupted.
end
def gitaly_url
ENV.fetch('GITALY_REPO_URL', nil)
end end
def setup_workhorse def setup_workhorse
......
# frozen_string_literal: true
require_relative 'helpers/test_env'
RSpec.configure do |config|
config.before(:each, :praefect) do
allow(Gitlab.config.repositories.storages['default']).to receive(:[]).and_call_original
allow(Gitlab.config.repositories.storages['default']).to receive(:[]).with('gitaly_address')
.and_return(TestEnv.praefect_socket_path)
end
end
...@@ -45,11 +45,11 @@ RSpec.shared_examples 'a BulkInsertSafe model' do |klass| ...@@ -45,11 +45,11 @@ RSpec.shared_examples 'a BulkInsertSafe model' do |klass|
expect { target_class.bulk_insert!(items) }.to change { target_class.count }.by(items.size) expect { target_class.bulk_insert!(items) }.to change { target_class.count }.by(items.size)
end end
it 'returns true' do it 'returns an empty array' do
items = valid_items_for_bulk_insertion items = valid_items_for_bulk_insertion
expect(items).not_to be_empty expect(items).not_to be_empty
expect(target_class.bulk_insert!(items)).to be true expect(target_class.bulk_insert!(items)).to eq([])
end end
end end
...@@ -69,7 +69,7 @@ RSpec.shared_examples 'a BulkInsertSafe model' do |klass| ...@@ -69,7 +69,7 @@ RSpec.shared_examples 'a BulkInsertSafe model' do |klass|
# it is not always possible to create invalid items # it is not always possible to create invalid items
if items.any? if items.any?
expect(target_class.bulk_insert!(items, validate: false)).to be(true) expect(target_class.bulk_insert!(items, validate: false)).to eq([])
expect(target_class.count).to eq(items.size) expect(target_class.count).to eq(items.size)
end end
end end
......
...@@ -786,10 +786,10 @@ ...@@ -786,10 +786,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.115.0.tgz#2762ad045d5a2bd728f74fcb4c00caa9bd6dbc22" resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.115.0.tgz#2762ad045d5a2bd728f74fcb4c00caa9bd6dbc22"
integrity sha512-jlmNGqCTpSiPFrNbLaW6GGXNbvIShLdrpeYTtSEz/yFJMClQfPjHc8Zm9bl/PqAM5d/yGQqk8e+rBc4LeAhEfg== integrity sha512-jlmNGqCTpSiPFrNbLaW6GGXNbvIShLdrpeYTtSEz/yFJMClQfPjHc8Zm9bl/PqAM5d/yGQqk8e+rBc4LeAhEfg==
"@gitlab/ui@^10.0.0": "@gitlab/ui@^10.0.1":
version "10.0.0" version "10.0.1"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-10.0.0.tgz#dced1119237f328367e8c4922cf4e1ae986fac54" resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-10.0.1.tgz#65deee8ded3b8d003dfd74cd93c7eb0549e11b37"
integrity sha512-+qsojtfE5mhryjJyReXBY9C3J4s4jlRpHfEcaCFuhcebtq5Uhd6xgLwgxT+E7fMvtLQpGATMo1DiD80yhLb2pQ== integrity sha512-RMOJjpZjmWJnu0ebfGJsPOn6/ko+HlfHYbBXBImpTIk6Xsr5AaRjT4yCYEoefZ55jK/SJ2nxHytqrMe26wjfDA==
dependencies: dependencies:
"@babel/standalone" "^7.0.0" "@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0" "@gitlab/vue-toasted" "^1.3.0"
......
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