Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4597f7fe47
commit
05ade12880
161 changed files with 1123 additions and 296 deletions
|
@ -67,7 +67,7 @@ variables:
|
|||
RAILS_ENV: "test"
|
||||
NODE_ENV: "test"
|
||||
BUNDLE_WITHOUT: "production:development"
|
||||
BUNDLE_INSTALL_FLAGS: "--jobs=$(nproc) --retry=3 --quiet"
|
||||
BUNDLE_INSTALL_FLAGS: "--jobs=$(nproc) --retry=3"
|
||||
BUNDLE_FROZEN: "true"
|
||||
# we override the max_old_space_size to prevent OOM errors
|
||||
NODE_OPTIONS: --max_old_space_size=3584
|
||||
|
|
|
@ -1801,6 +1801,10 @@
|
|||
when: never
|
||||
- <<: *if-default-branch-or-tag
|
||||
changes: *code-backstage-qa-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes: [".gitlab/ci/setup.gitlab-ci.yml"]
|
||||
when: manual
|
||||
allow_failure: true
|
||||
|
||||
.setup:rules:dont-interrupt-me:
|
||||
rules:
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
cache gems:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .rails-cache
|
||||
- .ruby-cache
|
||||
- .default-before_script
|
||||
- .setup:rules:cache-gems
|
||||
stage: test
|
||||
needs: ["setup-test-env"]
|
||||
stage: prepare
|
||||
needs: []
|
||||
variables:
|
||||
BUNDLE_INSTALL_FLAGS: --with=production --with=development --with=test --jobs=2 --path=vendor --retry=3 --quiet
|
||||
BUNDLE_WITHOUT: ""
|
||||
BUNDLE_WITH: "production:development:test"
|
||||
SETUP_DB: "false"
|
||||
script:
|
||||
- bundle package --all --all-platforms
|
||||
- echo -e "\e[0Ksection_start:`date +%s`:bundle-package[collapsed=true]\r\e[0KPackaging gems"
|
||||
- bundle config set cache_all true
|
||||
- run_timed_command "bundle package --all-platforms"
|
||||
- echo -e "\e[0Ksection_end:`date +%s`:bundle-package\r\e[0K"
|
||||
artifacts:
|
||||
paths:
|
||||
- vendor/cache
|
||||
|
|
|
@ -69,14 +69,18 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="!isLocalStorageAvailable" ref="localStorageNote" class="dropdown-info-note">
|
||||
<div
|
||||
v-if="!isLocalStorageAvailable"
|
||||
data-testid="local-storage-note"
|
||||
class="dropdown-info-note"
|
||||
>
|
||||
{{ __('This feature requires local storage to be enabled') }}
|
||||
</div>
|
||||
<ul v-else-if="hasItems">
|
||||
<li
|
||||
v-for="(item, index) in processedItems"
|
||||
ref="dropdownItem"
|
||||
:key="`processed-items-${index}`"
|
||||
data-testid="dropdown-item"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -100,7 +104,7 @@ export default {
|
|||
<li class="divider"></li>
|
||||
<li>
|
||||
<button
|
||||
ref="clearButton"
|
||||
data-testid="clear-button"
|
||||
type="button"
|
||||
class="filtered-search-history-clear-button"
|
||||
@click="onRequestClearRecentSearches($event)"
|
||||
|
@ -109,7 +113,7 @@ export default {
|
|||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else ref="dropdownNote" class="dropdown-info-note">
|
||||
<div v-else data-testid="dropdown-note" class="dropdown-info-note">
|
||||
{{ __("You don't have any recent searches") }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -58,7 +58,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="frequent-items-list-container">
|
||||
<ul ref="frequentItemsList" class="list-unstyled">
|
||||
<ul data-testid="frequent-items-list" class="list-unstyled">
|
||||
<li
|
||||
v-if="isListEmpty"
|
||||
:class="{ 'section-failure': isFetchFailed }"
|
||||
|
|
|
@ -79,16 +79,19 @@ export default {
|
|||
:project-name="itemName"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div ref="frequentItemsItemMetadataContainer" class="frequent-items-item-metadata-container">
|
||||
<div
|
||||
data-testid="frequent-items-item-metadata-container"
|
||||
class="frequent-items-item-metadata-container"
|
||||
>
|
||||
<div
|
||||
ref="frequentItemsItemTitle"
|
||||
v-safe-html="highlightedItemName"
|
||||
data-testid="frequent-items-item-title"
|
||||
:title="itemName"
|
||||
class="frequent-items-item-title"
|
||||
></div>
|
||||
<div
|
||||
v-if="namespace"
|
||||
ref="frequentItemsItemNamespace"
|
||||
data-testid="frequent-items-item-namespace"
|
||||
:title="namespace"
|
||||
class="frequent-items-item-namespace"
|
||||
>
|
||||
|
|
|
@ -65,7 +65,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
|
|||
add_pagination_headers(tokens)
|
||||
end
|
||||
|
||||
::API::Entities::PersonalAccessTokenWithDetails.represent(tokens)
|
||||
::PersonalAccessTokenSerializer.new.represent(tokens)
|
||||
end
|
||||
|
||||
def add_pagination_headers(relation)
|
||||
|
|
|
@ -220,7 +220,13 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
def context_commits
|
||||
# Get commits from repository
|
||||
# or from cache if already merged
|
||||
commits = ContextCommitsFinder.new(project, @merge_request, { search: params[:search], limit: params[:limit], offset: params[:offset] }).execute
|
||||
commits = ContextCommitsFinder.new(project, @merge_request, {
|
||||
search: params[:search],
|
||||
author: params[:author],
|
||||
committed_before: convert_date_to_epoch(params[:committed_before]),
|
||||
committed_after: convert_date_to_epoch(params[:committed_after]),
|
||||
limit: params[:limit]
|
||||
}).execute
|
||||
render json: CommitEntity.represent(commits, { type: :full, request: merge_request })
|
||||
end
|
||||
|
||||
|
@ -553,6 +559,11 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
|
||||
diffs_metadata_project_json_merge_request_path(project, merge_request, 'json', params)
|
||||
end
|
||||
|
||||
def convert_date_to_epoch(date)
|
||||
Date.strptime(date, "%Y-%m-%d")&.to_time&.to_i if date
|
||||
rescue Date::Error, TypeError
|
||||
end
|
||||
end
|
||||
|
||||
Projects::MergeRequestsController.prepend_mod_with('Projects::MergeRequestsController')
|
||||
|
|
|
@ -5,8 +5,10 @@ class ContextCommitsFinder
|
|||
@project = project
|
||||
@merge_request = merge_request
|
||||
@search = params[:search]
|
||||
@author = params[:author]
|
||||
@committed_before = params[:committed_before]
|
||||
@committed_after = params[:committed_after]
|
||||
@limit = (params[:limit] || 40).to_i
|
||||
@offset = (params[:offset] || 0).to_i
|
||||
end
|
||||
|
||||
def execute
|
||||
|
@ -16,13 +18,13 @@ class ContextCommitsFinder
|
|||
|
||||
private
|
||||
|
||||
attr_reader :project, :merge_request, :search, :limit, :offset
|
||||
attr_reader :project, :merge_request, :search, :author, :committed_before, :committed_after, :limit
|
||||
|
||||
def init_collection
|
||||
if search.present?
|
||||
search_commits
|
||||
else
|
||||
project.repository.commits(merge_request.target_branch, { limit: limit, offset: offset })
|
||||
project.repository.commits(merge_request.target_branch, { limit: limit })
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -41,7 +43,8 @@ class ContextCommitsFinder
|
|||
commits = [commit_by_sha] if commit_by_sha
|
||||
end
|
||||
else
|
||||
commits = project.repository.find_commits_by_message(search, merge_request.target_branch, nil, 20)
|
||||
commits = project.repository.list_commits_by(search, merge_request.target_branch,
|
||||
author: author, before: committed_before, after: committed_after, limit: limit)
|
||||
end
|
||||
|
||||
commits
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
module Groups
|
||||
class AcceptingGroupTransfersFinder < Base
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def initialize(current_user, group_to_be_transferred, params = {})
|
||||
@current_user = current_user
|
||||
@group_to_be_transferred = group_to_be_transferred
|
||||
|
@ -11,7 +13,12 @@ module Groups
|
|||
def execute
|
||||
return Group.none unless can_transfer_group?
|
||||
|
||||
items = find_groups
|
||||
items = if Feature.enabled?(:include_groups_from_group_shares_in_group_transfer_locations)
|
||||
find_all_groups
|
||||
else
|
||||
find_groups
|
||||
end
|
||||
|
||||
items = by_search(items)
|
||||
|
||||
sort(items)
|
||||
|
@ -29,11 +36,30 @@ module Groups
|
|||
).execute.without_order
|
||||
end
|
||||
|
||||
def exclude_groups
|
||||
exclude_groups = group_to_be_transferred.self_and_descendants.pluck_primary_key
|
||||
exclude_groups << group_to_be_transferred.parent_id if group_to_be_transferred.parent_id
|
||||
def find_all_groups
|
||||
::Namespace.from_union(
|
||||
[
|
||||
find_groups,
|
||||
groups_originating_from_group_shares_with_owner_access
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
exclude_groups
|
||||
def groups_originating_from_group_shares_with_owner_access
|
||||
GroupGroupLink
|
||||
.with_owner_access
|
||||
.groups_accessible_via(
|
||||
current_user.owned_groups.select(:id)
|
||||
).id_not_in(exclude_groups)
|
||||
end
|
||||
|
||||
def exclude_groups
|
||||
strong_memoize(:exclude_groups) do
|
||||
exclude_groups = group_to_be_transferred.self_and_descendants.pluck_primary_key
|
||||
exclude_groups << group_to_be_transferred.parent_id if group_to_be_transferred.parent_id
|
||||
|
||||
exclude_groups
|
||||
end
|
||||
end
|
||||
|
||||
def can_transfer_group?
|
||||
|
|
|
@ -976,6 +976,11 @@ module Ci
|
|||
object_hierarchy.base_and_ancestors
|
||||
end
|
||||
|
||||
# With multi-project and parent-child pipelines
|
||||
def self_and_downstreams
|
||||
object_hierarchy.base_and_descendants
|
||||
end
|
||||
|
||||
# With multi-project and parent-child pipelines
|
||||
def upstream_and_all_downstreams
|
||||
object_hierarchy.all_objects
|
||||
|
@ -1012,7 +1017,12 @@ module Ci
|
|||
# Follow the upstream pipeline relationships, regardless of multi-project or
|
||||
# parent-child, and return the top-level ancestor.
|
||||
def upstream_root
|
||||
object_hierarchy.base_and_ancestors(hierarchy_order: :desc).first
|
||||
@upstream_root ||= object_hierarchy.base_and_ancestors(hierarchy_order: :desc).first
|
||||
end
|
||||
|
||||
# Applies to all parent-child and multi-project pipelines
|
||||
def complete_hierarchy_count
|
||||
upstream_root.self_and_downstreams.count
|
||||
end
|
||||
|
||||
def bridge_triggered?
|
||||
|
|
|
@ -53,7 +53,7 @@ module Ci
|
|||
find_by(file_type: file_type)
|
||||
end
|
||||
|
||||
def create_or_replace_for_pipeline!(pipeline:, file_type:, file:, size:)
|
||||
def create_or_replace_for_pipeline!(pipeline:, file_type:, file:, size:, locked: :unknown)
|
||||
transaction do
|
||||
pipeline.pipeline_artifacts.find_by_file_type(file_type)&.destroy!
|
||||
|
||||
|
@ -63,7 +63,8 @@ module Ci
|
|||
size: size,
|
||||
file: file,
|
||||
file_format: REPORT_TYPES[file_type],
|
||||
expire_at: EXPIRATION_DATE.from_now
|
||||
expire_at: EXPIRATION_DATE.from_now,
|
||||
locked: locked
|
||||
)
|
||||
end
|
||||
rescue ActiveRecord::ActiveRecordError => err
|
||||
|
|
|
@ -348,6 +348,12 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
def owner_project
|
||||
return unless project_type?
|
||||
|
||||
runner_projects.order(:id).first.project
|
||||
end
|
||||
|
||||
def belongs_to_one_project?
|
||||
runner_projects.count == 1
|
||||
end
|
||||
|
|
|
@ -319,11 +319,7 @@ class CommitStatus < Ci::ApplicationRecord
|
|||
end
|
||||
|
||||
def stage_name
|
||||
if Feature.enabled?(:ci_read_stage_records, project)
|
||||
ci_stage&.name
|
||||
else
|
||||
stage
|
||||
end
|
||||
ci_stage&.name
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -19,6 +19,10 @@ class GroupGroupLink < ApplicationRecord
|
|||
where(group_access: [Gitlab::Access::OWNER, Gitlab::Access::MAINTAINER])
|
||||
end
|
||||
|
||||
scope :with_owner_access, -> do
|
||||
where(group_access: [Gitlab::Access::OWNER])
|
||||
end
|
||||
|
||||
scope :groups_accessible_via, -> (shared_with_group_ids) do
|
||||
links = where(shared_with_group_id: shared_with_group_ids)
|
||||
# a group share also gives you access to the descendants of the group being shared,
|
||||
|
|
|
@ -194,6 +194,18 @@ class Repository
|
|||
CommitCollection.new(container, commits, ref)
|
||||
end
|
||||
|
||||
def list_commits_by(query, ref, author: nil, before: nil, after: nil, limit: 1000)
|
||||
return [] unless exists?
|
||||
return [] unless has_visible_content?
|
||||
return [] unless query.present? && ref.present?
|
||||
|
||||
commits = raw_repository.list_commits_by(
|
||||
query, ref, author: author, before: before, after: after, limit: limit).map do |c|
|
||||
commit(c)
|
||||
end
|
||||
CommitCollection.new(container, commits, ref)
|
||||
end
|
||||
|
||||
def find_branch(name)
|
||||
raw_repository.find_branch(name)
|
||||
end
|
||||
|
|
8
app/serializers/access_token_entity_base.rb
Normal file
8
app/serializers/access_token_entity_base.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop: disable Gitlab/NamespacedClass
|
||||
class AccessTokenEntityBase < API::Entities::PersonalAccessToken
|
||||
expose :expired?, as: :expired
|
||||
expose :expires_soon?, as: :expires_soon
|
||||
end
|
||||
# rubocop: enable Gitlab/NamespacedClass
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop: disable Gitlab/NamespacedClass
|
||||
class GroupAccessTokenEntity < API::Entities::PersonalAccessToken
|
||||
class GroupAccessTokenEntity < AccessTokenEntityBase
|
||||
include Gitlab::Routing
|
||||
|
||||
expose :revoke_path do |token, options|
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop: disable Gitlab/NamespacedClass
|
||||
class ImpersonationAccessTokenEntity < API::Entities::PersonalAccessToken
|
||||
class ImpersonationAccessTokenEntity < AccessTokenEntityBase
|
||||
include Gitlab::Routing
|
||||
|
||||
expose :revoke_path do |token, _options|
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop: disable Gitlab/NamespacedClass
|
||||
class PersonalAccessTokenEntity < API::Entities::PersonalAccessToken
|
||||
class PersonalAccessTokenEntity < AccessTokenEntityBase
|
||||
include Gitlab::Routing
|
||||
|
||||
expose :revoke_path do |token, options|
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop: disable Gitlab/NamespacedClass
|
||||
class ProjectAccessTokenEntity < API::Entities::PersonalAccessToken
|
||||
class ProjectAccessTokenEntity < AccessTokenEntityBase
|
||||
include Gitlab::Routing
|
||||
|
||||
expose :revoke_path do |token, options|
|
||||
|
|
|
@ -27,12 +27,18 @@ module Ci
|
|||
end
|
||||
|
||||
def pipeline_artifact_params
|
||||
{
|
||||
attributes = {
|
||||
pipeline: pipeline,
|
||||
file_type: :code_coverage,
|
||||
file: carrierwave_file,
|
||||
size: carrierwave_file['tempfile'].size
|
||||
}
|
||||
|
||||
if ::Feature.enabled?(:ci_update_unlocked_pipeline_artifacts, pipeline.project)
|
||||
attributes[:locked] = pipeline.locked
|
||||
end
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
def carrierwave_file
|
||||
|
|
|
@ -13,22 +13,32 @@ module Ci
|
|||
return if pipeline.has_codequality_mr_diff_report?
|
||||
return unless new_errors_introduced?
|
||||
|
||||
pipeline.pipeline_artifacts.create!(**artifact_attributes)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :pipeline
|
||||
|
||||
def artifact_attributes
|
||||
file = build_carrierwave_file!
|
||||
|
||||
pipeline.pipeline_artifacts.create!(
|
||||
attributes = {
|
||||
project_id: pipeline.project_id,
|
||||
file_type: :code_quality_mr_diff,
|
||||
file_format: Ci::PipelineArtifact::REPORT_TYPES.fetch(:code_quality_mr_diff),
|
||||
size: file["tempfile"].size,
|
||||
file: file,
|
||||
expire_at: Ci::PipelineArtifact::EXPIRATION_DATE.from_now
|
||||
)
|
||||
}
|
||||
|
||||
if ::Feature.enabled?(:ci_update_unlocked_pipeline_artifacts, pipeline.project)
|
||||
attributes[:locked] = pipeline.locked
|
||||
end
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :pipeline
|
||||
|
||||
def merge_requests
|
||||
strong_memoize(:merge_requests) do
|
||||
pipeline.merge_requests_as_head_pipeline
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module Runners
|
||||
class SetRunnerAssociatedProjectsService
|
||||
# @param [Ci::Runner] runner: the project runner to assign/unassign projects from
|
||||
# @param [User] current_user: the user performing the operation
|
||||
# @param [Array<Integer>] project_ids: the IDs of the associated projects to assign the runner to
|
||||
def initialize(runner:, current_user:, project_ids:)
|
||||
@runner = runner
|
||||
@current_user = current_user
|
||||
@project_ids = project_ids
|
||||
end
|
||||
|
||||
def execute
|
||||
unless current_user&.can?(:assign_runner, runner)
|
||||
return ServiceResponse.error(message: 'user not allowed to assign runner', http_status: :forbidden)
|
||||
end
|
||||
|
||||
set_associated_projects
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_associated_projects
|
||||
new_project_ids = [runner.owner_project.id] + project_ids
|
||||
|
||||
response = ServiceResponse.success
|
||||
runner.transaction do
|
||||
# rubocop:disable CodeReuse/ActiveRecord
|
||||
current_project_ids = runner.projects.ids
|
||||
# rubocop:enable CodeReuse/ActiveRecord
|
||||
|
||||
unless associate_new_projects(new_project_ids, current_project_ids)
|
||||
response = ServiceResponse.error(message: 'failed to assign projects to runner')
|
||||
raise ActiveRecord::Rollback, response.errors
|
||||
end
|
||||
|
||||
unless disassociate_old_projects(new_project_ids, current_project_ids)
|
||||
response = ServiceResponse.error(message: 'failed to destroy runner project')
|
||||
raise ActiveRecord::Rollback, response.errors
|
||||
end
|
||||
end
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
def associate_new_projects(new_project_ids, current_project_ids)
|
||||
missing_projects = Project.id_in(new_project_ids - current_project_ids)
|
||||
missing_projects.each do |project|
|
||||
return false unless runner.assign_to(project, current_user)
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def disassociate_old_projects(new_project_ids, current_project_ids)
|
||||
Ci::RunnerProject
|
||||
.destroy_by(project_id: current_project_ids - new_project_ids)
|
||||
.all?(&:destroyed?)
|
||||
end
|
||||
|
||||
attr_reader :runner, :current_user, :project_ids
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Ci::Runners::SetRunnerAssociatedProjectsService.prepend_mod
|
|
@ -7,9 +7,12 @@ module Ci
|
|||
def execute(ci_ref, before_pipeline = nil)
|
||||
results = {
|
||||
unlocked_pipelines: 0,
|
||||
unlocked_job_artifacts: 0
|
||||
unlocked_job_artifacts: 0,
|
||||
unlocked_pipeline_artifacts: 0
|
||||
}
|
||||
|
||||
unlock_pipeline_artifacts_enabled = ::Feature.enabled?(:ci_update_unlocked_pipeline_artifacts, ci_ref.project)
|
||||
|
||||
if ::Feature.enabled?(:ci_update_unlocked_job_artifacts, ci_ref.project)
|
||||
loop do
|
||||
unlocked_pipelines = []
|
||||
|
@ -18,6 +21,10 @@ module Ci
|
|||
::Ci::Pipeline.transaction do
|
||||
unlocked_pipelines = unlock_pipelines(ci_ref, before_pipeline)
|
||||
unlocked_job_artifacts = unlock_job_artifacts(unlocked_pipelines)
|
||||
|
||||
if unlock_pipeline_artifacts_enabled
|
||||
results[:unlocked_pipeline_artifacts] += unlock_pipeline_artifacts(unlocked_pipelines)
|
||||
end
|
||||
end
|
||||
|
||||
break if unlocked_pipelines.empty?
|
||||
|
@ -100,6 +107,14 @@ module Ci
|
|||
)
|
||||
end
|
||||
|
||||
# rubocop:disable CodeReuse/ActiveRecord
|
||||
def unlock_pipeline_artifacts(pipelines)
|
||||
return 0 if pipelines.empty?
|
||||
|
||||
::Ci::PipelineArtifact.where(pipeline_id: pipelines.rows.flatten).update_all(locked: :unlocked)
|
||||
end
|
||||
# rubocop:enable CodeReuse/ActiveRecord
|
||||
|
||||
def unlock_pipelines(ci_ref, before_pipeline)
|
||||
::Ci::Pipeline.connection.exec_query(unlock_pipelines_query(ci_ref, before_pipeline))
|
||||
end
|
||||
|
|
|
@ -5,7 +5,6 @@ module Ci
|
|||
def log_downstream_pipeline_creation(downstream_pipeline)
|
||||
return unless downstream_pipeline&.persisted?
|
||||
|
||||
hierarchy_size = downstream_pipeline.upstream_and_all_downstreams.count
|
||||
root_pipeline = downstream_pipeline.upstream_root
|
||||
|
||||
::Gitlab::AppLogger.info(
|
||||
|
@ -14,7 +13,7 @@ module Ci
|
|||
root_pipeline_id: root_pipeline.id,
|
||||
downstream_pipeline_id: downstream_pipeline.id,
|
||||
downstream_pipeline_relationship: downstream_pipeline.parent_pipeline? ? :parent_child : :multi_project,
|
||||
hierarchy_size: hierarchy_size,
|
||||
hierarchy_size: downstream_pipeline.complete_hierarchy_count,
|
||||
root_pipeline_plan: root_pipeline.project.actual_plan_name,
|
||||
root_pipeline_namespace_path: root_pipeline.project.namespace.full_path,
|
||||
root_pipeline_project_path: root_pipeline.project.full_path
|
||||
|
|
|
@ -234,6 +234,7 @@ module MergeRequests
|
|||
end
|
||||
|
||||
# Add comment about pushing new commits to merge requests and send nofitication emails
|
||||
#
|
||||
def notify_about_push(merge_request)
|
||||
return unless @commits.present?
|
||||
|
||||
|
|
|
@ -8,16 +8,15 @@
|
|||
|
||||
%h1.page-title.gl-font-size-h-display
|
||||
= s_('TagsPage|New Tag')
|
||||
%hr
|
||||
|
||||
= form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "common-note-form tag-form js-quick-submit js-requires-input" do
|
||||
.form-group.row
|
||||
= label_tag :tag_name, nil, class: 'col-form-label col-sm-2'
|
||||
.col-sm-10
|
||||
.col-sm-12
|
||||
= label_tag :tag_name, nil
|
||||
= text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control', data: { qa_selector: "tag_name_field" }
|
||||
.form-group.row
|
||||
= label_tag :ref, 'Create from', class: 'col-form-label col-sm-2'
|
||||
.col-sm-10.create-from
|
||||
.col-sm-12.create-from
|
||||
= label_tag :ref, 'Create from'
|
||||
.dropdown
|
||||
= hidden_field_tag :ref, default_ref
|
||||
= button_tag type: 'button', title: default_ref, class: 'dropdown-menu-toggle wide js-branch-select monospace', required: true, data: { toggle: 'dropdown', selected: default_ref, field_name: 'ref' } do
|
||||
|
@ -27,15 +26,14 @@
|
|||
.form-text.text-muted
|
||||
= s_('TagsPage|Existing branch name, tag, or commit SHA')
|
||||
.form-group.row
|
||||
= label_tag :message, nil, class: 'col-form-label col-sm-2'
|
||||
.col-sm-10
|
||||
.col-sm-12
|
||||
= label_tag :message, nil
|
||||
= text_area_tag :message, @message, required: false, class: 'form-control', rows: 5, data: { qa_selector: "tag_message_field" }
|
||||
.form-text.text-muted
|
||||
= tag_description_help_text
|
||||
%hr
|
||||
.form-group.row
|
||||
= label_tag :release_description, s_('TagsPage|Release notes'), class: 'col-form-label col-sm-2'
|
||||
.col-sm-10
|
||||
.col-sm-12
|
||||
= label_tag :release_description, s_('TagsPage|Release notes'), class: 'gl-mb-0'
|
||||
.form-text.mb-3
|
||||
- link_start = '<a href="%{url}" rel="noopener noreferrer" target="_blank">'.html_safe
|
||||
- releases_page_path = project_releases_path(@project)
|
||||
|
@ -49,7 +47,7 @@
|
|||
= render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
|
||||
= render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description, qa_selector: 'release_notes_field'
|
||||
= render 'shared/notes/hints'
|
||||
.form-actions.gl-display-flex
|
||||
.gl-display-flex
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { class: 'gl-mr-3', data: { qa_selector: "create_tag_button" }, type: 'submit' }) do
|
||||
= s_('TagsPage|Create tag')
|
||||
= render Pajamas::ButtonComponent.new(href: project_tags_path(@project)) do
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: ci_read_stage_records
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94941
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371486
|
||||
name: ci_update_unlocked_pipeline_artifacts
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97228
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372835
|
||||
milestone: '15.4'
|
||||
type: development
|
||||
group: group::pipeline execution
|
||||
group: group::pipeline insights
|
||||
default_enabled: false
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: include_groups_from_group_shares_in_group_transfer_locations
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96347
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371961
|
||||
milestone: '15.4'
|
||||
type: development
|
||||
group: group::workspace
|
||||
default_enabled: false
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ScheduleDisableLegacyOpenSourceLicenseForProjectsLessThanOneMb < Gitlab::Database::Migration[2.0]
|
||||
MIGRATION = 'DisableLegacyOpenSourceLicenseForProjectsLessThanOneMb'
|
||||
INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 4_000
|
||||
MAX_BATCH_SIZE = 50_000
|
||||
SUB_BATCH_SIZE = 250
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
return unless Gitlab.com?
|
||||
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:project_settings,
|
||||
:project_id,
|
||||
job_interval: INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
max_batch_size: MAX_BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
return unless Gitlab.com?
|
||||
|
||||
delete_batched_background_migration(MIGRATION, :project_settings, :project_id, [])
|
||||
end
|
||||
end
|
1
db/schema_migrations/20220906074449
Normal file
1
db/schema_migrations/20220906074449
Normal file
|
@ -0,0 +1 @@
|
|||
fc34cdbddc61ee9c23b790101f911d21892cf2ace34e3615b920817374c803f9
|
|
@ -147,6 +147,18 @@ Do not use **and so on**. Instead, be more specific. For details, see
|
|||
|
||||
Use [**section**](#section) instead of **area**. The only exception is [the Admin Area](#admin-area).
|
||||
|
||||
## as
|
||||
|
||||
Do not use **as** to mean **because**.
|
||||
|
||||
Use:
|
||||
|
||||
- Because none of the endpoints return an ID...
|
||||
|
||||
Instead of:
|
||||
|
||||
- As none of the endpoints return an ID...
|
||||
|
||||
## associate
|
||||
|
||||
Do not use **associate** when describing adding issues to epics, or users to issues, merge requests,
|
||||
|
@ -619,6 +631,10 @@ Instead of:
|
|||
- Buy a license.
|
||||
- Purchase a license.
|
||||
|
||||
## limitations
|
||||
|
||||
Do not use **limitations**. Use **known issues** instead.
|
||||
|
||||
## log in, log on
|
||||
|
||||
Do not use **log in** or **log on**. Use [sign in](#sign-in) instead. If the user interface has **Log in**, you can use it.
|
||||
|
|
|
@ -20,6 +20,32 @@ NOTE:
|
|||
Support for tracking commits cherry-picked from the command line
|
||||
is tracked [in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/202215).
|
||||
|
||||
## Cherry-pick example
|
||||
|
||||
In this example of cherry-picking, a Git repository has two branches: `develop` and `main`.
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit id: "A"
|
||||
branch develop
|
||||
commit id:"B"
|
||||
checkout main
|
||||
commit id:"C"
|
||||
checkout develop
|
||||
commit id:"D"
|
||||
checkout main
|
||||
commit id:"E"
|
||||
cherry-pick id:"B"
|
||||
commit id:"G"
|
||||
checkout develop
|
||||
commit id:"H"
|
||||
```
|
||||
|
||||
The example shows a cherry-pick of commit `B` from the `develop` branch, which is added
|
||||
after commit `E` in the `main` branch.
|
||||
|
||||
Commit `G` is added after the cherry-pick.
|
||||
|
||||
## Cherry-pick all changes from a merge request
|
||||
|
||||
After a merge request is merged, you can cherry-pick all changes introduced
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Entities
|
||||
class PersonalAccessTokenWithDetails < Entities::PersonalAccessToken
|
||||
expose :expired?, as: :expired
|
||||
expose :expires_soon?, as: :expires_soon
|
||||
expose :revoke_path do |token|
|
||||
Gitlab::Routing.url_helpers.revoke_profile_personal_access_token_path(token)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
# Set `project_settings.legacy_open_source_license_available` to false for projects less than 1 MB
|
||||
class DisableLegacyOpenSourceLicenseForProjectsLessThanOneMb < ::Gitlab::BackgroundMigration::BatchedMigrationJob
|
||||
scope_to ->(relation) { relation.where(legacy_open_source_license_available: true) }
|
||||
|
||||
def perform
|
||||
each_sub_batch(operation_name: :disable_legacy_open_source_license_for_projects_less_than_one_mb) do |sub_batch|
|
||||
updates = { legacy_open_source_license_available: false, updated_at: Time.current }
|
||||
|
||||
sub_batch
|
||||
.joins('INNER JOIN project_statistics ON project_statistics.project_id = project_settings.project_id')
|
||||
.where('project_statistics.repository_size < ?', 1.megabyte)
|
||||
.update_all(updates)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1056,6 +1056,24 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def list_commits_by(query, ref, author: nil, before: nil, after: nil, limit: 1000)
|
||||
params = {
|
||||
author: author,
|
||||
ignore_case: true,
|
||||
commit_message_patterns: query,
|
||||
before: before,
|
||||
after: after,
|
||||
reverse: false,
|
||||
pagination_params: { limit: limit }
|
||||
}
|
||||
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_commit_client
|
||||
.list_commits([ref], params)
|
||||
.map { |c| commit(c) }
|
||||
end
|
||||
end
|
||||
|
||||
def list_last_commits_for_tree(sha, path, offset: 0, limit: 25, literal_pathspec: false)
|
||||
wrapped_gitaly_errors do
|
||||
gitaly_commit_client.list_last_commits_for_tree(sha, path, offset: offset, limit: limit, literal_pathspec: literal_pathspec)
|
||||
|
|
|
@ -251,14 +251,23 @@ module Gitlab
|
|||
consume_commits_response(response)
|
||||
end
|
||||
|
||||
def list_commits(revisions, reverse: false, pagination_params: nil)
|
||||
def list_commits(revisions, params = {})
|
||||
request = Gitaly::ListCommitsRequest.new(
|
||||
repository: @gitaly_repo,
|
||||
revisions: Array.wrap(revisions),
|
||||
reverse: reverse,
|
||||
pagination_params: pagination_params
|
||||
reverse: !!params[:reverse],
|
||||
ignore_case: params[:ignore_case],
|
||||
pagination_params: params[:pagination_params]
|
||||
)
|
||||
|
||||
if params[:commit_message_patterns]
|
||||
request.commit_message_patterns += Array.wrap(params[:commit_message_patterns])
|
||||
end
|
||||
|
||||
request.author = encode_binary(params[:author]) if params[:author]
|
||||
request.before = GitalyClient.timestamp(params[:before]) if params[:before]
|
||||
request.after = GitalyClient.timestamp(params[:after]) if params[:after]
|
||||
|
||||
response = GitalyClient.call(@repository.storage, :commit_service, :list_commits, request, timeout: GitalyClient.medium_timeout)
|
||||
consume_commits_response(response)
|
||||
end
|
||||
|
|
|
@ -43942,9 +43942,6 @@ msgstr ""
|
|||
msgid "Vulnerability|Information related to how the vulnerability was discovered and its impact on the system."
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Learn more about this vulnerability and the best way to resolve it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Vulnerability|Links"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ function bundle_install_script() {
|
|||
exit 1;
|
||||
fi;
|
||||
|
||||
echo -e "section_start:`date +%s`:bundle-install[collapsed=true]\r\e[0KInstalling gems"
|
||||
|
||||
gem --version
|
||||
bundle --version
|
||||
gem install bundler --no-document --conservative --version 2.3.15
|
||||
|
@ -48,7 +50,7 @@ function bundle_install_script() {
|
|||
echo "${BUNDLE_WITHOUT}"
|
||||
bundle config
|
||||
|
||||
run_timed_command "bundle install ${BUNDLE_INSTALL_FLAGS} ${extra_install_args} && bundle check"
|
||||
run_timed_command "bundle install ${BUNDLE_INSTALL_FLAGS} ${extra_install_args}"
|
||||
|
||||
if [[ $(bundle info pg) ]]; then
|
||||
# When we test multiple versions of PG in the same pipeline, we have a single `setup-test-env`
|
||||
|
@ -56,6 +58,8 @@ function bundle_install_script() {
|
|||
# Uncomment the following line if multiple versions of PG are tested in the same pipeline.
|
||||
run_timed_command "bundle pristine pg"
|
||||
fi
|
||||
|
||||
echo -e "section_end:`date +%s`:bundle-install\r\e[0K"
|
||||
}
|
||||
|
||||
function setup_db_user_only() {
|
||||
|
|
|
@ -48,8 +48,8 @@ RSpec.describe Profiles::PersonalAccessTokensController do
|
|||
end
|
||||
|
||||
it "only includes details of the active personal access token" do
|
||||
active_personal_access_tokens_detail = ::API::Entities::PersonalAccessTokenWithDetails
|
||||
.represent([active_personal_access_token])
|
||||
active_personal_access_tokens_detail =
|
||||
::PersonalAccessTokenSerializer.new.represent([active_personal_access_token])
|
||||
|
||||
expect(assigns(:active_personal_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json)
|
||||
end
|
||||
|
@ -100,8 +100,8 @@ RSpec.describe Profiles::PersonalAccessTokensController do
|
|||
get :index
|
||||
|
||||
first_token = assigns(:active_personal_access_tokens).first.as_json
|
||||
expect(first_token[:name]).to eq("Token1")
|
||||
expect(first_token[:expires_at]).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
|
||||
expect(first_token['name']).to eq("Token1")
|
||||
expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
|
||||
end
|
||||
|
||||
it "orders tokens on id in case token has same expires_at" do
|
||||
|
@ -110,12 +110,12 @@ RSpec.describe Profiles::PersonalAccessTokensController do
|
|||
get :index
|
||||
|
||||
first_token = assigns(:active_personal_access_tokens).first.as_json
|
||||
expect(first_token[:name]).to eq("Token3")
|
||||
expect(first_token[:expires_at]).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
|
||||
expect(first_token['name']).to eq("Token3")
|
||||
expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
|
||||
|
||||
second_token = assigns(:active_personal_access_tokens).second.as_json
|
||||
expect(second_token[:name]).to eq("Token1")
|
||||
expect(second_token[:expires_at]).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
|
||||
expect(second_token['name']).to eq("Token1")
|
||||
expect(second_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ RSpec.describe 'Developer creates tag' do
|
|||
|
||||
it 'opens dropdown for ref', :js do
|
||||
click_link 'New tag'
|
||||
ref_row = find('.form-group:nth-of-type(2) .col-sm-10')
|
||||
ref_row = find('.form-group:nth-of-type(2) .col-sm-12')
|
||||
page.within ref_row do
|
||||
ref_input = find('[name="ref"]', visible: false)
|
||||
expect(ref_input.value).to eq 'master'
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe ContextCommitsFinder do
|
||||
describe "#execute" do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:merge_request) { create(:merge_request) }
|
||||
let(:merge_request) { create(:merge_request, source_branch: 'feature', target_branch: 'master') }
|
||||
let(:commit) { create(:commit, id: '6d394385cf567f80a8fd85055db1ab4c5295806f') }
|
||||
|
||||
it 'filters commits by valid sha/commit message' do
|
||||
|
@ -24,5 +24,29 @@ RSpec.describe ContextCommitsFinder do
|
|||
|
||||
expect(commits).to be_empty
|
||||
end
|
||||
|
||||
it 'returns commits based in author filter' do
|
||||
params = { search: 'test text', author: 'Job van der Voort' }
|
||||
commits = described_class.new(project, merge_request, params).execute
|
||||
|
||||
expect(commits.length).to eq(1)
|
||||
expect(commits[0].id).to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
|
||||
end
|
||||
|
||||
it 'returns commits based in before filter' do
|
||||
params = { search: 'test text', committed_before: 1474828200 }
|
||||
commits = described_class.new(project, merge_request, params).execute
|
||||
|
||||
expect(commits.length).to eq(1)
|
||||
expect(commits[0].id).to eq('498214de67004b1da3d820901307bed2a68a8ef6')
|
||||
end
|
||||
|
||||
it 'returns commits based in after filter' do
|
||||
params = { search: 'test text', committed_after: 1474828200 }
|
||||
commits = described_class.new(project, merge_request, params).execute
|
||||
|
||||
expect(commits.length).to eq(1)
|
||||
expect(commits[0].id).to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,9 +29,27 @@ RSpec.describe Groups::AcceptingGroupTransfersFinder do
|
|||
end
|
||||
end
|
||||
|
||||
let_it_be(:shared_with_group_where_direct_owner_as_guest) { create(:group) }
|
||||
let_it_be(:shared_with_group_where_direct_owner_as_owner) { create(:group) }
|
||||
let_it_be(:subgroup_of_shared_with_group_where_direct_owner_as_owner) do
|
||||
create(:group, parent: shared_with_group_where_direct_owner_as_owner)
|
||||
end
|
||||
|
||||
let(:params) { {} }
|
||||
|
||||
describe '#execute' do
|
||||
before_all do
|
||||
create(:group_group_link, :owner,
|
||||
shared_with_group: group_where_user_has_owner_access,
|
||||
shared_group: shared_with_group_where_direct_owner_as_owner
|
||||
)
|
||||
|
||||
create(:group_group_link, :guest,
|
||||
shared_with_group: group_where_user_has_owner_access,
|
||||
shared_group: shared_with_group_where_direct_owner_as_guest
|
||||
)
|
||||
end
|
||||
|
||||
let(:group_to_be_transferred) { parent_group }
|
||||
|
||||
subject(:result) do
|
||||
|
@ -69,6 +87,10 @@ RSpec.describe Groups::AcceptingGroupTransfersFinder do
|
|||
expect(result).not_to include(group_where_user_has_developer_access)
|
||||
end
|
||||
|
||||
it 'excludes the groups arising from group shares where the user does not have OWNER access' do
|
||||
expect(result).not_to include(shared_with_group_where_direct_owner_as_guest)
|
||||
end
|
||||
|
||||
it 'includes ancestors, except immediate parent of the group to be transferred' do
|
||||
expect(result).to include(great_grandparent_group)
|
||||
end
|
||||
|
@ -81,6 +103,13 @@ RSpec.describe Groups::AcceptingGroupTransfersFinder do
|
|||
expect(result).to include(subgroup_of_group_where_user_has_owner_access)
|
||||
end
|
||||
|
||||
it 'includes the groups where the user has OWNER access through group shares' do
|
||||
expect(result).to include(
|
||||
shared_with_group_where_direct_owner_as_owner,
|
||||
subgroup_of_shared_with_group_where_direct_owner_as_owner
|
||||
)
|
||||
end
|
||||
|
||||
context 'on searching with a specific term' do
|
||||
let(:params) { { search: 'great grandparent group' } }
|
||||
|
||||
|
@ -88,6 +117,19 @@ RSpec.describe Groups::AcceptingGroupTransfersFinder do
|
|||
expect(result).to contain_exactly(great_grandparent_group)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature flag `include_groups_from_group_shares_in_group_transfer_locations` is turned off' do
|
||||
before do
|
||||
stub_feature_flags(include_groups_from_group_shares_in_group_transfer_locations: false)
|
||||
end
|
||||
|
||||
it 'excludes the groups where the user has OWNER access through group shares' do
|
||||
expect(result).not_to include(
|
||||
shared_with_group_where_direct_owner_as_owner,
|
||||
subgroup_of_shared_with_group_where_direct_owner_as_owner
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,9 +48,6 @@ testUtilsConfig.deprecationWarningHandler = (method, message) => {
|
|||
const ALLOWED_DEPRECATED_METHODS = [
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/295679
|
||||
'finding components with `find` or `get`',
|
||||
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/295680
|
||||
'finding components with `findAll`',
|
||||
];
|
||||
if (!ALLOWED_DEPRECATED_METHODS.includes(method)) {
|
||||
global.console.error(message);
|
||||
|
|
|
@ -46,6 +46,6 @@ describe('ReviewTabContainer', () => {
|
|||
|
||||
it('renders all passed commits as list', () => {
|
||||
createWrapper({ commits: [commit] });
|
||||
expect(wrapper.findAll(CommitItem).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(CommitItem).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -67,7 +67,7 @@ describe('AlertIntegrationsList', () => {
|
|||
});
|
||||
|
||||
it('renders an an edit and delete button for each integration', () => {
|
||||
expect(findTableComponent().findAll(GlButton).length).toBe(4);
|
||||
expect(findTableComponent().findAllComponents(GlButton).length).toBe(4);
|
||||
});
|
||||
|
||||
it('renders an highlighted row when a current integration is selected to edit', () => {
|
||||
|
|
|
@ -83,7 +83,7 @@ describe('ProjectsDropdownFilter component', () => {
|
|||
|
||||
const findDropdownItems = () =>
|
||||
findDropdown()
|
||||
.findAll(GlDropdownItem)
|
||||
.findAllComponents(GlDropdownItem)
|
||||
.filter((w) => w.text() !== 'No matching results');
|
||||
|
||||
const findDropdownAtIndex = (index) => findDropdownItems().at(index);
|
||||
|
@ -106,7 +106,7 @@ describe('ProjectsDropdownFilter component', () => {
|
|||
};
|
||||
|
||||
// NOTE: Selected items are now visually separated from unselected items
|
||||
const findSelectedDropdownItems = () => findHighlightedItems().findAll(GlDropdownItem);
|
||||
const findSelectedDropdownItems = () => findHighlightedItems().findAllComponents(GlDropdownItem);
|
||||
|
||||
const findSelectedDropdownAtIndex = (index) => findSelectedDropdownItems().at(index);
|
||||
const findSelectedButtonIdentIconAtIndex = (index) =>
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('UsageTrendsApp', () => {
|
|||
['Total projects & groups', 'Pipelines', 'Issues & merge requests'].forEach((usage) => {
|
||||
it(`displays the ${usage} chart`, () => {
|
||||
const chartTitles = wrapper
|
||||
.findAll(UsageTrendsCountChart)
|
||||
.findAllComponents(UsageTrendsCountChart)
|
||||
.wrappers.map((chartComponent) => chartComponent.props('chartTitle'));
|
||||
|
||||
expect(chartTitles).toContain(usage);
|
||||
|
|
|
@ -35,7 +35,9 @@ describe('RecoveryCodes', () => {
|
|||
const findRecoveryCodes = () => wrapper.findByTestId('recovery-codes');
|
||||
const findCopyButton = () => wrapper.findComponent(ClipboardButton);
|
||||
const findButtonByText = (text) =>
|
||||
wrapper.findAll(GlButton).wrappers.find((buttonWrapper) => buttonWrapper.text() === text);
|
||||
wrapper
|
||||
.findAllComponents(GlButton)
|
||||
.wrappers.find((buttonWrapper) => buttonWrapper.text() === text);
|
||||
const findDownloadButton = () => findButtonByText('Download codes');
|
||||
const findPrintButton = () => findButtonByText('Print codes');
|
||||
const findProceedButton = () => findButtonByText('Proceed');
|
||||
|
|
|
@ -35,13 +35,13 @@ describe('Batch comments diff file drafts component', () => {
|
|||
it('renders list of draft notes', () => {
|
||||
factory();
|
||||
|
||||
expect(vm.findAll(DraftNote).length).toEqual(2);
|
||||
expect(vm.findAllComponents(DraftNote).length).toEqual(2);
|
||||
});
|
||||
|
||||
it('renders index of draft note', () => {
|
||||
factory();
|
||||
|
||||
const elements = vm.findAll(DesignNotePin);
|
||||
const elements = vm.findAllComponents(DesignNotePin);
|
||||
|
||||
expect(elements.length).toEqual(2);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('Batch comments publish dropdown component', () => {
|
|||
it('renders list of drafts', () => {
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.findAll(GlDropdownItem).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(GlDropdownItem).length).toBe(2);
|
||||
});
|
||||
|
||||
it('renders draft count in dropdown title', () => {
|
||||
|
|
|
@ -21,7 +21,7 @@ describe('Branch divergence graph component', () => {
|
|||
maxCommits: 100,
|
||||
});
|
||||
|
||||
expect(vm.findAll(GraphBar).length).toBe(2);
|
||||
expect(vm.findAllComponents(GraphBar).length).toBe(2);
|
||||
expect(vm.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -45,7 +45,7 @@ describe('Branch divergence graph component', () => {
|
|||
maxCommits: 100,
|
||||
});
|
||||
|
||||
expect(vm.findAll(GraphBar).length).toBe(1);
|
||||
expect(vm.findAllComponents(GraphBar).length).toBe(1);
|
||||
expect(vm.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ describe('LockPopovers', () => {
|
|||
});
|
||||
|
||||
it('mounts multiple popovers', () => {
|
||||
const popovers = wrapper.findAll(GlPopover).wrappers;
|
||||
const popovers = wrapper.findAllComponents(GlPopover).wrappers;
|
||||
|
||||
expectCorrectPopoverTarget(popoverMountEl1, popovers[0]);
|
||||
expectCorrectPopoverTarget(popoverMountEl2, popovers[1]);
|
||||
|
|
|
@ -65,7 +65,7 @@ describe('Ci variable modal', () => {
|
|||
const findAddorUpdateButton = () => wrapper.findByTestId('ciUpdateOrAddVariableBtn');
|
||||
const deleteVariableButton = () =>
|
||||
findModal()
|
||||
.findAll(GlButton)
|
||||
.findAllComponents(GlButton)
|
||||
.wrappers.find((button) => button.props('variant') === 'danger');
|
||||
const findProtectedVariableCheckbox = () =>
|
||||
wrapper.findByTestId('ci-variable-protected-checkbox');
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('Ci variable modal', () => {
|
|||
const findAddorUpdateButton = () => findModal().find('[data-testid="ciUpdateOrAddVariableBtn"]');
|
||||
const deleteVariableButton = () =>
|
||||
findModal()
|
||||
.findAll(GlButton)
|
||||
.findAllComponents(GlButton)
|
||||
.wrappers.find((button) => button.props('variant') === 'danger');
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -65,7 +65,7 @@ describe('InstallAgentModal', () => {
|
|||
const findAgentInstructions = () => findModal().findComponent(AgentToken);
|
||||
const findButtonByVariant = (variant) =>
|
||||
findModal()
|
||||
.findAll(GlButton)
|
||||
.findAllComponents(GlButton)
|
||||
.wrappers.find((button) => button.props('variant') === variant);
|
||||
const findActionButton = () => findButtonByVariant('confirm');
|
||||
const findCancelButton = () => findButtonByVariant('default');
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('Confidential merge request project dropdown component', () => {
|
|||
},
|
||||
]);
|
||||
|
||||
expect(vm.findAll(GlDropdownItem).length).toBe(2);
|
||||
expect(vm.findAllComponents(GlDropdownItem).length).toBe(2);
|
||||
});
|
||||
|
||||
it('shows lock icon', () => {
|
||||
|
|
|
@ -30,8 +30,8 @@ describe('Deploy freeze timezone dropdown', () => {
|
|||
wrapper.setData({ searchTerm });
|
||||
};
|
||||
|
||||
const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
|
||||
const findDropdownItemByIndex = (index) => wrapper.findAll(GlDropdownItem).at(index);
|
||||
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
|
|
|
@ -274,7 +274,7 @@ describe('diffs/components/app', () => {
|
|||
});
|
||||
|
||||
expect(wrapper.findComponent(NoChanges).exists()).toBe(false);
|
||||
expect(wrapper.findAll(DiffFile).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(DiffFile).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -636,7 +636,7 @@ describe('diffs/components/app', () => {
|
|||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.findAll(DiffFile).length).toBe(1);
|
||||
expect(wrapper.findAllComponents(DiffFile).length).toBe(1);
|
||||
});
|
||||
|
||||
describe('pagination', () => {
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('CompareDropdownLayout', () => {
|
|||
findListItems().wrappers.map((listItem) => ({
|
||||
href: listItem.find('a').attributes('href'),
|
||||
text: trimText(listItem.text()),
|
||||
createdAt: listItem.findAll(TimeAgo).wrappers[0]?.props('time'),
|
||||
createdAt: listItem.findAllComponents(TimeAgo).wrappers[0]?.props('time'),
|
||||
isActive: listItem.classes().includes('is-active'),
|
||||
}));
|
||||
|
||||
|
|
|
@ -34,9 +34,9 @@ describe('DiffDiscussions', () => {
|
|||
|
||||
expect(wrapper.findComponent(NoteableDiscussion).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(DiscussionNotes).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(DiscussionNotes).findAll(TimelineEntryItem).length).toBe(
|
||||
discussionsMockData.notes.length,
|
||||
);
|
||||
expect(
|
||||
wrapper.findComponent(DiscussionNotes).findAllComponents(TimelineEntryItem).length,
|
||||
).toBe(discussionsMockData.notes.length);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ describe('diff_stats', () => {
|
|||
describe('files changes', () => {
|
||||
const findIcon = (name) =>
|
||||
wrapper
|
||||
.findAll(GlIcon)
|
||||
.findAllComponents(GlIcon)
|
||||
.filter((c) => c.attributes('name') === name)
|
||||
.at(0).element.parentNode;
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ describe('DiffView', () => {
|
|||
diffLines: [{ renderCommentRow: true, ...sides }],
|
||||
inline: type === 'inline',
|
||||
});
|
||||
expect(wrapper.findAll(DiffCommentCell).length).toBe(total);
|
||||
expect(wrapper.findAllComponents(DiffCommentCell).length).toBe(total);
|
||||
expect(wrapper.find(container).findComponent(DiffCommentCell).exists()).toBe(true);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('Emoji category component', () => {
|
|||
});
|
||||
|
||||
it('renders emoji groups', () => {
|
||||
expect(wrapper.findAll(EmojiGroup).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(EmojiGroup).length).toBe(2);
|
||||
});
|
||||
|
||||
it('renders group', async () => {
|
||||
|
|
|
@ -76,7 +76,7 @@ describe('error tracking settings project dropdown', () => {
|
|||
|
||||
it('contains a number of dropdown items', () => {
|
||||
expect(wrapper.findComponent(GlDropdownItem).exists()).toBe(true);
|
||||
expect(wrapper.findAll(GlDropdownItem).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(GlDropdownItem).length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import RecentSearchesDropdownContent from '~/filtered_search/components/recent_searches_dropdown_content.vue';
|
||||
import eventHub from '~/filtered_search/event_hub';
|
||||
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
||||
|
@ -6,12 +6,12 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
|
|||
describe('Recent Searches Dropdown Content', () => {
|
||||
let wrapper;
|
||||
|
||||
const findLocalStorageNote = () => wrapper.findComponent({ ref: 'localStorageNote' });
|
||||
const findDropdownItems = () => wrapper.findAll({ ref: 'dropdownItem' });
|
||||
const findDropdownNote = () => wrapper.findComponent({ ref: 'dropdownNote' });
|
||||
const findLocalStorageNote = () => wrapper.findByTestId('local-storage-note');
|
||||
const findDropdownItems = () => wrapper.findAllByTestId('dropdown-item');
|
||||
const findDropdownNote = () => wrapper.findByTestId('dropdown-note');
|
||||
|
||||
const createComponent = (props) => {
|
||||
wrapper = shallowMount(RecentSearchesDropdownContent, {
|
||||
wrapper = shallowMountExtended(RecentSearchesDropdownContent, {
|
||||
propsData: {
|
||||
allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(),
|
||||
items: [],
|
||||
|
@ -94,7 +94,7 @@ describe('Recent Searches Dropdown Content', () => {
|
|||
});
|
||||
|
||||
it('emits requestClearRecentSearches on Clear resent searches button', () => {
|
||||
wrapper.findComponent({ ref: 'clearButton' }).trigger('click');
|
||||
wrapper.findByTestId('clear-button').trigger('click');
|
||||
|
||||
expect(onRequestClearRecentSearchesSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GlButton } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
||||
import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue';
|
||||
|
@ -16,18 +16,18 @@ describe('FrequentItemsListItemComponent', () => {
|
|||
let trackingSpy;
|
||||
let store;
|
||||
|
||||
const findTitle = () => wrapper.findComponent({ ref: 'frequentItemsItemTitle' });
|
||||
const findTitle = () => wrapper.findByTestId('frequent-items-item-title');
|
||||
const findAvatar = () => wrapper.findComponent(ProjectAvatar);
|
||||
const findAllTitles = () => wrapper.findAll({ ref: 'frequentItemsItemTitle' });
|
||||
const findNamespace = () => wrapper.findComponent({ ref: 'frequentItemsItemNamespace' });
|
||||
const findAllTitles = () => wrapper.findAllByTestId('frequent-items-item-title');
|
||||
const findNamespace = () => wrapper.findByTestId('frequent-items-item-namespace');
|
||||
const findAllButtons = () => wrapper.findAllComponents(GlButton);
|
||||
const findAllNamespace = () => wrapper.findAll({ ref: 'frequentItemsItemNamespace' });
|
||||
const findAllNamespace = () => wrapper.findAllByTestId('frequent-items-item-namespace');
|
||||
const findAllAvatars = () => wrapper.findAllComponents(ProjectAvatar);
|
||||
const findAllMetadataContainers = () =>
|
||||
wrapper.findAll({ ref: 'frequentItemsItemMetadataContainer' });
|
||||
wrapper.findAllByTestId('frequent-items-item-metadata-container');
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = shallowMount(frequentItemsListItemComponent, {
|
||||
wrapper = shallowMountExtended(frequentItemsListItemComponent, {
|
||||
store,
|
||||
propsData: {
|
||||
itemId: mockProject.id,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import frequentItemsListComponent from '~/frequent_items/components/frequent_items_list.vue';
|
||||
import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue';
|
||||
import { createStore } from '~/frequent_items/store';
|
||||
|
@ -12,7 +12,7 @@ describe('FrequentItemsListComponent', () => {
|
|||
let wrapper;
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = mount(frequentItemsListComponent, {
|
||||
wrapper = mountExtended(frequentItemsListComponent, {
|
||||
store: createStore(),
|
||||
propsData: {
|
||||
namespace: 'projects',
|
||||
|
@ -94,8 +94,8 @@ describe('FrequentItemsListComponent', () => {
|
|||
|
||||
await nextTick();
|
||||
expect(wrapper.classes('frequent-items-list-container')).toBe(true);
|
||||
expect(wrapper.findAll({ ref: 'frequentItemsList' })).toHaveLength(1);
|
||||
expect(wrapper.findAll(frequentItemsListItemComponent)).toHaveLength(5);
|
||||
expect(wrapper.findAllByTestId('frequent-items-list')).toHaveLength(1);
|
||||
expect(wrapper.findAllComponents(frequentItemsListItemComponent)).toHaveLength(5);
|
||||
});
|
||||
|
||||
it('should render component element with empty message', async () => {
|
||||
|
@ -105,7 +105,7 @@ describe('FrequentItemsListComponent', () => {
|
|||
|
||||
await nextTick();
|
||||
expect(wrapper.vm.$el.querySelectorAll('li.section-empty')).toHaveLength(1);
|
||||
expect(wrapper.findAll(frequentItemsListItemComponent)).toHaveLength(0);
|
||||
expect(wrapper.findAllComponents(frequentItemsListItemComponent)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('ImportProjectsTable', () => {
|
|||
|
||||
const findImportAllButton = () =>
|
||||
wrapper
|
||||
.findAll(GlButton)
|
||||
.findAllComponents(GlButton)
|
||||
.filter((w) => w.props().variant === 'confirm')
|
||||
.at(0);
|
||||
const findImportAllModal = () => wrapper.findComponent({ ref: 'importAllModal' });
|
||||
|
@ -118,7 +118,7 @@ describe('ImportProjectsTable', () => {
|
|||
.exists(),
|
||||
).toBe(true);
|
||||
|
||||
expect(wrapper.findAll(ProviderRepoTableRow)).toHaveLength(repositories.length);
|
||||
expect(wrapper.findAllComponents(ProviderRepoTableRow)).toHaveLength(repositories.length);
|
||||
});
|
||||
|
||||
it.each`
|
||||
|
|
|
@ -44,12 +44,12 @@ describe('Incidents List', () => {
|
|||
const findTableRows = () => wrapper.findAll('table tbody tr');
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findLoader = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findTimeAgo = () => wrapper.findAll(TimeAgoTooltip);
|
||||
const findTimeAgo = () => wrapper.findAllComponents(TimeAgoTooltip);
|
||||
const findAssignees = () => wrapper.findAll('[data-testid="incident-assignees"]');
|
||||
const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]');
|
||||
const findClosedIcon = () => wrapper.findAll("[data-testid='incident-closed']");
|
||||
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
const findSeverity = () => wrapper.findAll(SeverityToken);
|
||||
const findSeverity = () => wrapper.findAllComponents(SeverityToken);
|
||||
const findEscalationStatus = () => wrapper.findAll('[data-testid="incident-escalation-status"]');
|
||||
const findIncidentLink = () => wrapper.findByTestId('incident-link');
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('IncidentsSettingTabs', () => {
|
|||
const findToggleButton = () => wrapper.findComponent({ ref: 'toggleBtn' });
|
||||
const findSectionHeader = () => wrapper.findComponent({ ref: 'sectionHeader' });
|
||||
|
||||
const findIntegrationTabs = () => wrapper.findAll(GlTab);
|
||||
const findIntegrationTabs = () => wrapper.findAllComponents(GlTab);
|
||||
it('renders header text', () => {
|
||||
expect(findSectionHeader().text()).toBe('Incidents');
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ describe('TriggerFields', () => {
|
|||
});
|
||||
|
||||
const findTriggerLabel = () => wrapper.findByTestId('trigger-fields-group').find('label');
|
||||
const findAllGlFormGroups = () => wrapper.find('#trigger-fields').findAll(GlFormGroup);
|
||||
const findAllGlFormGroups = () => wrapper.find('#trigger-fields').findAllComponents(GlFormGroup);
|
||||
const findAllGlFormCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
|
||||
const findAllGlFormInputs = () => wrapper.findAllComponents(GlFormInput);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('IssueAssigneesComponent', () => {
|
|||
});
|
||||
|
||||
const findTooltipText = () => wrapper.find('.js-assignee-tooltip').text();
|
||||
const findAvatars = () => wrapper.findAll(UserAvatarLink);
|
||||
const findAvatars = () => wrapper.findAllComponents(UserAvatarLink);
|
||||
const findOverflowCounter = () => wrapper.find('.avatar-counter');
|
||||
|
||||
it('returns default data props', () => {
|
||||
|
|
|
@ -20,7 +20,7 @@ describe('Issue title suggestions item component', () => {
|
|||
}
|
||||
|
||||
const findLink = () => wrapper.findComponent(GlLink);
|
||||
const findAuthorLink = () => wrapper.findAll(GlLink).at(1);
|
||||
const findAuthorLink = () => wrapper.findAllComponents(GlLink).at(1);
|
||||
const findIcon = () => wrapper.findComponent(GlIcon);
|
||||
const findTooltip = () => wrapper.findComponent(GlTooltip);
|
||||
const findUserAvatar = () => wrapper.findComponent(UserAvatarImage);
|
||||
|
|
|
@ -83,7 +83,7 @@ describe('Issue title suggestions component', () => {
|
|||
wrapper.setData(data);
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.findAll(TitleSuggestionsItem).length).toBe(2);
|
||||
expect(wrapper.findAllComponents(TitleSuggestionsItem).length).toBe(2);
|
||||
});
|
||||
|
||||
it('adds margin class to first item', async () => {
|
||||
|
|
|
@ -65,9 +65,9 @@ describe('RelatedMergeRequests', () => {
|
|||
describe('template', () => {
|
||||
it('should render related merge request items', () => {
|
||||
expect(wrapper.find('[data-testid="count"]').text()).toBe('2');
|
||||
expect(wrapper.findAll(RelatedIssuableItem)).toHaveLength(2);
|
||||
expect(wrapper.findAllComponents(RelatedIssuableItem)).toHaveLength(2);
|
||||
|
||||
const props = wrapper.findAll(RelatedIssuableItem).at(1).props();
|
||||
const props = wrapper.findAllComponents(RelatedIssuableItem).at(1).props();
|
||||
const data = mockData[1];
|
||||
|
||||
expect(props.idKey).toEqual(data.id);
|
||||
|
|
|
@ -70,12 +70,12 @@ describe('HeaderActions component', () => {
|
|||
const findDropdownBy = (dataTestId) => wrapper.find(`[data-testid="${dataTestId}"]`);
|
||||
const findMobileDropdown = () => findDropdownBy('mobile-dropdown');
|
||||
const findDesktopDropdown = () => findDropdownBy('desktop-dropdown');
|
||||
const findMobileDropdownItems = () => findMobileDropdown().findAll(GlDropdownItem);
|
||||
const findDesktopDropdownItems = () => findDesktopDropdown().findAll(GlDropdownItem);
|
||||
const findMobileDropdownItems = () => findMobileDropdown().findAllComponents(GlDropdownItem);
|
||||
const findDesktopDropdownItems = () => findDesktopDropdown().findAllComponents(GlDropdownItem);
|
||||
|
||||
const findModal = () => wrapper.findComponent(GlModal);
|
||||
|
||||
const findModalLinkAt = (index) => findModal().findAll(GlLink).at(index);
|
||||
const findModalLinkAt = (index) => findModal().findAllComponents(GlLink).at(index);
|
||||
|
||||
const mountComponent = ({
|
||||
props = {},
|
||||
|
|
|
@ -61,7 +61,7 @@ describe('Incident Tabs component', () => {
|
|||
);
|
||||
};
|
||||
|
||||
const findTabs = () => wrapper.findAll(GlTab);
|
||||
const findTabs = () => wrapper.findAllComponents(GlTab);
|
||||
const findSummaryTab = () => findTabs().at(0);
|
||||
const findAlertDetailsTab = () => wrapper.find('[data-testid="alert-details-tab"]');
|
||||
const findAlertDetailsComponent = () => wrapper.findComponent(AlertDetailsTable);
|
||||
|
|
|
@ -59,7 +59,7 @@ describe('IncidentTimelineEventList', () => {
|
|||
};
|
||||
|
||||
const findTimelineEventGroups = () => wrapper.findAllByTestId('timeline-group');
|
||||
const findItems = (base = wrapper) => base.findAll(IncidentTimelineEventItem);
|
||||
const findItems = (base = wrapper) => base.findAllComponents(IncidentTimelineEventItem);
|
||||
const findFirstTimelineEventGroup = () => findTimelineEventGroups().at(0);
|
||||
const findSecondTimelineEventGroup = () => findTimelineEventGroups().at(1);
|
||||
const findDates = () => wrapper.findAllByTestId('event-date');
|
||||
|
|
|
@ -9,7 +9,7 @@ const plainStatusUrl = 'https://status.com';
|
|||
describe('PinnedLinks', () => {
|
||||
let wrapper;
|
||||
|
||||
const findButtons = () => wrapper.findAll(GlButton);
|
||||
const findButtons = () => wrapper.findAllComponents(GlButton);
|
||||
|
||||
const createComponent = (props) => {
|
||||
wrapper = shallowMount(PinnedLinks, {
|
||||
|
|
|
@ -50,7 +50,7 @@ describe('GroupsList', () => {
|
|||
|
||||
const findGlAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findAllItems = () => wrapper.findAll(GroupsListItem);
|
||||
const findAllItems = () => wrapper.findAllComponents(GroupsListItem);
|
||||
const findFirstItem = () => findAllItems().at(0);
|
||||
const findSecondItem = () => findAllItems().at(1);
|
||||
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
|
|
|
@ -288,7 +288,7 @@ describe('JiraImportForm', () => {
|
|||
});
|
||||
|
||||
it('updates the user list', () => {
|
||||
expect(getUserDropdown().findAll(GlDropdownItem)).toHaveLength(1);
|
||||
expect(getUserDropdown().findAllComponents(GlDropdownItem)).toHaveLength(1);
|
||||
expect(getUserDropdown().findComponent(GlDropdownItem).text()).toContain(
|
||||
'fchopin (Frederic Chopin)',
|
||||
);
|
||||
|
|
|
@ -103,12 +103,12 @@ describe('Milestone combobox component', () => {
|
|||
const findProjectMilestonesSection = () =>
|
||||
wrapper.find('[data-testid="project-milestones-section"]');
|
||||
const findProjectMilestonesDropdownItems = () =>
|
||||
findProjectMilestonesSection().findAll(GlDropdownItem);
|
||||
findProjectMilestonesSection().findAllComponents(GlDropdownItem);
|
||||
const findFirstProjectMilestonesDropdownItem = () => findProjectMilestonesDropdownItems().at(0);
|
||||
|
||||
const findGroupMilestonesSection = () => wrapper.find('[data-testid="group-milestones-section"]');
|
||||
const findGroupMilestonesDropdownItems = () =>
|
||||
findGroupMilestonesSection().findAll(GlDropdownItem);
|
||||
findGroupMilestonesSection().findAllComponents(GlDropdownItem);
|
||||
const findFirstGroupMilestonesDropdownItem = () => findGroupMilestonesDropdownItems().at(0);
|
||||
|
||||
//
|
||||
|
|
|
@ -57,7 +57,7 @@ describe('CustomNotificationsModal', () => {
|
|||
}
|
||||
|
||||
const findModalBodyDescription = () => wrapper.findComponent(GlSprintf);
|
||||
const findAllCheckboxes = () => wrapper.findAll(GlFormCheckbox);
|
||||
const findAllCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
|
||||
const findCheckboxAt = (index) => findAllCheckboxes().at(index);
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -42,7 +42,8 @@ describe('NotificationsDropdown', () => {
|
|||
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`);
|
||||
const findAllNotificationsDropdownItems = () => wrapper.findAll(NotificationsDropdownItem);
|
||||
const findAllNotificationsDropdownItems = () =>
|
||||
wrapper.findAllComponents(NotificationsDropdownItem);
|
||||
const findDropdownItemAt = (index) =>
|
||||
findAllNotificationsDropdownItems().at(index).findComponent(GlDropdownItem);
|
||||
const findNotificationsModal = () => wrapper.findComponent(CustomNotificationsModal);
|
||||
|
|
|
@ -32,7 +32,7 @@ describe('tags list row', () => {
|
|||
const findShortRevision = () => wrapper.find('[data-testid="digest"]');
|
||||
const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
|
||||
const findTimeAgoTooltip = () => wrapper.findComponent(TimeAgoTooltip);
|
||||
const findDetailsRows = () => wrapper.findAll(DetailsRow);
|
||||
const findDetailsRows = () => wrapper.findAllComponents(DetailsRow);
|
||||
const findPublishedDateDetail = () => wrapper.find('[data-testid="published-date-detail"]');
|
||||
const findManifestDetail = () => wrapper.find('[data-testid="manifest-detail"]');
|
||||
const findConfigurationDetail = () => wrapper.find('[data-testid="configuration-detail"]');
|
||||
|
|
|
@ -5,7 +5,7 @@ import { GlSkeletonLoader } from '../../stubs';
|
|||
describe('TagsLoader component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findGlSkeletonLoaders = () => wrapper.findAll(GlSkeletonLoader);
|
||||
const findGlSkeletonLoaders = () => wrapper.findAllComponents(GlSkeletonLoader);
|
||||
|
||||
const mountComponent = () => {
|
||||
wrapper = shallowMount(component, {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { imagesListResponse, pageInfo as defaultPageInfo } from '../../mock_data
|
|||
describe('Image List', () => {
|
||||
let wrapper;
|
||||
|
||||
const findRow = () => wrapper.findAll(ImageListRow);
|
||||
const findRow = () => wrapper.findAllComponents(ImageListRow);
|
||||
const findPagination = () => wrapper.findComponent(GlKeysetPagination);
|
||||
|
||||
const mountComponent = (props) => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { harborImagesList } from '../../mock_data';
|
|||
describe('Harbor List', () => {
|
||||
let wrapper;
|
||||
|
||||
const findHarborListRow = () => wrapper.findAll(HarborListRow);
|
||||
const findHarborListRow = () => wrapper.findAllComponents(HarborListRow);
|
||||
|
||||
const mountComponent = (props) => {
|
||||
wrapper = shallowMount(HarborList, {
|
||||
|
|
|
@ -7,7 +7,7 @@ describe('packages_filter', () => {
|
|||
let wrapper;
|
||||
|
||||
const findFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
|
||||
const findFilteredSearchSuggestions = () => wrapper.findAll(GlFilteredSearchSuggestion);
|
||||
const findFilteredSearchSuggestions = () => wrapper.findAllComponents(GlFilteredSearchSuggestion);
|
||||
|
||||
const mountComponent = ({ attrs, listeners } = {}) => {
|
||||
wrapper = shallowMount(component, {
|
||||
|
|
|
@ -23,7 +23,7 @@ describe('cli_commands', () => {
|
|||
let wrapper;
|
||||
|
||||
const findDropdownButton = () => wrapper.findComponent(GlDropdown);
|
||||
const findCodeInstruction = () => wrapper.findAll(CodeInstruction);
|
||||
const findCodeInstruction = () => wrapper.findAllComponents(CodeInstruction);
|
||||
|
||||
const mountComponent = () => {
|
||||
wrapper = mount(QuickstartDropdown, {
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('BitbucketServerStatusTable', () => {
|
|||
|
||||
const findReconfigureButton = () =>
|
||||
wrapper
|
||||
.findAll(GlButton)
|
||||
.findAllComponents(GlButton)
|
||||
.filter((w) => w.props().variant === 'info')
|
||||
.at(0);
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ describe('ForkForm component', () => {
|
|||
it('displays the correct description', () => {
|
||||
createComponent();
|
||||
|
||||
const formRadios = wrapper.findAll(GlFormRadio);
|
||||
const formRadios = wrapper.findAllComponents(GlFormRadio);
|
||||
|
||||
Object.keys(PROJECT_VISIBILITY_TYPE).forEach((visibilityType, index) => {
|
||||
expect(formRadios.at(index).text()).toBe(PROJECT_VISIBILITY_TYPE[visibilityType]);
|
||||
|
@ -210,7 +210,7 @@ describe('ForkForm component', () => {
|
|||
it('displays all 3 visibility levels', () => {
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.findAll(GlFormRadio)).toHaveLength(3);
|
||||
expect(wrapper.findAllComponents(GlFormRadio)).toHaveLength(3);
|
||||
});
|
||||
|
||||
describe('when the namespace is changed', () => {
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('Code Coverage', () => {
|
|||
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findAreaChart = () => wrapper.findComponent(GlAreaChart);
|
||||
const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
|
||||
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findFirstDropdownItem = () => findAllDropdownItems().at(0);
|
||||
const findSecondDropdownItem = () => findAllDropdownItems().at(1);
|
||||
const findDownloadButton = () => wrapper.find('[data-testid="download-button"]');
|
||||
|
|
|
@ -119,7 +119,7 @@ describe('Pipeline editor branch switcher', () => {
|
|||
};
|
||||
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findDropdownItems = () => wrapper.findAll(GlDropdownItem);
|
||||
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const findInfiniteScroll = () => wrapper.findComponent(GlInfiniteScroll);
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('Pipeline editor file nav', () => {
|
|||
|
||||
const findTip = () => wrapper.findComponent(GlAlert);
|
||||
const findCurrentConfigFilename = () => wrapper.findByTestId('current-config-filename');
|
||||
const fileTreeItems = () => wrapper.findAll(PipelineEditorFileTreeItem);
|
||||
const fileTreeItems = () => wrapper.findAllComponents(PipelineEditorFileTreeItem);
|
||||
|
||||
afterEach(() => {
|
||||
localStorage.clear();
|
||||
|
|
|
@ -58,7 +58,7 @@ describe('~/pipeline_editor/components/ui/editor_tab.vue', () => {
|
|||
|
||||
const findSlotComponent = () => wrapper.findComponent(MockSourceEditor);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findBadges = () => wrapper.findAll(GlBadge);
|
||||
const findBadges = () => wrapper.findAllComponents(GlBadge);
|
||||
|
||||
beforeEach(() => {
|
||||
mockChildMounted = jest.fn();
|
||||
|
|
|
@ -20,7 +20,7 @@ describe('Pipeline New Form', () => {
|
|||
let mock;
|
||||
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findRefsDropdownItems = () => wrapper.findAll(GlDropdownItem);
|
||||
const findRefsDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
|
||||
const createComponent = (props = {}, mountFn = shallowMount) => {
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
describe('Pipeline DAG graph wrapper', () => {
|
||||
let wrapper;
|
||||
const getAlert = () => wrapper.findComponent(GlAlert);
|
||||
const getAllAlerts = () => wrapper.findAll(GlAlert);
|
||||
const getAllAlerts = () => wrapper.findAllComponents(GlAlert);
|
||||
const getGraph = () => wrapper.findComponent(DagGraph);
|
||||
const getNotes = () => wrapper.findComponent(DagAnnotations);
|
||||
const getErrorText = (type) => wrapper.vm.$options.errorTexts[type];
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue