Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
423309c4ae
commit
2d337eacd9
|
@ -212,7 +212,7 @@ jest minimal:
|
|||
- !reference [jest, needs]
|
||||
- "detect-tests"
|
||||
script:
|
||||
- run_timed_command "yarn jest:ci:minimal"
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]]; then run_timed_command "yarn jest:ci:minimal"; fi
|
||||
|
||||
jest as-if-foss:
|
||||
extends:
|
||||
|
@ -231,7 +231,7 @@ jest minimal as-if-foss:
|
|||
- "rspec-all frontend_fixture as-if-foss"
|
||||
- "detect-tests"
|
||||
script:
|
||||
- run_timed_command "yarn jest:ci:minimal"
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]]; then run_timed_command "yarn jest:ci:minimal"; fi
|
||||
|
||||
jest-integration:
|
||||
extends:
|
||||
|
@ -259,7 +259,9 @@ coverage-frontend:
|
|||
script:
|
||||
- run_timed_command "yarn node scripts/frontend/merge_coverage_frontend.js"
|
||||
# Removing the individual coverage results, as we just merged them.
|
||||
- rm -r coverage-frontend/jest-*
|
||||
- if ls coverage-frontend/jest-* > /dev/null 2>&1; then
|
||||
rm -r coverage-frontend/jest-*;
|
||||
fi
|
||||
coverage: '/^Statements\s*:\s*?(\d+(?:\.\d+)?)%/'
|
||||
artifacts:
|
||||
name: coverage-frontend
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -338,7 +338,6 @@ gem 'peek', '~> 1.1'
|
|||
gem 'snowplow-tracker', '~> 0.6.1'
|
||||
|
||||
# Metrics
|
||||
gem 'method_source', '~> 1.0', require: false
|
||||
gem 'webrick', '~> 1.6.1', require: false
|
||||
gem 'prometheus-client-mmap', '~> 0.16', require: 'prometheus/client'
|
||||
|
||||
|
|
|
@ -1654,7 +1654,6 @@ DEPENDENCIES
|
|||
mail-smtp_pool (~> 0.1.0)!
|
||||
marginalia (~> 1.10.0)
|
||||
memory_profiler (~> 0.9)
|
||||
method_source (~> 1.0)
|
||||
mini_magick (~> 4.10.1)
|
||||
minitest (~> 5.11.0)
|
||||
multi_json (~> 1.14.1)
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
.signin-text {
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.borderless {
|
||||
.login-box,
|
||||
.omniauth-container {
|
||||
|
|
|
@ -474,6 +474,10 @@ input:-ms-input-placeholder {
|
|||
.login-page p {
|
||||
font-size: 13px;
|
||||
}
|
||||
.login-page .signin-text p {
|
||||
margin-bottom: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.login-page .borderless .login-box,
|
||||
.login-page .borderless .omniauth-container {
|
||||
box-shadow: none;
|
||||
|
|
|
@ -38,10 +38,16 @@ module Mutations
|
|||
required: false,
|
||||
description: 'ID of issue that should be placed after the current issue.'
|
||||
|
||||
argument :position_in_list, GraphQL::Types::Int,
|
||||
required: false,
|
||||
description: "Position of issue within the board list. Positions start at 0. "\
|
||||
"Use #{::Boards::Issues::MoveService::LIST_END_POSITION} to move to the end of the list."
|
||||
|
||||
def ready?(**args)
|
||||
if move_arguments(args).blank?
|
||||
raise Gitlab::Graphql::Errors::ArgumentError,
|
||||
'At least one of the arguments fromListId, toListId, afterId or beforeId is required'
|
||||
'At least one of the arguments ' \
|
||||
'fromListId, toListId, positionInList, moveAfterId, or moveBeforeId is required'
|
||||
end
|
||||
|
||||
if move_list_arguments(args).one?
|
||||
|
@ -49,6 +55,24 @@ module Mutations
|
|||
'Both fromListId and toListId must be present'
|
||||
end
|
||||
|
||||
if args[:position_in_list].present?
|
||||
if move_list_arguments(args).empty?
|
||||
raise Gitlab::Graphql::Errors::ArgumentError,
|
||||
'Both fromListId and toListId are required when positionInList is given'
|
||||
end
|
||||
|
||||
if args[:move_before_id].present? || args[:move_after_id].present?
|
||||
raise Gitlab::Graphql::Errors::ArgumentError,
|
||||
'positionInList is mutually exclusive with any of moveBeforeId or moveAfterId'
|
||||
end
|
||||
|
||||
if args[:position_in_list] != ::Boards::Issues::MoveService::LIST_END_POSITION &&
|
||||
args[:position_in_list] < 0
|
||||
raise Gitlab::Graphql::Errors::ArgumentError,
|
||||
"positionInList must be >= 0 or #{::Boards::Issues::MoveService::LIST_END_POSITION}"
|
||||
end
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
|
@ -77,7 +101,7 @@ module Mutations
|
|||
end
|
||||
|
||||
def move_arguments(args)
|
||||
args.slice(:from_list_id, :to_list_id, :move_after_id, :move_before_id)
|
||||
args.slice(:from_list_id, :to_list_id, :position_in_list, :move_after_id, :move_before_id)
|
||||
end
|
||||
|
||||
def error_for(result)
|
||||
|
|
|
@ -296,6 +296,12 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
after_transition any => ::Ci::Pipeline.completed_statuses do |pipeline|
|
||||
pipeline.run_after_commit do
|
||||
::Ci::JobArtifacts::TrackArtifactReportWorker.perform_async(pipeline.id)
|
||||
end
|
||||
end
|
||||
|
||||
after_transition any => ::Ci::Pipeline.stopped_statuses do |pipeline|
|
||||
pipeline.run_after_commit do
|
||||
pipeline.persistent_ref.delete
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
module Boards
|
||||
class BaseItemMoveService < Boards::BaseService
|
||||
LIST_END_POSITION = -1
|
||||
|
||||
def execute(issuable)
|
||||
issuable_modification_params = issuable_params(issuable)
|
||||
return if issuable_modification_params.empty?
|
||||
|
@ -32,7 +34,13 @@ module Boards
|
|||
)
|
||||
end
|
||||
|
||||
reposition_ids = move_between_ids(params)
|
||||
move_params = if params[:position_in_list].present?
|
||||
move_params_from_list_position(params[:position_in_list])
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
reposition_ids = move_between_ids(move_params)
|
||||
attrs.merge!(reposition_params(reposition_ids)) if reposition_ids
|
||||
|
||||
attrs
|
||||
|
@ -90,6 +98,18 @@ module Boards
|
|||
::Label.ids_on_board(board.id)
|
||||
end
|
||||
|
||||
def move_params_from_list_position(position)
|
||||
if position == LIST_END_POSITION
|
||||
{ move_before_id: moving_to_list_items_relation.reverse_order.pick(:id), move_after_id: nil }
|
||||
else
|
||||
item_at_position = moving_to_list_items_relation.offset(position).pick(:id) # rubocop: disable CodeReuse/ActiveRecord
|
||||
|
||||
return move_params_from_list_position(LIST_END_POSITION) if item_at_position.nil?
|
||||
|
||||
{ move_before_id: nil, move_after_id: item_at_position }
|
||||
end
|
||||
end
|
||||
|
||||
def move_between_ids(move_params)
|
||||
ids = [move_params[:move_before_id], move_params[:move_after_id]]
|
||||
.map(&:to_i)
|
||||
|
|
|
@ -54,6 +54,10 @@ module Boards
|
|||
def update(issue, issue_modification_params)
|
||||
::Issues::UpdateService.new(project: issue.project, current_user: current_user, params: issue_modification_params).execute(issue)
|
||||
end
|
||||
|
||||
def moving_to_list_items_relation
|
||||
Boards::Issues::ListService.new(board.resource_parent, current_user, board_id: board.id, id: moving_to_list.id).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module JobArtifacts
|
||||
class TrackArtifactReportService
|
||||
include Gitlab::Utils::UsageData
|
||||
|
||||
REPORT_TRACKED = %i[test].freeze
|
||||
VALUES_DELIMITER = '_'
|
||||
|
||||
def execute(pipeline)
|
||||
REPORT_TRACKED.each do |report|
|
||||
if pipeline.has_reports?(Ci::JobArtifact.of_report_type(report))
|
||||
track_usage_event(event_name(report), [pipeline.id, pipeline.user_id].join(VALUES_DELIMITER))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def event_name(report)
|
||||
"i_testing_#{report}_report_uploaded"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -24,7 +24,7 @@ module Issues
|
|||
return issue
|
||||
end
|
||||
|
||||
if perform_close(issue)
|
||||
if issue.close(current_user)
|
||||
event_service.close_issue(issue, current_user)
|
||||
create_note(issue, closed_via) if system_note
|
||||
|
||||
|
@ -51,11 +51,6 @@ module Issues
|
|||
|
||||
private
|
||||
|
||||
# Overridden on EE
|
||||
def perform_close(issue)
|
||||
issue.close(current_user)
|
||||
end
|
||||
|
||||
def can_close?(issue, skip_authorization: false)
|
||||
skip_authorization || can?(current_user, :update_issue, issue) || issue.is_a?(ExternalIssue)
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module Issues
|
|||
def execute(issue, skip_authorization: false)
|
||||
return issue unless can_reopen?(issue, skip_authorization: skip_authorization)
|
||||
|
||||
if perform_reopen(issue)
|
||||
if issue.reopen
|
||||
event_service.reopen_issue(issue, current_user)
|
||||
create_note(issue, 'reopened')
|
||||
notification_service.async.reopen_issue(issue, current_user)
|
||||
|
@ -22,11 +22,6 @@ module Issues
|
|||
|
||||
private
|
||||
|
||||
# Overriden on EE
|
||||
def perform_reopen(issue)
|
||||
issue.reopen
|
||||
end
|
||||
|
||||
def can_reopen?(issue, skip_authorization: false)
|
||||
skip_authorization || can?(current_user, :reopen_issue, issue)
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ module MergeRequests
|
|||
merge_request_activity_counter.track_users_assigned_to_mr(users: new_assignees)
|
||||
merge_request_activity_counter.track_assignees_changed_action(user: current_user)
|
||||
|
||||
execute_assignees_hooks(merge_request, old_assignees) if options[:execute_hooks]
|
||||
execute_assignees_hooks(merge_request, old_assignees) if options['execute_hooks']
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
= current_appearance&.title.presence || _('GitLab')
|
||||
- if current_appearance&.description?
|
||||
= brand_text
|
||||
= render_if_exists 'layouts/devise_help_text'
|
||||
.mb-3
|
||||
.gl-w-half.gl-xs-w-full.gl-ml-auto.gl-mr-auto.bar
|
||||
= yield
|
||||
= render_if_exists 'layouts/devise_help_text'
|
||||
|
||||
|
||||
= render 'devise/shared/footer', footer_message: footer_message
|
||||
|
|
|
@ -41,40 +41,4 @@
|
|||
= c.body do
|
||||
= _('Mirror settings are only available to GitLab administrators.')
|
||||
|
||||
.panel.panel-default
|
||||
.table-responsive
|
||||
%table.table.push-pull-table
|
||||
%thead
|
||||
%tr
|
||||
%th
|
||||
= _('Mirrored repositories')
|
||||
= render_if_exists 'projects/mirrors/mirrored_repositories_count'
|
||||
%th= _('Direction')
|
||||
%th= _('Last update attempt')
|
||||
%th= _('Last successful update')
|
||||
%th
|
||||
%th
|
||||
%tbody.js-mirrors-table-body
|
||||
= render_if_exists 'projects/mirrors/table_pull_row'
|
||||
- @project.remote_mirrors.each_with_index do |mirror, index|
|
||||
- next if mirror.new_record?
|
||||
%tr.rspec-mirrored-repository-row{ class: ('bg-secondary' if mirror.disabled?), data: { qa_selector: 'mirrored_repository_row' } }
|
||||
%td{ data: { qa_selector: 'mirror_repository_url_cell' } }= mirror.safe_url || _('Invalid URL')
|
||||
%td= _('Push')
|
||||
%td
|
||||
= mirror.last_update_started_at.present? ? time_ago_with_tooltip(mirror.last_update_started_at) : _('Never')
|
||||
%td{ data: { qa_selector: 'mirror_last_update_at_cell' } }= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never')
|
||||
%td
|
||||
- if mirror.disabled?
|
||||
= render 'projects/mirrors/disabled_mirror_badge'
|
||||
- if mirror.last_error.present?
|
||||
= gl_badge_tag _('Error'), { variant: :danger }, { data: { toggle: 'tooltip', html: 'true', qa_selector: 'mirror_error_badge' }, title: html_escape(mirror.last_error.try(:strip)) }
|
||||
%td.gl-display-flex
|
||||
- if mirror_settings_enabled
|
||||
.btn-group.mirror-actions-group{ role: 'group' }
|
||||
- if mirror.ssh_key_auth?
|
||||
= clipboard_button(text: mirror.ssh_public_key, class: 'gl-button btn btn-default btn-icon', title: _('Copy SSH public key'), qa_selector: 'copy_public_key_button')
|
||||
= render 'shared/remote_mirror_update_button', remote_mirror: mirror
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger,
|
||||
icon: 'remove',
|
||||
button_options: { class: 'js-delete-mirror qa-delete-mirror rspec-delete-mirror', title: _('Remove'), data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' } })
|
||||
= render 'projects/mirrors/mirror_repos_list'
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
- mirror_settings_enabled = can?(current_user, :admin_remote_mirror, @project)
|
||||
|
||||
.panel.panel-default
|
||||
.table-responsive
|
||||
- if !@project.mirror? && @project.remote_mirrors.count == 0
|
||||
.gl-card.gl-mt-5
|
||||
.gl-card-header
|
||||
%strong
|
||||
= _('Mirrored repositories') + ' (0)'
|
||||
.gl-card-body
|
||||
= _('There are currently no mirrored repositories.')
|
||||
- else
|
||||
%table.table.push-pull-table
|
||||
%thead
|
||||
%tr
|
||||
%th
|
||||
= _('Mirrored repositories')
|
||||
= render_if_exists 'projects/mirrors/mirrored_repositories_count'
|
||||
%th= _('Direction')
|
||||
%th= _('Last update attempt')
|
||||
%th= _('Last successful update')
|
||||
%th
|
||||
%th
|
||||
%tbody.js-mirrors-table-body
|
||||
= render_if_exists 'projects/mirrors/table_pull_row'
|
||||
- @project.remote_mirrors.each_with_index do |mirror, index|
|
||||
- next if mirror.new_record?
|
||||
%tr.rspec-mirrored-repository-row{ class: ('bg-secondary' if mirror.disabled?), data: { qa_selector: 'mirrored_repository_row' } }
|
||||
%td{ data: { qa_selector: 'mirror_repository_url_cell' } }= mirror.safe_url || _('Invalid URL')
|
||||
%td= _('Push')
|
||||
%td
|
||||
= mirror.last_update_started_at.present? ? time_ago_with_tooltip(mirror.last_update_started_at) : _('Never')
|
||||
%td{ data: { qa_selector: 'mirror_last_update_at_cell' } }= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never')
|
||||
%td
|
||||
- if mirror.disabled?
|
||||
= render 'projects/mirrors/disabled_mirror_badge'
|
||||
- if mirror.last_error.present?
|
||||
= gl_badge_tag _('Error'), { variant: :danger }, { data: { toggle: 'tooltip', html: 'true', qa_selector: 'mirror_error_badge' }, title: html_escape(mirror.last_error.try(:strip)) }
|
||||
%td.gl-display-flex
|
||||
- if mirror_settings_enabled
|
||||
.btn-group.mirror-actions-group{ role: 'group' }
|
||||
- if mirror.ssh_key_auth?
|
||||
= clipboard_button(text: mirror.ssh_public_key, class: 'gl-button btn btn-default btn-icon', title: _('Copy SSH public key'), qa_selector: 'copy_public_key_button')
|
||||
= render 'shared/remote_mirror_update_button', remote_mirror: mirror
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger,
|
||||
icon: 'remove',
|
||||
button_options: { class: 'js-delete-mirror qa-delete-mirror rspec-delete-mirror', title: _('Remove'), data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' } })
|
|
@ -1,6 +1,7 @@
|
|||
#blob-content.file-content.code.js-syntax-highlight
|
||||
- offset = defined?(first_line_number) ? first_line_number : 1
|
||||
- blame_path = project_blame_path(@project, tree_join(@ref, blob.path))
|
||||
- if Feature.enabled?(:file_line_blame)
|
||||
- blame_path = project_blame_path(@project, tree_join(@ref, blob.path))
|
||||
.line-numbers{ class: "gl-px-0!", data: { blame_path: blame_path } }
|
||||
- if blob.data.present?
|
||||
- link = blob_link if defined?(blob_link)
|
||||
|
|
|
@ -1596,6 +1596,15 @@
|
|||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: pipeline_background:ci_job_artifacts_track_artifact_report
|
||||
:worker_name: Ci::JobArtifacts::TrackArtifactReportWorker
|
||||
:feature_category: :code_testing
|
||||
:has_external_dependencies: false
|
||||
:urgency: :low
|
||||
:resource_boundary: :unknown
|
||||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: pipeline_background:ci_pending_builds_update_group
|
||||
:worker_name: Ci::PendingBuilds::UpdateGroupWorker
|
||||
:feature_category: :continuous_integration
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module JobArtifacts
|
||||
class TrackArtifactReportWorker
|
||||
include ApplicationWorker
|
||||
|
||||
data_consistency :delayed
|
||||
|
||||
include PipelineBackgroundQueue
|
||||
|
||||
feature_category :code_testing
|
||||
|
||||
idempotent!
|
||||
|
||||
def perform(pipeline_id)
|
||||
Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline|
|
||||
Ci::JobArtifacts::TrackArtifactReportService.new.execute(pipeline)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: usage_data_ci_i_testing_test_report_uploaded
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95112
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339720
|
||||
milestone: '15.4'
|
||||
type: development
|
||||
group: group::pipeline insights
|
||||
default_enabled: false
|
|
@ -17,7 +17,6 @@
|
|||
if Gitlab::Metrics.enabled? && !Rails.env.test? && !(Rails.env.development? && defined?(Rails::Generators))
|
||||
require 'pathname'
|
||||
require 'connection_pool'
|
||||
require 'method_source'
|
||||
|
||||
# These are manually require'd so the classes are registered properly with
|
||||
# ActiveSupport.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.testing.i_testing_test_report_uploaded_monthly
|
||||
description: "MAU of junit test reports uploaded by customers per pipeline"
|
||||
product_section: ops
|
||||
product_stage: verify
|
||||
product_group: pipeline_insights
|
||||
product_category: testing
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.4"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95112
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
events:
|
||||
- i_testing_test_report_uploaded
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.testing.i_testing_test_report_uploaded_weekly
|
||||
description: "MAU of junit test reports uploaded by customers per pipeline"
|
||||
product_section: ops
|
||||
product_stage: verify
|
||||
product_group: pipeline_insights
|
||||
product_category: testing
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.4"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95112
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
events:
|
||||
- i_testing_test_report_uploaded
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
|
@ -202,6 +202,22 @@ sudo chmod 700 /scripts
|
|||
sudo gitlab-rails runner /scripts/helloworld.rb
|
||||
```
|
||||
|
||||
## Find specific methods for an object
|
||||
|
||||
```ruby
|
||||
Array.methods.select { |m| m.to_s.include? "sing" }
|
||||
Array.methods.grep(/sing/)
|
||||
```
|
||||
|
||||
## Find method source
|
||||
|
||||
```ruby
|
||||
instance_of_object.method(:foo).source_location
|
||||
|
||||
# Example for when we would call project.private?
|
||||
project.method(:private?).source_location
|
||||
```
|
||||
|
||||
## Active Record objects
|
||||
|
||||
### Looking up database-persisted objects
|
||||
|
|
|
@ -28,22 +28,6 @@ mentioned above, we recommend running these scripts under the supervision of a
|
|||
Support Engineer, who can also verify that they continue to work as they
|
||||
should and, if needed, update the script for the latest version of GitLab.
|
||||
|
||||
## Find specific methods for an object
|
||||
|
||||
```ruby
|
||||
Array.methods.select { |m| m.to_s.include? "sing" }
|
||||
Array.methods.grep(/sing/)
|
||||
```
|
||||
|
||||
## Find method source
|
||||
|
||||
```ruby
|
||||
instance_of_object.method(:foo).source_location
|
||||
|
||||
# Example for when we would call project.private?
|
||||
project.method(:private?).source_location
|
||||
```
|
||||
|
||||
## Attributes
|
||||
|
||||
View available attributes, formatted using pretty print (`pp`).
|
||||
|
@ -813,18 +797,6 @@ You can use this method when a configured external authentication provider (thro
|
|||
Gitlab::CurrentSettings.update!(password_authentication_enabled_for_web: true)
|
||||
```
|
||||
|
||||
## SCIM
|
||||
|
||||
### Find groups using an SQL query
|
||||
|
||||
Find and store an array of groups based on an SQL query:
|
||||
|
||||
```ruby
|
||||
# Finds groups and subgroups that end with '%oup'
|
||||
Group.find_by_sql("SELECT * FROM namespaces WHERE name LIKE '%oup'")
|
||||
=> [#<Group id:3 @test-group>, #<Group id:4 @template-group/template-subgroup>]
|
||||
```
|
||||
|
||||
## Routes
|
||||
|
||||
### Remove redirecting routes
|
||||
|
|
|
@ -3038,6 +3038,7 @@ Input type: `IssueMoveListInput`
|
|||
| <a id="mutationissuemovelistiid"></a>`iid` | [`String!`](#string) | IID of the issue to mutate. |
|
||||
| <a id="mutationissuemovelistmoveafterid"></a>`moveAfterId` | [`ID`](#id) | ID of issue that should be placed after the current issue. |
|
||||
| <a id="mutationissuemovelistmovebeforeid"></a>`moveBeforeId` | [`ID`](#id) | ID of issue that should be placed before the current issue. |
|
||||
| <a id="mutationissuemovelistpositioninlist"></a>`positionInList` | [`Int`](#int) | Position of issue within the board list. Positions start at 0. Use -1 to move to the end of the list. |
|
||||
| <a id="mutationissuemovelistprojectpath"></a>`projectPath` | [`ID!`](#id) | Project the issue to mutate is in. |
|
||||
| <a id="mutationissuemovelisttolistid"></a>`toListId` | [`ID`](#id) | ID of the board list that the issue will be moved to. |
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ There are two places defined variables can be used. On the:
|
|||
| [`environment:url`](../yaml/index.md#environmenturl) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab.<br/><br/>Supported are all variables defined for a job (project/group variables, variables from `.gitlab-ci.yml`, variables from triggers, variables from pipeline schedules).<br/><br/>Not supported are variables defined in the GitLab Runner `config.toml` and variables created in the job's `script`. |
|
||||
| [`except:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).<br/>- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).<br/>- [Persisted variables](#persisted-variables). |
|
||||
| [`image`](../yaml/index.md#image) | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
|
||||
| [`include`](../yaml/index.md#include) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. <br/><br/>Predefined project variables are supported: `GITLAB_FEATURES`, `CI_DEFAULT_BRANCH`, and all variables that start with `CI_PROJECT_` (for example `CI_PROJECT_NAME`). |
|
||||
| [`include`](../yaml/index.md#include) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. <br/><br/>See [Use variables with include](../yaml/includes.md#use-variables-with-include) for more information on supported variables. |
|
||||
| [`only:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).<br/>- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).<br/>- [Persisted variables](#persisted-variables). |
|
||||
| [`resource_group`](../yaml/index.md#resource_group) | yes | GitLab | Similar to `environment:url`, but the variables expansion doesn't support the following:<br/>- `CI_ENVIRONMENT_URL`<br/>- [Persisted variables](#persisted-variables). |
|
||||
| [`rules:if`](../yaml/index.md#rulesif) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).<br/>- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).<br/>- [Persisted variables](#persisted-variables). |
|
||||
|
|
|
@ -569,3 +569,13 @@ the following checks when creating or updating namespaces or groups:
|
|||
|
||||
In the unlikely event that you see these errors in your GitLab installation,
|
||||
[contact Support](https://about.gitlab.com/support/) so that we can improve this validation.
|
||||
|
||||
### Find groups using an SQL query
|
||||
|
||||
To find and store an array of groups based on an SQL query in the [rails console](../../administration/operations/rails_console.md):
|
||||
|
||||
```ruby
|
||||
# Finds groups and subgroups that end with '%oup'
|
||||
Group.find_by_sql("SELECT * FROM namespaces WHERE name LIKE '%oup'")
|
||||
=> [#<Group id:3 @test-group>, #<Group id:4 @template-group/template-subgroup>]
|
||||
```
|
||||
|
|
|
@ -31,7 +31,8 @@ module Banzai
|
|||
private
|
||||
|
||||
def lang_tag
|
||||
@lang_tag ||= Gitlab::Utils::Nokogiri.css_to_xpath('pre[lang="plantuml"] > code').freeze
|
||||
@lang_tag ||= Gitlab::Utils::Nokogiri
|
||||
.css_to_xpath('pre[lang="plantuml"] > code, pre > code[lang="plantuml"]').freeze
|
||||
end
|
||||
|
||||
def settings
|
||||
|
|
|
@ -146,6 +146,11 @@
|
|||
category: testing
|
||||
redis_slot: testing
|
||||
aggregation: weekly
|
||||
- name: i_testing_test_report_uploaded
|
||||
category: testing
|
||||
redis_slot: testing
|
||||
aggregation: weekly
|
||||
feature_flag: usage_data_ci_i_testing_test_report_uploaded
|
||||
# Project Management group
|
||||
- name: g_project_management_issue_title_changed
|
||||
category: issues_edit
|
||||
|
|
|
@ -4334,9 +4334,6 @@ msgstr[1] ""
|
|||
msgid "An error occurred while saving your settings. Try saving them again."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while subscribing to notifications."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while triggering the job."
|
||||
msgstr ""
|
||||
|
||||
|
@ -4352,9 +4349,6 @@ msgstr ""
|
|||
msgid "An error occurred while trying to unfollow this user, please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while unsubscribing to notifications."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while updating approvers"
|
||||
msgstr ""
|
||||
|
||||
|
@ -15027,12 +15021,6 @@ msgstr ""
|
|||
msgid "Epics|Add an existing epic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|An error occurred while saving the %{epicDateType} date"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|An error occurred while updating labels."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -15099,18 +15087,9 @@ msgstr ""
|
|||
msgid "Epics|This will also remove any descendents of %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|To schedule your epic's %{epicDateType} date based on milestones, assign a milestone with a %{epicDateType} date to any issue in the epic."
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|Unable to save epic. Please try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|due"
|
||||
msgstr ""
|
||||
|
||||
msgid "Epics|start"
|
||||
msgstr ""
|
||||
|
||||
msgid "Erased"
|
||||
msgstr ""
|
||||
|
||||
|
@ -26351,9 +26330,6 @@ msgstr ""
|
|||
msgid "No deployments found"
|
||||
msgstr ""
|
||||
|
||||
msgid "No due date"
|
||||
msgstr ""
|
||||
|
||||
msgid "No email participants were added. Either none were provided, or they already exist."
|
||||
msgstr ""
|
||||
|
||||
|
@ -26528,9 +26504,6 @@ msgstr ""
|
|||
msgid "No starrers matched your search"
|
||||
msgstr ""
|
||||
|
||||
msgid "No start date"
|
||||
msgstr ""
|
||||
|
||||
msgid "No suggestions found"
|
||||
msgstr ""
|
||||
|
||||
|
@ -39649,6 +39622,9 @@ msgstr ""
|
|||
msgid "There are currently no events."
|
||||
msgstr ""
|
||||
|
||||
msgid "There are currently no mirrored repositories."
|
||||
msgstr ""
|
||||
|
||||
msgid "There are merge conflicts"
|
||||
msgstr ""
|
||||
|
||||
|
@ -45220,7 +45196,7 @@ msgstr ""
|
|||
msgid "You have successfully purchased %{product}. You'll receive a receipt by email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet."
|
||||
msgstr ""
|
||||
|
||||
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email."
|
||||
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email. It might take a moment for GitLab.com to fully reflect your purchase."
|
||||
msgstr ""
|
||||
|
||||
msgid "You have unsaved changes"
|
||||
|
|
|
@ -13,6 +13,9 @@ module QA
|
|||
view 'app/views/projects/mirrors/_mirror_repos.html.haml' do
|
||||
element :mirror_repository_url_input
|
||||
element :mirror_repository_button
|
||||
end
|
||||
|
||||
view 'app/views/projects/mirrors/_mirror_repos_list.html.haml' do
|
||||
element :mirror_repository_url_cell
|
||||
element :mirror_last_update_at_cell
|
||||
element :mirror_error_badge
|
||||
|
|
|
@ -55,7 +55,7 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do
|
|||
let(:move_params) { {} }
|
||||
|
||||
it 'generates an error' do
|
||||
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'At least one of the arguments fromListId, toListId, afterId or beforeId is required') do
|
||||
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'At least one of the arguments fromListId, toListId, positionInList, moveAfterId, or moveBeforeId is required') do
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
@ -71,6 +71,50 @@ RSpec.describe Mutations::Boards::Issues::IssueMoveList do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when positionInList is given' do
|
||||
let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0 } }
|
||||
|
||||
context 'when fromListId and toListId are missing' do
|
||||
let(:move_params) { { position_in_list: 0 } }
|
||||
|
||||
it 'generates an error' do
|
||||
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'Both fromListId and toListId are required when positionInList is given') do
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when move_before_id is also given' do
|
||||
let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0, move_before_id: 1 } }
|
||||
|
||||
it 'generates an error' do
|
||||
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'positionInList is mutually exclusive with any of moveBeforeId or moveAfterId') do
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when move_after_id is also given' do
|
||||
let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0, move_after_id: 1 } }
|
||||
|
||||
it 'generates an error' do
|
||||
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'positionInList is mutually exclusive with any of moveBeforeId or moveAfterId') do
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when position_in_list is invalid' do
|
||||
let(:move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: -5 } }
|
||||
|
||||
it 'generates an error' do
|
||||
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, "positionInList must be >= 0 or #{Boards::Issues::MoveService::LIST_END_POSITION}") do
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user have access to resources' do
|
||||
it 'moves and repositions issue' do
|
||||
subject
|
||||
|
|
|
@ -15,6 +15,16 @@ RSpec.describe Banzai::Filter::PlantumlFilter do
|
|||
expect(doc.to_s).to eq output
|
||||
end
|
||||
|
||||
it 'allows the lang attribute on the code tag to support RST files processed by gitlab-markup gem' do
|
||||
stub_application_setting(plantuml_enabled: true, plantuml_url: "http://localhost:8080")
|
||||
|
||||
input = '<pre><code lang="plantuml">Bob -> Sara : Hello</code></pre>'
|
||||
output = '<img class="plantuml" src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq" data-diagram="plantuml" data-diagram-src="data:text/plain;base64,Qm9iIC0+IFNhcmEgOiBIZWxsbw==">'
|
||||
doc = filter(input)
|
||||
|
||||
expect(doc.to_s).to eq output
|
||||
end
|
||||
|
||||
it 'does not replace plantuml pre tag with img tag if disabled' do
|
||||
stub_application_setting(plantuml_enabled: false)
|
||||
|
||||
|
|
|
@ -1556,6 +1556,42 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'track artifact report' do
|
||||
let(:pipeline) { create(:ci_pipeline, :running, :with_test_reports, status: :running) }
|
||||
|
||||
context 'when transitioning to completed status' do
|
||||
%i[drop! skip! succeed! cancel!].each do |command|
|
||||
it "performs worker on transition to #{command}" do
|
||||
expect(Ci::JobArtifacts::TrackArtifactReportWorker).to receive(:perform_async).with(pipeline.id)
|
||||
pipeline.send(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline retried from failed to success', :clean_gitlab_redis_shared_state do
|
||||
let(:test_event_name) { 'i_testing_test_report_uploaded' }
|
||||
let(:start_time) { 1.week.ago }
|
||||
let(:end_time) { 1.week.from_now }
|
||||
|
||||
it 'counts only one report' do
|
||||
expect(Ci::JobArtifacts::TrackArtifactReportWorker).to receive(:perform_async).with(pipeline.id).twice.and_call_original
|
||||
|
||||
Sidekiq::Testing.inline! do
|
||||
pipeline.drop!
|
||||
pipeline.run!
|
||||
pipeline.succeed!
|
||||
end
|
||||
|
||||
unique_pipeline_pass = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
|
||||
event_names: test_event_name,
|
||||
start_date: start_time,
|
||||
end_date: end_time
|
||||
)
|
||||
expect(unique_pipeline_pass).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'merge request metrics' do
|
||||
let(:pipeline) { create(:ci_empty_pipeline, status: from_status) }
|
||||
|
||||
|
|
|
@ -100,6 +100,20 @@ RSpec.describe 'Reposition and move issue within board lists' do
|
|||
expect(response_issue['labels']['edges'][0]['node']['title']).to eq(testing.title)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when moving an issue using position_in_list' do
|
||||
let(:issue_move_params) { { from_list_id: list1.id, to_list_id: list2.id, position_in_list: 0 } }
|
||||
|
||||
it 'repositions an issue' do
|
||||
post_graphql_mutation(mutation(params), current_user: current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
response_issue = json_response['data'][mutation_result_identifier]['issue']
|
||||
expect(response_issue['iid']).to eq(issue1.iid.to_s)
|
||||
expect(response_issue['labels']['edges'][0]['node']['title']).to eq(testing.title)
|
||||
expect(response_issue['relativePosition']).to be < existing_issue1.relative_position
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has no access to resources' do
|
||||
|
|
|
@ -93,6 +93,16 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
|
|||
expect(response).to have_gitlab_http_status(:success)
|
||||
expect(mutation_assignee_nodes).to match_array(expected_result)
|
||||
end
|
||||
|
||||
it 'triggers webhooks', :sidekiq_inline do
|
||||
hook = create(:project_hook, merge_requests_events: true, project: merge_request.project)
|
||||
|
||||
expect(WebHookWorker).to receive(:perform_async).with(hook.id, anything, 'merge_request_hooks', anything)
|
||||
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passing an empty list of assignees' do
|
||||
|
|
|
@ -2337,6 +2337,16 @@ RSpec.describe API::MergeRequests do
|
|||
|
||||
expect(merge_request.notes.system.last.note).to include("assigned to #{user2.to_reference}")
|
||||
end
|
||||
|
||||
it 'triggers webhooks', :sidekiq_inline do
|
||||
hook = create(:project_hook, merge_requests_events: true, project: merge_request.project)
|
||||
|
||||
expect(WebHookWorker).to receive(:perform_async).with(hook.id, anything, 'merge_request_hooks', anything)
|
||||
|
||||
put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when assignee_id=user2.id' do
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
|
||||
describe '#execute', :clean_gitlab_redis_shared_state do
|
||||
let_it_be(:group) { create(:group, :private) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:test_event_name) { 'i_testing_test_report_uploaded' }
|
||||
let(:values_delimiter) { '_' }
|
||||
let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
|
||||
let(:start_time) { 1.week.ago }
|
||||
let(:end_time) { 1.week.from_now }
|
||||
|
||||
subject(:track_artifact_report) { described_class.new.execute(pipeline) }
|
||||
|
||||
context 'when pipeline has test reports' do
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) }
|
||||
|
||||
before do
|
||||
2.times do
|
||||
pipeline.builds << build(:ci_build, :test_reports, pipeline: pipeline, project: pipeline.project)
|
||||
end
|
||||
end
|
||||
|
||||
it 'tracks the event using HLLRedisCounter' do
|
||||
allow(Gitlab::UsageDataCounters::HLLRedisCounter)
|
||||
.to receive(:track_event)
|
||||
.with(test_event_name, values: [pipeline.id, user.id].join(values_delimiter))
|
||||
.and_call_original
|
||||
|
||||
expect { track_artifact_report }
|
||||
.to change {
|
||||
counter.unique_events(event_names: test_event_name,
|
||||
start_date: start_time,
|
||||
end_date: end_time)
|
||||
}
|
||||
.by 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline does not have test reports' do
|
||||
let_it_be(:pipeline) { create(:ci_empty_pipeline) }
|
||||
|
||||
it 'does not track the event' do
|
||||
track_artifact_report
|
||||
|
||||
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
|
||||
.not_to receive(:track_event)
|
||||
.with(anything, test_event_name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multiple pipelines have test reports' do
|
||||
let_it_be(:pipeline1) { create(:ci_pipeline, :with_test_reports, project: project, user: user) }
|
||||
let_it_be(:pipeline2) { create(:ci_pipeline, :with_test_reports, project: project, user: user) }
|
||||
|
||||
it 'tracks all pipelines using HLLRedisCounter' do
|
||||
allow(Gitlab::UsageDataCounters::HLLRedisCounter)
|
||||
.to receive(:track_event)
|
||||
.with(test_event_name, values: [pipeline1.id, user.id].join(values_delimiter))
|
||||
.and_call_original
|
||||
|
||||
allow(Gitlab::UsageDataCounters::HLLRedisCounter)
|
||||
.to receive(:track_event)
|
||||
.with(test_event_name, values: [pipeline2.id, user.id].join(values_delimiter))
|
||||
.and_call_original
|
||||
|
||||
expect do
|
||||
described_class.new.execute(pipeline1)
|
||||
described_class.new.execute(pipeline2)
|
||||
end
|
||||
.to change {
|
||||
counter.unique_events(event_names: test_event_name,
|
||||
start_date: start_time,
|
||||
end_date: end_time)
|
||||
}
|
||||
.by 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -102,7 +102,7 @@ RSpec.describe MergeRequests::HandleAssigneesChangeService do
|
|||
end
|
||||
|
||||
context 'when execute_hooks option is set to true' do
|
||||
let(:options) { { execute_hooks: true } }
|
||||
let(:options) { { 'execute_hooks' => true } }
|
||||
|
||||
it 'executes hooks and integrations' do
|
||||
expect(merge_request.project).to receive(:execute_hooks).with(anything, :merge_request_hooks)
|
||||
|
|
|
@ -140,6 +140,40 @@ RSpec.shared_examples 'issues move service' do |group|
|
|||
expect(issue2.reload.updated_at.change(usec: 0)).to eq updated_at2.change(usec: 0)
|
||||
end
|
||||
|
||||
context 'when moving to a specific list position' do
|
||||
before do
|
||||
[issue1, issue2, issue].each do |issue|
|
||||
issue.move_to_end && issue.save!
|
||||
end
|
||||
end
|
||||
|
||||
it 'moves issue to the top of the list' do
|
||||
described_class.new(parent, user, params.merge({ position_in_list: 0 })).execute(issue)
|
||||
|
||||
expect(issue.relative_position).to be < issue1.relative_position
|
||||
end
|
||||
|
||||
it 'moves issue to a position in the middle of the list' do
|
||||
described_class.new(parent, user, params.merge({ position_in_list: 1 })).execute(issue)
|
||||
|
||||
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
|
||||
end
|
||||
|
||||
it 'moves issue to the bottom of the list' do
|
||||
described_class.new(parent, user, params.merge({ position_in_list: -1 })).execute(issue1)
|
||||
|
||||
expect(issue1.relative_position).to be > issue.relative_position
|
||||
end
|
||||
|
||||
context 'when given position is greater than number of issues in the list' do
|
||||
it 'moves the issue to the bottom of the list' do
|
||||
described_class.new(parent, user, params.merge({ position_in_list: 5 })).execute(issue1)
|
||||
|
||||
expect(issue1.relative_position).to be > issue.relative_position
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reorder_issues(params, issues: [])
|
||||
issues.each do |issue|
|
||||
issue.move_to_end && issue.save!
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::JobArtifacts::TrackArtifactReportWorker do
|
||||
describe '#perform', :clean_gitlab_redis_shared_state do
|
||||
let_it_be(:group) { create(:group, :private) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project, user: user) }
|
||||
|
||||
subject(:perform) { described_class.new.perform(pipeline_id) }
|
||||
|
||||
context 'when pipeline is found' do
|
||||
let(:pipeline_id) { pipeline.id }
|
||||
|
||||
it 'executed service' do
|
||||
expect_next_instance_of(Ci::JobArtifacts::TrackArtifactReportService) do |instance|
|
||||
expect(instance).to receive(:execute).with(pipeline)
|
||||
end
|
||||
|
||||
perform
|
||||
end
|
||||
|
||||
it_behaves_like 'an idempotent worker' do
|
||||
let(:job_args) { pipeline_id }
|
||||
let(:test_event_name) { 'i_testing_test_report_uploaded' }
|
||||
let(:start_time) { 1.week.ago }
|
||||
let(:end_time) { 1.week.from_now }
|
||||
|
||||
subject(:idempotent_perform) { perform_multiple(pipeline_id, exec_times: 2) }
|
||||
|
||||
it 'does not try to increment again' do
|
||||
idempotent_perform
|
||||
|
||||
unique_pipeline_pass = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
|
||||
event_names: test_event_name,
|
||||
start_date: start_time,
|
||||
end_date: end_time
|
||||
)
|
||||
expect(unique_pipeline_pass).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pipeline is not found' do
|
||||
let(:pipeline_id) { non_existing_record_id }
|
||||
|
||||
it 'does not execute service' do
|
||||
allow_next_instance_of(Ci::JobArtifacts::TrackArtifactReportService) do |instance|
|
||||
expect(instance).not_to receive(:execute)
|
||||
end
|
||||
|
||||
expect { perform }
|
||||
.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -32,8 +32,8 @@ require (
|
|||
gocloud.dev v0.25.0
|
||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93
|
||||
golang.org/x/tools v0.1.11
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
|
||||
golang.org/x/tools v0.1.12
|
||||
google.golang.org/grpc v1.49.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
honnef.co/go/tools v0.3.3
|
||||
|
@ -106,8 +106,8 @@ require (
|
|||
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
|
|
|
@ -1119,6 +1119,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
gitlab.com/gitlab-org/gitaly v1.68.0 h1:VlcJs1+PrhW7lqJUU7Fh1q8FMJujmbbivdfde/cwB98=
|
||||
|
@ -1331,8 +1332,9 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
|||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -1369,8 +1371,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -1476,8 +1479,9 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -1577,8 +1581,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
Loading…
Reference in New Issue