From 2d337eacd93f459f702e032077b5ba123ed90c00 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 2 Sep 2022 12:10:32 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/frontend.gitlab-ci.yml | 8 +- Gemfile | 1 - Gemfile.lock | 1 - app/assets/stylesheets/pages/login.scss | 7 ++ .../stylesheets/startup/startup-signin.scss | 4 + .../boards/issues/issue_move_list.rb | 28 ++++++- app/models/ci/pipeline.rb | 6 ++ app/services/boards/base_item_move_service.rb | 22 ++++- app/services/boards/issues/move_service.rb | 4 + .../track_artifact_report_service.rb | 24 ++++++ app/services/issues/close_service.rb | 7 +- app/services/issues/reopen_service.rb | 7 +- .../handle_assignees_change_service.rb | 2 +- app/views/layouts/devise.html.haml | 2 +- .../projects/mirrors/_mirror_repos.html.haml | 38 +-------- .../mirrors/_mirror_repos_list.html.haml | 47 +++++++++++ app/views/shared/_file_highlight.html.haml | 3 +- app/workers/all_queues.yml | 9 ++ .../track_artifact_report_worker.rb | 23 +++++ ...data_ci_i_testing_test_report_uploaded.yml | 8 ++ config/initializers/zz_metrics.rb | 1 - ...i_testing_test_report_uploaded_monthly.yml | 26 ++++++ ..._i_testing_test_report_uploaded_weekly.yml | 26 ++++++ .../operations/rails_console.md | 16 ++++ .../gitlab_rails_cheat_sheet.md | 28 ------- doc/api/graphql/reference/index.md | 1 + .../variables/where_variables_can_be_used.md | 2 +- doc/user/group/manage.md | 10 +++ lib/banzai/filter/plantuml_filter.rb | 3 +- .../known_events/common.yml | 5 ++ locale/gitlab.pot | 32 +------ .../settings/mirroring_repositories.rb | 3 + .../boards/issues/issue_move_list_spec.rb | 46 +++++++++- .../lib/banzai/filter/plantuml_filter_spec.rb | 10 +++ spec/models/ci/pipeline_spec.rb | 36 ++++++++ .../boards/issues/issue_move_list_spec.rb | 14 ++++ .../merge_requests/set_assignees_spec.rb | 10 +++ spec/requests/api/merge_requests_spec.rb | 10 +++ .../track_artifact_report_service_spec.rb | 84 +++++++++++++++++++ .../handle_assignees_change_service_spec.rb | 2 +- .../issues_move_service_shared_examples.rb | 34 ++++++++ .../track_artifact_report_worker_spec.rb | 60 +++++++++++++ workhorse/go.mod | 8 +- workhorse/go.sum | 14 ++-- 44 files changed, 602 insertions(+), 130 deletions(-) create mode 100644 app/services/ci/job_artifacts/track_artifact_report_service.rb create mode 100644 app/views/projects/mirrors/_mirror_repos_list.html.haml create mode 100644 app/workers/ci/job_artifacts/track_artifact_report_worker.rb create mode 100644 config/feature_flags/development/usage_data_ci_i_testing_test_report_uploaded.yml create mode 100644 config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml create mode 100644 config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml create mode 100644 spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb create mode 100644 spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 59a144b952d..a4f21709a59 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -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 diff --git a/Gemfile b/Gemfile index 29ce34391ed..7a1fd731b82 100644 --- a/Gemfile +++ b/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' diff --git a/Gemfile.lock b/Gemfile.lock index 9451f114bae..d02f181665c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index 1beb9f05b6c..075d0e2424a 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -41,6 +41,13 @@ font-size: 13px; } + .signin-text { + p { + margin-bottom: 0; + line-height: 1.5; + } + } + .borderless { .login-box, .omniauth-container { diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss index 1e6fe32c0ee..b36b6827643 100644 --- a/app/assets/stylesheets/startup/startup-signin.scss +++ b/app/assets/stylesheets/startup/startup-signin.scss @@ -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; diff --git a/app/graphql/mutations/boards/issues/issue_move_list.rb b/app/graphql/mutations/boards/issues/issue_move_list.rb index 14fe9714f99..e9cae80e5f9 100644 --- a/app/graphql/mutations/boards/issues/issue_move_list.rb +++ b/app/graphql/mutations/boards/issues/issue_move_list.rb @@ -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) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index bf7eed9543d..f2d4c9a43c3 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -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 diff --git a/app/services/boards/base_item_move_service.rb b/app/services/boards/base_item_move_service.rb index 9d711d83fd2..c9da889c536 100644 --- a/app/services/boards/base_item_move_service.rb +++ b/app/services/boards/base_item_move_service.rb @@ -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) diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb index 90226b9d4e0..4de4d7c8f69 100644 --- a/app/services/boards/issues/move_service.rb +++ b/app/services/boards/issues/move_service.rb @@ -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 diff --git a/app/services/ci/job_artifacts/track_artifact_report_service.rb b/app/services/ci/job_artifacts/track_artifact_report_service.rb new file mode 100644 index 00000000000..349050c173e --- /dev/null +++ b/app/services/ci/job_artifacts/track_artifact_report_service.rb @@ -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 diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index d08e4d12a92..1799047cbdf 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -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 diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb index e003ecacb3f..f4f81e9455a 100644 --- a/app/services/issues/reopen_service.rb +++ b/app/services/issues/reopen_service.rb @@ -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 diff --git a/app/services/merge_requests/handle_assignees_change_service.rb b/app/services/merge_requests/handle_assignees_change_service.rb index 87cd6544406..51be4690af4 100644 --- a/app/services/merge_requests/handle_assignees_change_service.rb +++ b/app/services/merge_requests/handle_assignees_change_service.rb @@ -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 diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 87a8b6dd870..6650e07be2a 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -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 diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index 339042eb703..2ae7d300979 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -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' diff --git a/app/views/projects/mirrors/_mirror_repos_list.html.haml b/app/views/projects/mirrors/_mirror_repos_list.html.haml new file mode 100644 index 00000000000..2dbcbd659c8 --- /dev/null +++ b/app/views/projects/mirrors/_mirror_repos_list.html.haml @@ -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' } }) diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index 130e73a069f..89be816fc76 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -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) diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index e62e7019a11..63c647dc9ca 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -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 diff --git a/app/workers/ci/job_artifacts/track_artifact_report_worker.rb b/app/workers/ci/job_artifacts/track_artifact_report_worker.rb new file mode 100644 index 00000000000..3df8c284ab3 --- /dev/null +++ b/app/workers/ci/job_artifacts/track_artifact_report_worker.rb @@ -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 diff --git a/config/feature_flags/development/usage_data_ci_i_testing_test_report_uploaded.yml b/config/feature_flags/development/usage_data_ci_i_testing_test_report_uploaded.yml new file mode 100644 index 00000000000..1635427485b --- /dev/null +++ b/config/feature_flags/development/usage_data_ci_i_testing_test_report_uploaded.yml @@ -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 diff --git a/config/initializers/zz_metrics.rb b/config/initializers/zz_metrics.rb index 1aeb345badb..3a729e34135 100644 --- a/config/initializers/zz_metrics.rb +++ b/config/initializers/zz_metrics.rb @@ -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. diff --git a/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml b/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml new file mode 100644 index 00000000000..341d3810318 --- /dev/null +++ b/config/metrics/counts_28d/20220825142533_i_testing_test_report_uploaded_monthly.yml @@ -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 diff --git a/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml b/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml new file mode 100644 index 00000000000..814a50554c1 --- /dev/null +++ b/config/metrics/counts_7d/20220825142528_i_testing_test_report_uploaded_weekly.yml @@ -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 diff --git a/doc/administration/operations/rails_console.md b/doc/administration/operations/rails_console.md index 4838a3c5516..235f34e8de5 100644 --- a/doc/administration/operations/rails_console.md +++ b/doc/administration/operations/rails_console.md @@ -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 diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md index 4288a06e1b8..612cdd06e99 100644 --- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md +++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md @@ -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'") -=> [#, #] -``` - ## Routes ### Remove redirecting routes diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 2e77b196068..089c6e0d766 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -3038,6 +3038,7 @@ Input type: `IssueMoveListInput` | `iid` | [`String!`](#string) | IID of the issue to mutate. | | `moveAfterId` | [`ID`](#id) | ID of issue that should be placed after the current issue. | | `moveBeforeId` | [`ID`](#id) | ID of issue that should be placed before the current issue. | +| `positionInList` | [`Int`](#int) | Position of issue within the board list. Positions start at 0. Use -1 to move to the end of the list. | | `projectPath` | [`ID!`](#id) | Project the issue to mutate is in. | | `toListId` | [`ID`](#id) | ID of the board list that the issue will be moved to. | diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md index db83f2a14f3..e0ec0728c71 100644 --- a/doc/ci/variables/where_variables_can_be_used.md +++ b/doc/ci/variables/where_variables_can_be_used.md @@ -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.

Supported are all variables defined for a job (project/group variables, variables from `.gitlab-ci.yml`, variables from triggers, variables from pipeline schedules).

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:

- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).
- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).
- [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.

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.

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:

- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).
- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).
- [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:
- `CI_ENVIRONMENT_URL`
- [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:

- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).
- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).
- [Persisted variables](#persisted-variables). | diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md index 57070658355..78e65297d32 100644 --- a/doc/user/group/manage.md +++ b/doc/user/group/manage.md @@ -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'") +=> [#, #] +``` diff --git a/lib/banzai/filter/plantuml_filter.rb b/lib/banzai/filter/plantuml_filter.rb index cbcd547120d..82f6247cf03 100644 --- a/lib/banzai/filter/plantuml_filter.rb +++ b/lib/banzai/filter/plantuml_filter.rb @@ -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 diff --git a/lib/gitlab/usage_data_counters/known_events/common.yml b/lib/gitlab/usage_data_counters/known_events/common.yml index 6c4754ae19f..582f1dd797c 100644 --- a/lib/gitlab/usage_data_counters/known_events/common.yml +++ b/lib/gitlab/usage_data_counters/known_events/common.yml @@ -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 diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 37392993acf..985c1ecdbb1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -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" diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb index 501b31f8a95..7eeeeefdae6 100644 --- a/qa/qa/page/project/settings/mirroring_repositories.rb +++ b/qa/qa/page/project/settings/mirroring_repositories.rb @@ -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 diff --git a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb index 10aed8a1f00..8e9a567f614 100644 --- a/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb +++ b/spec/graphql/mutations/boards/issues/issue_move_list_spec.rb @@ -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 diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb index dcfeb2ce3ba..4373af90cde 100644 --- a/spec/lib/banzai/filter/plantuml_filter_spec.rb +++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb @@ -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 = '
Bob -> Sara : Hello
' + output = '' + 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) diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index cf80eafd137..85a30fe02cc 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -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) } diff --git a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb index 46ec22e7ef8..06093e9f7c2 100644 --- a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb +++ b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb @@ -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 diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb index 608b36e4f15..8cec5867aca 100644 --- a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb +++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb @@ -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 diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index f70e029bfd4..17cd86e73a1 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -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 diff --git a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb new file mode 100644 index 00000000000..1abf8eb562c --- /dev/null +++ b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb @@ -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 diff --git a/spec/services/merge_requests/handle_assignees_change_service_spec.rb b/spec/services/merge_requests/handle_assignees_change_service_spec.rb index c43f5db6059..3db3efedb84 100644 --- a/spec/services/merge_requests/handle_assignees_change_service_spec.rb +++ b/spec/services/merge_requests/handle_assignees_change_service_spec.rb @@ -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) diff --git a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb index 1638e2fa86a..162be24fe8f 100644 --- a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb +++ b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb @@ -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! diff --git a/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb b/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb new file mode 100644 index 00000000000..e18539cc6e3 --- /dev/null +++ b/spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb @@ -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 diff --git a/workhorse/go.mod b/workhorse/go.mod index 7b57cf0e8fd..2959cebdf0a 100644 --- a/workhorse/go.mod +++ b/workhorse/go.mod @@ -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 diff --git a/workhorse/go.sum b/workhorse/go.sum index 8bd801b0522..b61566a39c0 100644 --- a/workhorse/go.sum +++ b/workhorse/go.sum @@ -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=