Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
14ae125e1c
commit
6e7be08ca5
62 changed files with 552 additions and 177 deletions
|
@ -4,6 +4,7 @@ import { mapState } from 'vuex';
|
|||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { FIELDS } from '~/members/constants';
|
||||
import { parseSortParam, buildSortHref } from '~/members/utils';
|
||||
import { SORT_DIRECTION_UI } from '~/search/sort/constants';
|
||||
|
||||
export default {
|
||||
name: 'SortDropdown',
|
||||
|
@ -30,6 +31,9 @@ export default {
|
|||
isAscending() {
|
||||
return !this.sort.sortDesc;
|
||||
},
|
||||
sortDirectionData() {
|
||||
return this.isAscending ? SORT_DIRECTION_UI.asc : SORT_DIRECTION_UI.desc;
|
||||
},
|
||||
filteredOptions() {
|
||||
return FIELDS.filter(
|
||||
(field) => this.tableSortableFields.includes(field.key) && field.sort,
|
||||
|
@ -70,7 +74,7 @@ export default {
|
|||
data-testid="members-sort-dropdown"
|
||||
:text="activeOptionLabel"
|
||||
:is-ascending="isAscending"
|
||||
:sort-direction-tool-tip="__('Sort direction')"
|
||||
:sort-direction-tool-tip="sortDirectionData.tooltip"
|
||||
@sortDirectionChange="handleSortDirectionChange"
|
||||
>
|
||||
<gl-sorting-item
|
||||
|
|
|
@ -161,7 +161,7 @@ function mountAssigneesComponent() {
|
|||
fullPath,
|
||||
issuableType,
|
||||
issuableId: id,
|
||||
allowMultipleAssignees: !el.dataset.maxAssignees,
|
||||
allowMultipleAssignees: !el.dataset.maxAssignees || el.dataset.maxAssignees > 1,
|
||||
editable,
|
||||
},
|
||||
scopedSlots: {
|
||||
|
|
|
@ -243,6 +243,7 @@ export default {
|
|||
variant="confirm"
|
||||
category="primary"
|
||||
size="small"
|
||||
data-qa-selector="dismiss_suggestion_popover_button"
|
||||
@click="handleSuggestDismissed"
|
||||
>
|
||||
{{ __('Got it') }}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlSorting, GlSortingItem, GlFilteredSearch } from '@gitlab/ui';
|
||||
import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
|
||||
import { SORT_DIRECTION_UI } from '~/search/sort/constants';
|
||||
|
||||
const ASCENDING_ORDER = 'asc';
|
||||
const DESCENDING_ORDER = 'desc';
|
||||
|
@ -52,6 +53,9 @@ export default {
|
|||
return acc;
|
||||
}, {});
|
||||
},
|
||||
sortDirectionData() {
|
||||
return this.isSortAscending ? SORT_DIRECTION_UI.asc : SORT_DIRECTION_UI.desc;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateQueryData({ sorting = {}, filter = [] } = {}) {
|
||||
|
@ -119,6 +123,7 @@ export default {
|
|||
data-testid="registry-sort-dropdown"
|
||||
:text="sortText"
|
||||
:is-ascending="isSortAscending"
|
||||
:sort-direction-tool-tip="sortDirectionData.tooltip"
|
||||
@sortDirectionChange="onDirectionChange"
|
||||
>
|
||||
<gl-sorting-item
|
||||
|
|
|
@ -39,13 +39,13 @@ module FormHelper
|
|||
end
|
||||
end
|
||||
|
||||
def dropdown_max_select(data)
|
||||
return data[:'max-select'] unless Feature.enabled?(:limit_reviewer_and_assignee_size)
|
||||
def dropdown_max_select(data, feature_flag)
|
||||
return data[:'max-select'] unless Feature.enabled?(feature_flag)
|
||||
|
||||
if data[:'max-select'] && data[:'max-select'] < MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
if data[:'max-select'] && data[:'max-select'] < ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
data[:'max-select']
|
||||
else
|
||||
MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -162,7 +162,12 @@ module FormHelper
|
|||
|
||||
new_options[:title] = _('Select assignee(s)')
|
||||
new_options[:data][:'dropdown-header'] = 'Assignee(s)'
|
||||
|
||||
if Feature.enabled?(:limit_assignees_per_issuable)
|
||||
new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
else
|
||||
new_options[:data].delete(:'max-select')
|
||||
end
|
||||
|
||||
new_options
|
||||
end
|
||||
|
@ -174,7 +179,7 @@ module FormHelper
|
|||
new_options[:data][:'dropdown-header'] = _('Reviewer(s)')
|
||||
|
||||
if Feature.enabled?(:limit_reviewer_and_assignee_size)
|
||||
new_options[:data][:'max-select'] = MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
else
|
||||
new_options[:data].delete(:'max-select')
|
||||
end
|
||||
|
|
|
@ -64,12 +64,13 @@ module WikiHelper
|
|||
link_class = 'gl-button btn btn-default btn-icon has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort'
|
||||
reversed_direction = direction == 'desc' ? 'asc' : 'desc'
|
||||
icon_class = direction == 'desc' ? 'highest' : 'lowest'
|
||||
title = direction == 'desc' ? _('Sort direction: Descending') : _('Sort direction: Ascending')
|
||||
|
||||
link_options = { action: :pages, direction: reversed_direction }
|
||||
link_options[:sort] = sort unless wiki.disable_sorting?
|
||||
|
||||
link_to(wiki_path(wiki, **link_options),
|
||||
type: 'button', class: link_class, title: _('Sort direction')) do
|
||||
type: 'button', class: link_class, title: title) do
|
||||
sprite_icon("sort-#{icon_class}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,6 +33,7 @@ module Issuable
|
|||
DESCRIPTION_LENGTH_MAX = 1.megabyte
|
||||
DESCRIPTION_HTML_LENGTH_MAX = 5.megabytes
|
||||
SEARCHABLE_FIELDS = %w(title description).freeze
|
||||
MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS = 200
|
||||
|
||||
STATE_ID_MAP = {
|
||||
opened: 1,
|
||||
|
@ -95,6 +96,7 @@ module Issuable
|
|||
# to avoid breaking the existing Issuables which may have their descriptions longer
|
||||
validates :description, length: { maximum: DESCRIPTION_LENGTH_MAX }, allow_blank: true, on: :create
|
||||
validate :description_max_length_for_new_records_is_valid, on: :update
|
||||
validate :validate_assignee_size_length, unless: :importing?
|
||||
|
||||
before_validation :truncate_description_on_import!
|
||||
|
||||
|
@ -166,6 +168,11 @@ module Issuable
|
|||
def locking_enabled?
|
||||
false
|
||||
end
|
||||
|
||||
def max_number_of_assignees_or_reviewers_message
|
||||
# Assignees will be included in https://gitlab.com/gitlab-org/gitlab/-/issues/368936
|
||||
format(_("total must be less than or equal to %{size}"), size: MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS)
|
||||
end
|
||||
end
|
||||
|
||||
# We want to use optimistic lock for cases when only title or description are involved
|
||||
|
@ -227,6 +234,14 @@ module Issuable
|
|||
def truncate_description_on_import!
|
||||
self.description = description&.slice(0, Issuable::DESCRIPTION_LENGTH_MAX) if importing?
|
||||
end
|
||||
|
||||
def validate_assignee_size_length
|
||||
return true unless Feature.enabled?(:limit_assignees_per_issuable)
|
||||
return true unless assignees.size > MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
|
||||
errors.add :assignees,
|
||||
-> (_object, _data) { self.class.max_number_of_assignees_or_reviewers_message }
|
||||
end
|
||||
end
|
||||
|
||||
class_methods do
|
||||
|
|
|
@ -41,8 +41,6 @@ class MergeRequest < ApplicationRecord
|
|||
'Ci::CompareCodequalityReportsService' => ->(project) { true }
|
||||
}.freeze
|
||||
|
||||
MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS = 200
|
||||
|
||||
belongs_to :target_project, class_name: "Project"
|
||||
belongs_to :source_project, class_name: "Project"
|
||||
belongs_to :merge_user, class_name: "User"
|
||||
|
@ -294,7 +292,7 @@ class MergeRequest < ApplicationRecord
|
|||
validate :validate_branches, unless: [:allow_broken, :importing?, :closed_or_merged_without_fork?]
|
||||
validate :validate_fork, unless: :closed_or_merged_without_fork?
|
||||
validate :validate_target_project, on: :create
|
||||
validate :validate_reviewer_and_assignee_size_length, unless: :importing?
|
||||
validate :validate_reviewer_size_length, unless: :importing?
|
||||
|
||||
scope :by_source_or_target_branch, ->(branch_name) do
|
||||
where("source_branch = :branch OR target_branch = :branch", branch: branch_name)
|
||||
|
@ -1014,18 +1012,12 @@ class MergeRequest < ApplicationRecord
|
|||
'Source project is not a fork of the target project'
|
||||
end
|
||||
|
||||
def self.max_number_of_assignees_or_reviewers_message
|
||||
# Assignees will be included in https://gitlab.com/gitlab-org/gitlab/-/issues/368936
|
||||
_("total must be less than or equal to %{size}") % { size: MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS }
|
||||
end
|
||||
|
||||
def validate_reviewer_and_assignee_size_length
|
||||
# Assigness will be added in a subsequent MR https://gitlab.com/gitlab-org/gitlab/-/issues/368936
|
||||
def validate_reviewer_size_length
|
||||
return true unless Feature.enabled?(:limit_reviewer_and_assignee_size)
|
||||
return true unless reviewers.size > MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
|
||||
errors.add :reviewers,
|
||||
-> (_object, _data) { MergeRequest.max_number_of_assignees_or_reviewers_message }
|
||||
-> (_object, _data) { self.class.max_number_of_assignees_or_reviewers_message }
|
||||
end
|
||||
|
||||
def merge_ongoing?
|
||||
|
|
|
@ -3039,6 +3039,11 @@ class Project < ApplicationRecord
|
|||
pages_domains.count < Gitlab::CurrentSettings.max_pages_custom_domains_per_project
|
||||
end
|
||||
|
||||
# overridden in EE
|
||||
def can_suggest_reviewers?
|
||||
false
|
||||
end
|
||||
|
||||
# overridden in EE
|
||||
def suggested_reviewers_available?
|
||||
false
|
||||
|
|
|
@ -18,7 +18,17 @@ module MergeRequests
|
|||
return merge_request if old_ids.to_set == new_ids.to_set # no-change
|
||||
|
||||
attrs = update_attrs.merge(assignee_ids: new_ids)
|
||||
|
||||
# We now have assignees validation on merge request
|
||||
# If we use an update with bang, it will explode,
|
||||
# instead we need to check if its valid then return if its not valid.
|
||||
if Feature.enabled?(:limit_assignees_per_issuable)
|
||||
merge_request.update(**attrs)
|
||||
|
||||
return merge_request unless merge_request.valid?
|
||||
else
|
||||
merge_request.update!(**attrs)
|
||||
end
|
||||
|
||||
# Defer the more expensive operations (handle_assignee_changes) to the background
|
||||
MergeRequests::HandleAssigneesChangeService
|
||||
|
|
|
@ -88,12 +88,14 @@ module Notes
|
|||
return if quick_actions_service.commands_executed_count.to_i == 0
|
||||
|
||||
if update_params.present?
|
||||
if check_for_reviewer_validity(message, update_params)
|
||||
invalid_message = validate_commands(note, update_params)
|
||||
|
||||
if invalid_message
|
||||
note.errors.add(:validation, invalid_message)
|
||||
message = invalid_message
|
||||
else
|
||||
quick_actions_service.apply_updates(update_params, note)
|
||||
note.commands_changes = update_params
|
||||
else
|
||||
message = "Reviewers #{MergeRequest.max_number_of_assignees_or_reviewers_message}"
|
||||
note.errors.add(:validation, message)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -114,16 +116,36 @@ module Notes
|
|||
}
|
||||
end
|
||||
|
||||
def check_for_reviewer_validity(message, update_params)
|
||||
return true unless Feature.enabled?(:limit_reviewer_and_assignee_size)
|
||||
def validate_commands(note, update_params)
|
||||
if invalid_reviewers?(update_params)
|
||||
"Reviewers #{note.noteable.class.max_number_of_assignees_or_reviewers_message}"
|
||||
elsif invalid_assignees?(update_params)
|
||||
"Assignees #{note.noteable.class.max_number_of_assignees_or_reviewers_message}"
|
||||
end
|
||||
end
|
||||
|
||||
def invalid_reviewers?(update_params)
|
||||
return false unless Feature.enabled?(:limit_reviewer_and_assignee_size)
|
||||
|
||||
if update_params.key?(:reviewer_ids)
|
||||
possible_reviewers = update_params[:reviewer_ids]&.uniq&.size
|
||||
|
||||
return false if possible_reviewers > MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
possible_reviewers > ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
def invalid_assignees?(update_params)
|
||||
return false unless Feature.enabled?(:limit_assignees_per_issuable)
|
||||
|
||||
if update_params.key?(:assignee_ids)
|
||||
possible_assignees = update_params[:assignee_ids]&.uniq&.size
|
||||
|
||||
possible_assignees > ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def track_event(note, user)
|
||||
|
|
|
@ -30,7 +30,6 @@ module Projects
|
|||
end
|
||||
|
||||
def use_gitlab_service?
|
||||
Feature.enabled?(:container_registry_new_cleanup_service, project) &&
|
||||
container_repository.migrated? &&
|
||||
container_repository.gitlab_api_client.supports_gitlab_api?
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
- data[:multi_select] = true
|
||||
- data['dropdown-title'] = title
|
||||
- data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
|
||||
- data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
|
||||
- data['max-select'] = dropdown_max_select(dropdown_options[:data], :limit_assignees_per_issuable)
|
||||
- options[:data].merge!(data)
|
||||
|
||||
= render 'shared/issuable/sidebar_user_dropdown',
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
- data[:suggested_reviewers_header] = dropdown_options[:data][:suggested_reviewers_header]
|
||||
- data[:all_members_header] = dropdown_options[:data][:all_members_header]
|
||||
- data[:show_suggested] = dropdown_options[:data][:show_suggested]
|
||||
- data['max-select'] = dropdown_max_select(dropdown_options[:data])
|
||||
- data['max-select'] = dropdown_max_select(dropdown_options[:data], :limit_reviewer_and_assignee_size)
|
||||
- options[:data].merge!(data)
|
||||
|
||||
= render 'shared/issuable/sidebar_user_dropdown',
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: container_registry_new_cleanup_service
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98651
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375037
|
||||
name: limit_assignees_per_issuable
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95673
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373237
|
||||
milestone: '15.5'
|
||||
type: development
|
||||
group: group::package
|
||||
group: group::code review
|
||||
default_enabled: false
|
|
@ -1,62 +0,0 @@
|
|||
# Aggregated metrics that include EE only event names within `events:` attribute have to be defined at ee/config/metrics/aggregates/common.yml
|
||||
# instead of this file.
|
||||
# - name: unique name of aggregated metric
|
||||
# operator: aggregation operator. Valid values are:
|
||||
# - "OR": counts unique elements that were observed triggering any of following events
|
||||
# - "AND": counts unique elements that were observed triggering all of following events
|
||||
# events: list of events names to aggregate into metric. All events in this list must have the same 'redis_slot' and 'aggregation' attributes
|
||||
# see from lib/gitlab/usage_data_counters/known_events/ for the list of valid events.
|
||||
# source: defines which datasource will be used to locate events that should be included in aggregated metric. Valid values are:
|
||||
# - database
|
||||
# - redis
|
||||
# time_frame: defines time frames for aggregated metrics:
|
||||
# - 7d - last 7 days
|
||||
# - 28d - last 28 days
|
||||
# - all - all historical available data, this time frame is not available for redis source
|
||||
# feature_flag: name of development feature flag that will be checked before metrics aggregation is performed.
|
||||
# Corresponding feature flag should have `default_enabled` attribute set to `false`.
|
||||
# This attribute is OPTIONAL and can be omitted, when `feature_flag` is missing no feature flag will be checked.
|
||||
---
|
||||
- name: incident_management_incidents_total_unique_counts
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events:
|
||||
- 'incident_management_incident_created'
|
||||
- 'incident_management_incident_reopened'
|
||||
- 'incident_management_incident_closed'
|
||||
- 'incident_management_incident_assigned'
|
||||
- 'incident_management_incident_todo'
|
||||
- 'incident_management_incident_comment'
|
||||
- 'incident_management_incident_zoom_meeting'
|
||||
- 'incident_management_incident_published'
|
||||
- 'incident_management_incident_relate'
|
||||
- 'incident_management_incident_unrelate'
|
||||
- 'incident_management_incident_change_confidential'
|
||||
- name: xmau_plan
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
feature_flag: track_work_items_activity
|
||||
- name: xmau_project_management
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
feature_flag: track_work_items_activity
|
||||
- name: users_work_items
|
||||
operator: OR
|
||||
source: redis
|
||||
time_frame: [7d, 28d]
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
feature_flag: track_work_items_activity
|
|
@ -9,7 +9,24 @@ product_category: incident_management
|
|||
value_type: number
|
||||
status: active
|
||||
time_frame: 28d
|
||||
instrumentation_class: AggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- 'incident_management_incident_created'
|
||||
- 'incident_management_incident_reopened'
|
||||
- 'incident_management_incident_closed'
|
||||
- 'incident_management_incident_assigned'
|
||||
- 'incident_management_incident_todo'
|
||||
- 'incident_management_incident_comment'
|
||||
- 'incident_management_incident_zoom_meeting'
|
||||
- 'incident_management_incident_published'
|
||||
- 'incident_management_incident_relate'
|
||||
- 'incident_management_incident_unrelate'
|
||||
- 'incident_management_incident_change_confidential'
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -10,7 +10,16 @@ status: active
|
|||
milestone: '14.9'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81336
|
||||
time_frame: 28d
|
||||
instrumentation_class: WorkItemsActivityAggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -10,7 +10,16 @@ status: active
|
|||
milestone: '14.9'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81336
|
||||
time_frame: 28d
|
||||
instrumentation_class: WorkItemsActivityAggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -10,7 +10,16 @@ status: active
|
|||
milestone: '14.9'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81336
|
||||
time_frame: 28d
|
||||
instrumentation_class: WorkItemsActivityAggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -9,7 +9,24 @@ product_category: incident_management
|
|||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
instrumentation_class: AggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- 'incident_management_incident_created'
|
||||
- 'incident_management_incident_reopened'
|
||||
- 'incident_management_incident_closed'
|
||||
- 'incident_management_incident_assigned'
|
||||
- 'incident_management_incident_todo'
|
||||
- 'incident_management_incident_comment'
|
||||
- 'incident_management_incident_zoom_meeting'
|
||||
- 'incident_management_incident_published'
|
||||
- 'incident_management_incident_relate'
|
||||
- 'incident_management_incident_unrelate'
|
||||
- 'incident_management_incident_change_confidential'
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -9,8 +9,17 @@ value_type: number
|
|||
status: active
|
||||
milestone: '14.9'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81336
|
||||
time_frame: 7d
|
||||
instrumentation_class: WorkItemsActivityAggregatedMetric
|
||||
data_source: redis_hll
|
||||
time_frame: 7d
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -10,7 +10,16 @@ status: active
|
|||
milestone: '14.9'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81336
|
||||
time_frame: 7d
|
||||
instrumentation_class: WorkItemsActivityAggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -10,7 +10,16 @@ status: active
|
|||
milestone: '14.9'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81336
|
||||
time_frame: 7d
|
||||
instrumentation_class: WorkItemsActivityAggregatedMetric
|
||||
data_source: redis_hll
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- users_creating_work_items
|
||||
- users_updating_work_item_title
|
||||
- users_updating_work_item_dates
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -409,6 +409,8 @@
|
|||
- 1
|
||||
- - projects_refresh_build_artifacts_size_statistics
|
||||
- 1
|
||||
- - projects_register_suggested_reviewers_project
|
||||
- 1
|
||||
- - projects_schedule_bulk_repository_shard_moves
|
||||
- 1
|
||||
- - projects_update_repository_storage
|
||||
|
|
|
@ -2891,6 +2891,7 @@ Input type: `GitlabSubscriptionActivateInput`
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationgitlabsubscriptionactivateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationgitlabsubscriptionactivateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
| <a id="mutationgitlabsubscriptionactivatefuturesubscriptions"></a>`futureSubscriptions` | [`[SubscriptionFutureEntry!]`](#subscriptionfutureentry) | Array of future subscriptions. |
|
||||
| <a id="mutationgitlabsubscriptionactivatelicense"></a>`license` | [`CurrentLicense`](#currentlicense) | Current license. |
|
||||
|
||||
### `Mutation.groupUpdate`
|
||||
|
|
|
@ -112,7 +112,7 @@ POST /groups/:id/protected_environments
|
|||
| `approval_rules` | array | no | Array of access levels allowed to approve, with each described by a hash. One of `user_id`, `group_id` or `access_level`. They take the form of `{user_id: integer}`, `{group_id: integer}` or `{access_level: integer}` respectively. You can also specify the number of required approvals from the specified entity with `required_approvals` field. See [Multiple approval rules](../ci/environments/deployment_approvals.md#multiple-approval-rules) for more information. |
|
||||
|
||||
The assignable `user_id` are the users who belong to the given group with the Maintainer role (or above).
|
||||
The assignable `group_id` are the sub-groups under the given group.
|
||||
The assignable `group_id` are the subgroups under the given group.
|
||||
|
||||
```shell
|
||||
curl --header 'Content-Type: application/json' --request POST --data '{"name": "production", "deploy_access_levels": [{"group_id": 9899826}]}' --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/22034114/protected_environments"
|
||||
|
@ -157,7 +157,7 @@ PUT /groups/:id/protected_environments/:name
|
|||
To update:
|
||||
|
||||
- **`user_id`**: Ensure the updated user belongs to the given group with the Maintainer role (or above). You must also pass the `id` of either a `deploy_access_level` or `approval_rule` in the respective hash.
|
||||
- **`group_id`**: Ensure the updated group is a sub-group of the group this protected environment belongs to. You must also pass the `id` of either a `deploy_access_level` or `approval_rule` in the respective hash.
|
||||
- **`group_id`**: Ensure the updated group is a subgroup of the group this protected environment belongs to. You must also pass the `id` of either a `deploy_access_level` or `approval_rule` in the respective hash.
|
||||
|
||||
To delete:
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ Inc._
|
|||
- There is no way to automatically notify a user when they are approaching thresholds.
|
||||
- There is no single way to change limits for a namespace / project / user / customer.
|
||||
- There is no single way to monitor limits through real-time metrics.
|
||||
- There is no framework for hierarchical limit configuration (instance / namespace / sub-group / project).
|
||||
- There is no framework for hierarchical limit configuration (instance / namespace / subgroup / project).
|
||||
- We allow disabling rate-limiting for some marquee SaaS customers, but this
|
||||
increases a risk for those same customers. We should instead be able to set
|
||||
higher limits.
|
||||
|
|
|
@ -26,7 +26,7 @@ Maintainer role.
|
|||
|
||||
Prerequisites:
|
||||
|
||||
- When granting the **Allowed to deploy** permission to a group or sub-group, the user configuring the protected environment must be a **direct member** of the group or sub-group to be added. Otherwise, the group or sub-group will not show up in the dropdown. For more information see [issue #345140](https://gitlab.com/gitlab-org/gitlab/-/issues/345140).
|
||||
- When granting the **Allowed to deploy** permission to a group or subgroup, the user configuring the protected environment must be a **direct member** of the group or subgroup to be added. Otherwise, the group or subgroup will not show up in the dropdown. For more information see [issue #345140](https://gitlab.com/gitlab-org/gitlab/-/issues/345140).
|
||||
|
||||
To protect an environment:
|
||||
|
||||
|
@ -214,8 +214,8 @@ configured:
|
|||
They do *not* have access to the CI/CD configurations in the
|
||||
top-level group, so operators can ensure that the critical configuration won't
|
||||
be accidentally changed by the developers.
|
||||
- For sub-groups and child projects:
|
||||
- Regarding [sub-groups](../../user/group/subgroups/index.md), if a higher
|
||||
- For subgroups and child projects:
|
||||
- Regarding [subgroups](../../user/group/subgroups/index.md), if a higher
|
||||
group has configured the group-level protected environment, the lower groups
|
||||
cannot override it.
|
||||
- [Project-level protected environments](#protecting-environments) can be
|
||||
|
|
|
@ -358,6 +358,11 @@ with latest `master`, and then it triggers a regular branch pipeline for
|
|||
never be merged back to `master`. Any other Ruby 3 changes should go into
|
||||
`master` directly, which should be compatible with Ruby 2.7.
|
||||
|
||||
Previously, `ruby3-sync` was using a project token stored in `RUBY3_SYNC_TOKEN`
|
||||
(now backed up in `RUBY3_SYNC_TOKEN_NOT_USED`), however due to various
|
||||
permissions issues, we ended up using an access token from `gitlab-bot` so now
|
||||
`RUBY3_SYNC_TOKEN` is actually an access token from `gitlab-bot`.
|
||||
|
||||
### Long-term plan
|
||||
|
||||
We follow the [PostgreSQL versions shipped with Omnibus GitLab](../administration/package_information/postgresql_versions.md):
|
||||
|
|
|
@ -45,7 +45,7 @@ flowchart LR
|
|||
### Scanning
|
||||
|
||||
The scanning part is responsible for finding vulnerabilities in given resources, and exporting results.
|
||||
The scans are executed in CI/CD jobs via several small projects called [Analyzers](../../user/application_security/terminology/index.md#analyzer), which can be found in our [Analyzers sub-group](https://gitlab.com/gitlab-org/security-products/analyzers).
|
||||
The scans are executed in CI/CD jobs via several small projects called [Analyzers](../../user/application_security/terminology/index.md#analyzer), which can be found in our [Analyzers subgroup](https://gitlab.com/gitlab-org/security-products/analyzers).
|
||||
The Analyzers are wrappers around security tools called [Scanners](../../user/application_security/terminology/index.md#scanner), developed internally or externally, to integrate them into GitLab.
|
||||
The Analyzers are mainly written in Go.
|
||||
|
||||
|
|
|
@ -120,6 +120,22 @@ module QA
|
|||
end
|
||||
```
|
||||
|
||||
### The `product_group` metadata
|
||||
|
||||
Assign `product_group` metadata and specify what product group this test belongs to. In this case, `authentication_and_authorization`.
|
||||
|
||||
```ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Login', product_group: :authentication_and_authorization do
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### The `it` blocks (examples)
|
||||
|
||||
Every test suite contains at least one `it` block (example). A good way to start
|
||||
|
@ -128,7 +144,7 @@ writing end-to-end tests is to write test case descriptions as `it` blocks:
|
|||
```ruby
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Login' do
|
||||
describe 'Login', product_group: :authentication_and_authorization do
|
||||
it 'can login' do
|
||||
|
||||
end
|
||||
|
@ -152,7 +168,7 @@ Begin by logging in.
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Login' do
|
||||
describe 'Login', product_group: :authentication_and_authorization do
|
||||
it 'can login' do
|
||||
Flow::Login.sign_in
|
||||
|
||||
|
@ -175,7 +191,7 @@ should answer the question "What do we test?"
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Login' do
|
||||
describe 'Login', product_group: :authentication_and_authorization do
|
||||
it 'can login' do
|
||||
Flow::Login.sign_in
|
||||
|
||||
|
@ -222,7 +238,7 @@ a call to `sign_in`.
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Login' do
|
||||
describe 'Login', product_group: :authentication_and_authorization do
|
||||
before do
|
||||
Flow::Login.sign_in
|
||||
end
|
||||
|
@ -251,7 +267,7 @@ ensuring we now sign in at the beginning of each test.
|
|||
## Test setup using resources and page objects
|
||||
|
||||
Next, let's test something other than Login. Let's test Issues, which are owned by the Plan
|
||||
stage, so [create a file](#identify-the-devops-stage) in
|
||||
stage and the Project Management Group, so [create a file](#identify-the-devops-stage) in
|
||||
`qa/specs/features/browser_ui/3_create/issues` called `issues_spec.rb`.
|
||||
|
||||
```ruby
|
||||
|
@ -259,7 +275,7 @@ stage, so [create a file](#identify-the-devops-stage) in
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Plan' do
|
||||
describe 'Issues' do
|
||||
describe 'Issues', product_group: :project_management do
|
||||
let(:issue) do
|
||||
Resource::Issue.fabricate_via_api! do |issue|
|
||||
issue.title = 'My issue'
|
||||
|
|
|
@ -43,7 +43,7 @@ Benefits of the aggregated VSA backend:
|
|||
- Simpler database queries (fewer JOINs).
|
||||
- Faster aggregations, only a single table is accessed.
|
||||
- Possibility to introduce further aggregations for improving the first page load time.
|
||||
- Better performance for large groups (with many sub-groups, projects, issues and, merge requests).
|
||||
- Better performance for large groups (with many subgroups, projects, issues and, merge requests).
|
||||
- Ready for database decomposition. The VSA related database tables could live in a separate
|
||||
database with a minimal development effort.
|
||||
- Ready for keyset pagination which can be useful for exporting the data.
|
||||
|
@ -165,7 +165,7 @@ Creation time always happens first, so this stage always reports negative durati
|
|||
|
||||
The data collection scans and processes all issues and merge requests records in the group
|
||||
hierarchy, starting from the top-level group. This means that if a group only has one value stream
|
||||
in a sub-group, we nevertheless collect data of all issues and merge requests in the hierarchy of
|
||||
in a subgroup, we nevertheless collect data of all issues and merge requests in the hierarchy of
|
||||
this group. This aims to simplify the data collection mechanism. Moreover, data research shows
|
||||
that most group hierarchies have their stages configured on the top level.
|
||||
|
||||
|
|
|
@ -88,8 +88,8 @@ so that in future we can allow users to define custom WITs, we will move the
|
|||
to `work_item_types` will involve creating the set of WITs for all root-level groups.
|
||||
|
||||
NOTE:
|
||||
At first, defining a WIT will only be possible at the root-level group, which would then be inherited by sub-groups.
|
||||
We will investigate the possibility of defining new WITs at sub-group levels at a later iteration.
|
||||
At first, defining a WIT will only be possible at the root-level group, which would then be inherited by subgroups.
|
||||
We will investigate the possibility of defining new WITs at subgroup levels at a later iteration.
|
||||
|
||||
### Introducing work_item_types table
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ GitLab Dedicated enables you to offload the operational overhead of managing the
|
|||
|
||||
## Available features
|
||||
|
||||
- Authentication: Support for instance-level [SAML OmniAuth](../../integration/saml.md) functionality. GitLab Dedicated acts as the service provider, and you must provide the necessary [configuration](../../integration/saml.md#general-setup) in order for GitLab to communicate with your IdP. This is provided during onboarding. SAML [request signing](../../integration/saml.md#request-signing-optional) is supported.
|
||||
- Authentication: Support for instance-level [SAML OmniAuth](../../integration/saml.md) functionality. GitLab Dedicated acts as the service provider, and you must provide the necessary [configuration](../../integration/saml.md#general-setup) in order for GitLab to communicate with your IdP. This is provided during onboarding.
|
||||
- SAML [request signing](../../integration/saml.md#request-signing-optional), [group sync](../../user/group/saml_sso/group_sync.md#configure-saml-group-sync), and [SAML groups](../../integration/saml.md#saml-groups) are supported.
|
||||
- Networking:
|
||||
- Public connectivity with support for IP Allowlists. During onboarding, you can optionally specify a list of IP addresses that can access your Dedicated instance. Subsequently, when an IP not on the allowlist tries to access your instance the connection will be refused.
|
||||
- Optional. Private connectivity via [AWS PrivateLink](https://aws.amazon.com/privatelink/).
|
||||
|
@ -43,6 +44,7 @@ Features that are not available but we plan to support in the future:
|
|||
- FortiAuthenticator/FortiToken 2FA
|
||||
- Reply-by email
|
||||
- Service Desk
|
||||
- Any feature not listed [above](#available-features) which needs to be configured outside of the web interface.
|
||||
|
||||
Features that we do not plan to offer at all:
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ The following steps will help you get the most from GitLab application security
|
|||
1. Enable [Secret Detection](secret_detection/index.md) and [Dependency Scanning](dependency_scanning/index.md)
|
||||
to identify any leaked secrets and vulnerable packages in your codebase.
|
||||
|
||||
- For all security scanners, enable them by updating your `[.gitlab-ci.yml](../../ci/yaml/gitlab_ci_yaml.md)` directly on your `default` branch. This creates a baseline scan of your `default` branch, which is necessary for
|
||||
- For all security scanners, enable them by updating your [`.gitlab-ci.yml`](../../ci/yaml/gitlab_ci_yaml.md) directly on your `default` branch. This creates a baseline scan of your `default` branch, which is necessary for
|
||||
feature branch scans to be compared against. This allows [merge requests](../project/merge_requests/index.md)
|
||||
to display only newly-introduced vulnerabilities. Otherwise, merge requests will display every
|
||||
vulnerability in the branch, regardless of whether it was introduced by a change in the branch.
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
|
@ -32,6 +32,25 @@ schedule. Coverage includes:
|
|||
- Vulnerabilities in a running web application.
|
||||
- Infrastructure as code configuration.
|
||||
|
||||
Each of the GitLab application security tools is relevant to specific stages of the feature development workflow.
|
||||
|
||||
- Commit
|
||||
- SAST
|
||||
- Secret Detection
|
||||
- IaC Scanning
|
||||
- Dependency Scanning
|
||||
- License Scanning
|
||||
- Coverage-guided Fuzz Testing
|
||||
- Build
|
||||
- Container Scanning
|
||||
- Test
|
||||
- API Security
|
||||
- DAST
|
||||
- Deploy
|
||||
- Operational Container Scanning
|
||||
|
||||
![CI/CD stages and matching GitLab application security tools](img/secure_tools_and_cicd_stages.png)
|
||||
|
||||
### Source code analysis
|
||||
|
||||
Source code analysis occurs on every code commit. Details of vulnerabilities detected are provided
|
||||
|
@ -48,7 +67,7 @@ Analysis of the web application occurs on every code commit. As part of the CI/C
|
|||
application is built, deployed to a test environment, and subjected to the following tests:
|
||||
|
||||
- Test for known application vectors - [Dynamic Application Security Testing (DAST)](dast/index.md).
|
||||
- Analysis of APIs for known attack vectors - [DAST API](dast_api/index.md).
|
||||
- Analysis of APIs for known attack vectors - [API Security](dast_api/index.md).
|
||||
- Analysis of web APIs for unknown bugs and vulnerabilities - [API fuzzing](api_fuzzing/index.md).
|
||||
|
||||
### Dependency analysis
|
||||
|
@ -66,7 +85,7 @@ For more details, see
|
|||
[Dependency Scanning compared to Container Scanning](dependency_scanning/index.md#dependency-scanning-compared-to-container-scanning).
|
||||
|
||||
Additionally, dependencies in operational container images can be analyzed for vulnerabilities
|
||||
on a regular schedule or cadence. For more details, see [Cluster Image Scanning](../clusters/agent/vulnerabilities.md).
|
||||
on a regular schedule or cadence. For more details, see [Operational Container Scanning](../../user/clusters/agent/vulnerabilities.md).
|
||||
|
||||
### Infrastructure analysis
|
||||
|
||||
|
@ -486,6 +505,7 @@ Feedback is welcome on our vision for [unifying the user experience for these tw
|
|||
|
||||
<!-- NOTE: The below subsection(`### Secure job failing with exit code 1`) documentation URL is referred in the [/gitlab-org/security-products/analyzers/command](https://gitlab.com/gitlab-org/security-products/analyzers/command/-/blob/main/command.go#L19) repository. If this section/subsection changes, please ensure to update the corresponding URL in the mentioned repository.
|
||||
-->
|
||||
|
||||
### Secure job failing with exit code 1
|
||||
|
||||
WARNING:
|
||||
|
|
|
@ -9,11 +9,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
> - Group-level security policies were [introduced](https://gitlab.com/groups/gitlab-org/-/epics/4425) in GitLab 15.2.
|
||||
> - Group-level security policies were [enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/356258) in GitLab 15.4.
|
||||
|
||||
Group, sub-group, or project owners can use scan execution policies to require that security scans run on a specified
|
||||
schedule or with the project (or multiple projects if the policy is defined at a group or sub-group level) pipeline. Required scans are injected into the CI pipeline as new jobs
|
||||
Group, subgroup, or project owners can use scan execution policies to require that security scans run on a specified
|
||||
schedule or with the project (or multiple projects if the policy is defined at a group or subgroup level) pipeline. Required scans are injected into the CI pipeline as new jobs
|
||||
with a long, random job name. In the unlikely event of a job name collision, the security policy job overwrites
|
||||
any pre-existing job in the pipeline. If a policy is created at the group-level, it will apply to every child
|
||||
project or sub-group. A group-level policy cannot be edited from a child project or sub-group.
|
||||
project or subgroup. A group-level policy cannot be edited from a child project or subgroup.
|
||||
|
||||
This feature has some overlap with [compliance framework pipelines](../../group/manage.md#configure-a-compliance-pipeline),
|
||||
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
|
||||
|
@ -29,7 +29,7 @@ an error appears that states `chosen stage does not exist`.
|
|||
## Scan execution policy editor
|
||||
|
||||
NOTE:
|
||||
Only group, sub-group, or project Owners have the [permissions](../../permissions.md#project-members-permissions)
|
||||
Only group, subgroup, or project Owners have the [permissions](../../permissions.md#project-members-permissions)
|
||||
to select Security Policy Project.
|
||||
|
||||
Once your policy is complete, save it by selecting **Create via merge request**
|
||||
|
|
|
@ -109,7 +109,7 @@ Items that are migrated to the target instance include:
|
|||
- Namespace Settings
|
||||
- Releases
|
||||
- Milestones ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339422) in GitLab 15.0).
|
||||
- Sub-Groups
|
||||
- Subgroups
|
||||
- Uploads
|
||||
|
||||
Any other items are **not** migrated.
|
||||
|
|
|
@ -207,7 +207,7 @@ For role information, please see the [Group SAML page](index.md#user-access-and-
|
|||
|
||||
### Blocking access
|
||||
|
||||
To rescind access to the top-level group, all sub-groups, and projects, remove or deactivate the user
|
||||
To rescind access to the top-level group, all subgroups, and projects, remove or deactivate the user
|
||||
on the identity provider. After the identity provider performs a sync, based on its configured schedule, the user's membership is revoked and they lose access.
|
||||
|
||||
NOTE:
|
||||
|
|
|
@ -147,7 +147,7 @@ The scope determines the actions you can perform when you authenticate with a gr
|
|||
|
||||
## Enable or disable group access token creation
|
||||
|
||||
To enable or disable group access token creation for all sub-groups in a top-level group:
|
||||
To enable or disable group access token creation for all subgroups in a top-level group:
|
||||
|
||||
1. On the top bar, select **Main menu > Groups** and find your group.
|
||||
1. On the left sidebar, select **Settings > General**.
|
||||
|
|
|
@ -201,7 +201,7 @@ role on an ancestor group, add the user to the subgroup again with a higher role
|
|||
## Mention subgroups
|
||||
|
||||
Mentioning subgroups ([`@<subgroup_name>`](../../discussions/index.md#mentions)) in issues, commits, and merge requests
|
||||
notifies all direct members of that group. Inherited members of a sub-group are not notified by mentions. Mentioning works the same as for projects and groups, and you can choose the group
|
||||
notifies all direct members of that group. Inherited members of a subgroup are not notified by mentions. Mentioning works the same as for projects and groups, and you can choose the group
|
||||
of people to be notified.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
|
|
@ -26,7 +26,7 @@ everything you do as a GitLab administrator, including:
|
|||
Our goal is to reach feature parity between SaaS and self-managed installations, with all
|
||||
[Admin Area settings](/ee/user/admin_area/settings/index.md) moving to either:
|
||||
|
||||
- Groups. Available in the Workspace, top-level group namespaces, and sub-groups.
|
||||
- Groups. Available in the Workspace, top-level group namespaces, and subgroups.
|
||||
- Hardware Controls. For functionality that does not apply to groups, Hardware Controls are only
|
||||
applicable to self-managed installations. There is one Hardware Controls section per installation.
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Usage
|
||||
module Metrics
|
||||
module Instrumentations
|
||||
class WorkItemsActivityAggregatedMetric < AggregatedMetric
|
||||
available? { Feature.enabled?(:track_work_items_activity) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -28,7 +28,6 @@ namespace :tw do
|
|||
CodeOwnerRule.new('Compliance', '@eread'),
|
||||
CodeOwnerRule.new('Composition Analysis', '@rdickenson'),
|
||||
CodeOwnerRule.new('Configure', '@phillipwells'),
|
||||
CodeOwnerRule.new('Container Security', '@claytoncornell'),
|
||||
CodeOwnerRule.new('Contributor Experience', '@eread'),
|
||||
CodeOwnerRule.new('Conversion', '@kpaizee'),
|
||||
CodeOwnerRule.new('Database', '@aqualls'),
|
||||
|
@ -58,6 +57,7 @@ namespace :tw do
|
|||
CodeOwnerRule.new('Pipeline Execution', '@marcel.amirault'),
|
||||
CodeOwnerRule.new('Pipeline Insights', '@marcel.amirault'),
|
||||
CodeOwnerRule.new('Portfolio Management', '@msedlakjakubowski'),
|
||||
CodeOwnerRule.new('Product Analytics', '@lciutacu'),
|
||||
CodeOwnerRule.new('Product Intelligence', '@claytoncornell'),
|
||||
CodeOwnerRule.new('Product Planning', '@msedlakjakubowski'),
|
||||
CodeOwnerRule.new('Project Management', '@msedlakjakubowski'),
|
||||
|
@ -68,6 +68,7 @@ namespace :tw do
|
|||
CodeOwnerRule.new('Respond', '@msedlakjakubowski'),
|
||||
CodeOwnerRule.new('Runner', '@sselhorn'),
|
||||
CodeOwnerRule.new('Pods', '@sselhorn'),
|
||||
CodeOwnerRule.new('Security Policies', '@claytoncornell'),
|
||||
CodeOwnerRule.new('Source Code', '@aqualls'),
|
||||
CodeOwnerRule.new('Static Analysis', '@rdickenson'),
|
||||
CodeOwnerRule.new('Style Guide', '@sselhorn'),
|
||||
|
|
|
@ -242,6 +242,11 @@ module QA
|
|||
end
|
||||
|
||||
def fill_element(name, content)
|
||||
# `click_element_coordinates` is used to ensure the element is focused.
|
||||
# Without it, flakiness can occur on pages with GitLab keyboard shortcuts enabled,
|
||||
# where certain keys trigger actions when typed elsewhere on the page.
|
||||
click_element_coordinates(name)
|
||||
|
||||
find_element(name).set(content)
|
||||
end
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ module QA
|
|||
click_element :namespaces_list
|
||||
|
||||
within_element(:namespaces_list) do
|
||||
find_element(:namespaces_list_search).fill_in(with: item)
|
||||
fill_element(:namespaces_list_search, item)
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ module QA
|
|||
|
||||
def click_diffs_tab
|
||||
click_element(:diffs_tab)
|
||||
click_element(:dismiss_popover_button) if has_element?(:dismiss_popover_button, wait: 1)
|
||||
end
|
||||
|
||||
def has_file?(file_name)
|
||||
|
|
|
@ -108,6 +108,7 @@ module QA
|
|||
|
||||
view 'app/assets/javascripts/vue_shared/components/markdown/header.vue' do
|
||||
element :suggestion_button
|
||||
element :dismiss_suggestion_popover_button
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue' do
|
||||
|
@ -191,8 +192,11 @@ module QA
|
|||
wait_until(sleep_interval: 5) do
|
||||
has_css?('a[data-linenumber="1"]')
|
||||
end
|
||||
|
||||
all_elements(:new_diff_line_link, minimum: 1).first.hover
|
||||
click_element(:diff_comment_button)
|
||||
click_element(:dismiss_suggestion_popover_button) if has_element?(:dismiss_suggestion_popover_button, wait: 1)
|
||||
|
||||
fill_element(:reply_field, text)
|
||||
end
|
||||
|
||||
|
@ -208,7 +212,6 @@ module QA
|
|||
|
||||
def click_diffs_tab
|
||||
click_element(:diffs_tab)
|
||||
click_element(:dismiss_popover_button) if has_element?(:dismiss_popover_button, wait: 1)
|
||||
end
|
||||
|
||||
def click_pipeline_link
|
||||
|
|
|
@ -6,8 +6,8 @@ RSpec.describe 'Batch diffs', :js do
|
|||
include MergeRequestDiffHelpers
|
||||
include RepoHelpers
|
||||
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'empty-branch') }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let_it_be(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'empty-branch') }
|
||||
|
||||
before do
|
||||
sign_in(project.first_owner)
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('SortDropdown', () => {
|
|||
|
||||
const findSortingComponent = () => wrapper.findComponent(GlSorting);
|
||||
const findSortDirectionToggle = () =>
|
||||
findSortingComponent().find('button[title="Sort direction"]');
|
||||
findSortingComponent().find('button[title^="Sort direction"]');
|
||||
const findDropdownToggle = () => wrapper.find('button[aria-haspopup="true"]');
|
||||
const findDropdownItemByText = (text) =>
|
||||
wrapper
|
||||
|
|
|
@ -6,35 +6,85 @@ RSpec.describe FormHelper do
|
|||
include Devise::Test::ControllerHelpers
|
||||
|
||||
describe '#dropdown_max_select' do
|
||||
context "with the :limit_reviewer_and_assignee_size feature flag on" do
|
||||
it 'correctly returns the max amount of reviewers or assignees to allow' do
|
||||
max = MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
let(:feature_flag) { :limit_reviewer_and_assignee_size }
|
||||
|
||||
expect(helper.dropdown_max_select({}))
|
||||
context "with the :limit_reviewer_and_assignee_size feature flag on" do
|
||||
before do
|
||||
stub_feature_flags(feature_flag => true)
|
||||
end
|
||||
|
||||
it 'correctly returns the max amount of reviewers or assignees to allow' do
|
||||
max = Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
|
||||
|
||||
expect(helper.dropdown_max_select({}, feature_flag))
|
||||
.to eq(max)
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => 5 }))
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => 5 }, feature_flag))
|
||||
.to eq(5)
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => max + 5 }))
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => max + 5 }, feature_flag))
|
||||
.to eq(max)
|
||||
end
|
||||
end
|
||||
|
||||
context "with the :limit_reviewer_and_assignee_size feature flag off" do
|
||||
before do
|
||||
stub_feature_flags(limit_reviewer_and_assignee_size: false)
|
||||
stub_feature_flags(feature_flag => false)
|
||||
end
|
||||
|
||||
it 'correctly returns the max amount of reviewers or assignees to allow' do
|
||||
expect(helper.dropdown_max_select({}))
|
||||
expect(helper.dropdown_max_select({}, feature_flag))
|
||||
.to eq(nil)
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => 5 }))
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => 5 }, feature_flag))
|
||||
.to eq(5)
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => 120 }))
|
||||
expect(helper.dropdown_max_select({ 'max-select'.to_sym => 120 }, feature_flag))
|
||||
.to eq(120)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#assignees_dropdown_options' do
|
||||
let(:merge_request) { build(:merge_request) }
|
||||
|
||||
context "with the :limit_assignees_per_issuable feature flag on" do
|
||||
context "with multiple assignees" do
|
||||
it 'correctly returns the max amount of assignees to allow' do
|
||||
allow(helper).to receive(:merge_request_supports_multiple_assignees?).and_return(true)
|
||||
|
||||
expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
|
||||
.to eq(Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS)
|
||||
end
|
||||
end
|
||||
|
||||
context "with only 1 assignee" do
|
||||
it 'correctly returns the max amount of assignees to allow' do
|
||||
expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
|
||||
.to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with the :limit_assignees_per_issuable feature flag off" do
|
||||
before do
|
||||
stub_feature_flags(limit_assignees_per_issuable: false)
|
||||
end
|
||||
|
||||
context "with multiple assignees" do
|
||||
it 'correctly returns the max amount of assignees to allow' do
|
||||
allow(helper).to receive(:merge_request_supports_multiple_assignees?).and_return(true)
|
||||
|
||||
expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
|
||||
.to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with only 1 assignee" do
|
||||
it 'correctly returns the max amount of assignees to allow' do
|
||||
expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
|
||||
.to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reviewers_dropdown_options' do
|
||||
let(:merge_request) { build(:merge_request) }
|
||||
|
||||
|
@ -44,7 +94,7 @@ RSpec.describe FormHelper do
|
|||
allow(helper).to receive(:merge_request_supports_multiple_reviewers?).and_return(true)
|
||||
|
||||
expect(helper.reviewers_dropdown_options(merge_request)[:data][:'max-select'])
|
||||
.to eq(MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS)
|
||||
.to eq(Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -79,14 +79,16 @@ RSpec.describe WikiHelper do
|
|||
let(:classes) { "gl-button btn btn-default btn-icon has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort" }
|
||||
|
||||
def expected_link(sort, direction, icon_class)
|
||||
reversed_direction = direction == 'desc' ? 'asc' : 'desc'
|
||||
path =
|
||||
if sort
|
||||
"/#{wiki.project.full_path}/-/wikis/pages?direction=#{direction}&sort=#{sort}"
|
||||
"/#{wiki.project.full_path}/-/wikis/pages?direction=#{reversed_direction}&sort=#{sort}"
|
||||
else
|
||||
"/#{wiki.project.full_path}/-/wikis/pages?direction=#{direction}"
|
||||
"/#{wiki.project.full_path}/-/wikis/pages?direction=#{reversed_direction}"
|
||||
end
|
||||
|
||||
helper.link_to(path, type: 'button', class: classes, title: 'Sort direction') do
|
||||
title = direction == 'desc' ? _('Sort direction: Descending') : _('Sort direction: Ascending')
|
||||
helper.link_to(path, type: 'button', class: classes, title: title) do
|
||||
helper.sprite_icon("sort-#{icon_class}")
|
||||
end
|
||||
end
|
||||
|
@ -101,7 +103,7 @@ RSpec.describe WikiHelper do
|
|||
let(:direction) { nil }
|
||||
|
||||
it 'renders with default values' do
|
||||
expect(wiki_link).to eq(expected_link('title', 'desc', 'lowest'))
|
||||
expect(wiki_link).to eq(expected_link('title', 'asc', 'lowest'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -110,7 +112,7 @@ RSpec.describe WikiHelper do
|
|||
let(:direction) { 'asc' }
|
||||
|
||||
it 'renders a link with opposite direction' do
|
||||
expect(wiki_link).to eq(expected_link('title', 'desc', 'lowest'))
|
||||
expect(wiki_link).to eq(expected_link('title', 'aesc', 'lowest'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -119,7 +121,7 @@ RSpec.describe WikiHelper do
|
|||
let(:direction) { 'desc' }
|
||||
|
||||
it 'renders a link with opposite direction' do
|
||||
expect(wiki_link).to eq(expected_link('created_at', 'asc', 'highest'))
|
||||
expect(wiki_link).to eq(expected_link('created_at', 'desc', 'highest'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -134,7 +136,7 @@ RSpec.describe WikiHelper do
|
|||
let(:direction) { 'asc' }
|
||||
|
||||
it 'ignores created_at and renders a link with opposite direction' do
|
||||
expect(wiki_link).to eq(expected_link(nil, 'desc', 'lowest'))
|
||||
expect(wiki_link).to eq(expected_link(nil, 'asc', 'lowest'))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -143,7 +145,7 @@ RSpec.describe WikiHelper do
|
|||
let(:direction) { nil }
|
||||
|
||||
it 'renders with default values' do
|
||||
expect(wiki_link).to eq(expected_link(nil, 'desc', 'lowest'))
|
||||
expect(wiki_link).to eq(expected_link(nil, 'asc', 'lowest'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggregatedMetric do
|
||||
let(:metric_definition) do
|
||||
{
|
||||
data_source: 'redis_hll',
|
||||
time_frame: '7d',
|
||||
options: {
|
||||
aggregate: {
|
||||
operator: 'OR'
|
||||
},
|
||||
events: %w[
|
||||
users_creating_work_items
|
||||
users_updating_work_item_title
|
||||
users_updating_work_item_dates
|
||||
]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
around do |example|
|
||||
freeze_time { example.run }
|
||||
end
|
||||
|
||||
describe '#available?' do
|
||||
it 'returns false without track_work_items_activity feature' do
|
||||
stub_feature_flags(track_work_items_activity: false)
|
||||
|
||||
expect(described_class.new(metric_definition).available?).to eq(false)
|
||||
end
|
||||
|
||||
it 'returns true with track_work_items_activity feature' do
|
||||
stub_feature_flags(track_work_items_activity: true)
|
||||
|
||||
expect(described_class.new(metric_definition).available?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#value', :clean_gitlab_redis_shared_state do
|
||||
let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
|
||||
|
||||
before do
|
||||
counter.track_event(:users_creating_work_items, values: 1, time: 1.week.ago)
|
||||
counter.track_event(:users_updating_work_item_title, values: 1, time: 1.week.ago)
|
||||
counter.track_event(:users_updating_work_item_dates, values: 2, time: 1.week.ago)
|
||||
end
|
||||
|
||||
it 'has correct value' do
|
||||
expect(described_class.new(metric_definition).value).to eq 2
|
||||
end
|
||||
end
|
||||
end
|
|
@ -75,6 +75,24 @@ RSpec.describe Issuable do
|
|||
|
||||
it_behaves_like 'truncates the description to its allowed maximum length on import'
|
||||
end
|
||||
|
||||
describe '#validate_assignee_length' do
|
||||
let(:assignee_1) { create(:user) }
|
||||
let(:assignee_2) { create(:user) }
|
||||
let(:assignee_3) { create(:user) }
|
||||
|
||||
subject { create(:merge_request) }
|
||||
|
||||
before do
|
||||
stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 2)
|
||||
end
|
||||
|
||||
it 'will not exceed the assignee limit' do
|
||||
expect do
|
||||
subject.update!(assignees: [assignee_1, assignee_2, assignee_3])
|
||||
end.to raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Scope" do
|
||||
|
|
|
@ -8336,6 +8336,22 @@ RSpec.describe Project, factory_default: :keep do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#can_suggest_reviewers?' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
subject(:can_suggest_reviewers) { project.can_suggest_reviewers? }
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
|
||||
describe '#suggested_reviewers_available?' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
subject(:suggested_reviewers_available) { project.suggested_reviewers_available? }
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def finish_job(export_job)
|
||||
|
|
|
@ -36,6 +36,20 @@ RSpec.describe MergeRequests::UpdateAssigneesService do
|
|||
service.execute(merge_request)
|
||||
end
|
||||
|
||||
shared_examples 'it updates and enqueues the job' do
|
||||
it 'correctly updates the MR and enqueues the job' do
|
||||
expect_next(MergeRequests::HandleAssigneesChangeService, project: project, current_user: user) do |service|
|
||||
expect(service)
|
||||
.to receive(:async_execute).with(merge_request, [user3], execute_hooks: true)
|
||||
end
|
||||
|
||||
expect { update_merge_request }
|
||||
.to change { merge_request.reload.assignees }.from([user3]).to(new_users)
|
||||
.and change(merge_request, :updated_at)
|
||||
.and change(merge_request, :updated_by).to(user)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'removing all assignees' do
|
||||
it 'removes all assignees' do
|
||||
expect(update_merge_request).to have_attributes(assignees: be_empty, errors: be_none)
|
||||
|
@ -73,16 +87,8 @@ RSpec.describe MergeRequests::UpdateAssigneesService do
|
|||
it_behaves_like 'removing all assignees'
|
||||
end
|
||||
|
||||
it 'updates the MR, and queues the more expensive work for later' do
|
||||
expect_next(MergeRequests::HandleAssigneesChangeService, project: project, current_user: user) do |service|
|
||||
expect(service)
|
||||
.to receive(:async_execute).with(merge_request, [user3], execute_hooks: true)
|
||||
end
|
||||
|
||||
expect { update_merge_request }
|
||||
.to change { merge_request.reload.assignees }.from([user3]).to([user2])
|
||||
.and change(merge_request, :updated_at)
|
||||
.and change(merge_request, :updated_by).to(user)
|
||||
it_behaves_like 'it updates and enqueues the job' do
|
||||
let(:new_users) { [user2] }
|
||||
end
|
||||
|
||||
it 'does not update the assignees if they do not have access' do
|
||||
|
|
|
@ -86,14 +86,6 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
|
|||
end
|
||||
|
||||
it_behaves_like 'calling service', ::Projects::ContainerRepository::Gitlab::CleanupTagsService, extra_log_data: { gitlab_cleanup_tags_service: true }
|
||||
|
||||
context 'with container_registry_new_cleanup_service disabled' do
|
||||
before do
|
||||
stub_feature_flags(container_registry_new_cleanup_service: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'calling service', ::Projects::ContainerRepository::ThirdParty::CleanupTagsService, extra_log_data: { third_party_cleanup_tags_service: true }
|
||||
end
|
||||
end
|
||||
|
||||
context 'not supporting the gitlab api' do
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'does not exceed the issuable size limit' do
|
||||
let(:user1) { create(:user) }
|
||||
let(:user2) { create(:user) }
|
||||
let(:user3) { create(:user) }
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
project.add_maintainer(user1)
|
||||
project.add_maintainer(user2)
|
||||
project.add_maintainer(user3)
|
||||
end
|
||||
|
||||
context 'when feature flag is turned on' do
|
||||
context "when the number of users of issuable does exceed the limit" do
|
||||
before do
|
||||
stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 2)
|
||||
end
|
||||
|
||||
it 'will not add more than the allowed number of users' do
|
||||
allow_next_instance_of(update_service) do |service|
|
||||
expect(service).not_to receive(:execute)
|
||||
end
|
||||
|
||||
note = described_class.new(project, user, opts.merge(
|
||||
note: note_text,
|
||||
noteable_type: noteable_type,
|
||||
noteable_id: issuable.id,
|
||||
confidential: false
|
||||
)).execute
|
||||
|
||||
expect(note.errors[:validation]).to match_array([validation_message])
|
||||
end
|
||||
end
|
||||
|
||||
context "when the number of users does not exceed the limit" do
|
||||
before do
|
||||
stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 6)
|
||||
end
|
||||
|
||||
it 'calls execute and does not return an error' do
|
||||
allow_next_instance_of(update_service) do |service|
|
||||
expect(service).to receive(:execute).and_call_original
|
||||
end
|
||||
|
||||
note = described_class.new(project, user, opts.merge(
|
||||
note: note_text,
|
||||
noteable_type: noteable_type,
|
||||
noteable_id: issuable.id,
|
||||
confidential: false
|
||||
)).execute
|
||||
|
||||
expect(note.errors[:validation]).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature flag is off' do
|
||||
before do
|
||||
stub_feature_flags(feature_flag_hash)
|
||||
end
|
||||
|
||||
context "when the number of users of issuable does exceed the limit" do
|
||||
before do
|
||||
stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 2)
|
||||
end
|
||||
|
||||
it 'will not add more than the allowed number of users' do
|
||||
allow_next_instance_of(MergeRequests::UpdateService) do |service|
|
||||
expect(service).to receive(:execute).and_call_original
|
||||
end
|
||||
|
||||
note = described_class.new(project, user, opts.merge(
|
||||
note: note_text,
|
||||
noteable_type: 'MergeRequest',
|
||||
noteable_id: issuable.id,
|
||||
confidential: false
|
||||
)).execute
|
||||
|
||||
expect(note.errors[:validation]).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,7 +26,7 @@ require (
|
|||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/smartystreets/goconvey v1.7.2
|
||||
github.com/stretchr/testify v1.8.0
|
||||
gitlab.com/gitlab-org/gitaly/v15 v15.4.0
|
||||
gitlab.com/gitlab-org/gitaly/v15 v15.4.2
|
||||
gitlab.com/gitlab-org/golang-archive-zip v0.1.1
|
||||
gitlab.com/gitlab-org/labkit v1.16.0
|
||||
gocloud.dev v0.26.0
|
||||
|
|
|
@ -949,8 +949,8 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
|||
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/v15 v15.4.0 h1:fLGICSlAXbxxoat2dJt+DKrhRzdVkPXhMQUYKyFBDks=
|
||||
gitlab.com/gitlab-org/gitaly/v15 v15.4.0/go.mod h1:anANn2UwrECvFOEvLx8DkXYYDQ6g3+jmv0kP2VDYm70=
|
||||
gitlab.com/gitlab-org/gitaly/v15 v15.4.2 h1:evAILjEjT7M+pegcbP4QsViK4Hkt1I1IwJAr5AQjbdY=
|
||||
gitlab.com/gitlab-org/gitaly/v15 v15.4.2/go.mod h1:anANn2UwrECvFOEvLx8DkXYYDQ6g3+jmv0kP2VDYm70=
|
||||
gitlab.com/gitlab-org/golang-archive-zip v0.1.1 h1:35k9giivbxwF03+8A05Cm8YoxoakU8FBCj5gysjCTCE=
|
||||
gitlab.com/gitlab-org/golang-archive-zip v0.1.1/go.mod h1:ZDtqpWPGPB9qBuZnZDrKQjIdJtkN7ZAoVwhT6H2o2kE=
|
||||
gitlab.com/gitlab-org/labkit v1.16.0 h1:Vm3NAMZ8RqAunXlvPWby3GJ2R35vsYGP6Uu0YjyMIlY=
|
||||
|
|
Loading…
Reference in a new issue