Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bfd344aeac
commit
37a739daec
|
|
@ -261,6 +261,66 @@ ee:decomposition-multiple-db-parallel:
|
||||||
- !reference [.rules:test:qa-parallel, rules]
|
- !reference [.rules:test:qa-parallel, rules]
|
||||||
- if: $QA_SUITES =~ /Test::Instance::All/
|
- if: $QA_SUITES =~ /Test::Instance::All/
|
||||||
|
|
||||||
|
ee:object-storage:
|
||||||
|
extends: .qa
|
||||||
|
variables:
|
||||||
|
QA_SCENARIO: Test::Instance::Image
|
||||||
|
QA_RSPEC_TAGS: --tag object_storage
|
||||||
|
GITLAB_QA_OPTS: --omnibus-config object_storage
|
||||||
|
rules:
|
||||||
|
- !reference [.rules:test:qa-non-parallel, rules]
|
||||||
|
- if: $QA_SUITES =~ /Test::Instance::ObjectStorage/
|
||||||
|
ee:object-storage-parallel:
|
||||||
|
extends: ee:object-storage
|
||||||
|
parallel: 2
|
||||||
|
rules:
|
||||||
|
- !reference [.rules:test:qa-parallel, rules]
|
||||||
|
- if: $QA_SUITES =~ /Test::Instance::ObjectStorage/
|
||||||
|
|
||||||
|
ee:object-storage-aws:
|
||||||
|
extends: ee:object-storage
|
||||||
|
variables:
|
||||||
|
AWS_S3_ACCESS_KEY: $QA_AWS_S3_ACCESS_KEY
|
||||||
|
AWS_S3_BUCKET_NAME: $QA_AWS_S3_BUCKET_NAME
|
||||||
|
AWS_S3_KEY_ID: $QA_AWS_S3_KEY_ID
|
||||||
|
AWS_S3_REGION: $QA_AWS_S3_REGION
|
||||||
|
GITLAB_QA_OPTS: --omnibus-config object_storage_aws
|
||||||
|
ee:object-storage-aws-parallel:
|
||||||
|
extends: ee:object-storage-aws
|
||||||
|
parallel: 2
|
||||||
|
rules:
|
||||||
|
- !reference [ee:object-storage-parallel, rules]
|
||||||
|
|
||||||
|
ee:object-storage-gcs:
|
||||||
|
extends: ee:object-storage
|
||||||
|
variables:
|
||||||
|
GCS_BUCKET_NAME: $QA_GCS_BUCKET_NAME
|
||||||
|
GOOGLE_PROJECT: $QA_GOOGLE_PROJECT
|
||||||
|
GOOGLE_JSON_KEY: $QA_GOOGLE_JSON_KEY
|
||||||
|
GOOGLE_CLIENT_EMAIL: $QA_GOOGLE_CLIENT_EMAIL
|
||||||
|
GITLAB_QA_OPTS: --omnibus-config object_storage_gcs
|
||||||
|
ee:object-storage-gcs-parallel:
|
||||||
|
extends: ee:object-storage-gcs
|
||||||
|
parallel: 2
|
||||||
|
rules:
|
||||||
|
- !reference [ee:object-storage-parallel, rules]
|
||||||
|
|
||||||
|
ee:packages:
|
||||||
|
extends: .qa
|
||||||
|
variables:
|
||||||
|
QA_SCENARIO: Test::Instance::Image
|
||||||
|
QA_RSPEC_TAGS: --tag packages
|
||||||
|
GITLAB_QA_OPTS: --omnibus-config packages
|
||||||
|
rules:
|
||||||
|
- !reference [.rules:test:qa-non-parallel, rules]
|
||||||
|
- if: $QA_SUITES =~ /Test::Instance::Packages/
|
||||||
|
ee:packages-parallel:
|
||||||
|
extends: ee:packages
|
||||||
|
parallel: 2
|
||||||
|
rules:
|
||||||
|
- !reference [.rules:test:qa-parallel, rules]
|
||||||
|
- if: $QA_SUITES =~ /Test::Instance::Packages/
|
||||||
|
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
# Non parallel jobs
|
# Non parallel jobs
|
||||||
# ------------------------------------------
|
# ------------------------------------------
|
||||||
|
|
@ -370,9 +430,6 @@ ee:registry:
|
||||||
|
|
||||||
ee:registry-with-cdn:
|
ee:registry-with-cdn:
|
||||||
extends: .qa
|
extends: .qa
|
||||||
before_script:
|
|
||||||
- unset GITLAB_QA_ADMIN_ACCESS_TOKEN
|
|
||||||
- !reference [.gitlab-qa-install, before_script]
|
|
||||||
variables:
|
variables:
|
||||||
QA_SCENARIO: Test::Integration::RegistryWithCDN
|
QA_SCENARIO: Test::Integration::RegistryWithCDN
|
||||||
GCS_CDN_BUCKET_NAME: $QA_GCS_CDN_BUCKET_NAME
|
GCS_CDN_BUCKET_NAME: $QA_GCS_CDN_BUCKET_NAME
|
||||||
|
|
@ -380,6 +437,9 @@ ee:registry-with-cdn:
|
||||||
GOOGLE_CDN_JSON_KEY: $QA_GOOGLE_CDN_JSON_KEY
|
GOOGLE_CDN_JSON_KEY: $QA_GOOGLE_CDN_JSON_KEY
|
||||||
GOOGLE_CDN_SIGNURL_KEY: $QA_GOOGLE_CDN_SIGNURL_KEY
|
GOOGLE_CDN_SIGNURL_KEY: $QA_GOOGLE_CDN_SIGNURL_KEY
|
||||||
GOOGLE_CDN_SIGNURL_KEY_NAME: $QA_GOOGLE_CDN_SIGNURL_KEY_NAME
|
GOOGLE_CDN_SIGNURL_KEY_NAME: $QA_GOOGLE_CDN_SIGNURL_KEY_NAME
|
||||||
|
before_script:
|
||||||
|
- unset GITLAB_QA_ADMIN_ACCESS_TOKEN
|
||||||
|
- !reference [.qa, before_script]
|
||||||
rules:
|
rules:
|
||||||
- !reference [.rules:test:qa, rules]
|
- !reference [.rules:test:qa, rules]
|
||||||
- if: $QA_SUITES =~ /Test::Integration::RegistryWithCDN/
|
- if: $QA_SUITES =~ /Test::Integration::RegistryWithCDN/
|
||||||
|
|
@ -434,55 +494,17 @@ ee:metrics:
|
||||||
- !reference [.rules:test:qa, rules]
|
- !reference [.rules:test:qa, rules]
|
||||||
- if: $QA_SUITES =~ /Test::Instance::Metrics/
|
- if: $QA_SUITES =~ /Test::Instance::Metrics/
|
||||||
|
|
||||||
ee:packages:
|
|
||||||
extends: .qa
|
|
||||||
variables:
|
|
||||||
QA_SCENARIO: Test::Instance::Image
|
|
||||||
QA_RSPEC_TAGS: --tag packages
|
|
||||||
GITLAB_QA_OPTS: --omnibus-config packages
|
|
||||||
rules:
|
|
||||||
- !reference [.rules:test:qa, rules]
|
|
||||||
- if: $QA_SUITES =~ /Test::Instance::Packages/
|
|
||||||
|
|
||||||
ee:elasticsearch:
|
ee:elasticsearch:
|
||||||
extends: .qa
|
extends: .qa
|
||||||
variables:
|
variables:
|
||||||
QA_SCENARIO: "Test::Integration::Elasticsearch"
|
QA_SCENARIO: "Test::Integration::Elasticsearch"
|
||||||
script:
|
before_script:
|
||||||
- unset ELASTIC_URL # unset url which is globally defined in .gitlab-ci.yml
|
- unset ELASTIC_URL # unset url which is globally defined in .gitlab-ci.yml
|
||||||
- !reference [.qa, script]
|
- !reference [.qa, before_script]
|
||||||
rules:
|
rules:
|
||||||
- !reference [.rules:test:qa, rules]
|
- !reference [.rules:test:qa, rules]
|
||||||
- if: $QA_SUITES =~ /Test::Integration::Elasticsearch/
|
- if: $QA_SUITES =~ /Test::Integration::Elasticsearch/
|
||||||
|
|
||||||
ee:object-storage:
|
|
||||||
extends: .qa
|
|
||||||
variables:
|
|
||||||
QA_SCENARIO: Test::Instance::Image
|
|
||||||
QA_RSPEC_TAGS: --tag object_storage
|
|
||||||
GITLAB_QA_OPTS: --omnibus-config object_storage
|
|
||||||
rules:
|
|
||||||
- !reference [.rules:test:qa, rules]
|
|
||||||
- if: $QA_SUITES =~ /Test::Instance::ObjectStorage/
|
|
||||||
|
|
||||||
ee:object-storage-aws:
|
|
||||||
extends: ee:object-storage
|
|
||||||
variables:
|
|
||||||
AWS_S3_ACCESS_KEY: $QA_AWS_S3_ACCESS_KEY
|
|
||||||
AWS_S3_BUCKET_NAME: $QA_AWS_S3_BUCKET_NAME
|
|
||||||
AWS_S3_KEY_ID: $QA_AWS_S3_KEY_ID
|
|
||||||
AWS_S3_REGION: $QA_AWS_S3_REGION
|
|
||||||
GITLAB_QA_OPTS: --omnibus-config object_storage_aws
|
|
||||||
|
|
||||||
ee:object-storage-gcs:
|
|
||||||
extends: ee:object-storage
|
|
||||||
variables:
|
|
||||||
GCS_BUCKET_NAME: $QA_GCS_BUCKET_NAME
|
|
||||||
GOOGLE_PROJECT: $QA_GOOGLE_PROJECT
|
|
||||||
GOOGLE_JSON_KEY: $QA_GOOGLE_JSON_KEY
|
|
||||||
GOOGLE_CLIENT_EMAIL: $QA_GOOGLE_CLIENT_EMAIL
|
|
||||||
GITLAB_QA_OPTS: --omnibus-config object_storage_gcs
|
|
||||||
|
|
||||||
ee:registry-object-storage-tls:
|
ee:registry-object-storage-tls:
|
||||||
extends: ee:object-storage-aws
|
extends: ee:object-storage-aws
|
||||||
variables:
|
variables:
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,6 @@ Layout/FirstArrayElementIndentation:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'ee/lib/ee/api/helpers/award_emoji.rb'
|
- 'ee/lib/ee/api/helpers/award_emoji.rb'
|
||||||
- 'ee/spec/graphql/mutations/incident_management/escalation_policy/create_spec.rb'
|
- 'ee/spec/graphql/mutations/incident_management/escalation_policy/create_spec.rb'
|
||||||
- 'ee/spec/graphql/resolvers/dora_metrics_resolver_spec.rb'
|
|
||||||
- 'ee/spec/graphql/resolvers/security_orchestration/scan_execution_policy_resolver_spec.rb'
|
|
||||||
- 'ee/spec/graphql/resolvers/timebox_report_resolver_spec.rb'
|
|
||||||
- 'ee/spec/graphql/types/ci/pipeline_type_spec.rb'
|
|
||||||
- 'ee/spec/graphql/types/dast_scanner_profile_type_spec.rb'
|
|
||||||
- 'ee/spec/graphql/types/dast_site_profile_type_spec.rb'
|
|
||||||
- 'ee/spec/helpers/paid_feature_callout_helper_spec.rb'
|
|
||||||
- 'ee/spec/helpers/trial_status_widget_helper_spec.rb'
|
|
||||||
- 'ee/spec/lib/ee/gitlab/auth/ldap/access_levels_spec.rb'
|
|
||||||
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
|
|
||||||
- 'ee/spec/lib/ee/gitlab/usage_data_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/checks/diff_check_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/ci/config/security_orchestration_policies/processor_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/ci/templates/Jobs/browser_performance_testing_gitlab_ci_yaml_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/ci/templates/Jobs/dast_default_branch_gitlab_ci_yaml_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/ci/templates/Jobs/load_performance_testing_gitlab_ci_yaml_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/ci/yaml_processor_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/graphql/aggregations/epics/epic_node_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/graphql/aggregations/epics/lazy_links_aggregate_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/graphql/aggregations/issues/lazy_links_aggregate_spec.rb'
|
|
||||||
- 'ee/spec/lib/gitlab/graphql/loaders/bulk_epic_aggregate_loader_spec.rb'
|
- 'ee/spec/lib/gitlab/graphql/loaders/bulk_epic_aggregate_loader_spec.rb'
|
||||||
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_ci_builds_metric_spec.rb'
|
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_ci_builds_metric_spec.rb'
|
||||||
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_ci_builds_metric_spec.rb'
|
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_ci_builds_metric_spec.rb'
|
||||||
|
|
|
||||||
|
|
@ -428,6 +428,7 @@ RSpec/ExpectChange:
|
||||||
- 'spec/models/project_auto_devops_spec.rb'
|
- 'spec/models/project_auto_devops_spec.rb'
|
||||||
- 'spec/models/project_import_state_spec.rb'
|
- 'spec/models/project_import_state_spec.rb'
|
||||||
- 'spec/models/project_spec.rb'
|
- 'spec/models/project_spec.rb'
|
||||||
|
- 'spec/models/project_statistics_spec.rb'
|
||||||
- 'spec/models/projects/build_artifacts_size_refresh_spec.rb'
|
- 'spec/models/projects/build_artifacts_size_refresh_spec.rb'
|
||||||
- 'spec/models/projects/ci_feature_usage_spec.rb'
|
- 'spec/models/projects/ci_feature_usage_spec.rb'
|
||||||
- 'spec/models/release_spec.rb'
|
- 'spec/models/release_spec.rb'
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,7 @@ RSpec/PredicateMatcher:
|
||||||
- 'spec/models/concerns/awardable_spec.rb'
|
- 'spec/models/concerns/awardable_spec.rb'
|
||||||
- 'spec/models/concerns/chronic_duration_attribute_spec.rb'
|
- 'spec/models/concerns/chronic_duration_attribute_spec.rb'
|
||||||
- 'spec/models/concerns/ci/has_deployment_name_spec.rb'
|
- 'spec/models/concerns/ci/has_deployment_name_spec.rb'
|
||||||
|
- 'spec/models/concerns/counter_attribute_spec.rb'
|
||||||
- 'spec/models/concerns/featurable_spec.rb'
|
- 'spec/models/concerns/featurable_spec.rb'
|
||||||
- 'spec/models/concerns/ignorable_columns_spec.rb'
|
- 'spec/models/concerns/ignorable_columns_spec.rb'
|
||||||
- 'spec/models/concerns/integrations/has_data_fields_spec.rb'
|
- 'spec/models/concerns/integrations/has_data_fields_spec.rb'
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,10 @@ class Projects::BlameController < Projects::ApplicationController
|
||||||
environment_params[:find_latest] = true
|
environment_params[:find_latest] = true
|
||||||
@environment = ::Environments::EnvironmentsByDeploymentsFinder.new(@project, current_user, environment_params).execute.last
|
@environment = ::Environments::EnvironmentsByDeploymentsFinder.new(@project, current_user, environment_params).execute.last
|
||||||
|
|
||||||
blame_service = Projects::BlameService.new(@blob, @commit, params.permit(:page))
|
blame_service = Projects::BlameService.new(@blob, @commit, params.permit(:page, :no_pagination))
|
||||||
|
|
||||||
@blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate!
|
@blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate!
|
||||||
|
@blame_pagination = blame_service.pagination
|
||||||
render locals: { blame_pagination: blame_service.pagination }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,20 +64,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
|
||||||
|
|
||||||
return unless stale?(etag: [cache_context + diff_options_hash.fetch(:paths, []), diffs])
|
return unless stale?(etag: [cache_context + diff_options_hash.fetch(:paths, []), diffs])
|
||||||
|
|
||||||
if diff_options_hash[:paths].blank?
|
render json: PaginatedDiffSerializer.new(current_user: current_user).represent(diffs, options)
|
||||||
if Feature.enabled?(:remove_caching_diff_batches, @merge_request.project)
|
|
||||||
render json: PaginatedDiffSerializer.new(current_user: current_user).represent(diffs, options)
|
|
||||||
else
|
|
||||||
render_cached(
|
|
||||||
diffs,
|
|
||||||
with: PaginatedDiffSerializer.new(current_user: current_user),
|
|
||||||
cache_context: -> (_) { [Digest::SHA256.hexdigest(cache_context.to_s)] },
|
|
||||||
**options
|
|
||||||
)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
render json: PaginatedDiffSerializer.new(current_user: current_user).represent(diffs, options)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
# rubocop: enable Metrics/AbcSize
|
# rubocop: enable Metrics/AbcSize
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,12 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli
|
||||||
end
|
end
|
||||||
|
|
||||||
if Gitlab::Utils.to_boolean(approve_params[:approve])
|
if Gitlab::Utils.to_boolean(approve_params[:approve])
|
||||||
success = ::MergeRequests::ApprovalService.new(project: @project, current_user: current_user, params: approve_params).execute(merge_request)
|
unless merge_request.approved_by?(current_user)
|
||||||
|
success = ::MergeRequests::ApprovalService.new(project: @project, current_user: current_user, params: approve_params).execute(merge_request)
|
||||||
|
|
||||||
unless success
|
unless success
|
||||||
return render json: { message: _('An error occurred while approving, please try again.') }, status: :internal_server_error
|
return render json: { message: _('An error occurred while approving, please try again.') }, status: :internal_server_error
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
merge_request_activity_counter.track_submit_review_approve(user: current_user)
|
merge_request_activity_counter.track_submit_review_approve(user: current_user)
|
||||||
|
|
|
||||||
|
|
@ -92,32 +92,6 @@ module BlobHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace_blob_link(project = @project, ref = @ref, path = @path, blob:)
|
|
||||||
modify_file_button(
|
|
||||||
project,
|
|
||||||
ref,
|
|
||||||
path,
|
|
||||||
blob: blob,
|
|
||||||
label: _("Replace"),
|
|
||||||
action: "replace",
|
|
||||||
btn_class: "default",
|
|
||||||
modal_type: "upload"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete_blob_link(project = @project, ref = @ref, path = @path, blob:)
|
|
||||||
modify_file_button(
|
|
||||||
project,
|
|
||||||
ref,
|
|
||||||
path,
|
|
||||||
blob: blob,
|
|
||||||
label: _("Delete"),
|
|
||||||
action: "delete",
|
|
||||||
btn_class: "default",
|
|
||||||
modal_type: "remove"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def can_modify_blob?(blob, project = @project, ref = @ref)
|
def can_modify_blob?(blob, project = @project, ref = @ref)
|
||||||
!blob.stored_externally? && can_edit_tree?(project, ref)
|
!blob.stored_externally? && can_edit_tree?(project, ref)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,10 @@ module CounterAttribute
|
||||||
def counter_attribute_after_flush(&callback)
|
def counter_attribute_after_flush(&callback)
|
||||||
after_flush_callbacks << callback
|
after_flush_callbacks << callback
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def counter_attribute_enabled?(attribute)
|
||||||
|
counter_attributes.include?(attribute)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# This method must only be called by FlushCounterIncrementsWorker
|
# This method must only be called by FlushCounterIncrementsWorker
|
||||||
|
|
@ -157,7 +161,7 @@ module CounterAttribute
|
||||||
end
|
end
|
||||||
|
|
||||||
def counter_attribute_enabled?(attribute)
|
def counter_attribute_enabled?(attribute)
|
||||||
self.class.counter_attributes.include?(attribute)
|
self.class.counter_attribute_enabled?(attribute)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ class ProjectStatistics < ApplicationRecord
|
||||||
default_value_for :snippets_size, 0
|
default_value_for :snippets_size, 0
|
||||||
|
|
||||||
counter_attribute :build_artifacts_size
|
counter_attribute :build_artifacts_size
|
||||||
counter_attribute :storage_size
|
|
||||||
|
|
||||||
counter_attribute_after_flush do |project_statistic|
|
counter_attribute_after_flush do |project_statistic|
|
||||||
|
project_statistic.refresh_storage_size!
|
||||||
|
|
||||||
Namespaces::ScheduleAggregationWorker.perform_async(project_statistic.namespace_id)
|
Namespaces::ScheduleAggregationWorker.perform_async(project_statistic.namespace_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -21,7 +22,6 @@ class ProjectStatistics < ApplicationRecord
|
||||||
|
|
||||||
COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count, :snippets_size, :uploads_size, :container_registry_size].freeze
|
COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count, :snippets_size, :uploads_size, :container_registry_size].freeze
|
||||||
INCREMENTABLE_COLUMNS = {
|
INCREMENTABLE_COLUMNS = {
|
||||||
build_artifacts_size: %i[storage_size],
|
|
||||||
packages_size: %i[storage_size],
|
packages_size: %i[storage_size],
|
||||||
pipeline_artifacts_size: %i[storage_size],
|
pipeline_artifacts_size: %i[storage_size],
|
||||||
snippets_size: %i[storage_size]
|
snippets_size: %i[storage_size]
|
||||||
|
|
@ -109,21 +109,25 @@ class ProjectStatistics < ApplicationRecord
|
||||||
self.storage_size = storage_size
|
self.storage_size = storage_size
|
||||||
end
|
end
|
||||||
|
|
||||||
# Since this incremental update method does not call update_storage_size above,
|
def refresh_storage_size!
|
||||||
# we have to update the storage_size here as additional column.
|
update_storage_size
|
||||||
# Additional columns are updated depending on key => [columns], which allows
|
save!
|
||||||
# to update statistics which are and also those which aren't included in storage_size
|
end
|
||||||
# or any other additional summary column in the future.
|
|
||||||
|
# Since this incremental update method does not call update_storage_size above through before_save,
|
||||||
|
# we have to update the storage_size separately.
|
||||||
|
#
|
||||||
|
# For counter attributes, storage_size will be refreshed after the counter is flushed,
|
||||||
|
# through counter_attribute_after_flush
|
||||||
|
#
|
||||||
|
# For non-counter attributes, storage_size is updated depending on key => [columns] in INCREMENTABLE_COLUMNS
|
||||||
def self.increment_statistic(project, key, amount)
|
def self.increment_statistic(project, key, amount)
|
||||||
raise ArgumentError, "Cannot increment attribute: #{key}" unless INCREMENTABLE_COLUMNS.key?(key)
|
raise ArgumentError, "Cannot increment attribute: #{key}" unless incrementable_attribute?(key)
|
||||||
return if amount == 0
|
return if amount == 0
|
||||||
|
|
||||||
project.statistics.try do |project_statistics|
|
project.statistics.try do |project_statistics|
|
||||||
if project_statistics.counter_attribute_enabled?(key)
|
if counter_attribute_enabled?(key)
|
||||||
statistics_to_increment = [key] + INCREMENTABLE_COLUMNS[key].to_a
|
project_statistics.delayed_increment_counter(key, amount)
|
||||||
statistics_to_increment.each do |statistic|
|
|
||||||
project_statistics.delayed_increment_counter(statistic, amount)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
legacy_increment_statistic(project, key, amount)
|
legacy_increment_statistic(project, key, amount)
|
||||||
end
|
end
|
||||||
|
|
@ -149,6 +153,10 @@ class ProjectStatistics < ApplicationRecord
|
||||||
update_all(updates.join(', '))
|
update_all(updates.join(', '))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.incrementable_attribute?(key)
|
||||||
|
INCREMENTABLE_COLUMNS.key?(key) || counter_attribute_enabled?(key)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def schedule_namespace_aggregation_worker
|
def schedule_namespace_aggregation_worker
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,24 @@ module Packages
|
||||||
|
|
||||||
overrides(:read_package)
|
overrides(:read_package)
|
||||||
|
|
||||||
rule { anonymous & ~project.public_project }.prevent_all
|
condition(:package_registry_access_level_feature_flag_enabled, scope: :subject) do
|
||||||
|
::Feature.enabled?(:package_registry_access_level, @subject)
|
||||||
|
end
|
||||||
|
|
||||||
rule { ~project.public_project & ~project.internal_access & ~project.project_allowed_for_job_token }.prevent_all
|
condition(:packages_enabled_for_everyone, scope: :subject) do
|
||||||
|
@subject.package_registry_access_level == ProjectFeature::PUBLIC
|
||||||
|
end
|
||||||
|
|
||||||
|
# This rule can be removed if the `package_registry_access_level` feature flag is removed.
|
||||||
|
# Reason: If the feature flag is globally enabled, this rule will never be executed.
|
||||||
|
rule { anonymous & ~project.public_project & ~package_registry_access_level_feature_flag_enabled }.prevent_all
|
||||||
|
|
||||||
|
# This rule can be removed if the `package_registry_access_level` feature flag is removed.
|
||||||
|
# Reason: If the feature flag is globally enabled, this rule will never be executed.
|
||||||
|
rule do
|
||||||
|
~project.public_project & ~project.internal_access &
|
||||||
|
~project.project_allowed_for_job_token & ~package_registry_access_level_feature_flag_enabled
|
||||||
|
end.prevent_all
|
||||||
|
|
||||||
rule { project.packages_disabled }.policy do
|
rule { project.packages_disabled }.policy do
|
||||||
prevent(:read_package)
|
prevent(:read_package)
|
||||||
|
|
@ -30,6 +45,10 @@ module Packages
|
||||||
rule { project.write_package_registry_deploy_token }.policy do
|
rule { project.write_package_registry_deploy_token }.policy do
|
||||||
enable :read_package
|
enable :read_package
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rule { package_registry_access_level_feature_flag_enabled & packages_enabled_for_everyone }.policy do
|
||||||
|
enable :read_package
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ module Projects
|
||||||
@blob = blob
|
@blob = blob
|
||||||
@commit = commit
|
@commit = commit
|
||||||
@page = extract_page(params)
|
@page = extract_page(params)
|
||||||
|
@pagination_enabled = pagination_state(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :page
|
attr_reader :page
|
||||||
|
|
@ -19,7 +20,7 @@ module Projects
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination
|
def pagination
|
||||||
return unless pagination_enabled?
|
return unless pagination_enabled
|
||||||
|
|
||||||
Kaminari.paginate_array([], total_count: blob_lines_count, limit: per_page)
|
Kaminari.paginate_array([], total_count: blob_lines_count, limit: per_page)
|
||||||
.tap { |pagination| pagination.max_paginates_per(per_page) }
|
.tap { |pagination| pagination.max_paginates_per(per_page) }
|
||||||
|
|
@ -28,10 +29,10 @@ module Projects
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :blob, :commit
|
attr_reader :blob, :commit, :pagination_enabled
|
||||||
|
|
||||||
def blame_range
|
def blame_range
|
||||||
return unless pagination_enabled?
|
return unless pagination_enabled
|
||||||
|
|
||||||
first_line = (page - 1) * per_page + 1
|
first_line = (page - 1) * per_page + 1
|
||||||
last_line = (first_line + per_page).to_i - 1
|
last_line = (first_line + per_page).to_i - 1
|
||||||
|
|
@ -51,6 +52,12 @@ module Projects
|
||||||
PER_PAGE
|
PER_PAGE
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def pagination_state(params)
|
||||||
|
return false if Gitlab::Utils.to_boolean(params[:no_pagination], default: false)
|
||||||
|
|
||||||
|
Feature.enabled?(:blame_page_pagination, commit.project)
|
||||||
|
end
|
||||||
|
|
||||||
def overlimit?(page)
|
def overlimit?(page)
|
||||||
page * per_page >= blob_lines_count + per_page
|
page * per_page >= blob_lines_count + per_page
|
||||||
end
|
end
|
||||||
|
|
@ -58,9 +65,5 @@ module Projects
|
||||||
def blob_lines_count
|
def blob_lines_count
|
||||||
@blob_lines_count ||= blob.data.lines.count
|
@blob_lines_count ||= blob.data.lines.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def pagination_enabled?
|
|
||||||
Feature.enabled?(:blame_page_pagination, commit.project)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -158,14 +158,25 @@ module Projects
|
||||||
priority: UserProjectAccessChangedService::LOW_PRIORITY
|
priority: UserProjectAccessChangedService::LOW_PRIORITY
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@project.add_owner(@project.namespace.owner, current_user: current_user)
|
owner_user = @project.namespace.owner
|
||||||
|
owner_member = @project.add_owner(owner_user, current_user: current_user)
|
||||||
|
|
||||||
|
# There is a possibility that the sidekiq job to refresh the authorizations of the owner_user in this project
|
||||||
|
# isn't picked up (or finished) by the time the user is redirected to the newly created project's page.
|
||||||
|
# If that happens, the user will hit a 404. To avoid that scenario, we manually create a `project_authorizations` record for the user here.
|
||||||
|
if owner_member.persisted?
|
||||||
|
owner_user.project_authorizations.safe_find_or_create_by(
|
||||||
|
project: @project,
|
||||||
|
access_level: ProjectMember::OWNER
|
||||||
|
)
|
||||||
|
end
|
||||||
# During the process of adding a project owner, a check on permissions is made on the user which caches
|
# During the process of adding a project owner, a check on permissions is made on the user which caches
|
||||||
# the max member access for that user on this project.
|
# the max member access for that user on this project.
|
||||||
# Since that is `0` before the member is created - and we are still inside the request
|
# Since that is `0` before the member is created - and we are still inside the request
|
||||||
# cycle when we need to do other operations that might check those permissions (e.g. write a commit)
|
# cycle when we need to do other operations that might check those permissions (e.g. write a commit)
|
||||||
# we need to purge that cache so that the updated permissions is fetched instead of using the outdated cached value of 0
|
# we need to purge that cache so that the updated permissions is fetched instead of using the outdated cached value of 0
|
||||||
# from before member creation
|
# from before member creation
|
||||||
@project.team.purge_member_access_cache_for_user_id(@project.namespace.owner.id)
|
@project.team.purge_member_access_cache_for_user_id(owner_user.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
- page_title _("Blame"), @blob.path, @ref
|
- page_title _("Blame"), @blob.path, @ref
|
||||||
|
|
||||||
#blob-content-holder.tree-holder
|
#blob-content-holder.tree-holder{ data: { testid: 'blob-content-holder' } }
|
||||||
= render "projects/blob/breadcrumb", blob: @blob, blame: true
|
= render "projects/blob/breadcrumb", blob: @blob, blame: true
|
||||||
|
|
||||||
.file-holder
|
.file-holder.gl-overflow-hidden
|
||||||
= render "projects/blob/header", blob: @blob, blame: true
|
= render "projects/blob/header", blob: @blob, blame: true
|
||||||
|
|
||||||
.file-blame-legend
|
.file-blame-legend
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
%span.legend-box.legend-box-9
|
%span.legend-box.legend-box-9
|
||||||
%span.right-label Older
|
%span.right-label Older
|
||||||
|
|
||||||
.table-responsive.file-content.blame.code{ class: user_color_scheme, data: { qa_selector: 'blame_file_content' } }
|
.table-responsive.file-content.blame.code{ class: "#{user_color_scheme} gl-rounded-0!", data: { qa_selector: 'blame_file_content' } }
|
||||||
%table
|
%table
|
||||||
- current_line = @blame.first_line
|
- current_line = @blame.first_line
|
||||||
- @blame.groups.each do |blame_group|
|
- @blame.groups.each do |blame_group|
|
||||||
|
|
@ -59,5 +59,11 @@
|
||||||
|
|
||||||
- current_line += line_count
|
- current_line += line_count
|
||||||
|
|
||||||
- if blame_pagination
|
- if @blame_pagination
|
||||||
= paginate(blame_pagination, theme: "gitlab")
|
.gl-display-flex.gl-justify-content-center.gl-flex-direction-column.gl-align-items-center.gl-p-3.gl-bg-gray-50.gl-border-t-solid.gl-border-t-1.gl-border-gray-100
|
||||||
|
= _('For faster browsing, not all history is shown.')
|
||||||
|
= render Pajamas::ButtonComponent.new(href: namespace_project_blame_path(namespace_id: @project.namespace, project_id: @project, id: @id, no_pagination: true), size: :small, button_options: { class: 'gl-mt-3' }) do |c|
|
||||||
|
= _('View entire blame')
|
||||||
|
|
||||||
|
- if @blame_pagination
|
||||||
|
= paginate(@blame_pagination, theme: "gitlab")
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,6 @@
|
||||||
.file-actions.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-md-justify-content-end<
|
.file-actions.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-md-justify-content-end<
|
||||||
= render 'projects/blob/viewer_switcher', blob: blob unless blame
|
= render 'projects/blob/viewer_switcher', blob: blob unless blame
|
||||||
= render 'shared/web_ide_button', blob: blob
|
= render 'shared/web_ide_button', blob: blob
|
||||||
- unless blame
|
|
||||||
.btn-group{ role: "group", class: ("gl-ml-3" if current_user) }>
|
|
||||||
= render_if_exists 'projects/blob/header_file_locks_link'
|
|
||||||
- if current_user
|
|
||||||
= replace_blob_link(@project, @ref, @path, blob: blob)
|
|
||||||
= delete_blob_link(@project, @ref, @path, blob: blob)
|
|
||||||
.btn-group.gl-ml-3{ role: "group" }
|
.btn-group.gl-ml-3{ role: "group" }
|
||||||
= copy_blob_source_button(blob) unless blame
|
= copy_blob_source_button(blob) unless blame
|
||||||
= open_raw_blob_button(blob)
|
= open_raw_blob_button(blob)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ class FlushCounterIncrementsWorker
|
||||||
data_consistency :always
|
data_consistency :always
|
||||||
|
|
||||||
sidekiq_options retry: 3
|
sidekiq_options retry: 3
|
||||||
|
loggable_arguments 0, 2
|
||||||
|
|
||||||
# The increments in `ProjectStatistics` are owned by several teams depending
|
# The increments in `ProjectStatistics` are owned by several teams depending
|
||||||
# on the counter
|
# on the counter
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: remove_caching_diff_batches
|
name: draft_quick_action_non_toggle
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95562
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92654
|
||||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370933
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/368610
|
||||||
milestone: '15.4'
|
milestone: '15.4'
|
||||||
type: development
|
type: development
|
||||||
group: group::code review
|
group: group::code review
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
const vm = require('vm');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function uses Node's `vm` modules to evaluate the `module.exports` of a given source string
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* const { exports: moduleExports } = evaluateModuleFromSource("const foo = 7;\n module.exports.bar = 10 + foo;");
|
||||||
|
*
|
||||||
|
* assert(moduleExports.bar === 17);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {String} source to be evaluated using Node's `vm` modules
|
||||||
|
* @param {{ require: Function }} options used in the context during evaluation of the Node module
|
||||||
|
* @returns {{ exports: any }} exports added to the script's `module.exports` context
|
||||||
|
*/
|
||||||
|
const evaluateModuleFromSource = (source, { require } = {}) => {
|
||||||
|
const context = {
|
||||||
|
module: {
|
||||||
|
exports: {},
|
||||||
|
},
|
||||||
|
require,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const script = new vm.Script(source);
|
||||||
|
script.runInNewContext(context);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.module;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = { evaluateModuleFromSource };
|
||||||
|
|
@ -712,9 +712,6 @@ Gitlab.ee do
|
||||||
Settings.cron_jobs['ldap_sync_worker'] ||= Settingslogic.new({})
|
Settings.cron_jobs['ldap_sync_worker'] ||= Settingslogic.new({})
|
||||||
Settings.cron_jobs['ldap_sync_worker']['cron'] ||= '30 1 * * *'
|
Settings.cron_jobs['ldap_sync_worker']['cron'] ||= '30 1 * * *'
|
||||||
Settings.cron_jobs['ldap_sync_worker']['job_class'] = 'LdapSyncWorker'
|
Settings.cron_jobs['ldap_sync_worker']['job_class'] = 'LdapSyncWorker'
|
||||||
Settings.cron_jobs['free_user_cap_data_remediation'] ||= Settingslogic.new({})
|
|
||||||
Settings.cron_jobs['free_user_cap_data_remediation']['cron'] ||= '17 6,10,14,18 * * *'
|
|
||||||
Settings.cron_jobs['free_user_cap_data_remediation']['job_class'] = 'Namespaces::FreeUserCap::RemediationWorker'
|
|
||||||
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker'] ||= Settingslogic.new({})
|
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker'] ||= Settingslogic.new({})
|
||||||
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['cron'] ||= '0 12 * * *'
|
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['cron'] ||= '0 12 * * *'
|
||||||
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['job_class'] = 'UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker'
|
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['job_class'] = 'UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker'
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
const yaml = require('js-yaml');
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
|
const { evaluateModuleFromSource } = require('../helpers/evaluate_module_from_source');
|
||||||
|
|
||||||
const PLUGIN_NAME = 'GraphqlKnownOperationsPlugin';
|
const PLUGIN_NAME = 'GraphqlKnownOperationsPlugin';
|
||||||
const GRAPHQL_PATH_REGEX = /(query|mutation)\.graphql$/;
|
const GRAPHQL_PATH_REGEX = /(query|mutation)\.graphql$/;
|
||||||
const OPERATION_NAME_SOURCE_REGEX = /^\s*module\.exports.*oneQuery.*"(\w+)"/gm;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a given webpack module is a "graphql" module
|
* Returns whether a given webpack module is a "graphql" module
|
||||||
|
|
@ -26,9 +27,19 @@ const getOperationNames = (module) => {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const matches = originalSource.source().toString().matchAll(OPERATION_NAME_SOURCE_REGEX);
|
const { exports: moduleExports } = evaluateModuleFromSource(originalSource.source().toString(), {
|
||||||
|
// what: stub require(...) when evaluating the graphql module
|
||||||
|
// why: require(...) is used to fetch fragments. We only need operation metadata, so it's fine to stub these out.
|
||||||
|
require: () => ({ definitions: [] }),
|
||||||
|
});
|
||||||
|
|
||||||
return Array.from(matches).map((match) => match[1]);
|
const names = moduleExports.definitions
|
||||||
|
.filter((x) => ['query', 'mutation'].includes(x.operation))
|
||||||
|
.map((x) => x.name?.value)
|
||||||
|
// why: It's possible for operations to not have a name. That violates our eslint rule, but either way, let's ignore those here.
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
return names;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createFileContents = (knownOperations) => {
|
const createFileContents = (knownOperations) => {
|
||||||
|
|
@ -60,7 +71,7 @@ const onSucceedModule = ({ module, knownOperations }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getOperationNames(module).forEach((x) => knownOperations.add(x));
|
getOperationNames(module).forEach((name) => knownOperations.add(name));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCompilerEmit = ({ compilation, knownOperations, filename }) => {
|
const onCompilerEmit = ({ compilation, knownOperations, filename }) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveFreeUserCapRemediationWorker < Gitlab::Database::Migration[2.0]
|
||||||
|
def up
|
||||||
|
Sidekiq::Cron::Job.find('free_user_cap_data_remediation')&.destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# no-op
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddIndexToTodosPendingQuery < Gitlab::Database::Migration[2.0]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
INDEX_NAME = 'index_on_todos_user_project_target_and_state'
|
||||||
|
COLUMNS = %i[user_id project_id target_type target_id id].freeze
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_concurrent_index :todos, COLUMNS, name: INDEX_NAME, where: "state = 'pending'"
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_concurrent_index_by_name :todos, INDEX_NAME
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
d5d264f90203ba371edcf0688d1227aa69cbf0018033d141257e4c88072ee7d7
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
30d9f3352daa48f529486030e30667a1339b04e96b207be815505477ab498adb
|
||||||
|
|
@ -29531,6 +29531,8 @@ CREATE INDEX index_on_projects_path ON projects USING btree (path);
|
||||||
|
|
||||||
CREATE INDEX index_on_routes_lower_path ON routes USING btree (lower((path)::text));
|
CREATE INDEX index_on_routes_lower_path ON routes USING btree (lower((path)::text));
|
||||||
|
|
||||||
|
CREATE INDEX index_on_todos_user_project_target_and_state ON todos USING btree (user_id, project_id, target_type, target_id, id) WHERE ((state)::text = 'pending'::text);
|
||||||
|
|
||||||
CREATE INDEX index_on_users_lower_email ON users USING btree (lower((email)::text));
|
CREATE INDEX index_on_users_lower_email ON users USING btree (lower((email)::text));
|
||||||
|
|
||||||
CREATE INDEX index_on_users_lower_username ON users USING btree (lower((username)::text));
|
CREATE INDEX index_on_users_lower_username ON users USING btree (lower((username)::text));
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,6 @@ GET /groups/:id/billable_members
|
||||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) owned by the authenticated user |
|
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) owned by the authenticated user |
|
||||||
| `search` | string | no | A query string to search for group members by name, username, or public email. |
|
| `search` | string | no | A query string to search for group members by name, username, or public email. |
|
||||||
| `sort` | string | no | A query string containing parameters that specify the sort attribute and order. See supported values below. |
|
| `sort` | string | no | A query string containing parameters that specify the sort attribute and order. See supported values below. |
|
||||||
| `include_awaiting_members` | boolean | no | Determines if awaiting members are included. |
|
|
||||||
|
|
||||||
The supported values for the `sort` attribute are:
|
The supported values for the `sort` attribute are:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ Parameters:
|
||||||
| Attribute | Type | Required | Description |
|
| Attribute | Type | Required | Description |
|
||||||
| --------- | ---- | -------- | ----------- |
|
| --------- | ---- | -------- | ----------- |
|
||||||
| `id` | integer/string| yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user|
|
| `id` | integer/string| yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user|
|
||||||
| `order_by` | string | no | Return tags ordered by `name` or `updated` fields. Default is `updated` |
|
| `order_by` | string | no | Return tags ordered by `name`, `updated`, or `version` (since 15.4) fields. Default is `updated` |
|
||||||
| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` |
|
| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` |
|
||||||
| `search` | string | no | Return list of tags matching the search criteria. You can use `^term` and `term$` to find tags that begin and end with `term` respectively. No other regular expressions are supported. |
|
| `search` | string | no | Return list of tags matching the search criteria. You can use `^term` and `term$` to find tags that begin and end with `term` respectively. No other regular expressions are supported. |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ as it can cause the pipeline to behave unexpectedly.
|
||||||
| `CI_JOB_JWT` | 12.10 | all | A RS256 JSON web token to authenticate with third party systems that support JWT authentication, for example [HashiCorp's Vault](../secrets/index.md). |
|
| `CI_JOB_JWT` | 12.10 | all | A RS256 JSON web token to authenticate with third party systems that support JWT authentication, for example [HashiCorp's Vault](../secrets/index.md). |
|
||||||
| `CI_JOB_JWT_V1` | 14.6 | all | The same value as `CI_JOB_JWT`. |
|
| `CI_JOB_JWT_V1` | 14.6 | all | The same value as `CI_JOB_JWT`. |
|
||||||
| `CI_JOB_JWT_V2` | 14.6 | all | [**alpha:**](../../policy/alpha-beta-support.md#alpha-features) A newly formatted RS256 JSON web token to increase compatibility. Similar to `CI_JOB_JWT`, except the issuer (`iss`) claim is changed from `gitlab.com` to `https://gitlab.com`, `sub` has changed from `job_id` to a string that contains the project path, and an `aud` claim is added. Format is subject to change. Be aware, the `aud` field is a constant value. Trusting JWTs in multiple relying parties can lead to [one RP sending a JWT to another one and acting maliciously as a job](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72555#note_769112331). |
|
| `CI_JOB_JWT_V2` | 14.6 | all | [**alpha:**](../../policy/alpha-beta-support.md#alpha-features) A newly formatted RS256 JSON web token to increase compatibility. Similar to `CI_JOB_JWT`, except the issuer (`iss`) claim is changed from `gitlab.com` to `https://gitlab.com`, `sub` has changed from `job_id` to a string that contains the project path, and an `aud` claim is added. Format is subject to change. Be aware, the `aud` field is a constant value. Trusting JWTs in multiple relying parties can lead to [one RP sending a JWT to another one and acting maliciously as a job](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72555#note_769112331). |
|
||||||
| `CI_JOB_MANUAL` | 8.12 | all | `true` if a job was started manually. |
|
| `CI_JOB_MANUAL` | 8.12 | all | Only available if the job was started manually. `true` when available. |
|
||||||
| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job. |
|
| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job. |
|
||||||
| `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the job's stage. |
|
| `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the job's stage. |
|
||||||
| `CI_JOB_STATUS` | all | 13.5 | The status of the job as each runner stage is executed. Use with [`after_script`](../yaml/index.md#after_script). Can be `success`, `failed`, or `canceled`. |
|
| `CI_JOB_STATUS` | all | 13.5 | The status of the job as each runner stage is executed. Use with [`after_script`](../yaml/index.md#after_script). Can be `success`, `failed`, or `canceled`. |
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ The generated service account has the following roles:
|
||||||
- `roles/cloudbuild.builds.builder`
|
- `roles/cloudbuild.builds.builder`
|
||||||
- `roles/run.admin`
|
- `roles/run.admin`
|
||||||
- `roles/storage.admin`
|
- `roles/storage.admin`
|
||||||
- `roles/cloudsql.admin`
|
- `roles/cloudsql.client`
|
||||||
- `roles/browser`
|
- `roles/browser`
|
||||||
|
|
||||||
You can enhance security by storing CI variables in secret managers. Learn more about [secret management with GitLab](../ci/secrets/index.md).
|
You can enhance security by storing CI variables in secret managers. Learn more about [secret management with GitLab](../ci/secrets/index.md).
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,17 @@ See also [guidelines for reusing abstractions](../reusing_abstractions.md).
|
||||||
|
|
||||||
Everything listed here can be [reopened for discussion](https://about.gitlab.com/handbook/values/#disagree-commit-and-disagree).
|
Everything listed here can be [reopened for discussion](https://about.gitlab.com/handbook/values/#disagree-commit-and-disagree).
|
||||||
|
|
||||||
|
## String literals quoting
|
||||||
|
|
||||||
|
Due to the sheer amount of work to rectify, we do not care whether string
|
||||||
|
literals are single, or double quoted.
|
||||||
|
|
||||||
|
Previous discussions include:
|
||||||
|
|
||||||
|
- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44234>
|
||||||
|
- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36076>
|
||||||
|
- <https://gitlab.com/gitlab-org/gitlab/-/issues/198046>
|
||||||
|
|
||||||
## Instance variable access using `attr_reader`
|
## Instance variable access using `attr_reader`
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52351) in GitLab 14.1.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52351) in GitLab 14.1.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ the **Merge** button until you remove the **Draft** flag:
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32692) in GitLab 13.2, Work-In-Progress (WIP) merge requests were renamed to **Draft**.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32692) in GitLab 13.2, Work-In-Progress (WIP) merge requests were renamed to **Draft**.
|
||||||
> - [Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/228685) all support for using **WIP** in GitLab 14.8.
|
> - [Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/228685) all support for using **WIP** in GitLab 14.8.
|
||||||
> - **Mark as draft** and **Mark as ready** buttons [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227421) in GitLab 13.5.
|
> - **Mark as draft** and **Mark as ready** buttons [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227421) in GitLab 13.5.
|
||||||
|
> `/draft` quick action as a toggle [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92654) in GitLab 15.3.
|
||||||
|
|
||||||
There are several ways to flag a merge request as a draft:
|
There are several ways to flag a merge request as a draft:
|
||||||
|
|
||||||
|
|
@ -29,8 +30,7 @@ There are several ways to flag a merge request as a draft:
|
||||||
below the **Title** field.
|
below the **Title** field.
|
||||||
- **Commenting in an existing merge request**: Add the `/draft`
|
- **Commenting in an existing merge request**: Add the `/draft`
|
||||||
[quick action](../quick_actions.md#issues-merge-requests-and-epics)
|
[quick action](../quick_actions.md#issues-merge-requests-and-epics)
|
||||||
in a comment. This quick action is a toggle, and can be repeated to change the status
|
in a comment. GitLab 15.4 [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92654) the toggle behavior of `/draft`. To mark a merge request as ready, use `/ready`.
|
||||||
back to Ready.
|
|
||||||
- **Creating a commit**: Add `draft:`, `Draft:`, `fixup!`, or `Fixup!` to the
|
- **Creating a commit**: Add `draft:`, `Draft:`, `fixup!`, or `Fixup!` to the
|
||||||
beginning of a commit message targeting the merge request's source branch. This
|
beginning of a commit message targeting the merge request's source branch. This
|
||||||
is not a toggle, and adding this text again in a later commit doesn't mark the
|
is not a toggle, and adding this text again in a later commit doesn't mark the
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ threads. Some quick actions might not be available to all subscription tiers.
|
||||||
| `/copy_metadata <#issue>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Copy labels and milestone from another issue in the project. |
|
| `/copy_metadata <#issue>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Copy labels and milestone from another issue in the project. |
|
||||||
| `/create_merge_request <branch name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Create a new merge request starting from the current issue. |
|
| `/create_merge_request <branch name>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Create a new merge request starting from the current issue. |
|
||||||
| `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to do as done. |
|
| `/done` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Mark to do as done. |
|
||||||
| `/draft` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Toggle the [draft status](merge_requests/drafts.md). |
|
| `/draft` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Set the [draft status](merge_requests/drafts.md). Use for toggling the draft status ([deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92654) in GitLab 15.4.) |
|
||||||
| `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. |
|
| `/due <date>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. |
|
||||||
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. Also, mark both as related. |
|
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. Also, mark both as related. |
|
||||||
| `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. |
|
| `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. |
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ module API
|
||||||
params do
|
params do
|
||||||
optional :sort, type: String, values: %w[asc desc], default: 'desc',
|
optional :sort, type: String, values: %w[asc desc], default: 'desc',
|
||||||
desc: 'Return tags sorted in updated by `asc` or `desc` order.'
|
desc: 'Return tags sorted in updated by `asc` or `desc` order.'
|
||||||
optional :order_by, type: String, values: %w[name updated], default: 'updated',
|
optional :order_by, type: String, values: %w[name updated version], default: 'updated',
|
||||||
desc: 'Return tags ordered by `name` or `updated` fields.'
|
desc: 'Return tags ordered by `name`, `updated`, `version` fields.'
|
||||||
optional :search, type: String, desc: 'Return list of tags matching the search criteria'
|
optional :search, type: String, desc: 'Return list of tags matching the search criteria'
|
||||||
optional :page_token, type: String, desc: 'Name of tag to start the paginaition from'
|
optional :page_token, type: String, desc: 'Name of tag to start the paginaition from'
|
||||||
use :pagination
|
use :pagination
|
||||||
|
|
|
||||||
|
|
@ -88,33 +88,21 @@ module Gitlab
|
||||||
@execution_message[:rebase] = _('Scheduled a rebase of branch %{branch}.') % { branch: branch }
|
@execution_message[:rebase] = _('Scheduled a rebase of branch %{branch}.') % { branch: branch }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc { _('Toggle the Draft status') }
|
desc { _('Set the Draft status') }
|
||||||
explanation do
|
explanation do
|
||||||
noun = quick_action_target.to_ability_name.humanize(capitalize: false)
|
draft_action_message(_("Marks"))
|
||||||
if quick_action_target.draft?
|
|
||||||
_("Marks this %{noun} as ready.")
|
|
||||||
else
|
|
||||||
_("Marks this %{noun} as a draft.")
|
|
||||||
end % { noun: noun }
|
|
||||||
end
|
end
|
||||||
execution_message do
|
execution_message do
|
||||||
noun = quick_action_target.to_ability_name.humanize(capitalize: false)
|
draft_action_message(_("Marked"))
|
||||||
if quick_action_target.draft?
|
|
||||||
_("Marked this %{noun} as ready.")
|
|
||||||
else
|
|
||||||
_("Marked this %{noun} as a draft.")
|
|
||||||
end % { noun: noun }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
types MergeRequest
|
types MergeRequest
|
||||||
condition do
|
condition do
|
||||||
quick_action_target.respond_to?(:draft?) &&
|
quick_action_target.respond_to?(:draft?) &&
|
||||||
# Allow it to mark as draft on MR creation page or through MR notes
|
|
||||||
#
|
|
||||||
(quick_action_target.new_record? || current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target))
|
(quick_action_target.new_record? || current_user.can?(:"update_#{quick_action_target.to_ability_name}", quick_action_target))
|
||||||
end
|
end
|
||||||
command :draft do
|
command :draft do
|
||||||
@updates[:wip_event] = quick_action_target.draft? ? 'ready' : 'draft'
|
@updates[:wip_event] = draft_action_command
|
||||||
end
|
end
|
||||||
|
|
||||||
desc { _('Set the Ready status') }
|
desc { _('Set the Ready status') }
|
||||||
|
|
@ -317,6 +305,25 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def draft_action_message(verb)
|
||||||
|
noun = quick_action_target.to_ability_name.humanize(capitalize: false)
|
||||||
|
if !quick_action_target.draft?
|
||||||
|
_("%{verb} this %{noun} as a draft.")
|
||||||
|
elsif Feature.disabled?(:draft_quick_action_non_toggle, quick_action_target.project)
|
||||||
|
_("%{verb} this %{noun} as ready.")
|
||||||
|
else
|
||||||
|
_("No change to this %{noun}'s draft status.")
|
||||||
|
end % { verb: verb, noun: noun }
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_action_command
|
||||||
|
if Feature.disabled?(:draft_quick_action_non_toggle, quick_action_target.project)
|
||||||
|
quick_action_target.draft? ? 'ready' : 'draft'
|
||||||
|
else
|
||||||
|
'draft'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def merge_orchestration_service
|
def merge_orchestration_service
|
||||||
@merge_orchestration_service ||= ::MergeRequests::MergeOrchestrationService.new(project, current_user)
|
@merge_orchestration_service ||= ::MergeRequests::MergeOrchestrationService.new(project, current_user)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ module GoogleApi
|
||||||
"https://www.googleapis.com/auth/logging.write",
|
"https://www.googleapis.com/auth/logging.write",
|
||||||
"https://www.googleapis.com/auth/monitoring"
|
"https://www.googleapis.com/auth/monitoring"
|
||||||
].freeze
|
].freeze
|
||||||
ROLES_LIST = %w[roles/iam.serviceAccountUser roles/artifactregistry.admin roles/cloudbuild.builds.builder roles/run.admin roles/storage.admin roles/cloudsql.admin roles/browser].freeze
|
ROLES_LIST = %w[roles/iam.serviceAccountUser roles/artifactregistry.admin roles/cloudbuild.builds.builder roles/run.admin roles/storage.admin roles/cloudsql.client roles/browser].freeze
|
||||||
REVOKE_URL = 'https://oauth2.googleapis.com/revoke'
|
REVOKE_URL = 'https://oauth2.googleapis.com/revoke'
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
|
|
||||||
|
|
@ -1180,6 +1180,12 @@ msgstr ""
|
||||||
msgid "%{verb} %{time_spent_value} spent time."
|
msgid "%{verb} %{time_spent_value} spent time."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "%{verb} this %{noun} as a draft."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "%{verb} this %{noun} as ready."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
|
msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -16781,6 +16787,9 @@ msgstr ""
|
||||||
msgid "For example, the application using the token or the purpose of the token. Do not give sensitive information for the name of the token, as it will be visible to all %{resource_type} members."
|
msgid "For example, the application using the token or the purpose of the token. Do not give sensitive information for the name of the token, as it will be visible to all %{resource_type} members."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "For faster browsing, not all history is shown."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
|
msgid "For files larger than this limit, only index the file name. The file content is neither indexed nor searchable."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -24281,6 +24290,9 @@ msgstr ""
|
||||||
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
|
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Marked"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Marked For Deletion At - %{deletion_time}"
|
msgid "Marked For Deletion At - %{deletion_time}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -24290,9 +24302,6 @@ msgstr ""
|
||||||
msgid "Marked as ready. Merging is now allowed."
|
msgid "Marked as ready. Merging is now allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Marked this %{noun} as a draft."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Marked this %{noun} as ready."
|
msgid "Marked this %{noun} as ready."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -24305,7 +24314,7 @@ msgstr ""
|
||||||
msgid "Marked to do as done."
|
msgid "Marked to do as done."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Marks this %{noun} as a draft."
|
msgid "Marks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Marks this %{noun} as ready."
|
msgid "Marks this %{noun} as ready."
|
||||||
|
|
@ -36334,6 +36343,9 @@ msgstr ""
|
||||||
msgid "Set target branch to %{branch_name}."
|
msgid "Set target branch to %{branch_name}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Set the Draft status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Set the Ready status"
|
msgid "Set the Ready status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -41420,9 +41432,6 @@ msgstr ""
|
||||||
msgid "Toggle sidebar"
|
msgid "Toggle sidebar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Toggle the Draft status"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Toggle the Performance Bar"
|
msgid "Toggle the Performance Bar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -43485,6 +43494,9 @@ msgstr ""
|
||||||
msgid "View eligible approvers"
|
msgid "View eligible approvers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "View entire blame"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "View epics list"
|
msgid "View epics list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -46047,6 +46059,9 @@ msgstr ""
|
||||||
msgid "added %{emails}"
|
msgid "added %{emails}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "added a %{link_type} link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "added a Zoom call to this issue"
|
msgid "added a Zoom call to this issue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -47701,6 +47716,9 @@ msgstr ""
|
||||||
msgid "removed"
|
msgid "removed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "removed a %{link_type} link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "removed a Zoom call from this issue"
|
msgid "removed a Zoom call from this issue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,6 @@ module QA
|
||||||
element :lock_button
|
element :lock_button
|
||||||
end
|
end
|
||||||
|
|
||||||
view 'app/helpers/blob_helper.rb' do
|
|
||||||
element :edit_button, "_('Edit')" # rubocop:disable QA/ElementWithPattern
|
|
||||||
element :delete_button, '_("Delete")' # rubocop:disable QA/ElementWithPattern
|
|
||||||
end
|
|
||||||
|
|
||||||
view 'app/assets/javascripts/vue_shared/components/web_ide_link.vue' do
|
view 'app/assets/javascripts/vue_shared/components/web_ide_link.vue' do
|
||||||
element :edit_button
|
element :edit_button
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -471,6 +471,21 @@ RSpec.describe Projects::MergeRequests::DraftsController do
|
||||||
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
|
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
|
||||||
.to have_received(:track_submit_review_approve).with(user: user)
|
.to have_received(:track_submit_review_approve).with(user: user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when merge request is already approved by user' do
|
||||||
|
before do
|
||||||
|
create(:approval, merge_request: merge_request, user: user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does return 200' do
|
||||||
|
post :publish, params: params.merge!(approve: true)
|
||||||
|
|
||||||
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
|
|
||||||
|
expect(Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter)
|
||||||
|
.to have_received(:track_submit_review_approve).with(user: user)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,10 @@ RSpec.describe 'File blame', :js do
|
||||||
it 'displays the blame page without pagination' do
|
it 'displays the blame page without pagination' do
|
||||||
visit_blob_blame(path)
|
visit_blob_blame(path)
|
||||||
|
|
||||||
expect(page).to have_css('.blame-commit')
|
within '[data-testid="blob-content-holder"]' do
|
||||||
expect(page).not_to have_css('.gl-pagination')
|
expect(page).to have_css('.blame-commit')
|
||||||
|
expect(page).not_to have_css('.gl-pagination')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when blob length is over the blame range limit' do
|
context 'when blob length is over the blame range limit' do
|
||||||
|
|
@ -47,12 +49,15 @@ RSpec.describe 'File blame', :js do
|
||||||
it 'displays two first lines of the file with pagination' do
|
it 'displays two first lines of the file with pagination' do
|
||||||
visit_blob_blame(path)
|
visit_blob_blame(path)
|
||||||
|
|
||||||
expect(page).to have_css('.blame-commit')
|
within '[data-testid="blob-content-holder"]' do
|
||||||
expect(page).to have_css('.gl-pagination')
|
expect(page).to have_css('.blame-commit')
|
||||||
|
expect(page).to have_css('.gl-pagination')
|
||||||
|
expect(page).to have_link _('View entire blame')
|
||||||
|
|
||||||
expect(page).to have_css('#L1')
|
expect(page).to have_css('#L1')
|
||||||
expect(page).not_to have_css('#L3')
|
expect(page).not_to have_css('#L3')
|
||||||
expect(find('.page-link.active')).to have_text('1')
|
expect(find('.page-link.active')).to have_text('1')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user clicks on the next button' do
|
context 'when user clicks on the next button' do
|
||||||
|
|
@ -63,15 +68,35 @@ RSpec.describe 'File blame', :js do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'displays next two lines of the file with pagination' do
|
it 'displays next two lines of the file with pagination' do
|
||||||
expect(page).not_to have_css('#L1')
|
within '[data-testid="blob-content-holder"]' do
|
||||||
expect(page).to have_css('#L3')
|
expect(page).not_to have_css('#L1')
|
||||||
expect(find('.page-link.active')).to have_text('2')
|
expect(page).to have_css('#L3')
|
||||||
|
expect(find('.page-link.active')).to have_text('2')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'correctly redirects to the prior blame page' do
|
it 'correctly redirects to the prior blame page' do
|
||||||
find('.version-link').click
|
within '[data-testid="blob-content-holder"]' do
|
||||||
|
find('.version-link').click
|
||||||
|
|
||||||
expect(find('.page-link.active')).to have_text('2')
|
expect(find('.page-link.active')).to have_text('2')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user clicks on View entire blame button' do
|
||||||
|
before do
|
||||||
|
visit_blob_blame(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays the blame page without pagination' do
|
||||||
|
within '[data-testid="blob-content-holder"]' do
|
||||||
|
click_link _('View entire blame')
|
||||||
|
|
||||||
|
expect(page).to have_css('#L1')
|
||||||
|
expect(page).to have_css('#L3')
|
||||||
|
expect(page).not_to have_css('.gl-pagination')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -83,8 +108,11 @@ RSpec.describe 'File blame', :js do
|
||||||
it 'displays the blame page without pagination' do
|
it 'displays the blame page without pagination' do
|
||||||
visit_blob_blame(path)
|
visit_blob_blame(path)
|
||||||
|
|
||||||
expect(page).to have_css('.blame-commit')
|
within '[data-testid="blob-content-holder"]' do
|
||||||
expect(page).not_to have_css('.gl-pagination')
|
expect(page).to have_css('.blame-commit')
|
||||||
|
expect(page).not_to have_css('.gl-pagination')
|
||||||
|
expect(page).not_to have_link _('View entire blame')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -99,25 +127,29 @@ RSpec.describe 'File blame', :js do
|
||||||
it 'displays two hundred lines of the file with pagination' do
|
it 'displays two hundred lines of the file with pagination' do
|
||||||
visit_blob_blame(path)
|
visit_blob_blame(path)
|
||||||
|
|
||||||
expect(page).to have_css('.blame-commit')
|
within '[data-testid="blob-content-holder"]' do
|
||||||
expect(page).to have_css('.gl-pagination')
|
expect(page).to have_css('.blame-commit')
|
||||||
|
expect(page).to have_css('.gl-pagination')
|
||||||
|
|
||||||
expect(page).to have_css('#L1')
|
expect(page).to have_css('#L1')
|
||||||
expect(page).not_to have_css('#L201')
|
expect(page).not_to have_css('#L201')
|
||||||
expect(find('.page-link.active')).to have_text('1')
|
expect(find('.page-link.active')).to have_text('1')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user clicks on the next button' do
|
context 'when user clicks on the next button' do
|
||||||
before do
|
before do
|
||||||
visit_blob_blame(path)
|
visit_blob_blame(path)
|
||||||
|
|
||||||
find('.js-next-button').click
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'displays next two hundred lines of the file with pagination' do
|
it 'displays next two hundred lines of the file with pagination' do
|
||||||
expect(page).not_to have_css('#L1')
|
within '[data-testid="blob-content-holder"]' do
|
||||||
expect(page).to have_css('#L201')
|
find('.js-next-button').click
|
||||||
expect(find('.page-link.active')).to have_text('2')
|
|
||||||
|
expect(page).not_to have_css('#L1')
|
||||||
|
expect(page).to have_css('#L201')
|
||||||
|
expect(find('.page-link.active')).to have_text('2')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,16 @@ describe('keepAlive', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('converts a component to a keep-alive component', async () => {
|
it('converts a component to a keep-alive component', async () => {
|
||||||
const { element } = wrapper.find(component);
|
const { element } = wrapper.findComponent(component);
|
||||||
|
|
||||||
await wrapper.vm.deactivate();
|
await wrapper.vm.deactivate();
|
||||||
expect(wrapper.find(component).exists()).toBe(false);
|
expect(wrapper.findComponent(component).exists()).toBe(false);
|
||||||
|
|
||||||
await wrapper.vm.activate();
|
await wrapper.vm.activate();
|
||||||
|
|
||||||
// assert that when the component is destroyed and re-rendered, the
|
// assert that when the component is destroyed and re-rendered, the
|
||||||
// newly rendered component has the reference to the old component
|
// newly rendered component has the reference to the old component
|
||||||
// (i.e. the old component was deactivated and activated)
|
// (i.e. the old component was deactivated and activated)
|
||||||
expect(wrapper.find(component).element).toBe(element);
|
expect(wrapper.findComponent(component).element).toBe(element);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,14 @@ describe('~/access_tokens/components/new_access_token_app', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const triggerSuccess = async (newToken = 'new token') => {
|
const triggerSuccess = async (newToken = 'new token') => {
|
||||||
wrapper.find(DomElementListener).vm.$emit(EVENT_SUCCESS, { detail: [{ new_token: newToken }] });
|
wrapper
|
||||||
|
.findComponent(DomElementListener)
|
||||||
|
.vm.$emit(EVENT_SUCCESS, { detail: [{ new_token: newToken }] });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
};
|
};
|
||||||
|
|
||||||
const triggerError = async (errors = ['1', '2']) => {
|
const triggerError = async (errors = ['1', '2']) => {
|
||||||
wrapper.find(DomElementListener).vm.$emit(EVENT_ERROR, { detail: [{ errors }] });
|
wrapper.findComponent(DomElementListener).vm.$emit(EVENT_ERROR, { detail: [{ errors }] });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ describe('AddContextCommitsModal', () => {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
const findModal = () => wrapper.find(GlModal);
|
const findModal = () => wrapper.findComponent(GlModal);
|
||||||
const findSearch = () => wrapper.find(GlSearchBoxByType);
|
const findSearch = () => wrapper.findComponent(GlSearchBoxByType);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = createWrapper();
|
wrapper = createWrapper();
|
||||||
|
|
@ -107,7 +107,7 @@ describe('AddContextCommitsModal', () => {
|
||||||
|
|
||||||
it('a disabled ok button in first tab, when row is selected in second tab', () => {
|
it('a disabled ok button in first tab, when row is selected in second tab', () => {
|
||||||
createWrapper({ selectedContextCommits: [commit] });
|
createWrapper({ selectedContextCommits: [commit] });
|
||||||
expect(wrapper.find(GlModal).attributes('ok-disabled')).toBe('true');
|
expect(wrapper.findComponent(GlModal).attributes('ok-disabled')).toBe('true');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ describe('ReviewTabContainer', () => {
|
||||||
|
|
||||||
it('shows loading icon when commits are being loaded', () => {
|
it('shows loading icon when commits are being loaded', () => {
|
||||||
createWrapper({ isLoading: true });
|
createWrapper({ isLoading: true });
|
||||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
|
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows loading error text when API call fails', () => {
|
it('shows loading error text when API call fails', () => {
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ describe('TopicSelect', () => {
|
||||||
|
|
||||||
const dropdownItems = findAllDropdownItems();
|
const dropdownItems = findAllDropdownItems();
|
||||||
|
|
||||||
expect(dropdownItems.at(0).find(GlAvatarLabeled).props('label')).toBe('Topic 1');
|
expect(dropdownItems.at(0).findComponent(GlAvatarLabeled).props('label')).toBe('Topic 1');
|
||||||
expect(dropdownItems.at(1).find(GlAvatarLabeled).props('label')).toBe('GitLab');
|
expect(dropdownItems.at(1).findComponent(GlAvatarLabeled).props('label')).toBe('GitLab');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits `click` event when topic selected', () => {
|
it('emits `click` event when topic selected', () => {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ describe('AlertManagementEmptyState', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const EmptyState = () => wrapper.find(GlEmptyState);
|
const EmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||||
|
|
||||||
describe('Empty state', () => {
|
describe('Empty state', () => {
|
||||||
it('shows empty state', () => {
|
it('shows empty state', () => {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ describe('AlertManagementList', () => {
|
||||||
|
|
||||||
describe('Alert List Wrapper', () => {
|
describe('Alert List Wrapper', () => {
|
||||||
it('should show the empty state when alerts are not enabled', () => {
|
it('should show the empty state when alerts are not enabled', () => {
|
||||||
expect(wrapper.find(AlertManagementEmptyState).exists()).toBe(true);
|
expect(wrapper.findComponent(AlertManagementEmptyState).exists()).toBe(true);
|
||||||
expect(wrapper.find(AlertManagementTable).exists()).toBe(false);
|
expect(wrapper.findComponent(AlertManagementTable).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the alerts table when alerts are enabled', () => {
|
it('should show the alerts table when alerts are enabled', () => {
|
||||||
|
|
@ -39,8 +39,8 @@ describe('AlertManagementList', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(AlertManagementEmptyState).exists()).toBe(false);
|
expect(wrapper.findComponent(AlertManagementEmptyState).exists()).toBe(false);
|
||||||
expect(wrapper.find(AlertManagementTable).exists()).toBe(true);
|
expect(wrapper.findComponent(AlertManagementTable).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -172,8 +172,8 @@ describe('AlertManagementTable', () => {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(wrapper.find(GlTable).exists()).toBe(true);
|
expect(wrapper.findComponent(GlTable).exists()).toBe(true);
|
||||||
expect(findAlertsTable().find(GlIcon).classes('icon-critical')).toBe(true);
|
expect(findAlertsTable().findComponent(GlIcon).classes('icon-critical')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders severity text', () => {
|
it('renders severity text', () => {
|
||||||
|
|
@ -200,7 +200,7 @@ describe('AlertManagementTable', () => {
|
||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const avatar = findAssignees().at(1).find(GlAvatar);
|
const avatar = findAssignees().at(1).findComponent(GlAvatar);
|
||||||
const { src, label } = avatar.attributes();
|
const { src, label } = avatar.attributes();
|
||||||
const { name, avatarUrl } = mockAlerts[1].assignees.nodes[0];
|
const { name, avatarUrl } = mockAlerts[1].assignees.nodes[0];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ describe('AlertMappingBuilder', () => {
|
||||||
expect(findColumnInRow(0, 2).text()).toContain(i18n.columns.payloadKeyTitle);
|
expect(findColumnInRow(0, 2).text()).toContain(i18n.columns.payloadKeyTitle);
|
||||||
expect(findColumnInRow(0, 3).text()).toContain(i18n.columns.fallbackKeyTitle);
|
expect(findColumnInRow(0, 3).text()).toContain(i18n.columns.fallbackKeyTitle);
|
||||||
|
|
||||||
const fallbackColumnIcon = findColumnInRow(0, 3).find(GlIcon);
|
const fallbackColumnIcon = findColumnInRow(0, 3).findComponent(GlIcon);
|
||||||
expect(fallbackColumnIcon.exists()).toBe(true);
|
expect(fallbackColumnIcon.exists()).toBe(true);
|
||||||
expect(fallbackColumnIcon.attributes('name')).toBe('question');
|
expect(fallbackColumnIcon.attributes('name')).toBe('question');
|
||||||
expect(fallbackColumnIcon.attributes('title')).toBe(i18n.fallbackTooltip);
|
expect(fallbackColumnIcon.attributes('title')).toBe(i18n.fallbackTooltip);
|
||||||
|
|
@ -55,7 +55,7 @@ describe('AlertMappingBuilder', () => {
|
||||||
|
|
||||||
it('renders disabled form input for each mapped field', () => {
|
it('renders disabled form input for each mapped field', () => {
|
||||||
alertFields.forEach((field, index) => {
|
alertFields.forEach((field, index) => {
|
||||||
const input = findColumnInRow(index + 1, 0).find(GlFormInput);
|
const input = findColumnInRow(index + 1, 0).findComponent(GlFormInput);
|
||||||
const types = field.types.map((t) => capitalizeFirstCharacter(t.toLowerCase())).join(' or ');
|
const types = field.types.map((t) => capitalizeFirstCharacter(t.toLowerCase())).join(' or ');
|
||||||
expect(input.attributes('value')).toBe(`${field.label} (${types})`);
|
expect(input.attributes('value')).toBe(`${field.label} (${types})`);
|
||||||
expect(input.attributes('disabled')).toBe('');
|
expect(input.attributes('disabled')).toBe('');
|
||||||
|
|
@ -71,7 +71,7 @@ describe('AlertMappingBuilder', () => {
|
||||||
|
|
||||||
it('renders mapping dropdown for each field', () => {
|
it('renders mapping dropdown for each field', () => {
|
||||||
alertFields.forEach(({ types }, index) => {
|
alertFields.forEach(({ types }, index) => {
|
||||||
const dropdown = findColumnInRow(index + 1, 2).find(GlDropdown);
|
const dropdown = findColumnInRow(index + 1, 2).findComponent(GlDropdown);
|
||||||
const { searchBox, dropdownItems, mappingOptions } = getDropdownContent(dropdown, types);
|
const { searchBox, dropdownItems, mappingOptions } = getDropdownContent(dropdown, types);
|
||||||
|
|
||||||
expect(dropdown.exists()).toBe(true);
|
expect(dropdown.exists()).toBe(true);
|
||||||
|
|
@ -82,7 +82,7 @@ describe('AlertMappingBuilder', () => {
|
||||||
|
|
||||||
it('renders fallback dropdown only for the fields that have fallback', () => {
|
it('renders fallback dropdown only for the fields that have fallback', () => {
|
||||||
alertFields.forEach(({ types, numberOfFallbacks }, index) => {
|
alertFields.forEach(({ types, numberOfFallbacks }, index) => {
|
||||||
const dropdown = findColumnInRow(index + 1, 3).find(GlDropdown);
|
const dropdown = findColumnInRow(index + 1, 3).findComponent(GlDropdown);
|
||||||
expect(dropdown.exists()).toBe(Boolean(numberOfFallbacks));
|
expect(dropdown.exists()).toBe(Boolean(numberOfFallbacks));
|
||||||
|
|
||||||
if (numberOfFallbacks) {
|
if (numberOfFallbacks) {
|
||||||
|
|
@ -96,8 +96,8 @@ describe('AlertMappingBuilder', () => {
|
||||||
it('emits event with selected mapping', () => {
|
it('emits event with selected mapping', () => {
|
||||||
const mappingToSave = { fieldName: 'TITLE', mapping: 'PARSED_TITLE' };
|
const mappingToSave = { fieldName: 'TITLE', mapping: 'PARSED_TITLE' };
|
||||||
jest.spyOn(transformationUtils, 'transformForSave').mockReturnValue(mappingToSave);
|
jest.spyOn(transformationUtils, 'transformForSave').mockReturnValue(mappingToSave);
|
||||||
const dropdown = findColumnInRow(1, 2).find(GlDropdown);
|
const dropdown = findColumnInRow(1, 2).findComponent(GlDropdown);
|
||||||
const option = dropdown.find(GlDropdownItem);
|
const option = dropdown.findComponent(GlDropdownItem);
|
||||||
option.vm.$emit('click');
|
option.vm.$emit('click');
|
||||||
expect(wrapper.emitted('onMappingUpdate')[0]).toEqual([mappingToSave]);
|
expect(wrapper.emitted('onMappingUpdate')[0]).toEqual([mappingToSave]);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ describe('Alert integration settings form', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const service = { updateSettings: jest.fn().mockResolvedValue() };
|
const service = { updateSettings: jest.fn().mockResolvedValue() };
|
||||||
|
|
||||||
const findForm = () => wrapper.find({ ref: 'settingsForm' });
|
const findForm = () => wrapper.findComponent({ ref: 'settingsForm' });
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = shallowMount(AlertsSettingsForm, {
|
wrapper = shallowMount(AlertsSettingsForm, {
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ describe('AlertIntegrationsList', () => {
|
||||||
mountComponent();
|
mountComponent();
|
||||||
});
|
});
|
||||||
|
|
||||||
const findTableComponent = () => wrapper.find(GlTable);
|
const findTableComponent = () => wrapper.findComponent(GlTable);
|
||||||
const findTableComponentRows = () => wrapper.find(GlTable).findAll('table tbody tr');
|
const findTableComponentRows = () => wrapper.findComponent(GlTable).findAll('table tbody tr');
|
||||||
const finsStatusCell = () => wrapper.findAll('[data-testid="integration-activated-status"]');
|
const finsStatusCell = () => wrapper.findAll('[data-testid="integration-activated-status"]');
|
||||||
|
|
||||||
it('renders a table', () => {
|
it('renders a table', () => {
|
||||||
|
|
@ -78,7 +78,7 @@ describe('AlertIntegrationsList', () => {
|
||||||
describe('integration status', () => {
|
describe('integration status', () => {
|
||||||
it('enabled', () => {
|
it('enabled', () => {
|
||||||
const cell = finsStatusCell().at(0);
|
const cell = finsStatusCell().at(0);
|
||||||
const activatedIcon = cell.find(GlIcon);
|
const activatedIcon = cell.findComponent(GlIcon);
|
||||||
expect(cell.text()).toBe(i18n.status.enabled.name);
|
expect(cell.text()).toBe(i18n.status.enabled.name);
|
||||||
expect(activatedIcon.attributes('name')).toBe('check');
|
expect(activatedIcon.attributes('name')).toBe('check');
|
||||||
expect(activatedIcon.attributes('title')).toBe(i18n.status.enabled.tooltip);
|
expect(activatedIcon.attributes('title')).toBe(i18n.status.enabled.tooltip);
|
||||||
|
|
@ -86,7 +86,7 @@ describe('AlertIntegrationsList', () => {
|
||||||
|
|
||||||
it('disabled', () => {
|
it('disabled', () => {
|
||||||
const cell = finsStatusCell().at(1);
|
const cell = finsStatusCell().at(1);
|
||||||
const notActivatedIcon = cell.find(GlIcon);
|
const notActivatedIcon = cell.findComponent(GlIcon);
|
||||||
expect(cell.text()).toBe(i18n.status.disabled.name);
|
expect(cell.text()).toBe(i18n.status.disabled.name);
|
||||||
expect(notActivatedIcon.attributes('name')).toBe('warning-solid');
|
expect(notActivatedIcon.attributes('name')).toBe('warning-solid');
|
||||||
expect(notActivatedIcon.attributes('title')).toBe(i18n.status.disabled.tooltip);
|
expect(notActivatedIcon.attributes('title')).toBe(i18n.status.disabled.tooltip);
|
||||||
|
|
|
||||||
|
|
@ -325,9 +325,9 @@ describe('AlertsSettingsForm', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
expect(findSamplePayloadSection().find(GlFormTextarea).attributes('disabled')).toBe(
|
expect(
|
||||||
disabled,
|
findSamplePayloadSection().findComponent(GlFormTextarea).attributes('disabled'),
|
||||||
);
|
).toBe(disabled);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,14 +63,14 @@ describe('AlertsSettingsWrapper', () => {
|
||||||
|
|
||||||
const findLoader = () => wrapper.findComponent(IntegrationsList).findComponent(GlLoadingIcon);
|
const findLoader = () => wrapper.findComponent(IntegrationsList).findComponent(GlLoadingIcon);
|
||||||
const findIntegrationsList = () => wrapper.findComponent(IntegrationsList);
|
const findIntegrationsList = () => wrapper.findComponent(IntegrationsList);
|
||||||
const findIntegrations = () => wrapper.find(IntegrationsList).findAll('table tbody tr');
|
const findIntegrations = () => wrapper.findComponent(IntegrationsList).findAll('table tbody tr');
|
||||||
const findAddIntegrationBtn = () => wrapper.findByTestId('add-integration-btn');
|
const findAddIntegrationBtn = () => wrapper.findByTestId('add-integration-btn');
|
||||||
const findAlertsSettingsForm = () => wrapper.findComponent(AlertsSettingsForm);
|
const findAlertsSettingsForm = () => wrapper.findComponent(AlertsSettingsForm);
|
||||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||||
|
|
||||||
function destroyHttpIntegration(localWrapper) {
|
function destroyHttpIntegration(localWrapper) {
|
||||||
localWrapper
|
localWrapper
|
||||||
.find(IntegrationsList)
|
.findComponent(IntegrationsList)
|
||||||
.vm.$emit('delete-integration', { id: integrationToDestroy.id });
|
.vm.$emit('delete-integration', { id: integrationToDestroy.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ describe('AlertsSettingsWrapper', () => {
|
||||||
data: { integrations: [] },
|
data: { integrations: [] },
|
||||||
loading: true,
|
loading: true,
|
||||||
});
|
});
|
||||||
expect(wrapper.find(IntegrationsList).exists()).toBe(true);
|
expect(wrapper.findComponent(IntegrationsList).exists()).toBe(true);
|
||||||
expect(findLoader().exists()).toBe(true);
|
expect(findLoader().exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ describe('Activity Chart Bundle', () => {
|
||||||
wrapper = null;
|
wrapper = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const findChart = () => wrapper.find(GlColumnChart);
|
const findChart = () => wrapper.findComponent(GlColumnChart);
|
||||||
const findNoData = () => wrapper.find('[data-testid="noActivityChartData"]');
|
const findNoData = () => wrapper.find('[data-testid="noActivityChartData"]');
|
||||||
|
|
||||||
describe('Activity Chart', () => {
|
describe('Activity Chart', () => {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ describe('MetricPopover', () => {
|
||||||
const findAllMetricLinks = () => wrapper.findAll('[data-testid="metric-link"]');
|
const findAllMetricLinks = () => wrapper.findAll('[data-testid="metric-link"]');
|
||||||
const findMetricDescription = () => wrapper.findByTestId('metric-description');
|
const findMetricDescription = () => wrapper.findByTestId('metric-description');
|
||||||
const findMetricDocsLink = () => wrapper.findByTestId('metric-docs-link');
|
const findMetricDocsLink = () => wrapper.findByTestId('metric-docs-link');
|
||||||
const findMetricDocsLinkIcon = () => findMetricDocsLink().find(GlIcon);
|
const findMetricDocsLinkIcon = () => findMetricDocsLink().findComponent(GlIcon);
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
|
|
@ -83,7 +83,9 @@ describe('MetricPopover', () => {
|
||||||
const allLinkContainers = findAllMetricLinks();
|
const allLinkContainers = findAllMetricLinks();
|
||||||
|
|
||||||
expect(allLinkContainers.at(idx).text()).toContain(link.name);
|
expect(allLinkContainers.at(idx).text()).toContain(link.name);
|
||||||
expect(allLinkContainers.at(idx).find(GlLink).attributes('href')).toBe(link.url);
|
expect(allLinkContainers.at(idx).findComponent(GlLink).attributes('href')).toBe(
|
||||||
|
link.url,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ describe('ProjectsDropdownFilter component', () => {
|
||||||
const findClearAllButton = () => wrapper.findByText('Clear all');
|
const findClearAllButton = () => wrapper.findByText('Clear all');
|
||||||
const findSelectedProjectsLabel = () => wrapper.findComponent(GlTruncate);
|
const findSelectedProjectsLabel = () => wrapper.findComponent(GlTruncate);
|
||||||
|
|
||||||
const findDropdown = () => wrapper.find(GlDropdown);
|
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||||
|
|
||||||
const findDropdownItems = () =>
|
const findDropdownItems = () =>
|
||||||
findDropdown()
|
findDropdown()
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ describe('UsageTrendsApp', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the usage counts component', () => {
|
it('displays the usage counts component', () => {
|
||||||
expect(wrapper.find(UsageCounts).exists()).toBe(true);
|
expect(wrapper.findComponent(UsageCounts).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
['Total projects & groups', 'Pipelines', 'Issues & merge requests'].forEach((usage) => {
|
['Total projects & groups', 'Pipelines', 'Issues & merge requests'].forEach((usage) => {
|
||||||
|
|
@ -35,6 +35,6 @@ describe('UsageTrendsApp', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the users chart component', () => {
|
it('displays the users chart component', () => {
|
||||||
expect(wrapper.find(UsersChart).exists()).toBe(true);
|
expect(wrapper.findComponent(UsersChart).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ describe('UsageTrendsCountChart', () => {
|
||||||
wrapper = null;
|
wrapper = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const findLoader = () => wrapper.find(ChartSkeletonLoader);
|
const findLoader = () => wrapper.findComponent(ChartSkeletonLoader);
|
||||||
const findChart = () => wrapper.find(GlLineChart);
|
const findChart = () => wrapper.findComponent(GlLineChart);
|
||||||
const findAlert = () => wrapper.find(GlAlert);
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||||
|
|
||||||
describe('while loading', () => {
|
describe('while loading', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,9 @@ describe('UsersChart', () => {
|
||||||
wrapper = null;
|
wrapper = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const findLoader = () => wrapper.find(ChartSkeletonLoader);
|
const findLoader = () => wrapper.findComponent(ChartSkeletonLoader);
|
||||||
const findAlert = () => wrapper.find(GlAlert);
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||||
const findChart = () => wrapper.find(GlAreaChart);
|
const findChart = () => wrapper.findComponent(GlAreaChart);
|
||||||
|
|
||||||
describe('while loading', () => {
|
describe('while loading', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ describe('Keep latest artifact checkbox', () => {
|
||||||
const fullPath = 'gitlab-org/gitlab';
|
const fullPath = 'gitlab-org/gitlab';
|
||||||
const helpPagePath = '/help/ci/pipelines/job_artifacts';
|
const helpPagePath = '/help/ci/pipelines/job_artifacts';
|
||||||
|
|
||||||
const findCheckbox = () => wrapper.find(GlFormCheckbox);
|
const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
|
||||||
const findHelpLink = () => wrapper.find(GlLink);
|
const findHelpLink = () => wrapper.findComponent(GlLink);
|
||||||
|
|
||||||
const createComponent = (handlers) => {
|
const createComponent = (handlers) => {
|
||||||
requestHandlers = {
|
requestHandlers = {
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ describe('RecoveryCodes', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryByText = (text, options) => within(wrapper.element).queryByText(text, options);
|
const queryByText = (text, options) => within(wrapper.element).queryByText(text, options);
|
||||||
const findAlert = () => wrapper.find(GlAlert);
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||||
const findRecoveryCodes = () => wrapper.findByTestId('recovery-codes');
|
const findRecoveryCodes = () => wrapper.findByTestId('recovery-codes');
|
||||||
const findCopyButton = () => wrapper.find(ClipboardButton);
|
const findCopyButton = () => wrapper.findComponent(ClipboardButton);
|
||||||
const findButtonByText = (text) =>
|
const findButtonByText = (text) =>
|
||||||
wrapper.findAll(GlButton).wrappers.find((buttonWrapper) => buttonWrapper.text() === text);
|
wrapper.findAll(GlButton).wrappers.find((buttonWrapper) => buttonWrapper.text() === text);
|
||||||
const findDownloadButton = () => findButtonByText('Download codes');
|
const findDownloadButton = () => findButtonByText('Download codes');
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ describe('initRecoveryCodes', () => {
|
||||||
let el;
|
let el;
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
const findRecoveryCodesComponent = () => wrapper.find(RecoveryCodes);
|
const findRecoveryCodesComponent = () => wrapper.findComponent(RecoveryCodes);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
el = document.createElement('div');
|
el = document.createElement('div');
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ describe('BadgeSettings component', () => {
|
||||||
button.vm.$emit('click');
|
button.vm.$emit('click');
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
const modal = wrapper.find(GlModal);
|
const modal = wrapper.findComponent(GlModal);
|
||||||
expect(modal.isVisible()).toBe(true);
|
expect(modal.isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ describe('BadgeSettings component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays badge list', () => {
|
it('displays badge list', () => {
|
||||||
expect(wrapper.find(BadgeList).isVisible()).toBe(true);
|
expect(wrapper.findComponent(BadgeList).isVisible()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when editing', () => {
|
describe('when editing', () => {
|
||||||
|
|
@ -64,7 +64,7 @@ describe('BadgeSettings component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays no badge list', () => {
|
it('displays no badge list', () => {
|
||||||
expect(wrapper.find(BadgeList).isVisible()).toBe(false);
|
expect(wrapper.findComponent(BadgeList).isVisible()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ describe('Batch comments draft note component', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
expect(wrapper.findComponent(GlBadge).exists()).toBe(true);
|
expect(wrapper.findComponent(GlBadge).exists()).toBe(true);
|
||||||
|
|
||||||
const note = wrapper.find(NoteableNote);
|
const note = wrapper.findComponent(NoteableNote);
|
||||||
|
|
||||||
expect(note.exists()).toBe(true);
|
expect(note.exists()).toBe(true);
|
||||||
expect(note.props().note).toEqual(draft);
|
expect(note.props().note).toEqual(draft);
|
||||||
|
|
@ -122,7 +122,7 @@ describe('Batch comments draft note component', () => {
|
||||||
describe('update', () => {
|
describe('update', () => {
|
||||||
it('dispatches updateDraft', async () => {
|
it('dispatches updateDraft', async () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
const note = wrapper.find(NoteableNote);
|
const note = wrapper.findComponent(NoteableNote);
|
||||||
|
|
||||||
note.vm.$emit('handleEdit');
|
note.vm.$emit('handleEdit');
|
||||||
|
|
||||||
|
|
@ -147,7 +147,7 @@ describe('Batch comments draft note component', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
jest.spyOn(window, 'confirm').mockImplementation(() => true);
|
jest.spyOn(window, 'confirm').mockImplementation(() => true);
|
||||||
|
|
||||||
const note = wrapper.find(NoteableNote);
|
const note = wrapper.findComponent(NoteableNote);
|
||||||
|
|
||||||
note.vm.$emit('handleDeleteNote', draft);
|
note.vm.$emit('handleDeleteNote', draft);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,6 @@ describe('Batch comments publish dropdown component', () => {
|
||||||
it('renders draft count in dropdown title', () => {
|
it('renders draft count in dropdown title', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
expect(wrapper.find(GlDropdown).props('headerText')).toEqual('2 pending comments');
|
expect(wrapper.findComponent(GlDropdown).props('headerText')).toEqual('2 pending comments');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ describe('Captcha Modal', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const findGlModal = () => {
|
const findGlModal = () => {
|
||||||
const glModal = wrapper.find(GlModal);
|
const glModal = wrapper.findComponent(GlModal);
|
||||||
|
|
||||||
jest.spyOn(glModal.vm, 'show').mockImplementation(() => glModal.vm.$emit('shown'));
|
jest.spyOn(glModal.vm, 'show').mockImplementation(() => glModal.vm.$emit('shown'));
|
||||||
jest
|
jest
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ describe('LockPopovers', () => {
|
||||||
wrapper = mountExtended(LockPopovers);
|
wrapper = mountExtended(LockPopovers);
|
||||||
};
|
};
|
||||||
|
|
||||||
const findPopover = () => extendedWrapper(wrapper.find(GlPopover));
|
const findPopover = () => extendedWrapper(wrapper.findComponent(GlPopover));
|
||||||
const findByTextInPopover = (text, options) =>
|
const findByTextInPopover = (text, options) =>
|
||||||
findPopover().findByText((_, element) => element.textContent === text, options);
|
findPopover().findByText((_, element) => element.textContent === text, options);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ describe('CI Lint', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findEditor = () => wrapper.find(SourceEditor);
|
const findEditor = () => wrapper.findComponent(SourceEditor);
|
||||||
const findAlert = () => wrapper.find(GlAlert);
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||||
const findCiLintResults = () => wrapper.find(CiLintResults);
|
const findCiLintResults = () => wrapper.findComponent(CiLintResults);
|
||||||
const findValidateBtn = () => wrapper.find('[data-testid="ci-lint-validate"]');
|
const findValidateBtn = () => wrapper.find('[data-testid="ci-lint-validate"]');
|
||||||
const findClearBtn = () => wrapper.find('[data-testid="ci-lint-clear"]');
|
const findClearBtn = () => wrapper.find('[data-testid="ci-lint-clear"]');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,9 @@ describe('SecureFilesList', () => {
|
||||||
const [secureFile] = secureFiles;
|
const [secureFile] = secureFiles;
|
||||||
|
|
||||||
expect(findCell(0, 0).text()).toBe(secureFile.name);
|
expect(findCell(0, 0).text()).toBe(secureFile.name);
|
||||||
expect(findCell(0, 1).find(TimeAgoTooltip).props('time')).toBe(secureFile.created_at);
|
expect(findCell(0, 1).findComponent(TimeAgoTooltip).props('time')).toBe(
|
||||||
|
secureFile.created_at,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('event tracking', () => {
|
describe('event tracking', () => {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ describe('TriggersList', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findTable = () => wrapper.find(GlTable);
|
const findTable = () => wrapper.findComponent(GlTable);
|
||||||
const findHeaderAt = (i) => wrapper.findAll('thead th').at(i);
|
const findHeaderAt = (i) => wrapper.findAll('thead th').at(i);
|
||||||
const findRows = () => wrapper.findAll('tbody tr');
|
const findRows = () => wrapper.findAll('tbody tr');
|
||||||
const findRowAt = (i) => findRows().at(i);
|
const findRowAt = (i) => findRows().at(i);
|
||||||
const findCell = (i, col) => findRowAt(i).findAll('td').at(col);
|
const findCell = (i, col) => findRowAt(i).findAll('td').at(col);
|
||||||
const findClipboardBtn = (i) => findCell(i, 0).find(ClipboardButton);
|
const findClipboardBtn = (i) => findCell(i, 0).findComponent(ClipboardButton);
|
||||||
const findInvalidBadge = (i) => findCell(i, 0).find(GlBadge);
|
const findInvalidBadge = (i) => findCell(i, 0).findComponent(GlBadge);
|
||||||
const findEditBtn = (i) => findRowAt(i).find('[data-testid="edit-btn"]');
|
const findEditBtn = (i) => findRowAt(i).find('[data-testid="edit-btn"]');
|
||||||
const findRevokeBtn = (i) => findRowAt(i).find('[data-testid="trigger_revoke_button"]');
|
const findRevokeBtn = (i) => findRowAt(i).find('[data-testid="trigger_revoke_button"]');
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ describe('TriggersList', () => {
|
||||||
it('displays a time ago label when last used', () => {
|
it('displays a time ago label when last used', () => {
|
||||||
expect(findCell(0, 3).text()).toBe('Never');
|
expect(findCell(0, 3).text()).toBe('Never');
|
||||||
|
|
||||||
expect(findCell(1, 3).find(TimeAgoTooltip).props('time')).toBe(triggers[1].lastUsed);
|
expect(findCell(1, 3).findComponent(TimeAgoTooltip).props('time')).toBe(triggers[1].lastUsed);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays actions in a rows', () => {
|
it('displays actions in a rows', () => {
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ describe('Ci variable modal', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findCiEnvironmentsDropdown = () => wrapper.find(CiEnvironmentsDropdown);
|
const findCiEnvironmentsDropdown = () => wrapper.findComponent(CiEnvironmentsDropdown);
|
||||||
const findReferenceWarning = () => wrapper.findByTestId('contains-variable-reference');
|
const findReferenceWarning = () => wrapper.findByTestId('contains-variable-reference');
|
||||||
const findModal = () => wrapper.find(ModalStub);
|
const findModal = () => wrapper.findComponent(ModalStub);
|
||||||
const findAWSTip = () => wrapper.findByTestId('aws-guidance-tip');
|
const findAWSTip = () => wrapper.findByTestId('aws-guidance-tip');
|
||||||
const findAddorUpdateButton = () => wrapper.findByTestId('ciUpdateOrAddVariableBtn');
|
const findAddorUpdateButton = () => wrapper.findByTestId('ciUpdateOrAddVariableBtn');
|
||||||
const deleteVariableButton = () =>
|
const deleteVariableButton = () =>
|
||||||
|
|
@ -72,7 +72,8 @@ describe('Ci variable modal', () => {
|
||||||
const findMaskedVariableCheckbox = () => wrapper.findByTestId('ci-variable-masked-checkbox');
|
const findMaskedVariableCheckbox = () => wrapper.findByTestId('ci-variable-masked-checkbox');
|
||||||
const findValueField = () => wrapper.find('#ci-variable-value');
|
const findValueField = () => wrapper.find('#ci-variable-value');
|
||||||
const findEnvScopeLink = () => wrapper.findByTestId('environment-scope-link');
|
const findEnvScopeLink = () => wrapper.findByTestId('environment-scope-link');
|
||||||
const findEnvScopeInput = () => wrapper.findByTestId('environment-scope').find(GlFormInput);
|
const findEnvScopeInput = () =>
|
||||||
|
wrapper.findByTestId('environment-scope').findComponent(GlFormInput);
|
||||||
const findVariableTypeDropdown = () => wrapper.find('#ci-variable-type');
|
const findVariableTypeDropdown = () => wrapper.find('#ci-variable-type');
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ describe('Ci Variable Popover', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findButton = () => wrapper.find(GlButton);
|
const findButton = () => wrapper.findComponent(GlButton);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ describe('Ci variable modal', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findCiEnvironmentsDropdown = () => wrapper.find(CiEnvironmentsDropdown);
|
const findCiEnvironmentsDropdown = () => wrapper.findComponent(CiEnvironmentsDropdown);
|
||||||
const findModal = () => wrapper.find(ModalStub);
|
const findModal = () => wrapper.findComponent(ModalStub);
|
||||||
const findAddorUpdateButton = () => findModal().find('[data-testid="ciUpdateOrAddVariableBtn"]');
|
const findAddorUpdateButton = () => findModal().find('[data-testid="ciUpdateOrAddVariableBtn"]');
|
||||||
const deleteVariableButton = () =>
|
const deleteVariableButton = () =>
|
||||||
findModal()
|
findModal()
|
||||||
|
|
@ -213,7 +213,7 @@ describe('Ci variable modal', () => {
|
||||||
|
|
||||||
const environmentScopeInput = wrapper
|
const environmentScopeInput = wrapper
|
||||||
.find('[data-testid="environment-scope"]')
|
.find('[data-testid="environment-scope"]')
|
||||||
.find(GlFormInput);
|
.findComponent(GlFormInput);
|
||||||
expect(findCiEnvironmentsDropdown().exists()).toBe(false);
|
expect(findCiEnvironmentsDropdown().exists()).toBe(false);
|
||||||
expect(environmentScopeInput.attributes('readonly')).toBe('readonly');
|
expect(environmentScopeInput.attributes('readonly')).toBe('readonly');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ describe('AgentTable', () => {
|
||||||
|
|
||||||
const findAgentLink = (at) => wrapper.findAllByTestId('cluster-agent-name-link').at(at);
|
const findAgentLink = (at) => wrapper.findAllByTestId('cluster-agent-name-link').at(at);
|
||||||
const findStatusText = (at) => wrapper.findAllByTestId('cluster-agent-connection-status').at(at);
|
const findStatusText = (at) => wrapper.findAllByTestId('cluster-agent-connection-status').at(at);
|
||||||
const findStatusIcon = (at) => findStatusText(at).find(GlIcon);
|
const findStatusIcon = (at) => findStatusText(at).findComponent(GlIcon);
|
||||||
const findLastContactText = (at) => wrapper.findAllByTestId('cluster-agent-last-contact').at(at);
|
const findLastContactText = (at) => wrapper.findAllByTestId('cluster-agent-last-contact').at(at);
|
||||||
const findVersionText = (at) => wrapper.findAllByTestId('cluster-agent-version').at(at);
|
const findVersionText = (at) => wrapper.findAllByTestId('cluster-agent-version').at(at);
|
||||||
const findConfiguration = (at) =>
|
const findConfiguration = (at) =>
|
||||||
|
|
@ -113,7 +113,7 @@ describe('AgentTable', () => {
|
||||||
texts,
|
texts,
|
||||||
lineNumber,
|
lineNumber,
|
||||||
}) => {
|
}) => {
|
||||||
const findIcon = () => findVersionText(lineNumber).find(GlIcon);
|
const findIcon = () => findVersionText(lineNumber).findComponent(GlIcon);
|
||||||
const findPopover = () => wrapper.findByTestId(`popover-${agent}`);
|
const findPopover = () => wrapper.findByTestId(`popover-${agent}`);
|
||||||
const versionWarning = versionMismatch || versionOutdated;
|
const versionWarning = versionMismatch || versionOutdated;
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ describe('AgentTable', () => {
|
||||||
`(
|
`(
|
||||||
'displays config file path as "$agentPath" at line $lineNumber',
|
'displays config file path as "$agentPath" at line $lineNumber',
|
||||||
({ agentConfig, link, lineNumber }) => {
|
({ agentConfig, link, lineNumber }) => {
|
||||||
const findLink = findConfiguration(lineNumber).find(GlLink);
|
const findLink = findConfiguration(lineNumber).findComponent(GlLink);
|
||||||
|
|
||||||
expect(findLink.attributes('href')).toBe(link);
|
expect(findLink.attributes('href')).toBe(link);
|
||||||
expect(findConfiguration(lineNumber).text()).toBe(agentConfig);
|
expect(findConfiguration(lineNumber).text()).toBe(agentConfig);
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ describe('Agents', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays a loading icon', () => {
|
it('displays a loading icon', () => {
|
||||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
|
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ describe('ClustersAncestorNotice', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays link', () => {
|
it('displays link', () => {
|
||||||
expect(wrapper.find(GlLink).exists()).toBe(true);
|
expect(wrapper.findComponent(GlLink).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ describe('Clusters', () => {
|
||||||
({ lineNumber, result }) => {
|
({ lineNumber, result }) => {
|
||||||
const statuses = findStatuses();
|
const statuses = findStatuses();
|
||||||
const status = statuses.at(lineNumber);
|
const status = statuses.at(lineNumber);
|
||||||
expect(status.find(GlLoadingIcon).exists()).toBe(result);
|
expect(status.findComponent(GlLoadingIcon).exists()).toBe(result);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ describe('NodeErrorHelpText', () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
};
|
};
|
||||||
|
|
||||||
const findPopover = () => wrapper.find(GlPopover);
|
const findPopover = () => wrapper.findComponent(GlPopover);
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ describe('Code navigation app component', () => {
|
||||||
it('hides popover when no definition set', () => {
|
it('hides popover when no definition set', () => {
|
||||||
factory();
|
factory();
|
||||||
|
|
||||||
expect(wrapper.find(Popover).exists()).toBe(false);
|
expect(wrapper.findComponent(Popover).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders popover when definition set', () => {
|
it('renders popover when definition set', () => {
|
||||||
|
|
@ -73,7 +73,7 @@ describe('Code navigation app component', () => {
|
||||||
currentBlobPath: 'index.js',
|
currentBlobPath: 'index.js',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(Popover).exists()).toBe(true);
|
expect(wrapper.findComponent(Popover).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls showDefinition when clicking blob viewer', () => {
|
it('calls showDefinition when clicking blob viewer', () => {
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,8 @@ describe('Code navigation popover component', () => {
|
||||||
definitionPathPrefix: DEFINITION_PATH_PREFIX,
|
definitionPathPrefix: DEFINITION_PATH_PREFIX,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find({ ref: 'code-output' }).exists()).toBe(true);
|
expect(wrapper.findComponent({ ref: 'code-output' }).exists()).toBe(true);
|
||||||
expect(wrapper.find({ ref: 'doc-output' }).exists()).toBe(false);
|
expect(wrapper.findComponent({ ref: 'doc-output' }).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -128,8 +128,8 @@ describe('Code navigation popover component', () => {
|
||||||
definitionPathPrefix: DEFINITION_PATH_PREFIX,
|
definitionPathPrefix: DEFINITION_PATH_PREFIX,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find({ ref: 'code-output' }).exists()).toBe(false);
|
expect(wrapper.findComponent({ ref: 'code-output' }).exists()).toBe(false);
|
||||||
expect(wrapper.find({ ref: 'doc-output' }).exists()).toBe(true);
|
expect(wrapper.findComponent({ ref: 'doc-output' }).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ describe('Commit pipeline status component', () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findLoader = () => wrapper.find(GlLoadingIcon);
|
const findLoader = () => wrapper.findComponent(GlLoadingIcon);
|
||||||
const findLink = () => wrapper.find('a');
|
const findLink = () => wrapper.find('a');
|
||||||
const findCiIcon = () => findLink().find(CiIcon);
|
const findCiIcon = () => findLink().findComponent(CiIcon);
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,12 @@ describe('Confidential merge request project dropdown component', () => {
|
||||||
it('shows lock icon', () => {
|
it('shows lock icon', () => {
|
||||||
factory();
|
factory();
|
||||||
|
|
||||||
expect(vm.find(GlDropdown).props('icon')).toBe('lock');
|
expect(vm.findComponent(GlDropdown).props('icon')).toBe('lock');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has dropdown text', () => {
|
it('has dropdown text', () => {
|
||||||
factory();
|
factory();
|
||||||
|
|
||||||
expect(vm.find(GlDropdown).props('text')).toBe('Select private project');
|
expect(vm.findComponent(GlDropdown).props('text')).toBe('Select private project');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ describe.each`
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectFile = async (file) => {
|
const selectFile = async (file) => {
|
||||||
const input = wrapper.find({ ref: 'fileSelector' });
|
const input = wrapper.findComponent({ ref: 'fileSelector' });
|
||||||
|
|
||||||
// override the property definition because `input.files` isn't directly modifyable
|
// override the property definition because `input.files` isn't directly modifyable
|
||||||
Object.defineProperty(input.element, 'files', { value: [file], writable: true });
|
Object.defineProperty(input.element, 'files', { value: [file], writable: true });
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ describe('content_editor/components/toolbar_image_button', () => {
|
||||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||||
|
|
||||||
const selectFile = async (file) => {
|
const selectFile = async (file) => {
|
||||||
const input = wrapper.find({ ref: 'fileSelector' });
|
const input = wrapper.findComponent({ ref: 'fileSelector' });
|
||||||
|
|
||||||
// override the property definition because `input.files` isn't directly modifyable
|
// override the property definition because `input.files` isn't directly modifyable
|
||||||
Object.defineProperty(input.element, 'files', { value: [file], writable: true });
|
Object.defineProperty(input.element, 'files', { value: [file], writable: true });
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ describe('content_editor/components/toolbar_link_button', () => {
|
||||||
const findRemoveLinkButton = () => wrapper.findByText('Remove link');
|
const findRemoveLinkButton = () => wrapper.findByText('Remove link');
|
||||||
|
|
||||||
const selectFile = async (file) => {
|
const selectFile = async (file) => {
|
||||||
const input = wrapper.find({ ref: 'fileSelector' });
|
const input = wrapper.findComponent({ ref: 'fileSelector' });
|
||||||
|
|
||||||
// override the property definition because `input.files` isn't directly modifyable
|
// override the property definition because `input.files` isn't directly modifyable
|
||||||
Object.defineProperty(input.element, 'files', { value: [file], writable: true });
|
Object.defineProperty(input.element, 'files', { value: [file], writable: true });
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ describe('content/components/wrappers/code_block', () => {
|
||||||
it('does not render a preview if showPreview: false', async () => {
|
it('does not render a preview if showPreview: false', async () => {
|
||||||
createWrapper({ language: 'plantuml', isDiagram: true, showPreview: false });
|
createWrapper({ language: 'plantuml', isDiagram: true, showPreview: false });
|
||||||
|
|
||||||
expect(wrapper.find({ ref: 'diagramContainer' }).exists()).toBe(false);
|
expect(wrapper.findComponent({ ref: 'diagramContainer' }).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not update preview when diagram is not active', async () => {
|
it('does not update preview when diagram is not active', async () => {
|
||||||
|
|
@ -134,7 +134,7 @@ describe('content/components/wrappers/code_block', () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(wrapper.find('img').attributes('src')).toBe('url/to/some/diagram');
|
expect(wrapper.find('img').attributes('src')).toBe('url/to/some/diagram');
|
||||||
expect(wrapper.find(SandboxedMermaid).exists()).toBe(false);
|
expect(wrapper.findComponent(SandboxedMermaid).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an iframe with preview for a mermaid diagram', async () => {
|
it('renders an iframe with preview for a mermaid diagram', async () => {
|
||||||
|
|
@ -143,7 +143,7 @@ describe('content/components/wrappers/code_block', () => {
|
||||||
await emitEditorEvent({ event: 'transaction', tiptapEditor });
|
await emitEditorEvent({ event: 'transaction', tiptapEditor });
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(wrapper.find(SandboxedMermaid).props('source')).toBe('');
|
expect(wrapper.findComponent(SandboxedMermaid).props('source')).toBe('');
|
||||||
expect(wrapper.find('img').exists()).toBe(false);
|
expect(wrapper.find('img').exists()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ describe('Reusable form component', () => {
|
||||||
`(
|
`(
|
||||||
'should render the correct component for #$id with the value "$value"',
|
'should render the correct component for #$id with the value "$value"',
|
||||||
({ index, id, component, value }) => {
|
({ index, id, component, value }) => {
|
||||||
const findFormElement = () => findFormGroup(index).find(component);
|
const findFormElement = () => findFormGroup(index).findComponent(component);
|
||||||
|
|
||||||
expect(findFormElement().attributes('id')).toBe(id);
|
expect(findFormElement().attributes('id')).toBe(id);
|
||||||
expect(findFormElement().attributes('value')).toBe(value);
|
expect(findFormElement().attributes('value')).toBe(value);
|
||||||
|
|
@ -307,7 +307,8 @@ describe('Reusable form component', () => {
|
||||||
|
|
||||||
it('should render a checked GlFormCheckbox for #active', () => {
|
it('should render a checked GlFormCheckbox for #active', () => {
|
||||||
const activeCheckboxIndex = 6;
|
const activeCheckboxIndex = 6;
|
||||||
const findFormElement = () => findFormGroup(activeCheckboxIndex).find(GlFormCheckbox);
|
const findFormElement = () =>
|
||||||
|
findFormGroup(activeCheckboxIndex).findComponent(GlFormCheckbox);
|
||||||
|
|
||||||
expect(findFormElement().attributes('id')).toBe('active');
|
expect(findFormElement().attributes('id')).toBe('active');
|
||||||
expect(findFormElement().attributes('checked')).toBe('true');
|
expect(findFormElement().attributes('checked')).toBe('true');
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ describe('Value stream analytics component', () => {
|
||||||
it('renders the stage table with a loading icon', () => {
|
it('renders the stage table with a loading icon', () => {
|
||||||
const tableWrapper = findStageTable();
|
const tableWrapper = findStageTable();
|
||||||
expect(tableWrapper.exists()).toBe(true);
|
expect(tableWrapper.exists()).toBe(true);
|
||||||
expect(tableWrapper.find(GlLoadingIcon).exists()).toBe(true);
|
expect(tableWrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the path navigation loading state', () => {
|
it('renders the path navigation loading state', () => {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,9 @@ describe('Project PathNavigation', () => {
|
||||||
|
|
||||||
describe('displays correctly', () => {
|
describe('displays correctly', () => {
|
||||||
it('has the correct props', () => {
|
it('has the correct props', () => {
|
||||||
expect(wrapper.find(GlPath).props('items')).toMatchObject(transformedProjectStagePathData);
|
expect(wrapper.findComponent(GlPath).props('items')).toMatchObject(
|
||||||
|
transformedProjectStagePathData,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('contains all the expected stages', () => {
|
it('contains all the expected stages', () => {
|
||||||
|
|
@ -69,11 +71,11 @@ describe('Project PathNavigation', () => {
|
||||||
describe('loading', () => {
|
describe('loading', () => {
|
||||||
describe('is false', () => {
|
describe('is false', () => {
|
||||||
it('displays the gl-path component', () => {
|
it('displays the gl-path component', () => {
|
||||||
expect(wrapper.find(GlPath).exists()).toBe(true);
|
expect(wrapper.findComponent(GlPath).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the gl-skeleton-loading component', () => {
|
it('hides the gl-skeleton-loading component', () => {
|
||||||
expect(wrapper.find(GlSkeletonLoader).exists()).toBe(false);
|
expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders each stage', () => {
|
it('renders each stage', () => {
|
||||||
|
|
@ -112,11 +114,11 @@ describe('Project PathNavigation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hides the gl-path component', () => {
|
it('hides the gl-path component', () => {
|
||||||
expect(wrapper.find(GlPath).exists()).toBe(false);
|
expect(wrapper.findComponent(GlPath).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the gl-skeleton-loading component', () => {
|
it('displays the gl-skeleton-loading component', () => {
|
||||||
expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true);
|
expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ describe('Deploy freeze modal', () => {
|
||||||
|
|
||||||
wrapper.find('#deploy-freeze-start').trigger('input');
|
wrapper.find('#deploy-freeze-start').trigger('input');
|
||||||
wrapper.find('#deploy-freeze-end').trigger('input');
|
wrapper.find('#deploy-freeze-end').trigger('input');
|
||||||
wrapper.find(TimezoneDropdown).trigger('input');
|
wrapper.findComponent(TimezoneDropdown).trigger('input');
|
||||||
};
|
};
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,11 @@ describe('Deploy freeze settings', () => {
|
||||||
|
|
||||||
describe('Deploy freeze table contains components', () => {
|
describe('Deploy freeze table contains components', () => {
|
||||||
it('contains deploy freeze table', () => {
|
it('contains deploy freeze table', () => {
|
||||||
expect(wrapper.find(DeployFreezeTable).exists()).toBe(true);
|
expect(wrapper.findComponent(DeployFreezeTable).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('contains deploy freeze modal', () => {
|
it('contains deploy freeze modal', () => {
|
||||||
expect(wrapper.find(DeployFreezeModal).exists()).toBe(true);
|
expect(wrapper.findComponent(DeployFreezeModal).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ describe('Deploy freeze timezone dropdown', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders selected time zone as dropdown label', () => {
|
it('renders selected time zone as dropdown label', () => {
|
||||||
expect(wrapper.find(GlDropdown).vm.text).toBe('Alaska');
|
expect(wrapper.findComponent(GlDropdown).vm.text).toBe('Alaska');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ const UPDATED_COMMIT_URL = `${TEST_HOST}/COMMIT/NEW`;
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
function getCollapsedFilesWarning(wrapper) {
|
function getCollapsedFilesWarning(wrapper) {
|
||||||
return wrapper.find(CollapsedFilesWarning);
|
return wrapper.findComponent(CollapsedFilesWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('diffs/components/app', () => {
|
describe('diffs/components/app', () => {
|
||||||
|
|
@ -167,7 +167,7 @@ describe('diffs/components/app', () => {
|
||||||
state.diffs.isLoading = true;
|
state.diffs.isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
|
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays loading icon on batch loading', () => {
|
it('displays loading icon on batch loading', () => {
|
||||||
|
|
@ -175,13 +175,13 @@ describe('diffs/components/app', () => {
|
||||||
state.diffs.batchLoadingState = 'loading';
|
state.diffs.batchLoadingState = 'loading';
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
|
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays diffs container when not loading', () => {
|
it('displays diffs container when not loading', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
|
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
|
||||||
expect(wrapper.find('#diffs').exists()).toBe(true);
|
expect(wrapper.find('#diffs').exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@ describe('diffs/components/app', () => {
|
||||||
it('renders empty state when no diff files exist', () => {
|
it('renders empty state when no diff files exist', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
expect(wrapper.find(NoChanges).exists()).toBe(true);
|
expect(wrapper.findComponent(NoChanges).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not render empty state when diff files exist', () => {
|
it('does not render empty state when diff files exist', () => {
|
||||||
|
|
@ -273,7 +273,7 @@ describe('diffs/components/app', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(NoChanges).exists()).toBe(false);
|
expect(wrapper.findComponent(NoChanges).exists()).toBe(false);
|
||||||
expect(wrapper.findAll(DiffFile).length).toBe(1);
|
expect(wrapper.findAll(DiffFile).length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -487,8 +487,8 @@ describe('diffs/components/app', () => {
|
||||||
state.diffs.mergeRequestDiff = mergeRequestDiff;
|
state.diffs.mergeRequestDiff = mergeRequestDiff;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(CompareVersions).exists()).toBe(true);
|
expect(wrapper.findComponent(CompareVersions).exists()).toBe(true);
|
||||||
expect(wrapper.find(CompareVersions).props()).toEqual(
|
expect(wrapper.findComponent(CompareVersions).props()).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
diffFilesCountText: null,
|
diffFilesCountText: null,
|
||||||
}),
|
}),
|
||||||
|
|
@ -506,8 +506,8 @@ describe('diffs/components/app', () => {
|
||||||
state.diffs.size = 1;
|
state.diffs.size = 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(HiddenFilesWarning).exists()).toBe(true);
|
expect(wrapper.findComponent(HiddenFilesWarning).exists()).toBe(true);
|
||||||
expect(wrapper.find(HiddenFilesWarning).props()).toEqual(
|
expect(wrapper.findComponent(HiddenFilesWarning).props()).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
total: '5',
|
total: '5',
|
||||||
plainDiffPath: 'plain diff path',
|
plainDiffPath: 'plain diff path',
|
||||||
|
|
@ -547,7 +547,7 @@ describe('diffs/components/app', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(CommitWidget).exists()).toBe(true);
|
expect(wrapper.findComponent(CommitWidget).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display diff file if there are diff files', () => {
|
it('should display diff file if there are diff files', () => {
|
||||||
|
|
@ -555,13 +555,13 @@ describe('diffs/components/app', () => {
|
||||||
state.diffs.diffFiles.push({ sha: '123' });
|
state.diffs.diffFiles.push({ sha: '123' });
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(DiffFile).exists()).toBe(true);
|
expect(wrapper.findComponent(DiffFile).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("doesn't render tree list when no changes exist", () => {
|
it("doesn't render tree list when no changes exist", () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
expect(wrapper.find(TreeList).exists()).toBe(false);
|
expect(wrapper.findComponent(TreeList).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render tree list', () => {
|
it('should render tree list', () => {
|
||||||
|
|
@ -569,7 +569,7 @@ describe('diffs/components/app', () => {
|
||||||
state.diffs.diffFiles = [{ file_hash: '111', file_path: '111.js' }];
|
state.diffs.diffFiles = [{ file_hash: '111', file_path: '111.js' }];
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(TreeList).exists()).toBe(true);
|
expect(wrapper.findComponent(TreeList).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -641,7 +641,7 @@ describe('diffs/components/app', () => {
|
||||||
|
|
||||||
describe('pagination', () => {
|
describe('pagination', () => {
|
||||||
const fileByFileNav = () => wrapper.find('[data-testid="file-by-file-navigation"]');
|
const fileByFileNav = () => wrapper.find('[data-testid="file-by-file-navigation"]');
|
||||||
const paginator = () => fileByFileNav().find(GlPagination);
|
const paginator = () => fileByFileNav().findComponent(GlPagination);
|
||||||
|
|
||||||
it('sets previous button as disabled', async () => {
|
it('sets previous button as disabled', async () => {
|
||||||
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
|
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ describe('CollapsedFilesWarning', () => {
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
const getAlertActionButton = () =>
|
const getAlertActionButton = () =>
|
||||||
wrapper.find(CollapsedFilesWarning).find('button.gl-alert-action:first-child');
|
wrapper.findComponent(CollapsedFilesWarning).find('button.gl-alert-action:first-child');
|
||||||
const getAlertCloseButton = () => wrapper.find(CollapsedFilesWarning).find('button');
|
const getAlertCloseButton = () => wrapper.findComponent(CollapsedFilesWarning).find('button');
|
||||||
|
|
||||||
const createComponent = (props = {}, { full } = { full: false }) => {
|
const createComponent = (props = {}, { full } = { full: false }) => {
|
||||||
const mounter = full ? mount : shallowMount;
|
const mounter = full ? mount : shallowMount;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ describe('diffs/components/commit_item', () => {
|
||||||
const getAvatarElement = () => wrapper.find('.user-avatar-link');
|
const getAvatarElement = () => wrapper.find('.user-avatar-link');
|
||||||
const getCommitterElement = () => wrapper.find('.committer');
|
const getCommitterElement = () => wrapper.find('.committer');
|
||||||
const getCommitActionsElement = () => wrapper.find('.commit-actions');
|
const getCommitActionsElement = () => wrapper.find('.commit-actions');
|
||||||
const getCommitPipelineStatus = () => wrapper.find(CommitPipelineStatus);
|
const getCommitPipelineStatus = () => wrapper.findComponent(CommitPipelineStatus);
|
||||||
|
|
||||||
const mountComponent = (propsData) => {
|
const mountComponent = (propsData) => {
|
||||||
wrapper = mount(Component, {
|
wrapper = mount(Component, {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ describe('diffs/components/commit_widget', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders commit item', () => {
|
it('renders commit item', () => {
|
||||||
const commitElement = wrapper.find(CommitItem);
|
const commitElement = wrapper.findComponent(CommitItem);
|
||||||
|
|
||||||
expect(commitElement.exists()).toBe(true);
|
expect(commitElement.exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,24 +20,24 @@ describe('DiffCommentCell', () => {
|
||||||
it('renders discussions if line has discussions', () => {
|
it('renders discussions if line has discussions', () => {
|
||||||
const wrapper = createWrapper({ renderDiscussion: true });
|
const wrapper = createWrapper({ renderDiscussion: true });
|
||||||
|
|
||||||
expect(wrapper.find(DiffDiscussions).exists()).toBe(true);
|
expect(wrapper.findComponent(DiffDiscussions).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not render discussions if line has no discussions', () => {
|
it('does not render discussions if line has no discussions', () => {
|
||||||
const wrapper = createWrapper();
|
const wrapper = createWrapper();
|
||||||
|
|
||||||
expect(wrapper.find(DiffDiscussions).exists()).toBe(false);
|
expect(wrapper.findComponent(DiffDiscussions).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders discussion reply if line has no draft', () => {
|
it('renders discussion reply if line has no draft', () => {
|
||||||
const wrapper = createWrapper();
|
const wrapper = createWrapper();
|
||||||
|
|
||||||
expect(wrapper.find(DiffDiscussionReply).exists()).toBe(true);
|
expect(wrapper.findComponent(DiffDiscussionReply).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not render discussion reply if line has draft', () => {
|
it('does not render discussion reply if line has draft', () => {
|
||||||
const wrapper = createWrapper({ hasDraft: true });
|
const wrapper = createWrapper({ hasDraft: true });
|
||||||
|
|
||||||
expect(wrapper.find(DiffDiscussionReply).exists()).toBe(false);
|
expect(wrapper.findComponent(DiffDiscussionReply).exists()).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -110,13 +110,13 @@ describe('DiffContent', () => {
|
||||||
props: { diffFile: textDiffFile },
|
props: { diffFile: textDiffFile },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(DiffView).exists()).toBe(true);
|
expect(wrapper.findComponent(DiffView).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders rendering more lines loading icon', () => {
|
it('renders rendering more lines loading icon', () => {
|
||||||
createComponent({ props: { diffFile: { ...textDiffFile, renderingLines: true } } });
|
createComponent({ props: { diffFile: { ...textDiffFile, renderingLines: true } } });
|
||||||
|
|
||||||
expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
|
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -133,7 +133,7 @@ describe('DiffContent', () => {
|
||||||
props: { diffFile: { ...emptyDiffFile, viewer: { name: diffViewerModes.no_preview } } },
|
props: { diffFile: { ...emptyDiffFile, viewer: { name: diffViewerModes.no_preview } } },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(NoPreviewViewer).exists()).toBe(true);
|
expect(wrapper.findComponent(NoPreviewViewer).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render not diffable view if viewer set to non_diffable', () => {
|
it('should render not diffable view if viewer set to non_diffable', () => {
|
||||||
|
|
@ -141,7 +141,7 @@ describe('DiffContent', () => {
|
||||||
props: { diffFile: { ...emptyDiffFile, viewer: { name: diffViewerModes.not_diffable } } },
|
props: { diffFile: { ...emptyDiffFile, viewer: { name: diffViewerModes.not_diffable } } },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(NotDiffableViewer).exists()).toBe(true);
|
expect(wrapper.findComponent(NotDiffableViewer).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -156,7 +156,7 @@ describe('DiffContent', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(DiffDiscussions).exists()).toBe(true);
|
expect(wrapper.findComponent(DiffDiscussions).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits saveDiffDiscussion when note-form emits `handleFormUpdate`', () => {
|
it('emits saveDiffDiscussion when note-form emits `handleFormUpdate`', () => {
|
||||||
|
|
@ -169,7 +169,7 @@ describe('DiffContent', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find(NoteForm).vm.$emit('handleFormUpdate', noteStub);
|
wrapper.findComponent(NoteForm).vm.$emit('handleFormUpdate', noteStub);
|
||||||
expect(saveDiffDiscussionMock).toHaveBeenCalledWith(expect.any(Object), {
|
expect(saveDiffDiscussionMock).toHaveBeenCalledWith(expect.any(Object), {
|
||||||
note: noteStub,
|
note: noteStub,
|
||||||
formData: {
|
formData: {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ describe('DiffDiscussionReply', () => {
|
||||||
hasForm: false,
|
hasForm: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(ReplyPlaceholder).exists()).toBe(true);
|
expect(wrapper.findComponent(ReplyPlaceholder).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -83,6 +83,6 @@ describe('DiffDiscussionReply', () => {
|
||||||
hasForm: false,
|
hasForm: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find(NoteSignedOutWidget).exists()).toBe(true);
|
expect(wrapper.findComponent(NoteSignedOutWidget).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ describe('DiffDiscussions', () => {
|
||||||
it('should have notes list', () => {
|
it('should have notes list', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
expect(wrapper.find(NoteableDiscussion).exists()).toBe(true);
|
expect(wrapper.findComponent(NoteableDiscussion).exists()).toBe(true);
|
||||||
expect(wrapper.find(DiscussionNotes).exists()).toBe(true);
|
expect(wrapper.findComponent(DiscussionNotes).exists()).toBe(true);
|
||||||
expect(wrapper.find(DiscussionNotes).findAll(TimelineEntryItem).length).toBe(
|
expect(wrapper.findComponent(DiscussionNotes).findAll(TimelineEntryItem).length).toBe(
|
||||||
discussionsMockData.notes.length,
|
discussionsMockData.notes.length,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -48,7 +48,7 @@ describe('DiffDiscussions', () => {
|
||||||
const diffNotesToggle = findDiffNotesToggle();
|
const diffNotesToggle = findDiffNotesToggle();
|
||||||
|
|
||||||
expect(diffNotesToggle.exists()).toBe(true);
|
expect(diffNotesToggle.exists()).toBe(true);
|
||||||
expect(diffNotesToggle.find(GlIcon).exists()).toBe(true);
|
expect(diffNotesToggle.findComponent(GlIcon).exists()).toBe(true);
|
||||||
expect(diffNotesToggle.classes('diff-notes-collapse')).toBe(true);
|
expect(diffNotesToggle.classes('diff-notes-collapse')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -80,12 +80,12 @@ describe('DiffDiscussions', () => {
|
||||||
discussions[0].expanded = false;
|
discussions[0].expanded = false;
|
||||||
createComponent({ discussions, shouldCollapseDiscussions: true });
|
createComponent({ discussions, shouldCollapseDiscussions: true });
|
||||||
|
|
||||||
expect(wrapper.find(NoteableDiscussion).isVisible()).toBe(false);
|
expect(wrapper.findComponent(NoteableDiscussion).isVisible()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders badge on avatar', () => {
|
it('renders badge on avatar', () => {
|
||||||
createComponent({ renderAvatarBadge: true });
|
createComponent({ renderAvatarBadge: true });
|
||||||
const noteableDiscussion = wrapper.find(NoteableDiscussion);
|
const noteableDiscussion = wrapper.findComponent(NoteableDiscussion);
|
||||||
|
|
||||||
expect(noteableDiscussion.find('.design-note-pin').exists()).toBe(true);
|
expect(noteableDiscussion.find('.design-note-pin').exists()).toBe(true);
|
||||||
expect(noteableDiscussion.find('.design-note-pin').text().trim()).toBe('1');
|
expect(noteableDiscussion.find('.design-note-pin').text().trim()).toBe('1');
|
||||||
|
|
|
||||||
|
|
@ -76,18 +76,19 @@ describe('DiffFileHeader component', () => {
|
||||||
wrapper.destroy();
|
wrapper.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
const findHeader = () => wrapper.find({ ref: 'header' });
|
const findHeader = () => wrapper.findComponent({ ref: 'header' });
|
||||||
const findTitleLink = () => wrapper.find({ ref: 'titleWrapper' });
|
const findTitleLink = () => wrapper.findComponent({ ref: 'titleWrapper' });
|
||||||
const findExpandButton = () => wrapper.find({ ref: 'expandDiffToFullFileButton' });
|
const findExpandButton = () => wrapper.findComponent({ ref: 'expandDiffToFullFileButton' });
|
||||||
const findFileActions = () => wrapper.find('.file-actions');
|
const findFileActions = () => wrapper.find('.file-actions');
|
||||||
const findModeChangedLine = () => wrapper.find({ ref: 'fileMode' });
|
const findModeChangedLine = () => wrapper.findComponent({ ref: 'fileMode' });
|
||||||
const findLfsLabel = () => wrapper.find('[data-testid="label-lfs"]');
|
const findLfsLabel = () => wrapper.find('[data-testid="label-lfs"]');
|
||||||
const findToggleDiscussionsButton = () => wrapper.find({ ref: 'toggleDiscussionsButton' });
|
const findToggleDiscussionsButton = () =>
|
||||||
const findExternalLink = () => wrapper.find({ ref: 'externalLink' });
|
wrapper.findComponent({ ref: 'toggleDiscussionsButton' });
|
||||||
const findReplacedFileButton = () => wrapper.find({ ref: 'replacedFileButton' });
|
const findExternalLink = () => wrapper.findComponent({ ref: 'externalLink' });
|
||||||
const findViewFileButton = () => wrapper.find({ ref: 'viewButton' });
|
const findReplacedFileButton = () => wrapper.findComponent({ ref: 'replacedFileButton' });
|
||||||
const findCollapseIcon = () => wrapper.find({ ref: 'collapseIcon' });
|
const findViewFileButton = () => wrapper.findComponent({ ref: 'viewButton' });
|
||||||
const findEditButton = () => wrapper.find({ ref: 'editButton' });
|
const findCollapseIcon = () => wrapper.findComponent({ ref: 'collapseIcon' });
|
||||||
|
const findEditButton = () => wrapper.findComponent({ ref: 'editButton' });
|
||||||
const findReviewFileCheckbox = () => wrapper.find("[data-testid='fileReviewCheckbox']");
|
const findReviewFileCheckbox = () => wrapper.find("[data-testid='fileReviewCheckbox']");
|
||||||
|
|
||||||
const createComponent = ({ props, options = {} } = {}) => {
|
const createComponent = ({ props, options = {} } = {}) => {
|
||||||
|
|
@ -153,7 +154,7 @@ describe('DiffFileHeader component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays a copy to clipboard button', () => {
|
it('displays a copy to clipboard button', () => {
|
||||||
expect(wrapper.find(ClipboardButton).exists()).toBe(true);
|
expect(wrapper.findComponent(ClipboardButton).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers the copy to clipboard tracking event', () => {
|
it('triggers the copy to clipboard tracking event', () => {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue