Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-02 12:10:32 +00:00
parent 423309c4ae
commit 2d337eacd9
44 changed files with 602 additions and 130 deletions

View File

@ -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

View File

@ -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'

View File

@ -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)

View File

@ -41,6 +41,13 @@
font-size: 13px;
}
.signin-text {
p {
margin-bottom: 0;
line-height: 1.5;
}
}
.borderless {
.login-box,
.omniauth-container {

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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' } })

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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. |

View File

@ -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). |

View File

@ -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>]
```

View File

@ -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

View File

@ -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

View File

@ -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}. Youll receive a receipt via email."
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. Youll receive a receipt via email. It might take a moment for GitLab.com to fully reflect your purchase."
msgstr ""
msgid "You have unsaved changes"

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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) }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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!

View File

@ -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

View File

@ -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

View File

@ -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=